Jump to content

Need Help With Scrip Error


Recommended Posts

Need Help Reviewing some script, can't detect error: 

Error [mod0000_mergedfiles]game\player\playerwitcher.ws(10844): Unexpected end of file found after '{' at line 11
Error [mod0000_mergedfiles]game\player\r4player.ws(14519): Unexpected end of file found after '{' at line 2 
 
[spoiler]Playwitcher:
/***********************************************************************/
/** © 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.
/***********************************************************************/




statemachine class W3PlayerWitcher extends CR4Player
{

private saved var craftingSchematics : array;


private saved var alchemyRecipes : array;
// -= WMK:modAQOOM =-
public saved var wmkMapMenuData : WmkMapMenuData;
public var wmkMapMenu : WmkMapMenuEx;
// -= WMK:modAQOOM =-


private saved var booksRead : array;


private var fastAttackCounter, heavyAttackCounter : int;
private var isInFrenzy : bool;
private var hasRecentlyCountered : bool;
private saved var cannotUseUndyingSkill : bool;


protected saved var amountOfSetPiecesEquipped : array;


public var canSwitchFocusModeTarget : bool;
protected var switchFocusModeTargetAllowed : bool;
default canSwitchFocusModeTarget = true;
default switchFocusModeTargetAllowed = true;


private editable var signs : array< SWitcherSign >;
private saved var equippedSign : ESignType;
private var currentlyCastSign : ESignType; default currentlyCastSign = ST_None;
private var signOwner : W3SignOwnerPlayer;
private var usedQuenInCombat : bool;
public var yrdenEntities : array;
public saved var m_quenReappliedCount : int;

default equippedSign = ST_Aard;
default m_quenReappliedCount = 1;



private var bDispalyHeavyAttackIndicator : bool;
private var bDisplayHeavyAttackFirstLevelTimer : bool;
public var specialAttackHeavyAllowed : bool;

default bIsCombatActionAllowed = true;
default bDispalyHeavyAttackIndicator = false;
default bDisplayHeavyAttackFirstLevelTimer = true;



default explorationInputContext = 'Exploration';
default combatInputContext = 'Combat';
default combatFistsInputContext = 'Combat';


private saved var companionNPCTag : name;
private saved var companionNPCTag2 : name;

private saved var companionNPCIconPath : string;
private saved var companionNPCIconPath2 : string;


private saved var itemSlots : array;
private var remainingBombThrowDelaySlot1 : float;
private var remainingBombThrowDelaySlot2 : float;
private var previouslyUsedBolt : SItemUniqueId;
private saved var questMarkedSelectedQuickslotItems : array< SSelectedQuickslotItem >;

default isThrowingItem = false;
default remainingBombThrowDelaySlot1 = 0.f;
default remainingBombThrowDelaySlot2 = 0.f;





private saved var tempLearnedSignSkills : array;
public saved var autoLevel : bool;




protected saved var skillBonusPotionEffect : CBaseGameplayEffect;


public saved var levelManager : W3LevelManager;


saved var reputationManager : W3Reputation;


private editable var medallionEntity : CEntityTemplate;
private var medallionController : W3MedallionController;




public var bShowRadialMenu : bool;

private var _HoldBeforeOpenRadialMenuTime : float;

default _HoldBeforeOpenRadialMenuTime = 0.5f;

public var MappinToHighlight : array;


protected saved var horseManagerHandle : EntityHandle;


private var isInitialized : bool;
private var timeForPerk21 : float;

default isInitialized = false;


private var invUpdateTransaction : bool;
default invUpdateTransaction = false;












event OnSpawned( spawnData : SEntitySpawnData )
{
var i : int;
var items : array;
var items2 : array;
var horseTemplate : CEntityTemplate;
var horseManager : W3HorseManager;

AddAnimEventCallback( 'ActionBlend', 'OnAnimEvent_ActionBlend' );
AddAnimEventCallback('cast_begin', 'OnAnimEvent_Sign');
AddAnimEventCallback('cast_throw', 'OnAnimEvent_Sign');
AddAnimEventCallback('cast_end', 'OnAnimEvent_Sign');
AddAnimEventCallback('cast_friendly_begin', 'OnAnimEvent_Sign');
AddAnimEventCallback('cast_friendly_throw', 'OnAnimEvent_Sign');
AddAnimEventCallback('axii_ready', 'OnAnimEvent_Sign');
AddAnimEventCallback('axii_alternate_ready', 'OnAnimEvent_Sign');
AddAnimEventCallback('yrden_draw_ready', 'OnAnimEvent_Sign');

AddAnimEventCallback( 'ProjectileThrow', 'OnAnimEvent_Throwable' );
AddAnimEventCallback( 'OnWeaponReload', 'OnAnimEvent_Throwable' );
AddAnimEventCallback( 'ProjectileAttach', 'OnAnimEvent_Throwable' );
AddAnimEventCallback( 'Mutation11AnimEnd', 'OnAnimEvent_Mutation11AnimEnd' );
AddAnimEventCallback( 'Mutation11ShockWave', 'OnAnimEvent_Mutation11ShockWave' );



amountOfSetPiecesEquipped.Resize( EnumGetMax( 'EItemSetType' ) + 1 );

runewordInfusionType = ST_None;


inv = GetInventory();


signOwner = new W3SignOwnerPlayer in this;
signOwner.Init( this );

itemSlots.Resize( EnumGetMax('EEquipmentSlots')+1 );

if(!spawnData.restored)
{
levelManager = new W3LevelManager in this;
levelManager.Initialize();


inv.GetAllItems(items);
for(i=0; i {
if(inv.IsItemMounted(items[i]) && ( !inv.IsItemBody(items[i]) || inv.GetItemCategory(items[i]) == 'hair' ) )
EquipItem(items[i]);
}





AddAlchemyRecipe('Recipe for Swallow 1',true,true);
AddAlchemyRecipe('Recipe for Cat 1',true,true);
AddAlchemyRecipe('Recipe for White Honey 1',true,true);

AddAlchemyRecipe('Recipe for Samum 1',true,true);
AddAlchemyRecipe('Recipe for Grapeshot 1',true,true);

AddAlchemyRecipe('Recipe for Specter Oil 1',true,true);
AddAlchemyRecipe('Recipe for Necrophage Oil 1',true,true);
AddAlchemyRecipe('Recipe for Alcohest 1',true,true);
}
else
{
AddTimer('DelayedOnItemMount', 0.1, true);


CheckHairItem();
}


AddStartingSchematics();

super.OnSpawned( spawnData );


AddAlchemyRecipe('Recipe for Mutagen red',true,true);
AddAlchemyRecipe('Recipe for Mutagen green',true,true);
AddAlchemyRecipe('Recipe for Mutagen blue',true,true);
AddAlchemyRecipe('Recipe for Greater mutagen red',true,true);
AddAlchemyRecipe('Recipe for Greater mutagen green',true,true);
AddAlchemyRecipe('Recipe for Greater mutagen blue',true,true);

AddCraftingSchematic('Starting Armor Upgrade schematic 1',true,true);


if( inputHandler )
{
inputHandler.BlockAllActions( 'being_ciri', false );
}
SetBehaviorVariable( 'test_ciri_replacer', 0.0f);

if(!spawnData.restored)
{

abilityManager.GainStat(BCS_Toxicity, 0);
}

levelManager.PostInit(this, spawnData.restored, true);

SetBIsCombatActionAllowed( true );
SetBIsInputAllowed( true, 'OnSpawned' );


if ( !reputationManager )
{
reputationManager = new W3Reputation in this;
reputationManager.Initialize();
}

theSound.SoundParameter( "focus_aim", 1.0f, 1.0f );
theSound.SoundParameter( "focus_distance", 0.0f, 1.0f );






currentlyCastSign = ST_None;


if(!spawnData.restored)
{
horseTemplate = (CEntityTemplate)LoadResource("horse_manager");
horseManager = (W3HorseManager)theGame.CreateEntity(horseTemplate, GetWorldPosition(),,,,,PM_Persist);
horseManager.CreateAttachment(this);
horseManager.OnCreated();
EntityHandleSet( horseManagerHandle, horseManager );
}
else
{
AddTimer('DelayedHorseUpdate', 0.01, true);
}


RemoveAbility('Ciri_CombatRegen');
RemoveAbility('Ciri_Rage');
RemoveAbility('CiriBlink');
RemoveAbility('CiriCharge');
RemoveAbility('Ciri_Q205');
RemoveAbility('Ciri_Q305');
RemoveAbility('Ciri_Q403');
RemoveAbility('Ciri_Q111');
RemoveAbility('Ciri_Q501');
RemoveAbility('SkillCiri');

if(spawnData.restored)
{
RestoreQuen(savedQuenHealth, savedQuenDuration);
}
else
{
savedQuenHealth = 0.f;
savedQuenDuration = 0.f;
}

if(spawnData.restored)
{
ApplyPatchFixes();
}
else
{

FactsAdd( "new_game_started_in_1_20" );
}

if ( FactsQuerySum("NewGamePlus") > 0 )
{
NewGamePlusAdjustDLC1TemerianSet(inv);
NewGamePlusAdjustDLC5NilfgardianSet(inv);
NewGamePlusAdjustDLC10WolfSet(inv);
NewGamePlusAdjustDLC14SkelligeSet(inv);
if(horseManager)
{
NewGamePlusAdjustDLC1TemerianSet(horseManager.GetInventoryComponent());
NewGamePlusAdjustDLC5NilfgardianSet(horseManager.GetInventoryComponent());
NewGamePlusAdjustDLC10WolfSet(horseManager.GetInventoryComponent());
NewGamePlusAdjustDLC14SkelligeSet(horseManager.GetInventoryComponent());
}
}


ResumeStaminaRegen('WhirlSkill');

if(HasAbility('Runeword 4 _Stats', true))
StartVitalityRegen();


if(HasAbility('sword_s19'))
{
RemoveTemporarySkills();
}

inv = thePlayer.GetInventory();
inv.GetAllItems(items); // Leveling Starting Armor
for(i=0; i {
if( thePlayer.inv.ItemHasTag(items[i], 'ArmorMod') || thePlayer.inv.ItemHasTag(items[i], 'dlcModArmor') ) // Only ArmorMod items in your inventory
{
thePlayer.GetInventory().GetItemLevel(items[i]); // Makes sure the Item Level is Re-Set on level up
thePlayer.GetInventory().GetItemArmorTotal(items[i], true); // Makes sure the Item Armor is Re-Set on level up
} // End
}
HACK_UnequipWolfLiver();


if( HasBuff( EET_GryphonSetBonusYrden ) )
{
RemoveBuff( EET_GryphonSetBonusYrden, false, "GryphonSetBonusYrden" );
}

if( spawnData.restored )
{

UpdateEncumbrance();


RemoveBuff( EET_Mutation11Immortal );
}

isInitialized = true;
}





private function HACK_UnequipWolfLiver()
{
var itemName1, itemName2, itemName3, itemName4 : name;
var item1, item2, item3, item4 : SItemUniqueId;

GetItemEquippedOnSlot( EES_Potion1, item1 );
GetItemEquippedOnSlot( EES_Potion2, item2 );
GetItemEquippedOnSlot( EES_Potion3, item3 );
GetItemEquippedOnSlot( EES_Potion4, item4 );

if ( inv.IsIdValid( item1 ) )
itemName1 = inv.GetItemName( item1 );
if ( inv.IsIdValid( item2 ) )
itemName2 = inv.GetItemName( item2 );
if ( inv.IsIdValid( item3 ) )
itemName3 = inv.GetItemName( item3 );
if ( inv.IsIdValid( item4 ) )
itemName4 = inv.GetItemName( item4 );

if ( itemName1 == 'Wolf liver' || itemName3 == 'Wolf liver' )
{
if ( inv.IsIdValid( item1 ) )
UnequipItem( item1 );
if ( inv.IsIdValid( item3 ) )
UnequipItem( item3 );
}
else if ( itemName2 == 'Wolf liver' || itemName4 == 'Wolf liver' )
{
if ( inv.IsIdValid( item2 ) )
UnequipItem( item2 );
if ( inv.IsIdValid( item4 ) )
UnequipItem( item4 );
}
}





timer function DelayedHorseUpdate( dt : float, id : int )
{
var man : W3HorseManager;

man = GetHorseManager();
if(man)
{
if ( man.ApplyHorseUpdateOnSpawn() )
{

UpdateEncumbrance();

RemoveTimer( 'DelayedHorseUpdate' );
}
}
}

event OnAbilityAdded( abilityName : name)
{
super.OnAbilityAdded(abilityName);

if( HasAbility('Runeword 4 _Stats', true) )
{
StartVitalityRegen();
}

if ( abilityName == 'Runeword 8 _Stats' && GetStat(BCS_Focus, true) >= GetStatMax(BCS_Focus) && !HasBuff(EET_Runeword8) )
{
AddEffectDefault(EET_Runeword8, this, "equipped item");
}

}

private final function AddStartingSchematics()
{
AddCraftingSchematic('Starting Armor Upgrade schematic 1', true,true);
AddCraftingSchematic('Thread schematic', true, true);
AddCraftingSchematic('String schematic', true, true);
AddCraftingSchematic('Linen schematic', true, true);
AddCraftingSchematic('Silk schematic', true, true);
AddCraftingSchematic('Resin schematic', true, true);
AddCraftingSchematic('Blasting powder schematic', true, true);
AddCraftingSchematic('Haft schematic', true, true);
AddCraftingSchematic('Hardened timber schematic', true, true);
AddCraftingSchematic('Leather squares schematic', true, true);
AddCraftingSchematic('Leather schematic', true, true);
AddCraftingSchematic('Hardened leather schematic', true, true);
AddCraftingSchematic('Draconide leather schematic', true, true);
AddCraftingSchematic('Iron ingot schematic', true, true);
AddCraftingSchematic('Steel ingot schematic', true, true);
AddCraftingSchematic('Steel ingot schematic 1', true, true);
AddCraftingSchematic('Steel plate schematic', true, true);
AddCraftingSchematic('Dark iron ingot schematic', true, true);
AddCraftingSchematic('Dark iron plate schematic', true, true);
AddCraftingSchematic('Dark steel ingot schematic', true, true);
AddCraftingSchematic('Dark steel ingot schematic 1', true, true);
AddCraftingSchematic('Dark steel plate schematic', true, true);
AddCraftingSchematic('Silver ore schematic', true, true);
AddCraftingSchematic('Silver ingot schematic', true, true);
AddCraftingSchematic('Silver ingot schematic 1', true, true);
AddCraftingSchematic('Silver plate schematic', true, true);
AddCraftingSchematic('Meteorite ingot schematic', true, true);
AddCraftingSchematic('Meteorite silver ingot schematic', true, true);
AddCraftingSchematic('Meteorite silver plate schematic', true, true);
AddCraftingSchematic('Glowing ingot schematic', true, true);
AddCraftingSchematic('Dwimeryte ore schematic', true, true);
AddCraftingSchematic('Dwimeryte ingot schematic', true, true);
AddCraftingSchematic('Dwimeryte ingot schematic 1', true, true);
AddCraftingSchematic('Dwimeryte plate schematic', true, true);
AddCraftingSchematic('Infused dust schematic', true, true);
AddCraftingSchematic('Infused shard schematic', true, true);
AddCraftingSchematic('Infused crystal schematic', true, true);

if ( theGame.GetDLCManager().IsEP2Available() )
{
AddCraftingSchematic('Draconide infused leather schematic', true, true);
AddCraftingSchematic('Nickel ore schematic', true, true);
AddCraftingSchematic('Cupronickel ore schematic', true, true);
AddCraftingSchematic('Copper ore schematic', true, true);
AddCraftingSchematic('Copper ingot schematic', true, true);
AddCraftingSchematic('Copper plate schematic', true, true);
AddCraftingSchematic('Green gold ore schematic', true, true);
AddCraftingSchematic('Green gold ore schematic 1', true, true);
AddCraftingSchematic('Green gold ingot schematic', true, true);
AddCraftingSchematic('Green gold plate schematic', true, true);
AddCraftingSchematic('Orichalcum ore schematic', true, true);
AddCraftingSchematic('Orichalcum ore schematic 1', true, true);
AddCraftingSchematic('Orichalcum ingot schematic', true, true);
AddCraftingSchematic('Orichalcum plate schematic', true, true);
AddCraftingSchematic('Dwimeryte enriched ore schematic', true, true);
AddCraftingSchematic('Dwimeryte enriched ingot schematic', true, true);
AddCraftingSchematic('Dwimeryte enriched plate schematic', true, true);
}
}

private final function ApplyPatchFixes()
{
var cnt, transmutationCount, mutagenCount, i : int;
var transmutationAbility, itemName : name;
var pam : W3PlayerAbilityManager;
var slotId : int;
var offset : float;
var buffs : array;
var mutagen : W3Mutagen_Effect;
var skill : SSimpleSkill;
var spentSkillPoints, swordSkillPointsSpent, alchemySkillPointsSpent, perkSkillPointsSpent, pointsToAdd : int;
var mutagens : array< W3Mutagen_Effect >;

if(FactsQuerySum("ClearingPotionPassiveBonusFix") < 1)
{
pam = (W3PlayerAbilityManager)abilityManager;

cnt = GetAbilityCount('sword_adrenalinegain') - pam.GetPathPointsSpent(ESP_Sword);
if(cnt > 0)
RemoveAbilityMultiple('sword_adrenalinegain', cnt);

cnt = GetAbilityCount('magic_staminaregen') - pam.GetPathPointsSpent(ESP_Signs);
if(cnt > 0)
RemoveAbilityMultiple('magic_staminaregen', cnt);

cnt = GetAbilityCount('alchemy_potionduration') - pam.GetPathPointsSpent(ESP_Alchemy);
if(cnt > 0)
RemoveAbilityMultiple('alchemy_potionduration', cnt);

FactsAdd("ClearingPotionPassiveBonusFix");
}


if(FactsQuerySum("DimeritiumSynergyFix") < 1)
{
slotId = GetSkillSlotID(S_Alchemy_s19);
if(slotId != -1)
UnequipSkill(S_Alchemy_s19);

RemoveAbilityAll('greater_mutagen_color_green_synergy_bonus');
RemoveAbilityAll('mutagen_color_green_synergy_bonus');
RemoveAbilityAll('mutagen_color_lesser_green_synergy_bonus');

RemoveAbilityAll('greater_mutagen_color_blue_synergy_bonus');
RemoveAbilityAll('mutagen_color_blue_synergy_bonus');
RemoveAbilityAll('mutagen_color_lesser_blue_synergy_bonus');

RemoveAbilityAll('greater_mutagen_color_red_synergy_bonus');
RemoveAbilityAll('mutagen_color_red_synergy_bonus');
RemoveAbilityAll('mutagen_color_lesser_red_synergy_bonus');

if(slotId != -1)
EquipSkill(S_Alchemy_s19, slotId);

FactsAdd("DimeritiumSynergyFix");
}


if(FactsQuerySum("DontShowRecipePinTut") < 1)
{
FactsAdd( "DontShowRecipePinTut" );
TutorialScript('alchemyRecipePin', '');
TutorialScript('craftingRecipePin', '');
}


if(FactsQuerySum("LevelReqPotGiven") < 1)
{
FactsAdd("LevelReqPotGiven");
inv.AddAnItem('Wolf Hour', 1, false, false, true);
}


if(!HasBuff(EET_AutoStaminaRegen))
{
AddEffectDefault(EET_AutoStaminaRegen, this, 'autobuff', false);
}



buffs = GetBuffs();
offset = 0;
mutagenCount = 0;
for(i=0; i {
mutagen = (W3Mutagen_Effect)buffs[i];
if(mutagen)
{
offset += mutagen.GetToxicityOffset();
mutagenCount += 1;
}
}


if(offset != (GetStat(BCS_Toxicity) - GetStat(BCS_Toxicity, true)))
SetToxicityOffset(offset);


mutagenCount *= GetSkillLevel(S_Alchemy_s13);
transmutationAbility = GetSkillAbilityName(S_Alchemy_s13);
transmutationCount = GetAbilityCount(transmutationAbility);
if(mutagenCount < transmutationCount)
{
RemoveAbilityMultiple(transmutationAbility, transmutationCount - mutagenCount);
}
else if(mutagenCount > transmutationCount)
{
AddAbilityMultiple(transmutationAbility, mutagenCount - transmutationCount);
}


if(theGame.GetDLCManager().IsEP1Available())
{
theGame.GetJournalManager().ActivateEntryByScriptTag('TutorialJournalEnchanting', JS_Active);
}


if(HasAbility('sword_s19') && FactsQuerySum("Patch_Sword_s19") < 1)
{
pam = (W3PlayerAbilityManager)abilityManager;


skill.level = 0;
for(i = S_Magic_s01; i <= S_Magic_s20; i+=1)
{
skill.skillType = i;
pam.RemoveTemporarySkill(skill);
}


spentSkillPoints = levelManager.GetPointsUsed(ESkillPoint);
swordSkillPointsSpent = pam.GetPathPointsSpent(ESP_Sword);
alchemySkillPointsSpent = pam.GetPathPointsSpent(ESP_Alchemy);
perkSkillPointsSpent = pam.GetPathPointsSpent(ESP_Perks);

pointsToAdd = spentSkillPoints - swordSkillPointsSpent - alchemySkillPointsSpent - perkSkillPointsSpent;
if(pointsToAdd > 0)
levelManager.UnspendPoints(ESkillPoint, pointsToAdd);


RemoveAbilityAll('sword_s19');


FactsAdd("Patch_Sword_s19");
}


if( HasAbility( 'sword_s19' ) )
{
RemoveAbilityAll( 'sword_s19' );
}


if(FactsQuerySum("Patch_Armor_Type_Glyphwords") < 1)
{
pam = (W3PlayerAbilityManager)abilityManager;

pam.SetPerkArmorBonus( S_Perk_05, this );
pam.SetPerkArmorBonus( S_Perk_06, this );
pam.SetPerkArmorBonus( S_Perk_07, this );

FactsAdd("Patch_Armor_Type_Glyphwords");
}
else if( FactsQuerySum("154999") < 1 )
{

pam = (W3PlayerAbilityManager)abilityManager;

pam.SetPerkArmorBonus( S_Perk_05, this );
pam.SetPerkArmorBonus( S_Perk_06, this );
pam.SetPerkArmorBonus( S_Perk_07, this );

FactsAdd("154999");
}

if( FactsQuerySum( "Patch_Decoction_Buff_Icons" ) < 1 )
{
mutagens = GetMutagenBuffs();
for( i=0; i {
itemName = DecoctionEffectTypeToItemName( mutagens[i].GetEffectType() );
mutagens[i].OverrideIcon( itemName );
}

FactsAdd( "Patch_Decoction_Buff_Icons" );
}
}

public final function RestoreQuen( quenHealth : float, quenDuration : float, optional alternate : bool ) : bool
{
var restoredQuen : W3QuenEntity;

if(quenHealth > 0.f && quenDuration >= 3.f)
{
restoredQuen = (W3QuenEntity)theGame.CreateEntity( signs[ST_Quen].template, GetWorldPosition(), GetWorldRotation() );
restoredQuen.Init( signOwner, signs[ST_Quen].entity, true );

if( alternate )
{
restoredQuen.SetAlternateCast( S_Magic_s04 );
}

restoredQuen.OnStarted();
restoredQuen.OnThrowing();

if( !alternate )
{
restoredQuen.OnEnded();
}

restoredQuen.SetDataFromRestore(quenHealth, quenDuration);

return true;
}

return false;
}

public function IsInitialized() : bool
{
return isInitialized;
}

private function NewGamePlusInitialize()
{
var questItems : array;
var horseManager : W3HorseManager;
var horseInventory : CInventoryComponent;
var i, missingLevels, expDiff : int;

super.NewGamePlusInitialize();


horseManager = (W3HorseManager)EntityHandleGet(horseManagerHandle);
if(horseManager)
horseInventory = horseManager.GetInventoryComponent();


theGame.params.SetNewGamePlusLevel(GetLevel());


if (theGame.GetDLCManager().IsDLCAvailable('ep1'))
missingLevels = theGame.params.NEW_GAME_PLUS_EP1_MIN_LEVEL - GetLevel();
else
missingLevels = theGame.params.NEW_GAME_PLUS_MIN_LEVEL - GetLevel();

for(i=0; i {

expDiff = levelManager.GetTotalExpForNextLevel() - levelManager.GetPointsTotal(EExperiencePoint);
expDiff = CeilF( ((float)expDiff) / 2 );
AddPoints(EExperiencePoint, expDiff, false);
}





inv.RemoveItemByTag('Quest', -1);
horseInventory.RemoveItemByTag('Quest', -1);



questItems = theGame.GetDefinitionsManager().GetItemsWithTag('Quest');
for(i=0; i {
inv.RemoveItemByName(questItems[i], -1);
horseInventory.RemoveItemByName(questItems[i], -1);
}


inv.RemoveItemByName('mq1002_artifact_3', -1);
horseInventory.RemoveItemByName('mq1002_artifact_3', -1);


inv.RemoveItemByTag('NotTransferableToNGP', -1);
horseInventory.RemoveItemByTag('NotTransferableToNGP', -1);


inv.RemoveItemByTag('NoticeBoardNote', -1);
horseInventory.RemoveItemByTag('NoticeBoardNote', -1);


RemoveAllNonAutoBuffs();


RemoveAlchemyRecipe('Recipe for Trial Potion Kit');
RemoveAlchemyRecipe('Recipe for Pops Antidote');
RemoveAlchemyRecipe('Recipe for Czart Lure');
RemoveAlchemyRecipe('q603_diarrhea_potion_recipe');


inv.RemoveItemByTag('Trophy', -1);
horseInventory.RemoveItemByTag('Trophy', -1);


inv.RemoveItemByCategory('usable', -1);
horseInventory.RemoveItemByCategory('usable', -1);


RemoveAbility('StaminaTutorialProlog');
RemoveAbility('TutorialStaminaRegenHack');
RemoveAbility('area_novigrad');
RemoveAbility('NoRegenEffect');
RemoveAbility('HeavySwimmingStaminaDrain');
RemoveAbility('AirBoost');
RemoveAbility('area_nml');
RemoveAbility('area_skellige');


inv.RemoveItemByTag('GwintCard', -1);
horseInventory.RemoveItemByTag('GwintCard', -1);



inv.RemoveItemByTag('ReadableItem', -1);
horseInventory.RemoveItemByTag('ReadableItem', -1);


abilityManager.RestoreStats();


((W3PlayerAbilityManager)abilityManager).RemoveToxicityOffset(10000);


GetInventory().SingletonItemsRefillAmmo();


craftingSchematics.Clear();
AddStartingSchematics();


for( i=0; i {
amountOfSetPiecesEquipped[i] = 0;
}


inv.AddAnItem('Clearing Potion', 1, true, false, false);


inv.RemoveItemByName('q203_broken_eyeofloki', -1);
horseInventory.RemoveItemByName('q203_broken_eyeofloki', -1);


NewGamePlusReplaceViperSet(inv);
NewGamePlusReplaceViperSet(horseInventory);
NewGamePlusReplaceLynxSet(inv);
NewGamePlusReplaceLynxSet(horseInventory);
NewGamePlusReplaceGryphonSet(inv);
NewGamePlusReplaceGryphonSet(horseInventory);
NewGamePlusReplaceBearSet(inv);
NewGamePlusReplaceBearSet(horseInventory);
NewGamePlusReplaceEP1(inv);
NewGamePlusReplaceEP1(horseInventory);
NewGamePlusReplaceEP2WitcherSets(inv);
NewGamePlusReplaceEP2WitcherSets(horseInventory);
NewGamePlusReplaceEP2Items(inv);
NewGamePlusReplaceEP2Items(horseInventory);
NewGamePlusMarkItemsToNotAdjust(inv);
NewGamePlusMarkItemsToNotAdjust(horseInventory);


inputHandler.ClearLocksForNGP();


buffImmunities.Clear();
buffRemovedImmunities.Clear();

newGamePlusInitialized = true;


m_quenReappliedCount = 1;
}

private final function NewGamePlusMarkItemsToNotAdjust(out inv : CInventoryComponent)
{
var ids : array;
var i : int;
var n : name;

inv.GetAllItems(ids);
for( i=0; i {
inv.SetItemModifierInt(ids[i], 'NGPItemAdjusted', 1);
}
}

private final function NewGamePlusReplaceItem( item : name, new_item : name, out inv : CInventoryComponent)
{
var i, j : int;
var ids, new_ids, enh_ids : array;
var dye_ids : array;
var enh : array;
var wasEquipped : bool;
var wasEnchanted : bool;
var wasDyed : bool;
var enchantName, colorName : name;

if ( inv.HasItem( item ) )
{
ids = inv.GetItemsIds(item);
for (i = 0; i < ids.Size(); i += 1)
{
inv.GetItemEnhancementItems( ids[i], enh );
wasEnchanted = inv.IsItemEnchanted( ids[i] );
if ( wasEnchanted )
enchantName = inv.GetEnchantment( ids[i] );
wasEquipped = IsItemEquipped( ids[i] );
wasDyed = inv.IsItemColored( ids[i] );
if ( wasDyed )
{
colorName = inv.GetItemColor( ids[i] );
}

inv.RemoveItem( ids[i], 1 );
new_ids = inv.AddAnItem( new_item, 1, true, true, false );
if ( wasEquipped )
{
EquipItem( new_ids[0] );
}
if ( wasEnchanted )
{
inv.EnchantItem( new_ids[0], enchantName, getEnchamtmentStatName(enchantName) );
}
for (j = 0; j < enh.Size(); j += 1)
{
enh_ids = inv.AddAnItem( enh[j], 1, true, true, false );
inv.EnhanceItemScript( new_ids[0], enh_ids[0] );
}
if ( wasDyed )
{
dye_ids = inv.AddAnItem( colorName, 1, true, true, false );
inv.ColorItem( new_ids[0], dye_ids[0] );
inv.RemoveItem( dye_ids[0], 1 );
}

inv.SetItemModifierInt( new_ids[0], 'NGPItemAdjusted', 1 );
}
}
}

private final function NewGamePlusAdjustDLCItem(item : name, mod : name, inv : CInventoryComponent)
{
var ids : array;
var i : int;

if( inv.HasItem(item) )
{
ids = inv.GetItemsIds(item);
for (i = 0; i < ids.Size(); i += 1)
{
if ( inv.GetItemModifierInt(ids[i], 'DoNotAdjustNGPDLC') <= 0 )
{
inv.AddItemBaseAbility(ids[i], mod);
inv.SetItemModifierInt(ids[i], 'DoNotAdjustNGPDLC', 1);
}
}
}

}

private final function NewGamePlusAdjustDLC1TemerianSet(inv : CInventoryComponent)
{
NewGamePlusAdjustDLCItem('NGP DLC1 Temerian Armor', 'NGP DLC Compatibility Chest Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP DLC1 Temerian Gloves', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP DLC1 Temerian Pants', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP DLC1 Temerian Boots', 'NGP DLC Compatibility Armor Mod', inv);
}

private final function NewGamePlusAdjustDLC5NilfgardianSet(inv : CInventoryComponent)
{
NewGamePlusAdjustDLCItem('NGP DLC5 Nilfgaardian Armor', 'NGP DLC Compatibility Chest Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP DLC5 Nilfgaardian Gloves', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP DLC5 Nilfgaardian Pants', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP DLC5 Nilfgaardian Boots', 'NGP DLC Compatibility Armor Mod', inv);
}

private final function NewGamePlusAdjustDLC10WolfSet(inv : CInventoryComponent)
{
NewGamePlusAdjustDLCItem('NGP Wolf Armor', 'NGP DLC Compatibility Chest Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Armor 1', 'NGP DLC Compatibility Chest Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Armor 2', 'NGP DLC Compatibility Chest Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Armor 3', 'NGP DLC Compatibility Chest Armor Mod', inv);

NewGamePlusAdjustDLCItem('NGP Wolf Boots 1', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Boots 2', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Boots 3', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Boots 4', 'NGP DLC Compatibility Armor Mod', inv);

NewGamePlusAdjustDLCItem('NGP Wolf Gloves 1', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Gloves 2', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Gloves 3', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Gloves 4', 'NGP DLC Compatibility Armor Mod', inv);

NewGamePlusAdjustDLCItem('NGP Wolf Pants 1', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Pants 2', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Pants 3', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf Pants 4', 'NGP DLC Compatibility Armor Mod', inv);

NewGamePlusAdjustDLCItem('NGP Wolf School steel sword', 'NGP Wolf Steel Sword Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf School steel sword 1', 'NGP Wolf Steel Sword Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf School steel sword 2', 'NGP Wolf Steel Sword Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf School steel sword 3', 'NGP Wolf Steel Sword Mod', inv);

NewGamePlusAdjustDLCItem('NGP Wolf School silver sword', 'NGP Wolf Silver Sword Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf School silver sword 1', 'NGP Wolf Silver Sword Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf School silver sword 2', 'NGP Wolf Silver Sword Mod', inv);
NewGamePlusAdjustDLCItem('NGP Wolf School silver sword 3', 'NGP Wolf Silver Sword Mod', inv);
}

private final function NewGamePlusAdjustDLC14SkelligeSet(inv : CInventoryComponent)
{
NewGamePlusAdjustDLCItem('NGP DLC14 Skellige Armor', 'NGP DLC Compatibility Chest Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP DLC14 Skellige Gloves', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP DLC14 Skellige Pants', 'NGP DLC Compatibility Armor Mod', inv);
NewGamePlusAdjustDLCItem('NGP DLC14 Skellige Boots', 'NGP DLC Compatibility Armor Mod', inv);
}

private final function NewGamePlusReplaceViperSet(out inv : CInventoryComponent)
{
NewGamePlusReplaceItem('Viper School steel sword', 'NGP Viper School steel sword', inv);

NewGamePlusReplaceItem('Viper School silver sword', 'NGP Viper School silver sword', inv);
}

private final function NewGamePlusReplaceLynxSet(out inv : CInventoryComponent)
{
NewGamePlusReplaceItem('Lynx Armor', 'NGP Lynx Armor', inv);
NewGamePlusReplaceItem('Lynx Armor 1', 'NGP Lynx Armor 1', inv);
NewGamePlusReplaceItem('Lynx Armor 2', 'NGP Lynx Armor 2', inv);
NewGamePlusReplaceItem('Lynx Armor 3', 'NGP Lynx Armor 3', inv);

NewGamePlusReplaceItem('Lynx Gloves 1', 'NGP Lynx Gloves 1', inv);
NewGamePlusReplaceItem('Lynx Gloves 2', 'NGP Lynx Gloves 2', inv);
NewGamePlusReplaceItem('Lynx Gloves 3', 'NGP Lynx Gloves 3', inv);
NewGamePlusReplaceItem('Lynx Gloves 4', 'NGP Lynx Gloves 4', inv);

NewGamePlusReplaceItem('Lynx Pants 1', 'NGP Lynx Pants 1', inv);
NewGamePlusReplaceItem('Lynx Pants 2', 'NGP Lynx Pants 2', inv);
NewGamePlusReplaceItem('Lynx Pants 3', 'NGP Lynx Pants 3', inv);
NewGamePlusReplaceItem('Lynx Pants 4', 'NGP Lynx Pants 4', inv);

NewGamePlusReplaceItem('Lynx Boots 1', 'NGP Lynx Boots 1', inv);
NewGamePlusReplaceItem('Lynx Boots 2', 'NGP Lynx Boots 2', inv);
NewGamePlusReplaceItem('Lynx Boots 3', 'NGP Lynx Boots 3', inv);
NewGamePlusReplaceItem('Lynx Boots 4', 'NGP Lynx Boots 4', inv);

NewGamePlusReplaceItem('Lynx School steel sword', 'NGP Lynx School steel sword', inv);
NewGamePlusReplaceItem('Lynx School steel sword 1', 'NGP Lynx School steel sword 1', inv);
NewGamePlusReplaceItem('Lynx School steel sword 2', 'NGP Lynx School steel sword 2', inv);
NewGamePlusReplaceItem('Lynx School steel sword 3', 'NGP Lynx School steel sword 3', inv);

NewGamePlusReplaceItem('Lynx School silver sword', 'NGP Lynx School silver sword', inv);
NewGamePlusReplaceItem('Lynx School silver sword 1', 'NGP Lynx School silver sword 1', inv);
NewGamePlusReplaceItem('Lynx School silver sword 2', 'NGP Lynx School silver sword 2', inv);
NewGamePlusReplaceItem('Lynx School silver sword 3', 'NGP Lynx School silver sword 3', inv);
}

private final function NewGamePlusReplaceGryphonSet(out inv : CInventoryComponent)
{
NewGamePlusReplaceItem('Gryphon Armor', 'NGP Gryphon Armor', inv);
NewGamePlusReplaceItem('Gryphon Armor 1', 'NGP Gryphon Armor 1', inv);
NewGamePlusReplaceItem('Gryphon Armor 2', 'NGP Gryphon Armor 2', inv);
NewGamePlusReplaceItem('Gryphon Armor 3', 'NGP Gryphon Armor 3', inv);

NewGamePlusReplaceItem('Gryphon Gloves 1', 'NGP Gryphon Gloves 1', inv);
NewGamePlusReplaceItem('Gryphon Gloves 2', 'NGP Gryphon Gloves 2', inv);
NewGamePlusReplaceItem('Gryphon Gloves 3', 'NGP Gryphon Gloves 3', inv);
NewGamePlusReplaceItem('Gryphon Gloves 4', 'NGP Gryphon Gloves 4', inv);

NewGamePlusReplaceItem('Gryphon Pants 1', 'NGP Gryphon Pants 1', inv);
NewGamePlusReplaceItem('Gryphon Pants 2', 'NGP Gryphon Pants 2', inv);
NewGamePlusReplaceItem('Gryphon Pants 3', 'NGP Gryphon Pants 3', inv);
NewGamePlusReplaceItem('Gryphon Pants 4', 'NGP Gryphon Pants 4', inv);

NewGamePlusReplaceItem('Gryphon Boots 1', 'NGP Gryphon Boots 1', inv);
NewGamePlusReplaceItem('Gryphon Boots 2', 'NGP Gryphon Boots 2', inv);
NewGamePlusReplaceItem('Gryphon Boots 3', 'NGP Gryphon Boots 3', inv);
NewGamePlusReplaceItem('Gryphon Boots 4', 'NGP Gryphon Boots 4', inv);

NewGamePlusReplaceItem('Gryphon School steel sword', 'NGP Gryphon School steel sword', inv);
NewGamePlusReplaceItem('Gryphon School steel sword 1', 'NGP Gryphon School steel sword 1', inv);
NewGamePlusReplaceItem('Gryphon School steel sword 2', 'NGP Gryphon School steel sword 2', inv);
NewGamePlusReplaceItem('Gryphon School steel sword 3', 'NGP Gryphon School steel sword 3', inv);

NewGamePlusReplaceItem('Gryphon School silver sword', 'NGP Gryphon School silver sword', inv);
NewGamePlusReplaceItem('Gryphon School silver sword 1', 'NGP Gryphon School silver sword 1', inv);
NewGamePlusReplaceItem('Gryphon School silver sword 2', 'NGP Gryphon School silver sword 2', inv);
NewGamePlusReplaceItem('Gryphon School silver sword 3', 'NGP Gryphon School silver sword 3', inv);
}

private final function NewGamePlusReplaceBearSet(out inv : CInventoryComponent)
{
NewGamePlusReplaceItem('Bear Armor', 'NGP Bear Armor', inv);
NewGamePlusReplaceItem('Bear Armor 1', 'NGP Bear Armor 1', inv);
NewGamePlusReplaceItem('Bear Armor 2', 'NGP Bear Armor 2', inv);
NewGamePlusReplaceItem('Bear Armor 3', 'NGP Bear Armor 3', inv);

NewGamePlusReplaceItem('Bear Gloves 1', 'NGP Bear Gloves 1', inv);
NewGamePlusReplaceItem('Bear Gloves 2', 'NGP Bear Gloves 2', inv);
NewGamePlusReplaceItem('Bear Gloves 3', 'NGP Bear Gloves 3', inv);
NewGamePlusReplaceItem('Bear Gloves 4', 'NGP Bear Gloves 4', inv);

NewGamePlusReplaceItem('Bear Pants 1', 'NGP Bear Pants 1', inv);
NewGamePlusReplaceItem('Bear Pants 2', 'NGP Bear Pants 2', inv);
NewGamePlusReplaceItem('Bear Pants 3', 'NGP Bear Pants 3', inv);
NewGamePlusReplaceItem('Bear Pants 4', 'NGP Bear Pants 4', inv);

NewGamePlusReplaceItem('Bear Boots 1', 'NGP Bear Boots 1', inv);
NewGamePlusReplaceItem('Bear Boots 2', 'NGP Bear Boots 2', inv);
NewGamePlusReplaceItem('Bear Boots 3', 'NGP Bear Boots 3', inv);
NewGamePlusReplaceItem('Bear Boots 4', 'NGP Bear Boots 4', inv);

NewGamePlusReplaceItem('Bear School steel sword', 'NGP Bear School steel sword', inv);
NewGamePlusReplaceItem('Bear School steel sword 1', 'NGP Bear School steel sword 1', inv);
NewGamePlusReplaceItem('Bear School steel sword 2', 'NGP Bear School steel sword 2', inv);
NewGamePlusReplaceItem('Bear School steel sword 3', 'NGP Bear School steel sword 3', inv);

NewGamePlusReplaceItem('Bear School silver sword', 'NGP Bear School silver sword', inv);
NewGamePlusReplaceItem('Bear School silver sword 1', 'NGP Bear School silver sword 1', inv);
NewGamePlusReplaceItem('Bear School silver sword 2', 'NGP Bear School silver sword 2', inv);
NewGamePlusReplaceItem('Bear School silver sword 3', 'NGP Bear School silver sword 3', inv);
}

private final function NewGamePlusReplaceEP1(out inv : CInventoryComponent)
{
NewGamePlusReplaceItem('Ofir Armor', 'NGP Ofir Armor', inv);
NewGamePlusReplaceItem('Ofir Sabre 2', 'NGP Ofir Sabre 2', inv);

NewGamePlusReplaceItem('Crafted Burning Rose Armor', 'NGP Crafted Burning Rose Armor', inv);
NewGamePlusReplaceItem('Crafted Burning Rose Gloves', 'NGP Crafted Burning Rose Gloves', inv);
NewGamePlusReplaceItem('Crafted Burning Rose Sword', 'NGP Crafted Burning Rose Sword', inv);

NewGamePlusReplaceItem('Crafted Ofir Armor', 'NGP Crafted Ofir Armor', inv);
NewGamePlusReplaceItem('Crafted Ofir Boots', 'NGP Crafted Ofir Boots', inv);
NewGamePlusReplaceItem('Crafted Ofir Gloves', 'NGP Crafted Ofir Gloves', inv);
NewGamePlusReplaceItem('Crafted Ofir Pants', 'NGP Crafted Ofir Pants', inv);
NewGamePlusReplaceItem('Crafted Ofir Steel Sword', 'NGP Crafted Ofir Steel Sword', inv);

NewGamePlusReplaceItem('EP1 Crafted Witcher Silver Sword', 'NGP EP1 Crafted Witcher Silver Sword', inv);
NewGamePlusReplaceItem('Olgierd Sabre', 'NGP Olgierd Sabre', inv);

NewGamePlusReplaceItem('EP1 Witcher Armor', 'NGP EP1 Witcher Armor', inv);
NewGamePlusReplaceItem('EP1 Witcher Boots', 'NGP EP1 Witcher Boots', inv);
NewGamePlusReplaceItem('EP1 Witcher Gloves', 'NGP EP1 Witcher Gloves', inv);
NewGamePlusReplaceItem('EP1 Witcher Pants', 'NGP EP1 Witcher Pants', inv);
NewGamePlusReplaceItem('EP1 Viper School steel sword', 'NGP EP1 Viper School steel sword', inv);
NewGamePlusReplaceItem('EP1 Viper School silver sword', 'NGP EP1 Viper School silver sword', inv);
}

private final function NewGamePlusReplaceEP2WitcherSets(out inv : CInventoryComponent)
{
NewGamePlusReplaceItem('Lynx Armor 4', 'NGP Lynx Armor 4', inv);
NewGamePlusReplaceItem('Gryphon Armor 4', 'NGP Gryphon Armor 4', inv);
NewGamePlusReplaceItem('Bear Armor 4', 'NGP Bear Armor 4', inv);
NewGamePlusReplaceItem('Wolf Armor 4', 'NGP Wolf Armor 4', inv);
NewGamePlusReplaceItem('Red Wolf Armor 1', 'NGP Red Wolf Armor 1', inv);

NewGamePlusReplaceItem('Lynx Gloves 5', 'NGP Lynx Gloves 5', inv);
NewGamePlusReplaceItem('Gryphon Gloves 5', 'NGP Gryphon Gloves 5', inv);
NewGamePlusReplaceItem('Bear Gloves 5', 'NGP Bear Gloves 5', inv);
NewGamePlusReplaceItem('Wolf Gloves 5', 'NGP Wolf Gloves 5', inv);
NewGamePlusReplaceItem('Red Wolf Gloves 1', 'NGP Red Wolf Gloves 1', inv);

NewGamePlusReplaceItem('Lynx Pants 5', 'NGP Lynx Pants 5', inv);
NewGamePlusReplaceItem('Gryphon Pants 5', 'NGP Gryphon Pants 5', inv);
NewGamePlusReplaceItem('Bear Pants 5', 'NGP Bear Pants 5', inv);
NewGamePlusReplaceItem('Wolf Pants 5', 'NGP Wolf Pants 5', inv);
NewGamePlusReplaceItem('Red Wolf Pants 1', 'NGP Red Wolf Pants 1', inv);

NewGamePlusReplaceItem('Lynx Boots 5', 'NGP Lynx Boots 5', inv);
NewGamePlusReplaceItem('Gryphon Boots 5', 'NGP Gryphon Boots 5', inv);
NewGamePlusReplaceItem('Bear Boots 5', 'NGP Bear Boots 5', inv);
NewGamePlusReplaceItem('Wolf Boots 5', 'NGP Wolf Boots 5', inv);
NewGamePlusReplaceItem('Red Wolf Boots 1', 'NGP Red Wolf Boots 1', inv);


NewGamePlusReplaceItem('Lynx School steel sword 4', 'NGP Lynx School steel sword 4', inv);
NewGamePlusReplaceItem('Gryphon School steel sword 4', 'NGP Gryphon School steel sword 4', inv);
NewGamePlusReplaceItem('Bear School steel sword 4', 'NGP Bear School steel sword 4', inv);
NewGamePlusReplaceItem('Wolf School steel sword 4', 'NGP Wolf School steel sword 4', inv);
NewGamePlusReplaceItem('Red Wolf School steel sword 1', 'NGP Red Wolf School steel sword 1', inv);

NewGamePlusReplaceItem('Lynx School silver sword 4', 'NGP Lynx School silver sword 4', inv);
NewGamePlusReplaceItem('Gryphon School silver sword 4', 'NGP Gryphon School silver sword 4', inv);
NewGamePlusReplaceItem('Bear School silver sword 4', 'NGP Bear School silver sword 4', inv);
NewGamePlusReplaceItem('Wolf School silver sword 4', 'NGP Wolf School silver sword 4', inv);
NewGamePlusReplaceItem('Red Wolf School silver sword 1', 'NGP Red Wolf School silver sword 1', inv);
}

private final function NewGamePlusReplaceEP2Items(out inv : CInventoryComponent)
{
NewGamePlusReplaceItem('Guard Lvl1 Armor 3', 'NGP Guard Lvl1 Armor 3', inv);
NewGamePlusReplaceItem('Guard Lvl1 A Armor 3', 'NGP Guard Lvl1 A Armor 3', inv);
NewGamePlusReplaceItem('Guard Lvl2 Armor 3', 'NGP Guard Lvl2 Armor 3', inv);
NewGamePlusReplaceItem('Guard Lvl2 A Armor 3', 'NGP Guard Lvl2 A Armor 3', inv);
NewGamePlusReplaceItem('Knight Geralt Armor 3', 'NGP Knight Geralt Armor 3', inv);
NewGamePlusReplaceItem('Knight Geralt A Armor 3', 'NGP Knight Geralt A Armor 3', inv);
NewGamePlusReplaceItem('q702_vampire_armor', 'NGP q702_vampire_armor', inv);

NewGamePlusReplaceItem('Guard Lvl1 Gloves 3', 'NGP Guard Lvl1 Gloves 3', inv);
NewGamePlusReplaceItem('Guard Lvl1 A Gloves 3', 'NGP Guard Lvl1 A Gloves 3', inv);
NewGamePlusReplaceItem('Guard Lvl2 Gloves 3', 'NGP Guard Lvl2 Gloves 3', inv);
NewGamePlusReplaceItem('Guard Lvl2 A Gloves 3', 'NGP Guard Lvl2 A Gloves 3', inv);
NewGamePlusReplaceItem('Knight Geralt Gloves 3', 'NGP Knight Geralt Gloves 3', inv);
NewGamePlusReplaceItem('Knight Geralt A Gloves 3', 'NGP Knight Geralt A Gloves 3', inv);
NewGamePlusReplaceItem('q702_vampire_gloves', 'NGP q702_vampire_gloves', inv);

NewGamePlusReplaceItem('Guard Lvl1 Pants 3', 'NGP Guard Lvl1 Pants 3', inv);
NewGamePlusReplaceItem('Guard Lvl1 A Pants 3', 'NGP Guard Lvl1 A Pants 3', inv);
NewGamePlusReplaceItem('Guard Lvl2 Pants 3', 'NGP Guard Lvl2 Pants 3', inv);
NewGamePlusReplaceItem('Guard Lvl2 A Pants 3', 'NGP Guard Lvl2 A Pants 3', inv);
NewGamePlusReplaceItem('Knight Geralt Pants 3', 'NGP Knight Geralt Pants 3', inv);
NewGamePlusReplaceItem('Knight Geralt A Pants 3', 'NGP Knight Geralt A Pants 3', inv);
NewGamePlusReplaceItem('q702_vampire_pants', 'NGP q702_vampire_pants', inv);

NewGamePlusReplaceItem('Guard Lvl1 Boots 3', 'NGP Guard Lvl1 Boots 3', inv);
NewGamePlusReplaceItem('Guard Lvl1 A Boots 3', 'NGP Guard Lvl1 A Boots 3', inv);
NewGamePlusReplaceItem('Guard Lvl2 Boots 3', 'NGP Guard Lvl2 Boots 3', inv);
NewGamePlusReplaceItem('Guard Lvl2 A Boots 3', 'NGP Guard Lvl2 A Boots 3', inv);
NewGamePlusReplaceItem('Knight Geralt Boots 3', 'NGP Knight Geralt Boots 3', inv);
NewGamePlusReplaceItem('Knight Geralt A Boots 3', 'NGP Knight Geralt A Boots 3', inv);
NewGamePlusReplaceItem('q702_vampire_boots', 'NGP q702_vampire_boots', inv);

NewGamePlusReplaceItem('Serpent Steel Sword 1', 'NGP Serpent Steel Sword 1', inv);
NewGamePlusReplaceItem('Serpent Steel Sword 2', 'NGP Serpent Steel Sword 2', inv);
NewGamePlusReplaceItem('Serpent Steel Sword 3', 'NGP Serpent Steel Sword 3', inv);
NewGamePlusReplaceItem('Guard lvl1 steel sword 3', 'NGP Guard lvl1 steel sword 3', inv);
NewGamePlusReplaceItem('Guard lvl2 steel sword 3', 'NGP Guard lvl2 steel sword 3', inv);
NewGamePlusReplaceItem('Knights steel sword 3', 'NGP Knights steel sword 3', inv);
NewGamePlusReplaceItem('Hanza steel sword 3', 'NGP Hanza steel sword 3', inv);
NewGamePlusReplaceItem('Toussaint steel sword 3', 'NGP Toussaint steel sword 3', inv);
NewGamePlusReplaceItem('q702 vampire steel sword', 'NGP q702 vampire steel sword', inv);

NewGamePlusReplaceItem('Serpent Silver Sword 1', 'NGP Serpent Silver Sword 1', inv);
NewGamePlusReplaceItem('Serpent Silver Sword 2', 'NGP Serpent Silver Sword 2', inv);
NewGamePlusReplaceItem('Serpent Silver Sword 3', 'NGP Serpent Silver Sword 3', inv);
}

public function GetEquippedSword(steel : bool) : SItemUniqueId
{
var item : SItemUniqueId;

if(steel)
GetItemEquippedOnSlot(EES_SteelSword, item);
else
GetItemEquippedOnSlot(EES_SilverSword, item);

return item;
}

timer function BroadcastRain( deltaTime : float, id : int )
{
var rainStrength : float = 0;
rainStrength = GetRainStrength();
if( rainStrength > 0.5 )
{
theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( thePlayer, 'RainAction', 2.0f , 50.0f, -1.f, -1, true);
LogReactionSystem( "'RainAction' was sent by Player - single broadcast - distance: 50.0" );
}
}

function InitializeParryType()
{
var i, j : int;

parryTypeTable.Resize( EnumGetMax('EAttackSwingType')+1 );
for( i = 0; i < EnumGetMax('EAttackSwingType')+1; i += 1 )
{
parryTypeTable[i].Resize( EnumGetMax('EAttackSwingDirection')+1 );
}
parryTypeTable[AST_Horizontal][ASD_UpDown] = PT_None;
parryTypeTable[AST_Horizontal][ASD_DownUp] = PT_None;
parryTypeTable[AST_Horizontal][ASD_LeftRight] = PT_Left;
parryTypeTable[AST_Horizontal][ASD_RightLeft] = PT_Right;
parryTypeTable[AST_Vertical][ASD_UpDown] = PT_Up;
parryTypeTable[AST_Vertical][ASD_DownUp] = PT_Down;
parryTypeTable[AST_Vertical][ASD_LeftRight] = PT_None;
parryTypeTable[AST_Vertical][ASD_RightLeft] = PT_None;
parryTypeTable[AST_DiagonalUp][ASD_UpDown] = PT_None;
parryTypeTable[AST_DiagonalUp][ASD_DownUp] = PT_None;
parryTypeTable[AST_DiagonalUp][ASD_LeftRight] = PT_UpLeft;
parryTypeTable[AST_DiagonalUp][ASD_RightLeft] = PT_RightUp;
parryTypeTable[AST_DiagonalDown][ASD_UpDown] = PT_None;
parryTypeTable[AST_DiagonalDown][ASD_DownUp] = PT_None;
parryTypeTable[AST_DiagonalDown][ASD_LeftRight] = PT_LeftDown;
parryTypeTable[AST_DiagonalDown][ASD_RightLeft] = PT_DownRight;
parryTypeTable[AST_Jab][ASD_UpDown] = PT_Jab;
parryTypeTable[AST_Jab][ASD_DownUp] = PT_Jab;
parryTypeTable[AST_Jab][ASD_LeftRight] = PT_Jab;
parryTypeTable[AST_Jab][ASD_RightLeft] = PT_Jab;
}






event OnDeath( damageAction : W3DamageAction )
{
var items : array< SItemUniqueId >;
var i, size : int;
var slot : EEquipmentSlots;
var holdSlot : name;

super.OnDeath( damageAction );

items = GetHeldItems();

if( rangedWeapon && rangedWeapon.GetCurrentStateName() != 'State_WeaponWait')
{
OnRangedForceHolster( true, true, true );
rangedWeapon.ClearDeployedEntity(true);
}

size = items.Size();

if ( size > 0 )
{
for ( i = 0; i < size; i += 1 )
{
if ( this.inv.IsIdValid( items[i] ) && !( this.inv.IsItemCrossbow( items[i] ) ) )
{
holdSlot = this.inv.GetItemHoldSlot( items[i] );

if ( holdSlot == 'l_weapon' && this.IsHoldingItemInLHand() )
{
this.OnUseSelectedItem( true );
}

DropItemFromSlot( holdSlot, false );

if ( holdSlot == 'r_weapon' )
{
slot = this.GetItemSlot( items[i] );
if ( UnequipItemFromSlot( slot ) )
Log( "Unequip" );
}
}
}
}
}







function HandleMovement( deltaTime : float )
{
super.HandleMovement( deltaTime );

rawCameraHeading = theCamera.GetCameraHeading();
}







function ToggleSpecialAttackHeavyAllowed( toggle : bool)
{
specialAttackHeavyAllowed = toggle;
}

function GetReputationManager() : W3Reputation
{
return reputationManager;
}

function OnRadialMenuItemChoose( selectedItem : string )
{
var iSlotId : int;
var item : SItemUniqueId;

if ( selectedItem != "Crossbow" )
{
if ( rangedWeapon && rangedWeapon.GetCurrentStateName() != 'State_WeaponWait' )
OnRangedForceHolster( true, false );
}


switch(selectedItem)
{

case "Meditation":
theGame.RequestMenuWithBackground( 'MeditationClockMenu', 'CommonMenu' );
break;
case "Slot1":
GetItemEquippedOnSlot( EES_Petard1, item );
if( thePlayer.inv.IsIdValid( item ) )
{
SelectQuickslotItem( EES_Petard1 );
}
else
{
SelectQuickslotItem( EES_Petard2 );
}
break;

case "Slot2":
GetItemEquippedOnSlot( EES_Petard2, item );
if( thePlayer.inv.IsIdValid( item ) )
{
SelectQuickslotItem( EES_Petard2 );
}
else
{
SelectQuickslotItem( EES_Petard1 );
}
break;

case "Crossbow":
SelectQuickslotItem(EES_RangedWeapon);
break;

case "Slot3":
GetItemEquippedOnSlot( EES_Quickslot1, item );
if( thePlayer.inv.IsIdValid( item ) )
{
SelectQuickslotItem( EES_Quickslot1 );
}
else
{
SelectQuickslotItem( EES_Quickslot2 );
}
break;

case "Slot4":
GetItemEquippedOnSlot( EES_Quickslot2, item );
if( thePlayer.inv.IsIdValid( item ) )
{
SelectQuickslotItem( EES_Quickslot2 );
}
else
{
SelectQuickslotItem( EES_Quickslot1 );
}
break;

default:
SetEquippedSign(SignStringToEnum( selectedItem ));
FactsRemove("SignToggled");
break;
}
}

function ToggleNextItem()
{
var quickSlotItems : array< EEquipmentSlots >;
var currentSelectedItem : SItemUniqueId;
var item : SItemUniqueId;
var i : int;

for( i = EES_Quickslot2; i > EES_Petard1 - 1; i -= 1 )
{
GetItemEquippedOnSlot( i, item );
if( inv.IsIdValid( item ) )
{
quickSlotItems.PushBack( i );
}
}
if( !quickSlotItems.Size() )
{
return;
}

currentSelectedItem = GetSelectedItemId();

if( inv.IsIdValid( currentSelectedItem ) )
{
for( i = 0; i < quickSlotItems.Size(); i += 1 )
{
GetItemEquippedOnSlot( quickSlotItems[i], item );
if( currentSelectedItem == item )
{
if( i == quickSlotItems.Size() - 1 )
{
SelectQuickslotItem( quickSlotItems[ 0 ] );
}
else
{
SelectQuickslotItem( quickSlotItems[ i + 1 ] );
}
return;
}
}
}
else
{
SelectQuickslotItem( quickSlotItems[ 0 ] );
}
}


function SetEquippedSign( signType : ESignType )
{
if(!IsSignBlocked(signType))
{
equippedSign = signType;
FactsSet("CurrentlySelectedSign", equippedSign);
}
}

function GetEquippedSign() : ESignType
{
return equippedSign;
}

function GetCurrentlyCastSign() : ESignType
{
return currentlyCastSign;
}

function SetCurrentlyCastSign( type : ESignType, entity : W3SignEntity )
{
currentlyCastSign = type;

if( type != ST_None )
{
signs[currentlyCastSign].entity = entity;
}
}

function GetCurrentSignEntity() : W3SignEntity
{
if(currentlyCastSign == ST_None)
return NULL;

return signs[currentlyCastSign].entity;
}

public function GetSignEntity(type : ESignType) : W3SignEntity
{
if(type == ST_None)
return NULL;

return signs[type].entity;
}

public function GetSignTemplate(type : ESignType) : CEntityTemplate
{
if(type == ST_None)
return NULL;

return signs[type].template;
}

public function IsCurrentSignChanneled() : bool
{
if( currentlyCastSign != ST_None && signs[currentlyCastSign].entity)
return signs[currentlyCastSign].entity.OnCheckChanneling();

return false;
}

function IsCastingSign() : bool
{
return currentlyCastSign != ST_None;
}


protected function IsInCombatActionCameraRotationEnabled() : bool
{
if( IsInCombatAction() && ( GetCombatAction() == EBAT_EMPTY || GetCombatAction() == EBAT_Parry ) )
{
return true;
}

return !bIsInCombatAction;
}

function SetHoldBeforeOpenRadialMenuTime ( time : float )
{
_HoldBeforeOpenRadialMenuTime = time;
}







public function RepairItem ( rapairKitId : SItemUniqueId, usedOnItem : SItemUniqueId )
{
var itemMaxDurablity : float;
var itemCurrDurablity : float;
var baseRepairValue : float;
var reapirValue : float;
var itemAttribute : SAbilityAttributeValue;

itemMaxDurablity = inv.GetItemMaxDurability(usedOnItem);
itemCurrDurablity = inv.GetItemDurability(usedOnItem);
itemAttribute = inv.GetItemAttributeValue ( rapairKitId, 'repairValue' );

if( itemCurrDurablity >= itemMaxDurablity )
{
return;
}

if ( inv.IsItemAnyArmor ( usedOnItem )|| inv.IsItemWeapon( usedOnItem ) )
{

baseRepairValue = itemMaxDurablity * itemAttribute.valueMultiplicative;
reapirValue = MinF( itemCurrDurablity + baseRepairValue, itemMaxDurablity );

inv.SetItemDurabilityScript ( usedOnItem, MinF ( reapirValue, itemMaxDurablity ));
}

inv.RemoveItem ( rapairKitId, 1 );

}
public function HasRepairAbleGearEquiped ( ) : bool
{
var curEquipedItem : SItemUniqueId;

return ( GetItemEquippedOnSlot(EES_Armor, curEquipedItem) || GetItemEquippedOnSlot(EES_Boots, curEquipedItem) || GetItemEquippedOnSlot(EES_Pants, curEquipedItem) || GetItemEquippedOnSlot(EES_Gloves, curEquipedItem)) == true;
}
public function HasRepairAbleWaponEquiped () : bool
{
var curEquipedItem : SItemUniqueId;

return ( GetItemEquippedOnSlot(EES_SilverSword, curEquipedItem) || GetItemEquippedOnSlot(EES_SteelSword, curEquipedItem) ) == true;
}
public function IsItemRepairAble ( item : SItemUniqueId ) : bool
{
return inv.GetItemDurabilityRatio(item) <= 0.99999f;
}








public function ApplyOil( oilId : SItemUniqueId, usedOnItem : SItemUniqueId ) : bool
{
var tutStateOil : W3TutorialManagerUIHandlerStateOils;

if( !super.ApplyOil( oilId, usedOnItem ))
return false;


if(ShouldProcessTutorial('TutorialOilCanEquip3'))
{
tutStateOil = (W3TutorialManagerUIHandlerStateOils)theGame.GetTutorialSystem().uiHandler.GetCurrentState();
if(tutStateOil)
{
tutStateOil.OnOilApplied();
}
}

return true;
}

private final function RemoveExtraOilsFromItem( item : SItemUniqueId )
{
var oils : array< CBaseGameplayEffect >;
var i, cnt : int;
var buff : W3Effect_Oil;

oils = GetBuffs( EET_Oil );
for( i=0; i {
buff = (W3Effect_Oil) oils[ i ];
if( buff && buff.GetSwordItemId() == item )
{
cnt += 1;
}
}
while( cnt > 1 )
{
inv.RemoveOldestOilFromItem( item );
cnt -= 1;
}
}








function ReduceDamage(out damageData : W3DamageAction)
{
var actorAttacker : CActor;
var quen : W3QuenEntity;
var attackRange : CAIAttackRange;
var attackerMovementAdjustor : CMovementAdjustor;
var dist, distToAttacker, actionHeading, attackerHeading, currAdrenaline, adrenReducedDmg, focus : float;
var attackName : name;
var useQuenForBleeding : bool;
var min, max : SAbilityAttributeValue;
var skillLevel : int;

super.ReduceDamage(damageData);



quen = (W3QuenEntity)signs[ST_Quen].entity;
useQuenForBleeding = false;
if(quen && !damageData.DealsAnyDamage() && ((W3Effect_Bleeding)damageData.causer) && damageData.GetDamageValue(theGame.params.DAMAGE_NAME_DIRECT) > 0.f)
useQuenForBleeding = true;


if(!useQuenForBleeding && !damageData.DealsAnyDamage())
return;

actorAttacker = (CActor)damageData.attacker;


if(actorAttacker && IsCurrentlyDodging() && damageData.CanBeDodged())
{


actionHeading = evadeHeading;
attackerHeading = actorAttacker.GetHeading();
dist = AngleDistance(actionHeading, attackerHeading);
distToAttacker = VecDistance(this.GetWorldPosition(),damageData.attacker.GetWorldPosition());
attackName = actorAttacker.GetLastAttackRangeName();
attackRange = theGame.GetAttackRangeForEntity( actorAttacker, attackName );
attackerMovementAdjustor = actorAttacker.GetMovingAgentComponent().GetMovementAdjustor();
if( ( AbsF(dist) < 150 && attackName != 'stomp' && attackName != 'anchor_special_far' && attackName != 'anchor_far' )
|| ( ( attackName == 'stomp' || attackName == 'anchor_special_far' || attackName == 'anchor_far' ) && distToAttacker > attackRange.rangeMax * 0.75 ) )
{
if ( theGame.CanLog() )
{
LogDMHits("W3PlayerWitcher.ReduceDamage: Attack dodged by player - no damage done", damageData);
}
damageData.SetAllProcessedDamageAs(0);
damageData.SetWasDodged();
}

else if( !damageData.IsActionEnvironment() && !damageData.IsDoTDamage() && CanUseSkill( S_Sword_s09 ) )
{
skillLevel = GetSkillLevel( S_Sword_s09 );
if( skillLevel == GetSkillMaxLevel( S_Sword_s09 ) )
{
damageData.SetAllProcessedDamageAs(0);
damageData.SetWasDodged();
}
else
{
damageData.processedDmg.vitalityDamage *= 1 - CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s09, 'damage_reduction', false, true)) * skillLevel;
}

if ( theGame.CanLog() )
{
LogDMHits("W3PlayerWitcher.ReduceDamage: skill S_Sword_s09 reduced damage while dodging", damageData );
}
}
}


if(quen && damageData.GetBuffSourceName() != "FallingDamage")
{
if ( theGame.CanLog() )
{
LogDMHits("W3PlayerWitcher.ReduceDamage: Processing Quen sign damage reduction...", damageData);
}
quen.OnTargetHit( damageData );
}


if( HasBuff( EET_GryphonSetBonusYrden ) )
{
min = GetAttributeValue( 'gryphon_set_bns_dmg_reduction' );
damageData.processedDmg.vitalityDamage *= 1 - min.valueAdditive;
}


if( IsMutationActive( EPMT_Mutation5 ) && !IsAnyQuenActive() && !damageData.IsDoTDamage() )
{
focus = GetStat( BCS_Focus );
currAdrenaline = FloorF( focus );
if( currAdrenaline >= 1 )
{
theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation5', 'mut5_dmg_red_perc', min, max );
adrenReducedDmg = ( currAdrenaline * min.valueAdditive );
damageData.processedDmg.vitalityDamage *= 1 - adrenReducedDmg;


theGame.MutationHUDFeedback( MFT_PlayOnce );

if( focus >= 3.f )
{
PlayEffect( 'mutation_5_stage_03' );
}
else if( focus >= 2.f )
{
PlayEffect( 'mutation_5_stage_02' );
}
else
{
PlayEffect( 'mutation_5_stage_01' );
}
}
}


if(!damageData.GetIgnoreImmortalityMode())
{
if(!((W3PlayerWitcher)this))
Log("");


if( IsInvulnerable() )
{
if ( theGame.CanLog() )
{
LogDMHits("CActor.ReduceDamage: victim Invulnerable - no damage will be dealt", damageData );
}
damageData.SetAllProcessedDamageAs(0);
return;
}

if(actorAttacker && damageData.DealsAnyDamage() )
actorAttacker.SignalGameplayEventParamObject( 'DamageInstigated', damageData );


if( IsImmortal() )
{
if ( theGame.CanLog() )
{
LogDMHits("CActor.ReduceDamage: victim is Immortal, clamping damage", damageData );
}
damageData.processedDmg.vitalityDamage = ClampF(damageData.processedDmg.vitalityDamage, 0, GetStat(BCS_Vitality)-1 );
damageData.processedDmg.essenceDamage = ClampF(damageData.processedDmg.essenceDamage, 0, GetStat(BCS_Essence)-1 );
return;
}
}
else
{

if(actorAttacker && damageData.DealsAnyDamage() )
actorAttacker.SignalGameplayEventParamObject( 'DamageInstigated', damageData );
}
}

timer function UndyingSkillCooldown(dt : float, id : int)
{
cannotUseUndyingSkill = false;
}

event OnTakeDamage( action : W3DamageAction)
{
var currVitality, rgnVitality, hpTriggerTreshold : float;
var healingFactor : float;
var abilityName : name;
var abilityCount, maxStack, itemDurability : float;
var addAbility : bool;
var min, max : SAbilityAttributeValue;
var mutagenQuen : W3SignEntity;
var equipped : array;
var i : int;
var killSourceName : string;
var aerondight : W3Effect_Aerondight;

currVitality = GetStat(BCS_Vitality);


if(action.processedDmg.vitalityDamage >= currVitality)
{
killSourceName = action.GetBuffSourceName();


if( killSourceName != "Quest" && killSourceName != "Kill Trigger" && killSourceName != "Trap" && killSourceName != "FallingDamage" )
{

if(!cannotUseUndyingSkill && FloorF(GetStat(BCS_Focus)) >= 1 && CanUseSkill(S_Sword_s18) && HasBuff(EET_BattleTrance) )
{
healingFactor = CalculateAttributeValue( GetSkillAttributeValue(S_Sword_s18, 'healing_factor', false, true) );
healingFactor *= GetStatMax(BCS_Vitality);
healingFactor *= GetStat(BCS_Focus);
healingFactor *= 1 + CalculateAttributeValue( GetSkillAttributeValue(S_Sword_s18, 'healing_bonus', false, true) ) * (GetSkillLevel(S_Sword_s18) - 1);
ForceSetStat(BCS_Vitality, GetStatMax(BCS_Vitality));
DrainFocus(GetStat(BCS_Focus));
RemoveBuff(EET_BattleTrance);
cannotUseUndyingSkill = true;
AddTimer('UndyingSkillCooldown', CalculateAttributeValue( GetSkillAttributeValue(S_Sword_s18, 'trigger_delay', false, true) ), false, , , true);
}

else if( IsMutationActive( EPMT_Mutation11 ) && !HasBuff( EET_Mutation11Debuff ) && !IsInAir() )
{
theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation11', 'health_prc', min, max );

action.SetAllProcessedDamageAs( 0 );

OnMutation11Triggered();
}
else
{

equipped = GetEquippedItems();

for(i=0; i {
if ( !inv.IsIdValid( equipped[i] ) )
{
continue;
}
itemDurability = inv.GetItemDurability(equipped[i]);
if(inv.ItemHasAbility(equipped[i], 'MA_Reinforced') && itemDurability > 0)
{

inv.SetItemDurabilityScript(equipped[i], MaxF(0, itemDurability - action.processedDmg.vitalityDamage) );


action.processedDmg.vitalityDamage = 0;
ForceSetStat(BCS_Vitality, 1);

break;
}
}
}
}
}


if(action.DealsAnyDamage() && !((W3Effect_Toxicity)action.causer) )
{
if(HasBuff(EET_Mutagen10))
RemoveAbilityAll( GetBuff(EET_Mutagen10).GetAbilityName() );

if(HasBuff(EET_Mutagen15))
RemoveAbilityAll( GetBuff(EET_Mutagen15).GetAbilityName() );
}


if(HasBuff(EET_Mutagen19))
{
theGame.GetDefinitionsManager().GetAbilityAttributeValue(GetBuff(EET_Mutagen19).GetAbilityName(), 'max_hp_perc_trigger', min, max);
hpTriggerTreshold = GetStatMax(BCS_Vitality) * CalculateAttributeValue(GetAttributeRandomizedValue(min, max));

if(action.GetDamageDealt() >= hpTriggerTreshold)
{
mutagenQuen = (W3SignEntity)theGame.CreateEntity( signs[ST_Quen].template, GetWorldPosition(), GetWorldRotation() );
mutagenQuen.Init( signOwner, signs[ST_Quen].entity, true );
mutagenQuen.OnStarted();
mutagenQuen.OnThrowing();
mutagenQuen.OnEnded();
}
}


if(action.DealsAnyDamage() && !action.IsDoTDamage() && HasBuff(EET_Mutagen27))
{
abilityName = GetBuff(EET_Mutagen27).GetAbilityName();
abilityCount = GetAbilityCount(abilityName);

if(abilityCount == 0)
{
addAbility = true;
}
else
{
theGame.GetDefinitionsManager().GetAbilityAttributeValue(abilityName, 'mutagen27_max_stack', min, max);
maxStack = CalculateAttributeValue(GetAttributeRandomizedValue(min, max));

if(maxStack >= 0)
{
addAbility = (abilityCount < maxStack);
}
else
{
addAbility = true;
}
}

if(addAbility)
{
AddAbility(abilityName, true);
}
}

if(HasBuff(EET_Trap) && !action.IsDoTDamage() && action.attacker.HasAbility( 'mon_dettlaff_monster_base' ))
{
action.AddEffectInfo(EET_Knockdown);
RemoveBuff(EET_Trap, true);
}

super.OnTakeDamage(action);


if( !action.WasDodged() && action.DealtDamage() && inv.ItemHasTag( inv.GetCurrentlyHeldSword(), 'Aerondight' ) && !action.IsDoTDamage() && !( (W3Effect_Toxicity) action.causer ) )
{
aerondight = (W3Effect_Aerondight)GetBuff( EET_Aerondight );
if( aerondight && aerondight.GetCurrentCount() != 0 )
{
aerondight.ReduceAerondightStacks();
}
}


// if( !action.WasDodged() && action.DealtDamage() && !( (W3Effect_Toxicity) action.causer ) )
// {
// RemoveBuff( EET_Mutation3 );
// }
// }







event OnStartFistfightMinigame()
{
var i : int;
var buffs : array< CBaseGameplayEffect >;


effectManager.RemoveAllPotionEffects();

abilityManager.DrainToxicity(GetStatMax( BCS_Toxicity ));

buffs = GetBuffs( EET_WellFed );
for( i=buffs.Size()-1; i>=0; i-=1 )
{
RemoveEffect( buffs[i] );
}


buffs.Clear();
buffs = GetBuffs( EET_WellHydrated );
for( i=buffs.Size()-1; i>=0; i-=1 )
{
RemoveEffect( buffs[i] );
}

super.OnStartFistfightMinigame();
}

event OnEndFistfightMinigame()
{
super.OnEndFistfightMinigame();
}


public function GetCriticalHitChance( isLightAttack : bool, isHeavyAttack : bool, target : CActor, victimMonsterCategory : EMonsterCategory, isBolt : bool ) : float
{
var ret : float;
var thunder : W3Potion_Thunderbolt;
var min, max : SAbilityAttributeValue;

ret = super.GetCriticalHitChance( isLightAttack, isHeavyAttack, target, victimMonsterCategory, isBolt );







thunder = ( W3Potion_Thunderbolt )GetBuff( EET_Thunderbolt );
if( thunder && thunder.GetBuffLevel() == 3 && GetCurWeather() == EWE_Storm )
{
ret += 1.0f;
}


if( isBolt && IsMutationActive( EPMT_Mutation9 ) )
{
theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation9', 'critical_hit_chance', min, max);
ret += min.valueMultiplicative;
}


if( isBolt && CanUseSkill( S_Sword_s07 ) )
{
ret += CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s07, theGame.params.CRITICAL_HIT_CHANCE, false, true)) * GetSkillLevel(S_Sword_s07);
}

return ret;
}


public function GetCriticalHitDamageBonus(weaponId : SItemUniqueId, victimMonsterCategory : EMonsterCategory, isStrikeAtBack : bool) : SAbilityAttributeValue
{
var min, max, bonus, null, oilBonus : SAbilityAttributeValue;
var mutagen : CBaseGameplayEffect;
var monsterBonusType : name;

bonus = super.GetCriticalHitDamageBonus(weaponId, victimMonsterCategory, isStrikeAtBack);


if( inv.ItemHasActiveOilApplied( weaponId, victimMonsterCategory ) && GetStat( BCS_Focus ) >= 3 && CanUseSkill( S_Alchemy_s07 ) )
{
monsterBonusType = MonsterCategoryToAttackPowerBonus( victimMonsterCategory );
oilBonus = inv.GetItemAttributeValue( weaponId, monsterBonusType );
if(oilBonus != null)
{
bonus += GetSkillAttributeValue(S_Alchemy_s07, theGame.params.CRITICAL_HIT_DAMAGE_BONUS, false, true);
}
}


if (isStrikeAtBack && HasBuff(EET_Mutagen11))
{
mutagen = GetBuff(EET_Mutagen11);
theGame.GetDefinitionsManager().GetAbilityAttributeValue(mutagen.GetAbilityName(), 'damageIncrease', min, max);
bonus += GetAttributeRandomizedValue(min, max);
}

return bonus;
}

public function ProcessLockTarget( optional newLockTarget : CActor, optional checkLeftStickHeading : bool ) : bool
{
var newLockTargetFound : bool;

newLockTargetFound = super.ProcessLockTarget(newLockTarget, checkLeftStickHeading);

if(GetCurrentlyCastSign() == ST_Axii)
{
((W3AxiiEntity)GetCurrentSignEntity()).OnDisplayTargetChange(newLockTarget);
}

return newLockTargetFound;
}







event OnProcessActionPost(action : W3DamageAction)
{
var attackAction : W3Action_Attack;
var rendLoad : float;
var value : SAbilityAttributeValue;
var actorVictim : CActor;
var weaponId : SItemUniqueId;
var usesSteel, usesSilver, usesVitality, usesEssence : bool;
var abs : array;
var i : int;
var dm : CDefinitionsManagerAccessor;
var items : array;
var weaponEnt : CEntity;

super.OnProcessActionPost(action);

attackAction = (W3Action_Attack)action;
actorVictim = (CActor)action.victim;

if( !actorVictim.IsAlive() )
{
return false;
}

if(attackAction)
{
if(attackAction.IsActionMelee())
{

if(SkillNameToEnum(attackAction.GetAttackTypeName()) == S_Sword_s02)
{
rendLoad = GetSpecialAttackTimeRatio();


rendLoad = MinF(rendLoad * GetStatMax(BCS_Focus), GetStat(BCS_Focus));


rendLoad = FloorF(rendLoad);
DrainFocus(rendLoad);

OnSpecialAttackHeavyActionProcess();
}
else if(actorVictim && IsRequiredAttitudeBetween(this, actorVictim, true))
{


value = GetAttributeValue('focus_gain');

if( FactsQuerySum("debug_fact_focus_boy") > 0 )
{
Debug_FocusBoyFocusGain();
}


if ( CanUseSkill(S_Sword_s20) )
{
value += GetSkillAttributeValue(S_Sword_s20, 'focus_gain', false, true) * GetSkillLevel(S_Sword_s20);
}


if( IsMutationActive( EPMT_Mutation3 ) && IsRequiredAttitudeBetween( this, action.victim, true ) && !action.victim.HasTag( 'Mutation3InvalidTarget' ) && !attackAction.IsParried() && !attackAction.WasDodged() && !attackAction.IsCountered() && !inv.IsItemFists( attackAction.GetWeaponId() ) && !attackAction.WasDamageReturnedToAttacker() && attackAction.DealtDamage() )
{
AddEffectDefault( EET_Mutation3, this, "", false );
}

GainStat(BCS_Focus, 0.1f * (1 + CalculateAttributeValue(value)) );
}


weaponId = attackAction.GetWeaponId();
if(actorVictim && (ShouldProcessTutorial('TutorialWrongSwordSteel') || ShouldProcessTutorial('TutorialWrongSwordSilver')) && GetAttitudeBetween(actorVictim, this) == AIA_Hostile)
{
usesSteel = inv.IsItemSteelSwordUsableByPlayer(weaponId);
usesSilver = inv.IsItemSilverSwordUsableByPlayer(weaponId);
usesVitality = actorVictim.UsesVitality();
usesEssence = actorVictim.UsesEssence();

if(usesSilver && usesVitality)
{
FactsAdd('tut_wrong_sword_silver',1);
}
else if(usesSteel && usesEssence)
{
FactsAdd('tut_wrong_sword_steel',1);
}
else if(FactsQuerySum('tut_wrong_sword_steel') && usesSilver && usesEssence)
{
FactsAdd('tut_proper_sword_silver',1);
FactsRemove('tut_wrong_sword_steel');
}
else if(FactsQuerySum('tut_wrong_sword_silver') && usesSteel && usesVitality)
{
FactsAdd('tut_proper_sword_steel',1);
FactsRemove('tut_wrong_sword_silver');
}
}


if(!action.WasDodged() && HasAbility('Runeword 1 _Stats', true))
{
if(runewordInfusionType == ST_Axii)
{
actorVictim.SoundEvent('sign_axii_release');
}
else if(runewordInfusionType == ST_Igni)
{
actorVictim.SoundEvent('sign_igni_charge_begin');
}
else if(runewordInfusionType == ST_Quen)
{
value = GetAttributeValue('runeword1_quen_heal');
Heal( action.GetDamageDealt() * value.valueMultiplicative );
PlayEffectSingle('drain_energy_caretaker_shovel');
}
else if(runewordInfusionType == ST_Yrden)
{
actorVictim.SoundEvent('sign_yrden_shock_activate');
}
runewordInfusionType = ST_None;


items = inv.GetHeldWeapons();
weaponEnt = inv.GetItemEntityUnsafe(items[0]);
weaponEnt.StopEffect('runeword_aard');
weaponEnt.StopEffect('runeword_axii');
weaponEnt.StopEffect('runeword_igni');
weaponEnt.StopEffect('runeword_quen');
weaponEnt.StopEffect('runeword_yrden');
}


if(ShouldProcessTutorial('TutorialLightAttacks') || ShouldProcessTutorial('TutorialHeavyAttacks'))
{
if(IsLightAttack(attackAction.GetAttackName()))
{
theGame.GetTutorialSystem().IncreaseGeraltsLightAttacksCount(action.victim.GetTags());
}
else if(IsHeavyAttack(attackAction.GetAttackName()))
{
theGame.GetTutorialSystem().IncreaseGeraltsHeavyAttacksCount(action.victim.GetTags());
}
}
}
else if(attackAction.IsActionRanged())
{

if(CanUseSkill(S_Sword_s15))
{
value = GetSkillAttributeValue(S_Sword_s15, 'focus_gain', false, true) * GetSkillLevel(S_Sword_s15) ;
GainStat(BCS_Focus, CalculateAttributeValue(value) );
}


if(CanUseSkill(S_Sword_s12) && attackAction.IsCriticalHit() && actorVictim)
{

actorVictim.GetCharacterStats().GetAbilities(abs, false);
dm = theGame.GetDefinitionsManager();
for(i=abs.Size()-1; i>=0; i-=1)
{
if(!dm.AbilityHasTag(abs[i], theGame.params.TAG_MONSTER_SKILL) || actorVictim.IsAbilityBlocked(abs[i]))
{
abs.EraseFast(i);
}
}


if(abs.Size() > 0)
{
value = GetSkillAttributeValue(S_Sword_s12, 'duration', true, true) * GetSkillLevel(S_Sword_s12);
actorVictim.BlockAbility(abs[ RandRange(abs.Size()) ], true, CalculateAttributeValue(value));
}
}
}
}


if( IsMutationActive( EPMT_Mutation10 ) && ( action.IsActionMelee() || action.IsActionWitcherSign() ) )
{
PlayEffect( 'mutation_10_energy' );
}


if(CanUseSkill(S_Perk_18) && ((W3Petard)action.causer) && action.DealsAnyDamage() && !action.IsDoTDamage())
{
value = GetSkillAttributeValue(S_Perk_18, 'focus_gain', false, true);
GainStat(BCS_Focus, CalculateAttributeValue(value));
}


if( attackAction && IsHeavyAttack( attackAction.GetAttackName() ) && !IsUsingHorse() && attackAction.DealtDamage() && IsSetBonusActive( EISB_Lynx_1 ) && !attackAction.WasDodged() && !attackAction.IsParried() && !attackAction.IsCountered() && ( inv.IsItemSteelSwordUsableByPlayer( attackAction.GetWeaponId() ) || inv.IsItemSilverSwordUsableByPlayer( attackAction.GetWeaponId() ) ) )
{
AddEffectDefault( EET_LynxSetBonus, NULL, "HeavyAttack" );
SoundEvent( "ep2_setskill_lynx_activate" );
}
}


timer function Mutagen14Timer(dt : float, id : int)
{
var abilityName : name;
var abilityCount, maxStack : float;
var min, max : SAbilityAttributeValue;
var addAbility : bool;

abilityName = GetBuff(EET_Mutagen14).GetAbilityName();
abilityCount = GetAbilityCount(abilityName);

if(abilityCount == 0)
{
addAbility = true;
}
else
{
theGame.GetDefinitionsManager().GetAbilityAttributeValue(abilityName, 'mutagen14_max_stack', min, max);
maxStack = CalculateAttributeValue(GetAttributeRandomizedValue(min, max));

if(maxStack >= 0)
{
addAbility = (abilityCount < maxStack);
}
else
{
addAbility = true;
}
}

if(addAbility)
{
AddAbility(abilityName, true);
}
else
{

RemoveTimer('Mutagen14Timer');
}
}

public final function FailFundamentalsFirstAchievementCondition()
{
SetFailedFundamentalsFirstAchievementCondition(true);
}

public final function SetUsedQuenInCombat()
{
usedQuenInCombat = true;
}

public final function UsedQuenInCombat() : bool
{
return usedQuenInCombat;
}

event OnCombatStart()
{
var quenEntity, glyphQuen : W3QuenEntity;
var focus, stamina : float;
var glowTargets, moTargets, actors : array< CActor >;
var delays : array< float >;
var rand, i : int;
var isHostile, isAlive, isUnconscious : bool;

super.OnCombatStart();

if ( IsInCombatActionFriendly() )
{
SetBIsCombatActionAllowed(true);
SetBIsInputAllowed(true, 'OnCombatActionStart' );
}


if(HasBuff(EET_Mutagen14))
{
AddTimer('Mutagen14Timer', 2, true);
}


if(HasBuff(EET_Mutagen15))
{
AddAbility(GetBuff(EET_Mutagen15).GetAbilityName(), false);
}


mutation12IsOnCooldown = false;


quenEntity = (W3QuenEntity)signs[ST_Quen].entity;


if(quenEntity)
{
usedQuenInCombat = quenEntity.IsAnyQuenActive();
}
else
{
usedQuenInCombat = false;
}

if(usedQuenInCombat || HasPotionBuff() || IsEquippedSwordUpgradedWithOil(true) || IsEquippedSwordUpgradedWithOil(false))
{
SetFailedFundamentalsFirstAchievementCondition(true);
}
else
{
if(IsAnyItemEquippedOnSlot(EES_PotionMutagen1) || IsAnyItemEquippedOnSlot(EES_PotionMutagen2) || IsAnyItemEquippedOnSlot(EES_PotionMutagen3) || IsAnyItemEquippedOnSlot(EES_PotionMutagen4))
SetFailedFundamentalsFirstAchievementCondition(true);
else
SetFailedFundamentalsFirstAchievementCondition(false);
}

if(CanUseSkill(S_Sword_s20) && IsThreatened())
{
focus = GetStat(BCS_Focus);
if(focus < 1)
{
GainStat(BCS_Focus, 1 - focus);
}
}

if ( HasAbility('Glyphword 17 _Stats', true) && RandF() < CalculateAttributeValue(GetAttributeValue('quen_apply_chance')) )
{
stamina = GetStat(BCS_Stamina);
glyphQuen = (W3QuenEntity)theGame.CreateEntity( signs[ST_Quen].template, GetWorldPosition(), GetWorldRotation() );
glyphQuen.Init( signOwner, signs[ST_Quen].entity, true );
glyphQuen.OnStarted();
glyphQuen.OnThrowing();
glyphQuen.OnEnded();
ForceSetStat(BCS_Stamina, stamina);
}


MeditationForceAbort(true);





if( IsMutationActive( EPMT_Mutation4 ) )
{
AddEffectDefault( EET_Mutation4, this, "combat start", false );
}
if( IsMutationActive( EPMT_Mutation5 ) && GetStat( BCS_Focus ) >= 1.f ) //zur13 modSSS
{
AddEffectDefault( EET_Mutation5, this, "", false );
}

if( IsMutationActive( EPMT_Mutation7 ) ) //zur13 modSSS
{


RemoveTimer( 'Mutation7CombatStartHackFixGo' );


AddTimer( 'Mutation7CombatStartHackFix', 1.f, true, , , , true );

}
if( IsMutationActive( EPMT_Mutation8 ) ) //zur13 modSSS
{
theGame.MutationHUDFeedback( MFT_PlayRepeat );
}

if( IsMutationActive( EPMT_Mutation10 ) ) //zur13 modSSS
{

PlayEffect( 'mutation_10' );


PlayEffect( 'critical_toxicity' );
AddTimer( 'Mutation10StopEffect', 5.f );
}
}

timer function Mutation7CombatStartHackFix( dt : float, id : int )
{
var actors : array< CActor >;

actors = GetEnemies();

if( actors.Size() > 0 )
{

AddTimer( 'Mutation7CombatStartHackFixGo', 0.5f );
RemoveTimer( 'Mutation7CombatStartHackFix' );
}
}

timer function Mutation7CombatStartHackFixGo( dt : float, id : int )
{
var actors : array< CActor >;

if( IsMutationActive( EPMT_Mutation7 ) )
{
actors = GetEnemies();

if( actors.Size() > 1 )
{
AddEffectDefault( EET_Mutation7Buff, this, "Mutation 7, combat start" );
}
}
}

public final function IsInFistFight() : bool
{
var enemies : array< CActor >;
var i, j : int;
var invent : CInventoryComponent;
var weapons : array< SItemUniqueId >;

if( IsInFistFightMiniGame() )
{
return true;
}

enemies = GetEnemies();
for( i=0; i {
weapons.Clear();
invent = enemies[i].GetInventory();
weapons = invent.GetHeldWeapons();

for( j=0; j {
if( invent.IsItemFists( weapons[j] ) )
{
return true;
}
}
}

return false;
}

timer function Mutation10StopEffect( dt : float, id : int )
{
StopEffect( 'critical_toxicity' );
}


event OnCombatFinished()
{
var mut17 : W3Mutagen17_Effect;
var inGameConfigWrapper : CInGameConfigWrapper;
var disableAutoSheathe : bool;

super.OnCombatFinished();


if(HasBuff(EET_Mutagen10))
{
RemoveAbilityAll( GetBuff(EET_Mutagen10).GetAbilityName() );
}


if(HasBuff(EET_Mutagen14))
{
RemoveAbilityAll( GetBuff(EET_Mutagen14).GetAbilityName() );
}


if(HasBuff(EET_Mutagen15))
{
RemoveAbilityAll( GetBuff(EET_Mutagen15).GetAbilityName() );
}


if(HasBuff(EET_Mutagen17))
{
mut17 = (W3Mutagen17_Effect)GetBuff(EET_Mutagen17);
mut17.ClearBoost();
}


if(HasBuff(EET_Mutagen18))
{
RemoveAbilityAll( GetBuff(EET_Mutagen18).GetAbilityName() );
}


if(HasBuff(EET_Mutagen22))
{
RemoveAbilityAll( GetBuff(EET_Mutagen22).GetAbilityName() );
}


if(HasBuff(EET_Mutagen27))
{
RemoveAbilityAll( GetBuff(EET_Mutagen27).GetAbilityName() );
}


RemoveBuff( EET_Mutation3 );


RemoveBuff( EET_Mutation4 );


RemoveBuff( EET_Mutation5 );


RemoveBuff( EET_Mutation7Buff );
RemoveBuff( EET_Mutation7Debuff );

if( IsMutationActive( EPMT_Mutation7 ) )
{
theGame.MutationHUDFeedback( MFT_PlayHide );
}
if( IsMutationActive( EPMT_Mutation8 ) ) //zur13 modSSS
{
theGame.MutationHUDFeedback( MFT_PlayHide );
}


RemoveBuff( EET_Mutation10 );


RemoveBuff( EET_LynxSetBonus );


if(GetStat(BCS_Focus) > 0)
{
AddTimer('DelayedAdrenalineDrain', theGame.params.ADRENALINE_DRAIN_AFTER_COMBAT_DELAY, , , , true);
}


thePlayer.abilityManager.ResetOverhealBonus();

usedQuenInCombat = false;

theGame.GetGamerProfile().ResetStat(ES_FinesseKills);

LogChannel( 'OnCombatFinished', "OnCombatFinished: DelayedSheathSword timer added" );


inGameConfigWrapper = (CInGameConfigWrapper)theGame.GetInGameConfigWrapper();
disableAutoSheathe = inGameConfigWrapper.GetVarValue( 'Gameplay', 'DisableAutomaticSwordSheathe' );
if( !disableAutoSheathe )
{
if ( ShouldAutoSheathSwordInstantly() )
AddTimer( 'DelayedSheathSword', 0.5f );
else
AddTimer( 'DelayedSheathSword', 2.f );
}

OnBlockAllCombatTickets( false );


runewordInfusionType = ST_None;





}

public function PlayHitEffect( damageAction : W3DamageAction )
{
var hitReactionType : EHitReactionType;
var isAtBack : bool;


if( damageAction.GetMutation4Triggered() )
{
hitReactionType = damageAction.GetHitReactionType();
isAtBack = IsAttackerAtBack( damageAction.attacker );

if( hitReactionType != EHRT_Heavy )
{
if( isAtBack )
{
damageAction.SetHitEffect( 'light_hit_back_toxic', true );
}
else
{
damageAction.SetHitEffect( 'light_hit_toxic' );
}
}
else
{
if( isAtBack )
{
damageAction.SetHitEffect( 'heavy_hit_back_toxic' ,true );
}
else
{
damageAction.SetHitEffect( 'heavy_hit_toxic' );
}
}
}

super.PlayHitEffect( damageAction );
}

timer function DelayedAdrenalineDrain(dt : float, id : int)
{
if ( !HasBuff(EET_Runeword8) )
AddEffectDefault(EET_AdrenalineDrain, this, "after_combat_adrenaline_drain");
}


protected function Attack( hitTarget : CGameplayEntity, animData : CPreAttackEventData, weaponId : SItemUniqueId, parried : bool, countered : bool, parriedBy : array, attackAnimationName : name, hitTime : float, weaponEntity : CItemEntity)
{
var mutagen17 : W3Mutagen17_Effect;

super.Attack(hitTarget, animData, weaponId, parried, countered, parriedBy, attackAnimationName, hitTime, weaponEntity);

if( (CActor)hitTarget && HasBuff(EET_Mutagen17) )
{
mutagen17 = (W3Mutagen17_Effect)GetBuff(EET_Mutagen17);
if(mutagen17.HasBoost())
{
mutagen17.ClearBoost();
}
}
}

public final timer function SpecialAttackLightSustainCost(dt : float, id : int)
{
var focusPerSec, cost, delay : float;
var reduction : SAbilityAttributeValue;
var skillLevel : int;

if(abilityManager && abilityManager.IsInitialized() && IsAlive())
{
PauseStaminaRegen('WhirlSkill');

if(GetStat(BCS_Stamina) > 0)
{
cost = GetStaminaActionCost(ESAT_Ability, GetSkillAbilityName(S_Sword_s01), dt);
delay = GetStaminaActionDelay(ESAT_Ability, GetSkillAbilityName(S_Sword_s01), dt);
skillLevel = GetSkillLevel(S_Sword_s01);

if(skillLevel > 1)
{
reduction = GetSkillAttributeValue(S_Sword_s01, 'cost_reduction', false, true) * (skillLevel - 1);
cost = MaxF(0, cost * (1 - reduction.valueMultiplicative) - reduction.valueAdditive);
}

DrainStamina(ESAT_FixedValue, cost, delay, GetSkillAbilityName(S_Sword_s01));
}
else
{
GetSkillAttributeValue(S_Sword_s01, 'focus_cost_per_sec', false, true);
focusPerSec = GetWhirlFocusCostPerSec();
DrainFocus(focusPerSec * dt);
}
}

if(GetStat(BCS_Stamina) <= 0 && GetStat(BCS_Focus) <= 0)
{
OnPerformSpecialAttack(true, false);
}
}

public final function GetWhirlFocusCostPerSec() : float
{
var ability : SAbilityAttributeValue;
var val : float;
var skillLevel : int;

ability = GetSkillAttributeValue(S_Sword_s01, 'focus_cost_per_sec_initial', false, false);
skillLevel = GetSkillLevel(S_Sword_s01);

if(skillLevel > 1)
ability -= GetSkillAttributeValue(S_Sword_s01, 'cost_reduction', false, false) * (skillLevel-1);

val = CalculateAttributeValue(ability);

return val;
}

public final timer function SpecialAttackHeavySustainCost(dt : float, id : int)
{
var focusHighlight, ratio : float;
var hud : CR4ScriptedHud;
var hudWolfHeadModule : CR4HudModuleWolfHead;


DrainStamina(ESAT_Ability, 0, 0, GetSkillAbilityName(S_Sword_s02), dt);


if(GetStat(BCS_Stamina) <= 0)
OnPerformSpecialAttack(false, false);


ratio = EngineTimeToFloat(theGame.GetEngineTime() - specialHeavyStartEngineTime) / specialHeavyChargeDuration;


if(ratio > 0.95)
ratio = 1;

SetSpecialAttackTimeRatio(ratio);


focusHighlight = ratio * GetStatMax(BCS_Focus);
focusHighlight = MinF(focusHighlight, GetStat(BCS_Focus));
focusHighlight = FloorF(focusHighlight);

hud = (CR4ScriptedHud)theGame.GetHud();
if ( hud )
{
hudWolfHeadModule = (CR4HudModuleWolfHead)hud.GetHudModule( "WolfHeadModule" );
if ( hudWolfHeadModule )
{
hudWolfHeadModule.LockFocusPoints((int)focusHighlight);
}
}
}

public function OnSpecialAttackHeavyActionProcess()
{
var hud : CR4ScriptedHud;
var hudWolfHeadModule : CR4HudModuleWolfHead;

super.OnSpecialAttackHeavyActionProcess();

hud = (CR4ScriptedHud)theGame.GetHud();
if ( hud )
{
hudWolfHeadModule = (CR4HudModuleWolfHead)hud.GetHudModule( "WolfHeadModule" );
if ( hudWolfHeadModule )
{
hudWolfHeadModule.ResetFocusPoints();
}
}
}

timer function IsSpecialLightAttackInputHeld ( time : float, id : int )
{
var hasResource : bool;

if ( GetCurrentStateName() == 'CombatSteel' || GetCurrentStateName() == 'CombatSilver' )
{
if ( GetBIsCombatActionAllowed() && inputHandler.IsActionAllowed(EIAB_SwordAttack))
{
if(GetStat(BCS_Stamina) > 0)
{
hasResource = true;
}
else
{
hasResource = (GetStat(BCS_Focus) >= GetWhirlFocusCostPerSec() * time);
}

if(hasResource)
{
SetupCombatAction( EBAT_SpecialAttack_Light, BS_Pressed );
RemoveTimer('IsSpecialLightAttackInputHeld');
}
else if(!playedSpecialAttackMissingResourceSound)
{
IndicateTooLowAdrenaline();
playedSpecialAttackMissingResourceSound = true;
}
}
}
else
{
RemoveTimer('IsSpecialLightAttackInputHeld');
}
}

timer function IsSpecialHeavyAttackInputHeld ( time : float, id : int )
{
var cost : float;

if ( GetCurrentStateName() == 'CombatSteel' || GetCurrentStateName() == 'CombatSilver' )
{
cost = CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s02, 'stamina_cost_per_sec', false, false));

if( GetBIsCombatActionAllowed() && inputHandler.IsActionAllowed(EIAB_SwordAttack))
{
if(GetStat(BCS_Stamina) >= cost)
{
SetupCombatAction( EBAT_SpecialAttack_Heavy, BS_Pressed );
RemoveTimer('IsSpecialHeavyAttackInputHeld');
}
else if(!playedSpecialAttackMissingResourceSound)
{
IndicateTooLowAdrenaline();
playedSpecialAttackMissingResourceSound = true;
}
}
}
else
{
RemoveTimer('IsSpecialHeavyAttackInputHeld');
}
}

public function EvadePressed( bufferAction : EBufferActionType )
{
var cat : float;

if( (bufferAction == EBAT_Dodge && IsActionAllowed(EIAB_Dodge)) || (bufferAction == EBAT_Roll && IsActionAllowed(EIAB_Roll)) )
{

if(bufferAction != EBAT_Roll && ShouldProcessTutorial('TutorialDodge'))
{
FactsAdd("tut_in_dodge", 1, 2);

if(FactsQuerySum("tut_fight_use_slomo") > 0)
{
theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_TutorialFight) );
FactsRemove("tut_fight_slomo_ON");
}
}
else if(bufferAction == EBAT_Roll && ShouldProcessTutorial('TutorialRoll'))
{
FactsAdd("tut_in_roll", 1, 2);

if(FactsQuerySum("tut_fight_use_slomo") > 0)
{
theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_TutorialFight) );
FactsRemove("tut_fight_slomo_ON");
}
}

if ( GetBIsInputAllowed() )
{
if ( GetBIsCombatActionAllowed() )
{
CriticalEffectAnimationInterrupted("Dodge 2");
PushCombatActionOnBuffer( bufferAction, BS_Released );
ProcessCombatActionBuffer();
}
else if ( IsInCombatAction() && GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack )
{
if ( CanPlayHitAnim() && IsThreatened() )
{
CriticalEffectAnimationInterrupted("Dodge 1");
PushCombatActionOnBuffer( bufferAction, BS_Released );
ProcessCombatActionBuffer();
}
else
PushCombatActionOnBuffer( bufferAction, BS_Released );
}

else if ( !( IsCurrentSignChanneled() ) )
{

PushCombatActionOnBuffer( bufferAction, BS_Released );
}
}
else
{
if ( IsInCombatAction() && GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack )
{
if ( CanPlayHitAnim() && IsThreatened() )
{
CriticalEffectAnimationInterrupted("Dodge 3");
PushCombatActionOnBuffer( bufferAction, BS_Released );
ProcessCombatActionBuffer();
}
else
PushCombatActionOnBuffer( bufferAction, BS_Released );
}
LogChannel( 'InputNotAllowed', "InputNotAllowed" );
}
}
else
{
DisplayActionDisallowedHudMessage(EIAB_Dodge);
}
}


public function ProcessCombatActionBuffer() : bool
{
var action : EBufferActionType = this.BufferCombatAction;
var stage : EButtonStage = this.BufferButtonStage;
var throwStage : EThrowStage;
var actionResult : bool = true;


if( isInFinisher )
{
return false;
}

if ( action != EBAT_SpecialAttack_Heavy )
specialAttackCamera = false;


if(super.ProcessCombatActionBuffer())
return true;

switch ( action )
{
case EBAT_CastSign :
{
switch ( stage )
{
case BS_Pressed :
{






actionResult = this.CastSign();
LogChannel('SignDebug', "CastSign()");


} break;

default :
{
actionResult = false;
} break;
}
} break;

case EBAT_SpecialAttack_Light :
{
switch ( stage )
{
case BS_Pressed :
{

actionResult = this.OnPerformSpecialAttack( true, true );
} break;

case BS_Released :
{
actionResult = this.OnPerformSpecialAttack( true, false );
} break;

default :
{
actionResult = false;
} break;
}
} break;

case EBAT_SpecialAttack_Heavy :
{
switch ( stage )
{
case BS_Pressed :
{

actionResult = this.OnPerformSpecialAttack( false, true );
} break;

case BS_Released :
{
actionResult = this.OnPerformSpecialAttack( false, false );
} break;

default :
{
actionResult = false;
} break;
}
} break;

default:
return false;
}


this.CleanCombatActionBuffer();

if (actionResult)
{
SetCombatAction( action ) ;
}

return true;
}


event OnPerformSpecialAttack( isLightAttack : bool, enableAttack : bool ){}

public final function GetEnemies() : array< CActor >
{
var actors, actors2 : array;
var i : int;


actors = GetWitcherPlayer().GetHostileEnemies();
ArrayOfActorsAppendUnique( actors, GetWitcherPlayer().GetMoveTargets() );


thePlayer.GetVisibleEnemies( actors2 );
ArrayOfActorsAppendUnique( actors, actors2 );

for( i=actors.Size()-1; i>=0; i-=1 )
{
if( !IsRequiredAttitudeBetween( actors[i], this, true ) )
{
actors.EraseFast( i );
}
}

return actors;
}

event OnPlayerTickTimer( deltaTime : float )
{
super.OnPlayerTickTimer( deltaTime );

if ( !IsInCombat() )
{
fastAttackCounter = 0;
heavyAttackCounter = 0;
}
WmkGetMapMenuInstance().OnTick(deltaTime); // -= WMK:modAQOOM =-
}





protected function PrepareAttackAction( hitTarget : CGameplayEntity, animData : CPreAttackEventData, weaponId : SItemUniqueId, parried : bool, countered : bool, parriedBy : array, attackAnimationName : name, hitTime : float, weaponEntity : CItemEntity, out attackAction : W3Action_Attack) : bool
{
var ret : bool;
var skill : ESkill;

ret = super.PrepareAttackAction(hitTarget, animData, weaponId, parried, countered, parriedBy, attackAnimationName, hitTime, weaponEntity, attackAction);

if(!ret)
return false;


if(attackAction.IsActionMelee())
{
skill = SkillNameToEnum( attackAction.GetAttackTypeName() );
if( skill != S_SUndefined && CanUseSkill(skill))
{
if(IsLightAttack(animData.attackName))
fastAttackCounter += 1;
else
fastAttackCounter = 0;

if(IsHeavyAttack(animData.attackName))
heavyAttackCounter += 1;
else
heavyAttackCounter = 0;
}
}

AddTimer('FastAttackCounterDecay',5.0);
AddTimer('HeavyAttackCounterDecay',5.0);

return true;
}

protected function TestParryAndCounter(data : CPreAttackEventData, weaponId : SItemUniqueId, out parried : bool, out countered : bool) : array
{

if(SkillNameToEnum(attackActionName) == S_Sword_s02)
data.Can_Parry_Attack = false;

return super.TestParryAndCounter(data, weaponId, parried, countered);
}

private timer function FastAttackCounterDecay(delta : float, id : int)
{
fastAttackCounter = 0;
}

private timer function HeavyAttackCounterDecay(delta : float, id : int)
{
heavyAttackCounter = 0;
}


public function GetCraftingSchematicsNames() : array {return craftingSchematics;}

public function RemoveAllCraftingSchematics()
{
craftingSchematics.Clear();
}


function AddCraftingSchematic( nam : name, optional isSilent : bool, optional skipTutorialUpdate : bool ) : bool
{
var i : int;

if(!skipTutorialUpdate && ShouldProcessTutorial('TutorialCraftingGotRecipe'))
{
FactsAdd("tut_received_schematic");
}

for(i=0; i {
if(craftingSchematics[i] == nam)
return false;


if(StrCmp(craftingSchematics[i],nam) > 0)
{
craftingSchematics.Insert(i,nam);
AddCraftingHudNotification( nam, isSilent );
theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_CraftingSchematics );
return true;
}
}


craftingSchematics.PushBack(nam);
AddCraftingHudNotification( nam, isSilent );
theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_CraftingSchematics );
return true;
}

function AddCraftingHudNotification( nam : name, isSilent : bool )
{
var hud : CR4ScriptedHud;
if( !isSilent )
{
hud = (CR4ScriptedHud)theGame.GetHud();
if( hud )
{
hud.OnCraftingSchematicUpdate( nam );
}
}
}

function AddAlchemyHudNotification( nam : name, isSilent : bool )
{
var hud : CR4ScriptedHud;
if( !isSilent )
{
hud = (CR4ScriptedHud)theGame.GetHud();
if( hud )
{
hud.OnAlchemySchematicUpdate( nam );
}
}
}





event OnMutation11Triggered()
{
var min, max : SAbilityAttributeValue;
var healValue : float;
var quenEntity : W3QuenEntity;


if( IsSwimming() || IsDiving() || IsSailing() || IsUsingHorse() || IsUsingBoat() || IsUsingVehicle() || IsUsingExploration() )
{

ForceSetStat( BCS_Vitality, GetStatMax( BCS_Vitality ) );


theGame.MutationHUDFeedback( MFT_PlayOnce );


GCameraShake( 1.0f, , , , true, 'camera_shake_loop_lvl1_1' );
AddTimer( 'StopMutation11CamShake', 2.f );


theGame.VibrateControllerVeryHard( 2.f );


Mutation11ShockWave( true );


AddEffectDefault( EET_Mutation11Debuff, NULL, "Mutation 11 Debuff", false );
}
else
{
AddEffectDefault( EET_Mutation11Buff, this, "Mutation 11", false );
}
}

timer function StopMutation11CamShake( dt : float, id : int )
{
theGame.GetGameCamera().StopAnimation( 'camera_shake_loop_lvl1_1' );
}

private var mutation12IsOnCooldown : bool;

public final function AddMutation12Decoction()
{
var params : SCustomEffectParams;
var buffs : array< EEffectType >;
var existingDecoctionBuffs : array;
var i : int;
var effectType : EEffectType;
var decoctions : array< SItemUniqueId >;
var tmpName : name;
var min, max : SAbilityAttributeValue;

if( mutation12IsOnCooldown )
{
return;
}


existingDecoctionBuffs = GetDrunkMutagens( "Mutation12" );
theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation12', 'maxcap', min, max );
if( existingDecoctionBuffs.Size() >= min.valueAdditive )
{
return;
}


mutation12IsOnCooldown = true;
theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation12', 'cooldown', min, max );
AddTimer( 'Mutation12Cooldown', CalculateAttributeValue( min ) );


decoctions = inv.GetItemsByTag( 'Mutagen' );


for( i=decoctions.Size()-1; i>=0; i-=1 )
{
inv.GetPotionItemBuffData( decoctions[i], effectType, tmpName );
if( HasBuff( effectType ) )
{
decoctions.EraseFast( i );
continue;
}
buffs.PushBack( effectType );
}


if( buffs.Size() == 0 )
{
for( i=EET_Mutagen01; i<=EET_Mutagen28; i+=1 )
{
if( !HasBuff( i ) )
{
buffs.PushBack( i );
}
}
}


buffs.Remove( EET_Mutagen16 );
buffs.Remove( EET_Mutagen24 );


if( buffs.Size() == 0 )
{
return;
}


theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation12', 'duration', min, max );
params.effectType = buffs[ RandRange( buffs.Size() ) ];
params.creator = this;
params.sourceName = "Mutation12";
params.duration = min.valueAdditive;
AddEffectCustom( params );
( ( W3Mutagen_Effect ) GetBuff( params.effectType, params.sourceName ) ).OverrideIcon( DecoctionEffectTypeToItemName( params.effectType ) );


if ( !IsEffectActive( 'invisible' ) )
{
PlayEffect( 'use_potion' );
}

theGame.MutationHUDFeedback( MFT_PlayOnce );
}

timer function Mutation12Cooldown( dt : float, id : int )
{
mutation12IsOnCooldown = false;
}


public final function HasResourcesToStartAnyMutationResearch() : bool
{
var greenPoints, redPoints, bluePoints, count : int;
var itemIDs : array< SItemUniqueId >;

if( levelManager.GetPointsFree( ESkillPoint ) > 0 )
{
return true;
}


count = inv.GetItemQuantityByName( 'Greater mutagen green' );
if( count > 0 )
{
itemIDs = inv.GetItemsByName( 'Greater mutagen green' );
greenPoints = inv.GetMutationResearchPoints( SC_Green, itemIDs[0] );
if( greenPoints > 0 )
{
return true;
}
}
count = inv.GetItemQuantityByName( 'Greater mutagen red' );
if( count > 0 )
{
itemIDs.Clear();
itemIDs = inv.GetItemsByName( 'Greater mutagen red' );
redPoints = inv.GetMutationResearchPoints( SC_Red, itemIDs[0] );
if( redPoints > 0 )
{
return true;
}
}
count = inv.GetItemQuantityByName( 'Greater mutagen blue' );
if( count > 0 )
{
itemIDs.Clear();
itemIDs = inv.GetItemsByName( 'Greater mutagen blue' );
bluePoints = inv.GetMutationResearchPoints( SC_Blue, itemIDs[0] );
if( bluePoints > 0 )
{
return true;
}
}

return false;
}


public final function Mutation11StartAnimation()
{

thePlayer.ActionPlaySlotAnimationAsync( 'PLAYER_SLOT', 'geralt_mutation_11', 0.2, 0.2 );


BlockAllActions( 'Mutation11', true );


loopingCameraShakeAnimName = 'camera_shake_loop_lvl1_1';
GCameraShake( 1.0f, , , , true, loopingCameraShakeAnimName );


theGame.VibrateControllerVeryHard( 15.f );


storedInteractionPriority = GetInteractionPriority();
SetInteractionPriority( IP_Max_Unpushable );
}

event OnAnimEvent_Mutation11ShockWave( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
Mutation11ShockWave( false );
}

private final function Mutation11ShockWave( skipQuenSign : bool )
{
var action : W3DamageAction;
var ents : array< CGameplayEntity >;
var i, j : int;
var damages : array< SRawDamage >;


FindGameplayEntitiesInSphere(ents, GetWorldPosition(), 5.f, 1000, '', FLAG_OnlyAliveActors + FLAG_ExcludeTarget + FLAG_Attitude_Hostile + FLAG_Attitude_Neutral, this);

if( ents.Size() > 0 )
{
damages = theGame.GetDefinitionsManager().GetDamagesFromAbility( 'Mutation11' );
}


for(i=0; i {
action = new W3DamageAction in theGame;
action.Initialize( this, ents[i], NULL, "Mutation11", EHRT_Heavy, CPS_SpellPower, false, false, true, false );

for( j=0; j {
action.AddDamage( damages[j].dmgType, damages[j].dmgVal );
}

action.SetCannotReturnDamage( true );
action.SetProcessBuffsIfNoDamage( true );
action.AddEffectInfo( EET_KnockdownTypeApplicator );
action.SetHitAnimationPlayType( EAHA_ForceYes );
action.SetCanPlayHitParticle( false );

theGame.damageMgr.ProcessAction( action );
delete action;
}





mutation11QuenEntity = ( W3QuenEntity )GetSignEntity( ST_Quen );
if( !mutation11QuenEntity )
{
mutation11QuenEntity = (W3QuenEntity)theGame.CreateEntity( GetSignTemplate( ST_Quen ), GetWorldPosition(), GetWorldRotation() );
mutation11QuenEntity.CreateAttachment( this, 'quen_sphere' );
AddTimer( 'DestroyMutation11QuenEntity', 2.f );
}
mutation11QuenEntity.PlayHitEffect( 'quen_impulse_explode', mutation11QuenEntity.GetWorldRotation() );

if( !skipQuenSign )
{

PlayEffect( 'mutation_11_second_life' );


RestoreQuen( 1000000.f, 10.f, true );
}
}

private var mutation11QuenEntity : W3QuenEntity;
private var storedInteractionPriority : EInteractionPriority;

timer function DestroyMutation11QuenEntity( dt : float, id : int )
{
if( mutation11QuenEntity )
{
mutation11QuenEntity.Destroy();
}
}

event OnAnimEvent_Mutation11AnimEnd( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if( animEventType == AET_DurationEnd )
{

BlockAllActions( 'Mutation11', false );


theGame.GetGameCamera().StopAnimation( 'camera_shake_loop_lvl1_1' );


theGame.StopVibrateController();


SetInteractionPriority( storedInteractionPriority );


RemoveBuff( EET_Mutation11Buff, true );
}
else if ( animEventType == AET_DurationStart || animEventType == AET_DurationStartInTheMiddle )
{

SetBehaviorVariable( 'AIControlled', 0.f );
}
}

public final function MutationSystemEnable( enable : bool )
{
( ( W3PlayerAbilityManager ) abilityManager ).MutationSystemEnable( enable );
}

public final function IsMutationSystemEnabled() : bool
{
return ( ( W3PlayerAbilityManager ) abilityManager ).IsMutationSystemEnabled();
}

public final function GetMutation( mutationType : EPlayerMutationType ) : SMutation
{
return ( ( W3PlayerAbilityManager ) abilityManager ).GetMutation( mutationType );
}

public final function IsMutationActive( mutationType : EPlayerMutationType) : bool
{
var swordQuality : int;
var sword : SItemUniqueId;

if( !SSS_IsMutationEquipped( mutationType, GetEquippedMutationType() ) ) //zur13 modSSS
{
return false;
}

switch( mutationType )
{
case EPMT_Mutation4 :
case EPMT_Mutation5 :
case EPMT_Mutation7 :
case EPMT_Mutation8 :
case EPMT_Mutation10 :
case EPMT_Mutation11 :
case EPMT_Mutation12 :
if( IsInFistFight() )
{
return false;
}
}

if( mutationType == EPMT_Mutation1 )
{
sword = inv.GetCurrentlyHeldSword();
swordQuality = inv.GetItemQuality( sword );


if( swordQuality < 3 )
{
return false;
}
}

return true;
}

public final function SetEquippedMutation( mutationType : EPlayerMutationType ) : bool
{
return ( ( W3PlayerAbilityManager ) abilityManager ).SetEquippedMutation( mutationType );
}

public final function GetEquippedMutationType() : array< EPlayerMutationType > //zur13 modSSS
{
return ( ( W3PlayerAbilityManager ) abilityManager ).GetEquippedMutationType();
}

public final function CanEquipMutation(mutationType : EPlayerMutationType) : bool
{
return ( ( W3PlayerAbilityManager ) abilityManager ).CanEquipMutation( mutationType );
}

public final function CanResearchMutation( mutationType : EPlayerMutationType ) : bool
{
return ( ( W3PlayerAbilityManager ) abilityManager ).CanResearchMutation( mutationType );
}

public final function IsMutationResearched(mutationType : EPlayerMutationType) : bool
{
return ( ( W3PlayerAbilityManager ) abilityManager ).IsMutationResearched( mutationType );
}

public final function GetMutationResearchProgress(mutationType : EPlayerMutationType) : int
{
return ( ( W3PlayerAbilityManager ) abilityManager ).GetMutationResearchProgress( mutationType );
}

public final function GetMasterMutationStage() : int
{
return ( ( W3PlayerAbilityManager ) abilityManager ).GetMasterMutationStage();
}

public final function MutationResearchWithSkillPoints(mutation : EPlayerMutationType, skillPoints : int) : bool
{
return ( ( W3PlayerAbilityManager ) abilityManager ).MutationResearchWithSkillPoints( mutation, skillPoints );
}

public final function MutationResearchWithItem(mutation : EPlayerMutationType, item : SItemUniqueId) : bool
{
return ( ( W3PlayerAbilityManager ) abilityManager ).MutationResearchWithItem( mutation, item );
}

public final function GetMutationLocalizedName( mutationType : EPlayerMutationType ) : string
{
var pam : W3PlayerAbilityManager;
var locKey : name;

pam = (W3PlayerAbilityManager)GetWitcherPlayer().abilityManager;
locKey = pam.GetMutationNameLocalizationKey( mutationType );

return GetLocStringByKeyExt( locKey );
}

public final function GetMutationLocalizedDescription( mutationType : EPlayerMutationType ) : string
{
var pam : W3PlayerAbilityManager;
var locKey : name;
var arrStr : array< string >;
var dm : CDefinitionsManagerAccessor;
var min, max, sp : SAbilityAttributeValue;
var tmp, tmp2, tox, critBonusDamage, val : float;
var stats, stats2 : SPlayerOffenseStats;
var buffPerc, exampleEnemyCount, debuffPerc : int;

pam = (W3PlayerAbilityManager)GetWitcherPlayer().abilityManager;
locKey = pam.GetMutationDescriptionLocalizationKey( mutationType );
dm = theGame.GetDefinitionsManager();

switch( mutationType )
{
case EPMT_Mutation1 :
dm.GetAbilityAttributeValue('Mutation1', 'dmg_bonus_factor', min, max);
arrStr.PushBack( NoTrailZeros( RoundMath( 100 * min.valueAdditive ) ) );
break;

case EPMT_Mutation2 :
sp = GetPowerStatValue( CPS_SpellPower );


dm.GetAbilityAttributeValue( 'Mutation2', 'crit_chance_factor', min, max );
arrStr.PushBack( NoTrailZeros( RoundMath( 100 * ( min.valueAdditive + sp.valueMultiplicative * min.valueMultiplicative ) ) ) );


dm.GetAbilityAttributeValue( 'Mutation2', 'crit_damage_factor', min, max );
critBonusDamage = sp.valueMultiplicative * min.valueMultiplicative;

arrStr.PushBack( NoTrailZeros( RoundMath( 100 * critBonusDamage ) ) );
break;

case EPMT_Mutation3 :

dm.GetAbilityAttributeValue( 'Mutation3', 'attack_power', min, max );
tmp = min.valueMultiplicative;
arrStr.PushBack( NoTrailZeros( RoundMath( 100 * tmp ) ) );


dm.GetAbilityAttributeValue( 'Mutation3', 'maxcap', min, max );
arrStr.PushBack( NoTrailZeros( RoundMath( 100 * tmp * min.valueAdditive ) ) );
break;

case EPMT_Mutation4 :

dm.GetAbilityAttributeValue( 'AcidEffect', 'DirectDamage', min, max );
tmp2 = 100 * min.valueAdditive;
dm.GetAbilityAttributeValue( 'AcidEffect', 'duration', min, max );
tmp2 *= min.valueAdditive;
arrStr.PushBack( NoTrailZeros( tmp2 ) );


tox = GetStat( BCS_Toxicity );
if( tox > 0 )
{
tmp = RoundMath( tmp2 * tox );
}
else
{
tmp = tmp2;
}
arrStr.PushBack( NoTrailZeros( tmp ) );


tox = GetStatMax( BCS_Toxicity );
tmp = RoundMath( tmp2 * tox );
arrStr.PushBack( NoTrailZeros( tmp ) );
break;

case EPMT_Mutation5 :

dm.GetAbilityAttributeValue( 'Mutation5', 'mut5_dmg_red_perc', min, max );
tmp = min.valueAdditive;
arrStr.PushBack( NoTrailZeros( 100 * tmp ) );


arrStr.PushBack( NoTrailZeros( 100 * tmp * 3 ) );

break;

case EPMT_Mutation6 :

theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation6', 'full_freeze_chance', min, max );
arrStr.PushBack( NoTrailZeros( 100 * min.valueMultiplicative ) );


theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation6', 'ForceDamage', min, max );
sp = GetTotalSignSpellPower( S_Magic_1 );
val = sp.valueAdditive + sp.valueMultiplicative * ( sp.valueBase + min.valueAdditive );
arrStr.PushBack( NoTrailZeros( RoundMath( val ) ) );

break;

case EPMT_Mutation7 :

dm.GetAbilityAttributeValue( 'Mutation7Buff', 'attack_power', min, max );
buffPerc = (int) ( 100 * min.valueMultiplicative );
arrStr.PushBack( NoTrailZeros( buffPerc ) );


dm.GetAbilityAttributeValue( 'Mutation7BuffEffect', 'duration', min, max );
arrStr.PushBack( NoTrailZeros( min.valueAdditive ) );


exampleEnemyCount = 11;
arrStr.PushBack( exampleEnemyCount );


arrStr.PushBack( buffPerc * ( exampleEnemyCount -1 ) );


dm.GetAbilityAttributeValue( 'Mutation7Debuff', 'attack_power', min, max );
debuffPerc = (int) ( - 100 * min.valueMultiplicative );
arrStr.PushBack( NoTrailZeros( debuffPerc ) );


theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation7Debuff', 'minCapStacks', min, max );
arrStr.PushBack( NoTrailZeros( debuffPerc * min.valueAdditive ) );


dm.GetAbilityAttributeValue( 'Mutation7DebuffEffect', 'duration', min, max );
arrStr.PushBack( NoTrailZeros( min.valueAdditive ) );

break;

case EPMT_Mutation8 :

dm.GetAbilityAttributeValue( 'Mutation8', 'dmg_bonus', min, max );
arrStr.PushBack( NoTrailZeros( 100 * min.valueMultiplicative ) );


dm.GetAbilityAttributeValue( 'Mutation8', 'hp_perc_trigger', min, max );
arrStr.PushBack( NoTrailZeros( 100 * min.valueMultiplicative ) );

break;

case EPMT_Mutation9 :




stats = GetOffenseStatsList( 1 );
arrStr.PushBack( NoTrailZeros( RoundMath( stats.crossbowSteelDmg ) ) );


stats2 = GetOffenseStatsList( 2 );
arrStr.PushBack( NoTrailZeros( RoundMath( stats2.crossbowSteelDmg ) ) );


dm.GetAbilityAttributeValue( 'Mutation9', 'critical_hit_chance', min, max );
arrStr.PushBack( NoTrailZeros( 100 * min.valueMultiplicative ) );


dm.GetAbilityAttributeValue( 'Mutation9', 'health_reduction', min, max );
arrStr.PushBack( NoTrailZeros( 100 * min.valueMultiplicative ) );

break;

case EPMT_Mutation10 :

dm.GetAbilityAttributeValue( 'Mutation10Effect', 'mutation10_stat_boost', min, max );
arrStr.PushBack( NoTrailZeros( 100 * min.valueMultiplicative ) );


arrStr.PushBack( NoTrailZeros( 100 * min.valueMultiplicative * GetStatMax( BCS_Toxicity ) ) );

break;

case EPMT_Mutation11 :

arrStr.PushBack( 100 );


dm.GetAbilityAttributeValue( 'Mutation11DebuffEffect', 'duration', min, max);
arrStr.PushBack( NoTrailZeros( min.valueAdditive ) );
break;

case EPMT_Mutation12 :

dm.GetAbilityAttributeValue( 'Mutation12', 'duration', min, max );
arrStr.PushBack( NoTrailZeros( min.valueAdditive ) );


dm.GetAbilityAttributeValue( 'Mutation12', 'maxcap', min, max );
arrStr.PushBack( NoTrailZeros( min.valueAdditive ) );
break;

case EPMT_MutationMaster :

arrStr.PushBack( "4" );

break;
}

return GetLocStringByKeyExtWithParams( locKey, , , arrStr );
}

public final function ApplyMutation10StatBoost( out statValue : SAbilityAttributeValue )
{
var attValue : SAbilityAttributeValue;
var currToxicity : float;

if( IsMutationActive( EPMT_Mutation10 ) )
{
currToxicity = GetStat( BCS_Toxicity );
if( currToxicity > 0.f )
{
attValue = GetAttributeValue( 'mutation10_stat_boost' );
currToxicity *= attValue.valueMultiplicative;
statValue.valueMultiplicative += currToxicity;
}
}
}







public final function IsBookRead( bookName : name ):bool
{
return booksRead.Contains( bookName );
}

public final function AddReadBook( bookName : name ):void
{
if( !booksRead.Contains( bookName ) )
{
booksRead.PushBack( bookName );
}
}

public final function RemoveReadBook( bookName : name ):void
{
var idx : int = booksRead.FindFirst( bookName );

if( idx > -1 )
{
booksRead.Erase( idx );
}
}







public final function GetMutagenBuffs() : array< W3Mutagen_Effect >
{
var null : array< W3Mutagen_Effect >;

if(effectManager)
{
return effectManager.GetMutagenBuffs();
}

return null;
}

public function GetAlchemyRecipes() : array
{
return alchemyRecipes;
}

public function CanLearnAlchemyRecipe(recipeName : name) : bool
{
var dm : CDefinitionsManagerAccessor;
var recipeNode : SCustomNode;
var i, tmpInt : int;
var tmpName : name;

dm = theGame.GetDefinitionsManager();
if ( dm.GetSubNodeByAttributeValueAsCName( recipeNode, 'alchemy_recipes', 'name_name', recipeName ) )
{
return true;

}

return false;
}

private final function RemoveAlchemyRecipe(recipeName : name)
{
alchemyRecipes.Remove(recipeName);
}

private final function RemoveAllAlchemyRecipes()
{
alchemyRecipes.Clear();
}


function AddAlchemyRecipe(nam : name, optional isSilent : bool, optional skipTutorialUpdate : bool) : bool
{
var i, potions, bombs : int;
var found : bool;
var m_alchemyManager : W3AlchemyManager;
var recipe : SAlchemyRecipe;
var knownBombTypes : array;
var strRecipeName, recipeNameWithoutLevel : string;

if(!IsAlchemyRecipe(nam))
return false;

found = false;
for(i=0; i {
if(alchemyRecipes[i] == nam)
return false;


if(StrCmp(alchemyRecipes[i],nam) > 0)
{
alchemyRecipes.Insert(i,nam);
found = true;
AddAlchemyHudNotification(nam,isSilent);
break;
}
}

if(!found)
{
alchemyRecipes.PushBack(nam);
AddAlchemyHudNotification(nam,isSilent);
}

m_alchemyManager = new W3AlchemyManager in this;
m_alchemyManager.Init(alchemyRecipes);
m_alchemyManager.GetRecipe(nam, recipe);


if(CanUseSkill(S_Alchemy_s18))
{
if ((recipe.cookedItemType != EACIT_Bolt) && (recipe.cookedItemType != EACIT_Undefined) && (recipe.level <= GetSkillLevel(S_Alchemy_s18)))
AddAbility(SkillEnumToName(S_Alchemy_s18), true);

}


if(recipe.cookedItemType == EACIT_Bomb)
{
bombs = 0;
for(i=0; i {
m_alchemyManager.GetRecipe(alchemyRecipes[i], recipe);


if(recipe.cookedItemType == EACIT_Bomb)
{
strRecipeName = NameToString(alchemyRecipes[i]);
recipeNameWithoutLevel = StrLeft(strRecipeName, StrLen(strRecipeName)-2);
if(!knownBombTypes.Contains(recipeNameWithoutLevel))
{
bombs += 1;
knownBombTypes.PushBack(recipeNameWithoutLevel);
}
}
}

theGame.GetGamerProfile().SetStat(ES_KnownBombRecipes, bombs);
}

else if(recipe.cookedItemType == EACIT_Potion || recipe.cookedItemType == EACIT_MutagenPotion || recipe.cookedItemType == EACIT_Alcohol || recipe.cookedItemType == EACIT_Quest)
{
potions = 0;
for(i=0; i {
m_alchemyManager.GetRecipe(alchemyRecipes[i], recipe);


if(recipe.cookedItemType == EACIT_Potion || recipe.cookedItemType == EACIT_MutagenPotion || recipe.cookedItemType == EACIT_Alcohol || recipe.cookedItemType == EACIT_Quest)
{
potions += 1;
}
}
theGame.GetGamerProfile().SetStat(ES_KnownPotionRecipes, potions);
}

theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_AlchemyRecipe );

return true;
}







public function GetDisplayHeavyAttackIndicator() : bool
{
return bDispalyHeavyAttackIndicator;
}

public function SetDisplayHeavyAttackIndicator( val : bool )
{
bDispalyHeavyAttackIndicator = val;
}

public function GetDisplayHeavyAttackFirstLevelTimer() : bool
{
return bDisplayHeavyAttackFirstLevelTimer;
}

public function SetDisplayHeavyAttackFirstLevelTimer( val : bool )
{
bDisplayHeavyAttackFirstLevelTimer = val;
}







public function SelectQuickslotItem( slot : EEquipmentSlots )
{
var item : SItemUniqueId;

GetItemEquippedOnSlot(slot, item);
selectedItemId = item;
}







public function GetMedallion() : W3MedallionController
{
if ( !medallionController )
{
medallionController = new W3MedallionController in this;
}
return medallionController;
}


public final function HighlightObjects(range : float, optional highlightTime : float )
{
var ents : array;
var i : int;

FindGameplayEntitiesInSphere(ents, GetWorldPosition(), range, 100, 'HighlightedByMedalionFX', FLAG_ExcludePlayer);

if(highlightTime == 0)
highlightTime = 30;

for(i=0; i {
if(!ents[i].IsHighlighted())
{
ents[i].SetHighlighted( true );
ents[i].PlayEffectSingle( 'medalion_detection_fx' );
ents[i].AddTimer( 'MedallionEffectOff', highlightTime );
}
}
}


public final function HighlightEnemies(range : float, optional highlightTime : float )
{
var ents : array;
var i : int;
var catComponent : CGameplayEffectsComponent;

FindGameplayEntitiesInSphere(ents, GetWorldPosition(), range, 100, , FLAG_ExcludePlayer + FLAG_OnlyAliveActors);

if(highlightTime == 0)
highlightTime = 5;

for(i=0; i {
if(IsRequiredAttitudeBetween(this, ents[i], true))
{
catComponent = GetGameplayEffectsComponent(ents[i]);
if(catComponent)
{
catComponent.SetGameplayEffectFlag(EGEF_CatViewHiglight, true);
ents[i].AddTimer( 'EnemyHighlightOff', highlightTime, , , , , true );
}
}
}
}

function SpawnMedallionEntity()
{
var rot : EulerAngles;
var spawnedMedallion : CEntity;

spawnedMedallion = theGame.GetEntityByTag( 'new_Witcher_medallion_FX' );

if ( !spawnedMedallion )
theGame.CreateEntity( medallionEntity, GetWorldPosition(), rot, true, false );
}









public final function InterruptCombatFocusMode()
{
if( this.GetCurrentStateName() == 'CombatFocusMode_SelectSpot' )
{
SetCanPlayHitAnim( true );
PopState();
}
}

public final function IsInDarkPlace() : bool
{
var envs : array< string >;

if( FactsQuerySum( "tut_in_dark_place" ) )
{
return true;
}

GetActiveAreaEnvironmentDefinitions( envs );

if( envs.Contains( 'env_novigrad_cave' ) || envs.Contains( 'cave_catacombs' ) )
{
return true;
}

return false;
}





private saved var selectedPotionSlotUpper, selectedPotionSlotLower : EEquipmentSlots;
private var potionDoubleTapTimerRunning, potionDoubleTapSlotIsUpper : bool;
default selectedPotionSlotUpper = EES_Potion1;
default selectedPotionSlotLower = EES_Potion2;
default potionDoubleTapTimerRunning = false;

public final function SetPotionDoubleTapRunning(b : bool, optional isUpperSlot : bool)
{
if(b)
{
AddTimer('PotionDoubleTap', 0.3);
}
else
{
RemoveTimer('PotionDoubleTap');
}

potionDoubleTapTimerRunning = b;
potionDoubleTapSlotIsUpper = isUpperSlot;
}

public final function IsPotionDoubleTapRunning() : bool
{
return potionDoubleTapTimerRunning;
}

timer function PotionDoubleTap(dt : float, id : int)
{
potionDoubleTapTimerRunning = false;
OnPotionDrinkInput(potionDoubleTapSlotIsUpper);
}

public final function OnPotionDrinkInput(fromUpperSlot : bool)
{
var slot : EEquipmentSlots;

if(fromUpperSlot)
slot = GetSelectedPotionSlotUpper();
else
slot = GetSelectedPotionSlotLower();

DrinkPotionFromSlot(slot);
}

public final function OnPotionDrinkKeyboardsInput(slot : EEquipmentSlots)
{
DrinkPotionFromSlot(slot);
}

private function DrinkPotionFromSlot(slot : EEquipmentSlots):void
{
var item : SItemUniqueId;
var hud : CR4ScriptedHud;
var module : CR4HudModuleItemInfo;

GetItemEquippedOnSlot(slot, item);
if(inv.ItemHasTag(item, 'Edibles'))
{
ConsumeItem( item );
}
else
{
if (ToxicityLowEnoughToDrinkPotion(slot))
{
DrinkPreparedPotion(slot);
}
else
{
SendToxicityTooHighMessage();
}
}

hud = (CR4ScriptedHud)theGame.GetHud();
if ( hud )
{
module = (CR4HudModuleItemInfo)hud.GetHudModule("ItemInfoModule");
if( module )
{
module.ForceShowElement();
}
}
}

private function SendToxicityTooHighMessage()
{
var messageText : string;
var language : string;
var audioLanguage : string;

if (GetHudMessagesSize() < 2)
{
messageText = GetLocStringByKeyExt("menu_cannot_perform_action_now") + " " + GetLocStringByKeyExt("panel_common_statistics_tooltip_current_toxicity");

theGame.GetGameLanguageName(audioLanguage,language);
if (language == "AR")
{
messageText += (int)(abilityManager.GetStat(BCS_Toxicity, false)) + " / " + (int)(abilityManager.GetStatMax(BCS_Toxicity)) + " :";
}
else
{
messageText += ": " + (int)(abilityManager.GetStat(BCS_Toxicity, false)) + " / " + (int)(abilityManager.GetStatMax(BCS_Toxicity));
}

DisplayHudMessage(messageText);
}
theSound.SoundEvent("gui_global_denied");
}

public final function GetSelectedPotionSlotUpper() : EEquipmentSlots
{
return selectedPotionSlotUpper;
}

public final function GetSelectedPotionSlotLower() : EEquipmentSlots
{
return selectedPotionSlotLower;
}


public final function FlipSelectedPotion(isUpperSlot : bool) : bool
{
if(isUpperSlot)
{
if(selectedPotionSlotUpper == EES_Potion1 && IsAnyItemEquippedOnSlot(EES_Potion3))
{
selectedPotionSlotUpper = EES_Potion3;
return true;
}
else if(selectedPotionSlotUpper == EES_Potion3 && IsAnyItemEquippedOnSlot(EES_Potion1))
{
selectedPotionSlotUpper = EES_Potion1;
return true;
}
}
else
{
if(selectedPotionSlotLower == EES_Potion2 && IsAnyItemEquippedOnSlot(EES_Potion4))
{
selectedPotionSlotLower = EES_Potion4;
return true;
}
else if(selectedPotionSlotLower == EES_Potion4 && IsAnyItemEquippedOnSlot(EES_Potion2))
{
selectedPotionSlotLower = EES_Potion2;
return true;
}
}

return false;
}

public final function AddBombThrowDelay( bombId : SItemUniqueId )
{
var slot : EEquipmentSlots;

slot = GetItemSlot( bombId );

if( slot == EES_Unused )
{
return;
}

if( slot == EES_Petard1 || slot == EES_Quickslot1 )
{
remainingBombThrowDelaySlot1 = theGame.params.BOMB_THROW_DELAY;
AddTimer( 'BombDelay', 0.0f, true );
}
else if( slot == EES_Petard2 || slot == EES_Quickslot2 )
{
remainingBombThrowDelaySlot2 = theGame.params.BOMB_THROW_DELAY;
AddTimer( 'BombDelay', 0.0f, true );
}
else
{
return;
}
}

public final function GetBombDelay( slot : EEquipmentSlots ) : float
{
if( slot == EES_Petard1 || slot == EES_Quickslot1 )
{
return remainingBombThrowDelaySlot1;
}
else if( slot == EES_Petard2 || slot == EES_Quickslot2 )
{
return remainingBombThrowDelaySlot2;
}

return 0;
}

timer function BombDelay( dt : float, id : int )
{
remainingBombThrowDelaySlot1 = MaxF( 0.f , remainingBombThrowDelaySlot1 - dt );
remainingBombThrowDelaySlot2 = MaxF( 0.f , remainingBombThrowDelaySlot2 - dt );

if( remainingBombThrowDelaySlot1 <= 0.0f && remainingBombThrowDelaySlot2 <= 0.0f )
{
RemoveTimer('BombDelay');
}
}

public function ResetCharacterDev()
{

UnequipItemFromSlot(EES_SkillMutagen1);
UnequipItemFromSlot(EES_SkillMutagen2);
UnequipItemFromSlot(EES_SkillMutagen3);
UnequipItemFromSlot(EES_SkillMutagen4);

levelManager.ResetCharacterDev();
((W3PlayerAbilityManager)abilityManager).ResetCharacterDev();
}

public final function ResetMutationsDev()
{
levelManager.ResetMutationsDev();
((W3PlayerAbilityManager)abilityManager).ResetMutationsDev();
}

public final function GetHeldSword() : SItemUniqueId
{
var i : int;
var weapons : array< SItemUniqueId >;

weapons = inv.GetHeldWeapons();
for( i=0; i {
if( inv.IsItemSilverSwordUsableByPlayer( weapons[i] ) || inv.IsItemSteelSwordUsableByPlayer( weapons[i] ) )
{
return weapons[i];
}
}

return GetInvalidUniqueId();
}

public function ConsumeItem( itemId : SItemUniqueId ) : bool
{
var itemName : name;
var removedItem, willRemoveItem : bool;
var edibles : array;
var toSlot : EEquipmentSlots;
var i : int;
var equippedNewEdible : bool;

itemName = inv.GetItemName( itemId );

if (itemName == 'q111_imlerith_acorn' )
{
AddPoints(ESkillPoint, 2, true);
removedItem = inv.RemoveItem( itemId, 1 );
theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt("panel_character_popup_title_buy_skill") + "
" + GetLocStringByKeyExt("panel_character_availablepoints") + " +2");
theSound.SoundEvent("gui_character_buy_skill");
}
else if ( itemName == 'Clearing Potion' )
{
ResetCharacterDev();
removedItem = inv.RemoveItem( itemId, 1 );
theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt("panel_character_popup_character_cleared") );
theSound.SoundEvent("gui_character_synergy_effect");
}
else if ( itemName == 'Restoring Potion' )
{
ResetMutationsDev();
removedItem = inv.RemoveItem( itemId, 1 );
theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt("panel_character_popup_character_cleared") );
theSound.SoundEvent("gui_character_synergy_effect");
}
else if(itemName == 'Wolf Hour')
{
removedItem = inv.RemoveItem( itemId, 1 );
theSound.SoundEvent("gui_character_synergy_effect");
AddEffectDefault(EET_WolfHour, thePlayer, 'wolf hour');
}
else if ( itemName == 'q704_ft_golden_egg' )
{
AddPoints(ESkillPoint, 1, true);
removedItem = inv.RemoveItem( itemId, 1 );
theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt("panel_character_popup_title_buy_skill") + "
" + GetLocStringByKeyExt("panel_character_availablepoints") + " +1");
theSound.SoundEvent("gui_character_buy_skill");
}
else if ( itemName == 'mq7023_cake' )
{
this.AddAbility('mq7023_cake_vitality_bonus');
removedItem = inv.RemoveItem( itemId, 1 );
theSound.SoundEvent("gui_character_synergy_effect");
}
else
{
willRemoveItem = inv.GetItemQuantity(itemId) == 1 && !inv.ItemHasTag(itemId, 'InfiniteUse');

if(willRemoveItem)
toSlot = GetItemSlot(itemId);

removedItem = super.ConsumeItem(itemId);

if(willRemoveItem && removedItem)
{
edibles = inv.GetItemsByTag('Edibles');
equippedNewEdible = false;


for(i=0; i {
if(!IsItemEquipped(edibles[i]) && !inv.ItemHasTag(edibles[i], 'Alcohol') && inv.GetItemName(edibles[i]) != 'Clearing Potion' && inv.GetItemName(edibles[i]) != 'Wolf Hour')
{
EquipItemInGivenSlot(edibles[i], toSlot, true, false);
equippedNewEdible = true;
break;
}
}


if(!equippedNewEdible)
{
for(i=0; i {
if(!IsItemEquipped(edibles[i]) && inv.GetItemName(edibles[i]) != 'Clearing Potion' && inv.GetItemName(edibles[i]) != 'Wolf Hour')
{
EquipItemInGivenSlot(edibles[i], toSlot, true, false);
break;
}
}
}
}
}

return removedItem;
}


public final function GetAlcoholForAlchemicalItemsRefill() : SItemUniqueId
{
var alcos : array;
var id : SItemUniqueId;
var i, price, minPrice : int;

alcos = inv.GetItemsByTag(theGame.params.TAG_ALCHEMY_REFILL_ALCO);

if(alcos.Size() > 0)
{
if(inv.ItemHasTag(alcos[0], theGame.params.TAG_INFINITE_USE))
return alcos[0];

minPrice = inv.GetItemPrice(alcos[0]);
price = minPrice;
id = alcos[0];

for(i=1; i {
if(inv.ItemHasTag(alcos[i], theGame.params.TAG_INFINITE_USE))
return alcos[i];

price = inv.GetItemPrice(alcos[i]);

if(price < minPrice)
{
minPrice = price;
id = alcos[i];
}
}

return id;
}

return GetInvalidUniqueId();
}

public final function ClearPreviouslyUsedBolt()
{
previouslyUsedBolt = GetInvalidUniqueId();
}

public function GetCurrentInfiniteBoltName( optional forceBodkin : bool, optional forceHarpoon : bool ) : name
{
if(!forceBodkin && (forceHarpoon || GetCurrentStateName() == 'Swimming' || IsSwimming() || IsDiving()) )
{
return 'Harpoon Bolt';
}
return 'Bodkin Bolt';
}


public final function AddAndEquipInfiniteBolt(optional forceBodkin : bool, optional forceHarpoon : bool)
{
var bolt, bodkins, harpoons : array;
var boltItemName : name;
var i : int;


bodkins = inv.GetItemsByName('Bodkin Bolt');
harpoons = inv.GetItemsByName('Harpoon Bolt');

for(i=bodkins.Size()-1; i>=0; i-=1)
inv.RemoveItem(bodkins[i], inv.GetItemQuantity(bodkins[i]) );

for(i=harpoons.Size()-1; i>=0; i-=1)
inv.RemoveItem(harpoons[i], inv.GetItemQuantity(harpoons[i]) );



boltItemName = GetCurrentInfiniteBoltName( forceBodkin, forceHarpoon );


if(boltItemName == 'Bodkin Bolt' && inv.IsIdValid(previouslyUsedBolt))
{
bolt.PushBack(previouslyUsedBolt);
}
else
{

bolt = inv.AddAnItem(boltItemName, 1, true, true);


if(boltItemName == 'Harpoon Bolt')
{
GetItemEquippedOnSlot(EES_Bolt, previouslyUsedBolt);
}
}

EquipItem(bolt[0], EES_Bolt);
}


event OnItemGiven(data : SItemChangedData)
{
var m_guiManager : CR4GuiManager;

super.OnItemGiven(data);


if(!inv)
inv = GetInventory();


if(inv.IsItemEncumbranceItem(data.ids[0]))
UpdateEncumbrance();

m_guiManager = theGame.GetGuiManager();
if(m_guiManager)
m_guiManager.RegisterNewItem(data.ids[0]);
}


public final function CheckForFullyArmedAchievement()
{
if( HasAllItemsFromSet(theGame.params.ITEM_SET_TAG_BEAR) || HasAllItemsFromSet(theGame.params.ITEM_SET_TAG_GRYPHON) ||
HasAllItemsFromSet(theGame.params.ITEM_SET_TAG_LYNX) || HasAllItemsFromSet(theGame.params.ITEM_SET_TAG_WOLF) ||
HasAllItemsFromSet(theGame.params.ITEM_SET_TAG_VIPER)
)
{
theGame.GetGamerProfile().AddAchievement(EA_FullyArmed);
}
}


public final function HasAllItemsFromSet(setItemTag : name) : bool
{
var item : SItemUniqueId;

if(!GetItemEquippedOnSlot(EES_SteelSword, item) || !inv.ItemHasTag(item, setItemTag))
return false;

if(!GetItemEquippedOnSlot(EES_SilverSword, item) || !inv.ItemHasTag(item, setItemTag))
return false;

if(!GetItemEquippedOnSlot(EES_Boots, item) || !inv.ItemHasTag(item, setItemTag))
return false;

if(!GetItemEquippedOnSlot(EES_Pants, item) || !inv.ItemHasTag(item, setItemTag))
return false;

if(!GetItemEquippedOnSlot(EES_Gloves, item) || !inv.ItemHasTag(item, setItemTag))
return false;

if(!GetItemEquippedOnSlot(EES_Armor, item) || !inv.ItemHasTag(item, setItemTag))
return false;


if(setItemTag == theGame.params.ITEM_SET_TAG_BEAR || setItemTag == theGame.params.ITEM_SET_TAG_LYNX)
{
if(!GetItemEquippedOnSlot(EES_RangedWeapon, item) || !inv.ItemHasTag(item, setItemTag))
return false;
}

return true;
}




public function GetTotalArmor() : SAbilityAttributeValue
{
var armor : SAbilityAttributeValue;
var armorItem : SItemUniqueId;

armor = super.GetTotalArmor();

if(GetItemEquippedOnSlot(EES_Armor, armorItem))
{

armor -= inv.GetItemAttributeValue(armorItem, theGame.params.ARMOR_VALUE_NAME);


armor += inv.GetItemArmorTotal(armorItem);
}

if(GetItemEquippedOnSlot(EES_Pants, armorItem))
{

armor -= inv.GetItemAttributeValue(armorItem, theGame.params.ARMOR_VALUE_NAME);


armor += inv.GetItemArmorTotal(armorItem);
}

if(GetItemEquippedOnSlot(EES_Boots, armorItem))
{

armor -= inv.GetItemAttributeValue(armorItem, theGame.params.ARMOR_VALUE_NAME);


armor += inv.GetItemArmorTotal(armorItem);
}

if(GetItemEquippedOnSlot(EES_Gloves, armorItem))
{

armor -= inv.GetItemAttributeValue(armorItem, theGame.params.ARMOR_VALUE_NAME);


armor += inv.GetItemArmorTotal(armorItem);
}

return armor;
}



public function ReduceArmorDurability() : EEquipmentSlots
{
var r, sum : int;
var slot : EEquipmentSlots;
var id : SItemUniqueId;
var prevDurMult, currDurMult, ratio : float;


sum = theGame.params.DURABILITY_ARMOR_CHEST_WEIGHT;
sum += theGame.params.DURABILITY_ARMOR_PANTS_WEIGHT;
sum += theGame.params.DURABILITY_ARMOR_GLOVES_WEIGHT;
sum += theGame.params.DURABILITY_ARMOR_BOOTS_WEIGHT;
sum += theGame.params.DURABILITY_ARMOR_MISS_WEIGHT;

r = RandRange(sum);

if(r < theGame.params.DURABILITY_ARMOR_CHEST_WEIGHT)
slot = EES_Armor;
else if (r < theGame.params.DURABILITY_ARMOR_CHEST_WEIGHT + theGame.params.DURABILITY_ARMOR_PANTS_WEIGHT)
slot = EES_Pants;
else if (r < theGame.params.DURABILITY_ARMOR_CHEST_WEIGHT + theGame.params.DURABILITY_ARMOR_PANTS_WEIGHT + theGame.params.DURABILITY_ARMOR_GLOVES_WEIGHT)
slot = EES_Gloves;
else if (r < theGame.params.DURABILITY_ARMOR_CHEST_WEIGHT + theGame.params.DURABILITY_ARMOR_PANTS_WEIGHT + theGame.params.DURABILITY_ARMOR_GLOVES_WEIGHT + theGame.params.DURABILITY_ARMOR_BOOTS_WEIGHT)
slot = EES_Boots;
else
return EES_InvalidSlot;

GetItemEquippedOnSlot(slot, id);
ratio = inv.GetItemDurabilityRatio(id);
if(inv.ReduceItemDurability(id))
{
prevDurMult = theGame.params.GetDurabilityMultiplier(ratio, false);

ratio = inv.GetItemDurabilityRatio(id);
currDurMult = theGame.params.GetDurabilityMultiplier(ratio, false);

if(currDurMult != prevDurMult)
{




}

return slot;
}

return EES_InvalidSlot;
}


public function DismantleItem(dismantledItem : SItemUniqueId, toolItem : SItemUniqueId) : bool
{
var parts : array;
var i : int;

if(!inv.IsItemDismantleKit(toolItem))
return false;

parts = inv.GetItemRecyclingParts(dismantledItem);

if(parts.Size() <= 0)
return false;

for(i=0; i inv.AddAnItem(parts[i].itemName, parts[i].quantity, true, false);

inv.RemoveItem(toolItem);
inv.RemoveItem(dismantledItem);
return true;
}


public function GetItemEquippedOnSlot(slot : EEquipmentSlots, out item : SItemUniqueId) : bool
{
if(slot == EES_InvalidSlot || slot < 0 || slot > EnumGetMax('EEquipmentSlots'))
return false;

item = itemSlots[slot];

return inv.IsIdValid(item);
}


public function GetItemSlotByItemName(itemName : name) : EEquipmentSlots
{
var ids : array;
var i : int;
var slot : EEquipmentSlots;

ids = inv.GetItemsByName(itemName);
for(i=0; i {
slot = GetItemSlot(ids[i]);
if(slot != EES_InvalidSlot)
return slot;
}

return EES_InvalidSlot;
}


public function GetItemSlot(item : SItemUniqueId) : EEquipmentSlots
{
var i : int;

if(!inv.IsIdValid(item))
return EES_InvalidSlot;

for(i=0; i if(itemSlots[i] == item)
return i;

return EES_InvalidSlot;
}

public function GetEquippedItems() : array
{
return itemSlots;
}

public function IsItemEquipped(item : SItemUniqueId) : bool
{
if(!inv.IsIdValid(item))
return false;

return itemSlots.Contains(item);
}

public function IsItemHeld(item : SItemUniqueId) : bool
{
if(!inv.IsIdValid(item))
return false;

return inv.IsItemHeld(item);
}


public function IsAnyItemEquippedOnSlot(slot : EEquipmentSlots) : bool
{
if(slot == EES_InvalidSlot || slot < 0 || slot > EnumGetMax('EEquipmentSlots'))
return false;

return inv.IsIdValid(itemSlots[slot]);
}


public function GetFreeQuickslot() : EEquipmentSlots
{
if(!inv.IsIdValid(itemSlots[EES_Quickslot1])) return EES_Quickslot1;
if(!inv.IsIdValid(itemSlots[EES_Quickslot2])) return EES_Quickslot2;


return EES_InvalidSlot;
}


event OnEquipItemRequested(item : SItemUniqueId, ignoreMount : bool)
{
var slot : EEquipmentSlots;

if(inv.IsIdValid(item))
{
slot = inv.GetSlotForItemId(item);

if (slot != EES_InvalidSlot)
{


EquipItemInGivenSlot(item, slot, ignoreMount);
}
}
}

event OnUnequipItemRequested(item : SItemUniqueId)
{
UnequipItem(item);
}


public function EquipItem(item : SItemUniqueId, optional slot : EEquipmentSlots, optional toHand : bool) : bool
{
if(!inv.IsIdValid(item))
return false;

if(slot == EES_InvalidSlot)
{
slot = inv.GetSlotForItemId(item);

if(slot == EES_InvalidSlot)
return false;
}

ForceSoundAppearanceUpdate();

return EquipItemInGivenSlot(item, slot, false, toHand);
}

protected function ShouldMount(slot : EEquipmentSlots, item : SItemUniqueId, category : name):bool
{


return !IsSlotPotionMutagen(slot) && category != 'usable' && category != 'potion' && category != 'petard' && !inv.ItemHasTag(item, 'PlayerUnwearable');
}

protected function ShouldMountItemWithName( itemName: name ): bool
{
var slot : EEquipmentSlots;
var items : array;
var category : name;
var i : int;

items = inv.GetItemsByName( itemName );

category = inv.GetItemCategory( items[0] );

slot = GetItemSlot( items[0] );

return ShouldMount( slot, items[0], category );
}

public function GetMountableItems( out items : array< SItemUniqueId > )
{
var i : int;
var mountable : bool;
var mountableItems : array< SItemUniqueId >;
var slot : EEquipmentSlots;
var category : name;
var item: SItemUniqueId;

for ( i = 0; i < items.Size(); i += 1 )
{
item = items[i];

category = inv.GetItemCategory( item );

slot = GetItemSlot( item );

mountable = ShouldMount( slot, item, category );

if ( mountable )
{
mountableItems.PushBack( items[ i ] );
}
}
items = mountableItems;
}

public final function AddAndEquipItem( item : name ) : bool
{
var ids : array< SItemUniqueId >;

ids = inv.AddAnItem( item );
if( inv.IsIdValid( ids[ 0 ] ) )
{
return EquipItem( ids[ 0 ] );
}

return false;
}

public final function AddQuestMarkedSelectedQuickslotItem( sel : SSelectedQuickslotItem )
{
questMarkedSelectedQuickslotItems.PushBack( sel );
}

public final function GetQuestMarkedSelectedQuickslotItem( sourceName : name ) : SItemUniqueId
{
var i : int;

for( i=0; i {
if( questMarkedSelectedQuickslotItems[i].sourceName == sourceName )
{
return questMarkedSelectedQuickslotItems[i].itemID;
}
}

return GetInvalidUniqueId();
}

public final function SwapEquippedItems(slot1 : EEquipmentSlots, slot2 : EEquipmentSlots)
{
var temp : SItemUniqueId;
var pam : W3PlayerAbilityManager;

temp = itemSlots[slot1];
itemSlots[slot1] = itemSlots[slot2];
itemSlots[slot2] = temp;

if(IsSlotSkillMutagen(slot1))
{
pam = (W3PlayerAbilityManager)abilityManager;
if(pam)
pam.OnSwappedMutagensPost(itemSlots[slot1], itemSlots[slot2]);
}
}

public final function GetSlotForEquippedItem( itemID : SItemUniqueId ) : EEquipmentSlots
{
var i : int;

for( i=0; i {
if( itemSlots[i] == itemID )
{
return i;
}
}

return EES_InvalidSlot;
}

public function EquipItemInGivenSlot(item : SItemUniqueId, slot : EEquipmentSlots, ignoreMounting : bool, optional toHand : bool) : bool
{
var i, groupID : int;
var fistsID : array;
var pam : W3PlayerAbilityManager;
var isSkillMutagen : bool;
var armorEntity : CItemEntity;
var armorMeshComponent : CComponent;
var armorSoundIdentification : name;
var category : name;
var prevSkillColor : ESkillColor;
var containedAbilities : array;
var dm : CDefinitionsManagerAccessor;
var armorType : EArmorType;
var otherMask, previousItemInSlot : SItemUniqueId;
var tutStatePot : W3TutorialManagerUIHandlerStatePotions;
var tutStateFood : W3TutorialManagerUIHandlerStateFood;
var tutStateSecondPotionEquip : W3TutorialManagerUIHandlerStateSecondPotionEquip;
var boltItem : SItemUniqueId;
var aerondight : W3Effect_Aerondight;

if(!inv.IsIdValid(item))
{
LogAssert(false, "W3PlayerWitcher.EquipItemInGivenSlot: invalid item");
return false;
}
if(slot == EES_InvalidSlot || slot == EES_HorseBlinders || slot == EES_HorseSaddle || slot == EES_HorseBag || slot == EES_HorseTrophy)
{
LogAssert(false, "W3PlayerWitcher.EquipItem: Cannot equip item <<" + inv.GetItemName(item) + ">> - provided slot <<" + slot + ">> is invalid");
return false;
}
if(itemSlots[slot] == item)
{
return true;
}

if(!HasRequiredLevelToEquipItem(item))
{

return false;
}

if(inv.ItemHasTag(item, 'PhantomWeapon') && !GetPhantomWeaponMgr())
{
InitPhantomWeaponMgr();
}


if( slot == EES_SilverSword && inv.ItemHasTag( item, 'Aerondight' ) )
{
AddEffectDefault( EET_Aerondight, this, "Aerondight" );


aerondight = (W3Effect_Aerondight)GetBuff( EET_Aerondight );
aerondight.Pause( 'ManageAerondightBuff' );
}


previousItemInSlot = itemSlots[slot];
if( IsItemEquipped(item))
{
SwapEquippedItems(slot, GetItemSlot(item));
return true;
}


isSkillMutagen = IsSlotSkillMutagen(slot);
if(isSkillMutagen)
{
pam = (W3PlayerAbilityManager)abilityManager;
if(!pam.IsSkillMutagenSlotUnlocked(slot))
{
return false;
}
}


if(inv.IsIdValid(previousItemInSlot))
{
if(!UnequipItemFromSlot(slot, true))
{
LogAssert(false, "W3PlayerWitcher.EquipItem: Cannot equip item <<" + inv.GetItemName(item) + ">> !!");
return false;
}
}


if(inv.IsItemMask(item))
{
if(slot == EES_Quickslot1)
GetItemEquippedOnSlot(EES_Quickslot2, otherMask);
else
GetItemEquippedOnSlot(EES_Quickslot1, otherMask);

if(inv.IsItemMask(otherMask))
UnequipItem(otherMask);
}

if(isSkillMutagen)
{
groupID = pam.GetSkillGroupIdOfMutagenSlot(slot);
prevSkillColor = pam.GetSkillGroupColor(groupID);
}

itemSlots[slot] = item;

category = inv.GetItemCategory( item );


if( !ignoreMounting && ShouldMount(slot, item, category) )
{

inv.MountItem( item, toHand, IsSlotSkillMutagen( slot ) );
}

theTelemetry.LogWithLabelAndValue( TE_INV_ITEM_EQUIPPED, inv.GetItemName(item), slot );

if(slot == EES_RangedWeapon)
{
rangedWeapon = ( Crossbow )( inv.GetItemEntityUnsafe(item) );
if(!rangedWeapon)
AddTimer('DelayedOnItemMount', 0.1, true);

if ( IsSwimming() || IsDiving() )
{
GetItemEquippedOnSlot(EES_Bolt, boltItem);

if(inv.IsIdValid(boltItem))
{
if ( !inv.ItemHasTag(boltItem, 'UnderwaterAmmo' ))
{
AddAndEquipInfiniteBolt(false, true);
}
}
else if(!IsAnyItemEquippedOnSlot(EES_Bolt))
{
AddAndEquipInfiniteBolt(false, true);
}
}

else if(!IsAnyItemEquippedOnSlot(EES_Bolt))
AddAndEquipInfiniteBolt();
}
else if(slot == EES_Bolt)
{
if(rangedWeapon)
{ if ( !IsSwimming() || !IsDiving() )
{
rangedWeapon.OnReplaceAmmo();
rangedWeapon.OnWeaponReload();
}
else
{
DisplayHudMessage(GetLocStringByKeyExt( "menu_cannot_perform_action_now" ));
}
}
}

else if(isSkillMutagen)
{
pam.OnSkillMutagenEquipped(item, slot, prevSkillColor);
LogSkillColors("Mutagen <<" + inv.GetItemName(item) + ">> equipped to slot <<" + slot + ">>");
LogSkillColors("Group bonus color is now <<" + pam.GetSkillGroupColor(groupID) + ">>");
LogSkillColors("");
}
else if(slot == EES_Gloves && HasWeaponDrawn(false))
{
PlayRuneword4FX(PW_Steel);
PlayRuneword4FX(PW_Silver);
}

else if( ( slot == EES_Petard1 || slot == EES_Petard2 ) && inv.IsItemBomb( GetSelectedItemId() ) )
{
SelectQuickslotItem( slot );
}


if(inv.ItemHasAbility(item, 'MA_HtH'))
{
inv.GetItemContainedAbilities(item, containedAbilities);
fistsID = inv.GetItemsByName('fists');
dm = theGame.GetDefinitionsManager();
for(i=0; i {
if(dm.AbilityHasTag(containedAbilities[i], 'MA_HtH'))
{
inv.AddItemCraftedAbility(fistsID[0], containedAbilities[i], true);
}
}
}


if(inv.IsItemAnyArmor(item))
{
armorType = inv.GetArmorType(item);
pam = (W3PlayerAbilityManager)abilityManager;

if(armorType == EAT_Light)
{
if(CanUseSkill(S_Perk_05))
pam.SetPerkArmorBonus(S_Perk_05);
}
else if(armorType == EAT_Medium)
{
if(CanUseSkill(S_Perk_06))
pam.SetPerkArmorBonus(S_Perk_06);
}
else if(armorType == EAT_Heavy)
{
if(CanUseSkill(S_Perk_07))
pam.SetPerkArmorBonus(S_Perk_07);
}
}


UpdateItemSetBonuses( item, true );


theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnItemEquipped );


if(ShouldProcessTutorial('TutorialPotionCanEquip3'))
{
if(IsSlotPotionSlot(slot))
{
tutStatePot = (W3TutorialManagerUIHandlerStatePotions)theGame.GetTutorialSystem().uiHandler.GetCurrentState();
if(tutStatePot)
{
tutStatePot.OnPotionEquipped(inv.GetItemName(item));
}

tutStateSecondPotionEquip = (W3TutorialManagerUIHandlerStateSecondPotionEquip)theGame.GetTutorialSystem().uiHandler.GetCurrentState();
if(tutStateSecondPotionEquip)
{
tutStateSecondPotionEquip.OnPotionEquipped(inv.GetItemName(item));
}

}
}

if(ShouldProcessTutorial('TutorialFoodSelectTab'))
{
if( IsSlotPotionSlot(slot) && inv.IsItemFood(item))
{
tutStateFood = (W3TutorialManagerUIHandlerStateFood)theGame.GetTutorialSystem().uiHandler.GetCurrentState();
if(tutStateFood)
{
tutStateFood.OnFoodEquipped();
}
}
}


if(inv.IsItemSetItem(item))
{
CheckForFullyArmedAchievement();
}

return true;
}

private function CheckHairItem()
{
var ids : array;
var i : int;
var itemName : name;
var hairApplied : bool;

ids = inv.GetItemsByCategory('hair');

for(i=0; i {
itemName = inv.GetItemName( ids[i] );

if( itemName != 'Preview Hair' )
{
if( hairApplied == false )
{
inv.MountItem( ids[i], false );
hairApplied = true;
}
else
{
inv.RemoveItem( ids[i], 1 );
}

}
}

if( hairApplied == false )
{
ids = inv.AddAnItem('Half With Tail Hairstyle', 1, true, false);
inv.MountItem( ids[0], false );
}

}


timer function DelayedOnItemMount( dt : float, id : int )
{
var crossbowID : SItemUniqueId;
var invent : CInventoryComponent;

invent = GetInventory();
if(!invent)
return;


GetItemEquippedOnSlot(EES_RangedWeapon, crossbowID);

if(invent.IsIdValid(crossbowID))
{

rangedWeapon = ( Crossbow )(invent.GetItemEntityUnsafe(crossbowID) );

if(rangedWeapon)
{

RemoveTimer('DelayedOnItemMount');
}
}
else
{

RemoveTimer('DelayedOnItemMount');
}
}

public function GetHeldItems() : array
{
var items : array;
var item : SItemUniqueId;

if( inv.GetItemEquippedOnSlot(EES_SilverSword, item) && inv.IsItemHeld(item))
items.PushBack(item);

if( inv.GetItemEquippedOnSlot(EES_SteelSword, item) && inv.IsItemHeld(item))
items.PushBack(item);

if( inv.GetItemEquippedOnSlot(EES_RangedWeapon, item) && inv.IsItemHeld(item))
items.PushBack(item);

if( inv.GetItemEquippedOnSlot(EES_Quickslot1, item) && inv.IsItemHeld(item))
items.PushBack(item);

if( inv.GetItemEquippedOnSlot(EES_Quickslot2, item) && inv.IsItemHeld(item))
items.PushBack(item);

if( inv.GetItemEquippedOnSlot(EES_Petard1, item) && inv.IsItemHeld(item))
items.PushBack(item);

if( inv.GetItemEquippedOnSlot(EES_Petard2, item) && inv.IsItemHeld(item))
items.PushBack(item);

return items;
}


public function UnequipItemFromSlot(slot : EEquipmentSlots, optional reequipped : bool) : bool
{
var item, bolts, id : SItemUniqueId;
var items : array;
var retBool : bool;
var fistsID, bolt : array;
var i, groupID : int;
var pam : W3PlayerAbilityManager;
var prevSkillColor : ESkillColor;
var containedAbilities : array;
var dm : CDefinitionsManagerAccessor;
var armorType : EArmorType;
var isSwimming : bool;
var hud : CR4ScriptedHud;
var damagedItemModule : CR4HudModuleDamagedItems;

if(slot == EES_InvalidSlot || slot < 0 || slot > EnumGetMax('EEquipmentSlots') || !inv.IsIdValid(itemSlots[slot]))
return false;


if(IsSlotSkillMutagen(slot))
{

pam = (W3PlayerAbilityManager)abilityManager;
groupID = pam.GetSkillGroupIdOfMutagenSlot(slot);
prevSkillColor = pam.GetSkillGroupColor(groupID);
}


if(slot == EES_SilverSword || slot == EES_SteelSword)
{
PauseOilBuffs( slot == EES_SteelSword );
}

item = itemSlots[slot];
itemSlots[slot] = GetInvalidUniqueId();


if(inv.ItemHasTag( item, 'PhantomWeapon' ) && GetPhantomWeaponMgr())
{
DestroyPhantomWeaponMgr();
}




if( slot == EES_SilverSword && inv.ItemHasTag( item, 'Aerondight' ) )
{
RemoveBuff( EET_Aerondight );
}


if(slot == EES_RangedWeapon)
{

this.OnRangedForceHolster( true, true );
rangedWeapon.ClearDeployedEntity(true);
rangedWeapon = NULL;


if(GetItemEquippedOnSlot(EES_Bolt, bolts))
{
if(inv.ItemHasTag(bolts, theGame.params.TAG_INFINITE_AMMO))
{
inv.RemoveItem(bolts, inv.GetItemQuantity(bolts) );
}
}
}
else if(IsSlotSkillMutagen(slot))
{
pam.OnSkillMutagenUnequipped(item, slot, prevSkillColor);
LogSkillColors("Mutagen <<" + inv.GetItemName(item) + ">> unequipped from slot <<" + slot + ">>");
LogSkillColors("Group bonus color is now <<" + pam.GetSkillGroupColor(groupID) + ">>");
LogSkillColors("");
}


if(currentlyEquipedItem == item)
{
currentlyEquipedItem = GetInvalidUniqueId();
RaiseEvent('ForcedUsableItemUnequip');
}
if(currentlyEquipedItemL == item)
{
if ( currentlyUsedItemL )
{
currentlyUsedItemL.OnHidden( this );
}
HideUsableItem ( true );
}


if( !IsSlotPotionMutagen(slot) )
{
GetInventory().UnmountItem(item, true);
}

retBool = true;


if(IsAnyItemEquippedOnSlot(EES_RangedWeapon) && slot == EES_Bolt)
{
if(inv.ItemHasTag(item, theGame.params.TAG_INFINITE_AMMO))
{

inv.RemoveItem(item, inv.GetItemQuantityByName( inv.GetItemName(item) ) );
}
else if (!reequipped)
{

AddAndEquipInfiniteBolt();
}
}


if(slot == EES_SilverSword || slot == EES_SteelSword)
{
OnEquipMeleeWeapon(PW_None, true);
}

if( GetSelectedItemId() == item )
{
ClearSelectedItemId();
}

if(inv.IsItemBody(item))
{
retBool = true;
}

if(retBool && !reequipped)
{
theTelemetry.LogWithLabelAndValue( TE_INV_ITEM_UNEQUIPPED, inv.GetItemName(item), slot );


if(slot == EES_SteelSword && !IsAnyItemEquippedOnSlot(EES_SilverSword))
{
RemoveBuff(EET_EnhancedWeapon);
}
else if(slot == EES_SilverSword && !IsAnyItemEquippedOnSlot(EES_SteelSword))
{
RemoveBuff(EET_EnhancedWeapon);
}
else if(inv.IsItemAnyArmor(item))
{
if( !IsAnyItemEquippedOnSlot(EES_Armor) && !IsAnyItemEquippedOnSlot(EES_Gloves) && !IsAnyItemEquippedOnSlot(EES_Boots) && !IsAnyItemEquippedOnSlot(EES_Pants))
RemoveBuff(EET_EnhancedArmor);
}
}


if(inv.ItemHasAbility(item, 'MA_HtH'))
{
inv.GetItemContainedAbilities(item, containedAbilities);
fistsID = inv.GetItemsByName('fists');
dm = theGame.GetDefinitionsManager();
for(i=0; i {
if(dm.AbilityHasTag(containedAbilities[i], 'MA_HtH'))
{
inv.RemoveItemCraftedAbility(fistsID[0], containedAbilities[i]);
}
}
}


if(inv.IsItemAnyArmor(item))
{
armorType = inv.GetArmorType(item);
pam = (W3PlayerAbilityManager)abilityManager;

if(CanUseSkill(S_Perk_05) && (armorType == EAT_Light || GetCharacterStats().HasAbility('Glyphword 2 _Stats', true) || inv.ItemHasAbility(item, 'Glyphword 2 _Stats')))
{
pam.SetPerkArmorBonus(S_Perk_05);
}
if(CanUseSkill(S_Perk_06) && (armorType == EAT_Medium || GetCharacterStats().HasAbility('Glyphword 3 _Stats', true) || inv.ItemHasAbility(item, 'Glyphword 3 _Stats')) )
{
pam.SetPerkArmorBonus(S_Perk_06);
}
if(CanUseSkill(S_Perk_07) && (armorType == EAT_Heavy || GetCharacterStats().HasAbility('Glyphword 4 _Stats', true) || inv.ItemHasAbility(item, 'Glyphword 4 _Stats')) )
{
pam.SetPerkArmorBonus(S_Perk_07);
}
}


UpdateItemSetBonuses( item, false );


if( inv.ItemHasTag( item, theGame.params.ITEM_SET_TAG_BONUS ) && !IsSetBonusActive( EISB_RedWolf_2 ) )
{
SkillReduceBombAmmoBonus();
}

if( slot == EES_Gloves )
{
thePlayer.DestroyEffect('runeword_4');
}


hud = (CR4ScriptedHud)theGame.GetHud();
if ( hud )
{
damagedItemModule = hud.GetDamagedItemModule();
if ( damagedItemModule )
{
damagedItemModule.OnItemUnequippedFromSlot( slot );
}
}


theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnItemEquipped );

return retBool;
}

public function UnequipItem(item : SItemUniqueId) : bool
{
if(!inv.IsIdValid(item))
return false;

return UnequipItemFromSlot( itemSlots.FindFirst(item) );
}

public function DropItem( item : SItemUniqueId, quantity : int ) : bool
{
if(!inv.IsIdValid(item))
return false;
if(IsItemEquipped(item))
return UnequipItem(item);

return true;
}


public function IsItemEquippedByName(itemName : name) : bool
{
var i : int;

for(i=0; i if(inv.GetItemName(itemSlots[i]) == itemName)
return true;

return false;
}


public function IsItemEquippedByCategoryName(categoryName : name) : bool
{
var i : int;

for(i=0; i if(inv.GetItemCategory(itemSlots[i]) == categoryName)
return true;

return false;
}

public function GetMaxRunEncumbrance(out usesHorseBonus : bool) : float
{
var value : float;

value = CalculateAttributeValue(GetHorseManager().GetHorseAttributeValue('encumbrance', false));
usesHorseBonus = (value > 0);
value += CalculateAttributeValue( GetAttributeValue('encumbrance') );

return value;
}

public function GetEncumbrance() : float
{
var i: int;
var encumbrance : float;
var items : array;
var inve : CInventoryComponent;

inve = GetInventory();
inve.GetAllItems(items);

for(i=0; i {
encumbrance += inve.GetItemEncumbrance( items[i] );



}
return encumbrance;
}



public function StartInvUpdateTransaction():void
{
invUpdateTransaction = true;
}

public function FinishInvUpdateTransaction():void
{
invUpdateTransaction = false;



UpdateEncumbrance();
}


public function UpdateEncumbrance()
{
var temp : bool;

if (invUpdateTransaction)
{

return;
}



if ( GetEncumbrance() >= (GetMaxRunEncumbrance(temp) + 1) )
{
if( !HasBuff(EET_OverEncumbered) && FactsQuerySum( "DEBUG_EncumbranceBoy" ) == 0 )
{
AddEffectDefault(EET_OverEncumbered, NULL, "OverEncumbered");
}
}
else if(HasBuff(EET_OverEncumbered))
{
RemoveAllBuffsOfType(EET_OverEncumbered);
}
}

public final function GetSkillGroupIDFromIndex(idx : int) : int
{
var pam : W3PlayerAbilityManager;

pam = (W3PlayerAbilityManager)abilityManager;
if(pam && pam.IsInitialized())
return pam.GetSkillGroupIDFromIndex(idx);

return -1;
}

public final function GetSkillGroupColor(groupID : int) : ESkillColor
{
var pam : W3PlayerAbilityManager;

pam = (W3PlayerAbilityManager)abilityManager;
if(pam && pam.IsInitialized())
return pam.GetSkillGroupColor(groupID);

return SC_None;
}

public final function GetSkillGroupsCount() : int
{
var pam : W3PlayerAbilityManager;

pam = (W3PlayerAbilityManager)abilityManager;
if(pam && pam.IsInitialized())
return pam.GetSkillGroupsCount();

return 0;
}








function CycleSelectSign( bIsCyclingLeft : bool ) : ESignType
{
var signOrder : array;
var i : int;

signOrder.PushBack( ST_Yrden );
signOrder.PushBack( ST_Quen );
signOrder.PushBack( ST_Igni );
signOrder.PushBack( ST_Axii );
signOrder.PushBack( ST_Aard );

for( i = 0; i < signOrder.Size(); i += 1 )
if( signOrder[i] == equippedSign )
break;

if(bIsCyclingLeft)
return signOrder[ (4 + i) % 5 ];
else
return signOrder[ (6 + i) % 5 ];
}

function ToggleNextSign()
{
SetEquippedSign(CycleSelectSign( false ));
FactsAdd("SignToggled", 1, 1);
}

function TogglePreviousSign()
{
SetEquippedSign(CycleSelectSign( true ));
FactsAdd("SignToggled", 1, 1);
}

function ProcessSignEvent( eventName : name ) : bool
{
if( currentlyCastSign != ST_None && signs[currentlyCastSign].entity)
{
return signs[currentlyCastSign].entity.OnProcessSignEvent( eventName );
}

return false;
}

var findActorTargetTimeStamp : float;
var pcModeChanneledSignTimeStamp : float;
event OnProcessCastingOrientation( isContinueCasting : bool )
{
var customOrientationTarget : EOrientationTarget;
var checkHeading : float;
var rotHeading : float;
var playerToHeadingDist : float;
var slideTargetActor : CActor;
var newLockTarget : CActor;

var enableNoTargetOrientation : bool;

var currTime : float;

enableNoTargetOrientation = true;
if ( GetDisplayTarget() && this.IsDisplayTargetTargetable() )
{
enableNoTargetOrientation = false;
if ( theInput.GetActionValue( 'CastSignHold' ) > 0 || this.IsCurrentSignChanneled() )
{
if ( IsPCModeEnabled() )
{
if ( EngineTimeToFloat( theGame.GetEngineTime() ) > pcModeChanneledSignTimeStamp + 1.f )
enableNoTargetOrientation = true;
}
else
{
if ( GetCurrentlyCastSign() == ST_Igni || GetCurrentlyCastSign() == ST_Axii )
{
slideTargetActor = (CActor)GetDisplayTarget();
if ( slideTargetActor
&& ( !slideTargetActor.GetGameplayVisibility() || !CanBeTargetedIfSwimming( slideTargetActor ) || !slideTargetActor.IsAlive() ) )
{
SetSlideTarget( NULL );
if ( ProcessLockTarget() )
slideTargetActor = (CActor)slideTarget;
}

if ( !slideTargetActor )
{
LockToTarget( false );
enableNoTargetOrientation = true;
}
else if ( IsThreat( slideTargetActor ) || GetCurrentlyCastSign() == ST_Axii )
LockToTarget( true );
else
{
LockToTarget( false );
enableNoTargetOrientation = true;
}
}
}
}

if ( !enableNoTargetOrientation )
{
customOrientationTarget = OT_Actor;
}
}

if ( enableNoTargetOrientation )
{
if ( GetPlayerCombatStance() == PCS_AlertNear && theInput.GetActionValue( 'CastSignHold' ) > 0 )
{
if ( GetDisplayTarget() && !slideTargetActor )
{
currTime = EngineTimeToFloat( theGame.GetEngineTime() );
if ( currTime > findActorTargetTimeStamp + 1.5f )
{
findActorTargetTimeStamp = currTime;

newLockTarget = GetScreenSpaceLockTarget( GetDisplayTarget(), 180.f, 1.f, 0.f, true );

if ( newLockTarget && IsThreat( newLockTarget ) && IsCombatMusicEnabled() )
{
SetTarget( newLockTarget, true );
SetMoveTargetChangeAllowed( true );
SetMoveTarget( newLockTarget );
SetMoveTargetChangeAllowed( false );
SetSlideTarget( newLockTarget );
}
}
}
else
ProcessLockTarget();
}

if ( wasBRAxisPushed )
customOrientationTarget = OT_CameraOffset;
else
{
if ( !lastAxisInputIsMovement || theInput.LastUsedPCInput() )
customOrientationTarget = OT_CameraOffset;
else if ( theInput.GetActionValue( 'CastSignHold' ) > 0 )
{
if ( GetOrientationTarget() == OT_CameraOffset )
customOrientationTarget = OT_CameraOffset;
else if ( GetPlayerCombatStance() == PCS_AlertNear || GetPlayerCombatStance() == PCS_Guarded )
customOrientationTarget = OT_CameraOffset;
else
customOrientationTarget = OT_Player;
}
else
customOrientationTarget = OT_CustomHeading;
}
}

if ( GetCurrentlyCastSign() == ST_Quen )
{
if ( theInput.LastUsedPCInput() )
{
customOrientationTarget = OT_Camera;
}
else if ( IsCurrentSignChanneled() )
{
if ( bLAxisReleased )
customOrientationTarget = OT_Player;
else
customOrientationTarget = OT_Camera;
}
else
customOrientationTarget = OT_Player;
}

if ( GetCurrentlyCastSign() == ST_Axii && IsCurrentSignChanneled() )
{
if ( slideTarget && (CActor)slideTarget )
{
checkHeading = VecHeading( slideTarget.GetWorldPosition() - this.GetWorldPosition() );
rotHeading = checkHeading;
playerToHeadingDist = AngleDistance( GetHeading(), checkHeading );

if ( playerToHeadingDist > 45 )
SetCustomRotation( 'ChanneledSignAxii', rotHeading, 0.0, 0.5, false );
else if ( playerToHeadingDist < -45 )
SetCustomRotation( 'ChanneledSignAxii', rotHeading, 0.0, 0.5, false );
}
else
{
checkHeading = VecHeading( theCamera.GetCameraDirection() );
rotHeading = GetHeading();
playerToHeadingDist = AngleDistance( GetHeading(), checkHeading );

if ( playerToHeadingDist > 45 )
SetCustomRotation( 'ChanneledSignAxii', rotHeading - 22.5, 0.0, 0.5, false );
else if ( playerToHeadingDist < -45 )
SetCustomRotation( 'ChanneledSignAxii', rotHeading + 22.5, 0.0, 0.5, false );
}
}

if ( IsActorLockedToTarget() )
customOrientationTarget = OT_Actor;

AddCustomOrientationTarget( customOrientationTarget, 'Signs' );

if ( customOrientationTarget == OT_CustomHeading )
SetOrientationTargetCustomHeading( GetCombatActionHeading(), 'Signs' );
}

event OnRaiseSignEvent()
{
var newTarget : CActor;

if ( ( !IsCombatMusicEnabled() && !CanAttackWhenNotInCombat( EBAT_CastSign, false, newTarget ) ) || ( IsOnBoat() && !IsCombatMusicEnabled() ) )
{
if ( CastSignFriendly() )
return true;
}
else
{
RaiseEvent('CombatActionFriendlyEnd');
SetBehaviorVariable( 'SignNum', (int)equippedSign );
SetBehaviorVariable( 'combatActionType', (int)CAT_CastSign );

if ( IsPCModeEnabled() )
pcModeChanneledSignTimeStamp = EngineTimeToFloat( theGame.GetEngineTime() );

if( RaiseForceEvent('CombatAction') )
{
OnCombatActionStart();
findActorTargetTimeStamp = EngineTimeToFloat( theGame.GetEngineTime() );
theTelemetry.LogWithValueStr(TE_FIGHT_PLAYER_USE_SIGN, SignEnumToString( equippedSign ));
return true;
}
}

return false;
}

function CastSignFriendly() : bool
{
var actor : CActor;

SetBehaviorVariable( 'combatActionTypeForOverlay', (int)CAT_CastSign );
if ( RaiseCombatActionFriendlyEvent() )
{

return true;
}

return false;
}

function CastSign() : bool
{
var equippedSignStr : string;
var newSignEnt : W3SignEntity;
var spawnPos : Vector;
var slotMatrix : Matrix;
var target : CActor;

if ( IsInAir() )
{
return false;
}

AddTemporarySkills();



if(equippedSign == ST_Aard)
{
CalcEntitySlotMatrix('l_weapon', slotMatrix);
spawnPos = MatrixGetTranslation(slotMatrix);
}
else
{
spawnPos = GetWorldPosition();
}

if( equippedSign == ST_Aard || equippedSign == ST_Igni )
{
target = GetTarget();
if(target)
target.SignalGameplayEvent( 'DodgeSign' );
}

newSignEnt = (W3SignEntity)theGame.CreateEntity( signs[equippedSign].template, spawnPos, GetWorldRotation() );
return newSignEnt.Init( signOwner, signs[equippedSign].entity );
}


private function HAX_SignToThrowItemRestore()
{
var action : SInputAction;

action.value = theInput.GetActionValue('ThrowItemHold');
action.lastFrameValue = 0;

if(IsPressed(action) && CanSetupCombatAction_Throw())
{
if(inv.IsItemBomb(selectedItemId))
{
BombThrowStart();
}
else
{
UsableItemStart();
}

SetThrowHold( true );
}
}

event OnCFMCameraZoomFail(){}



public final function GetDrunkMutagens( optional sourceName : string ) : array
{
return effectManager.GetDrunkMutagens( sourceName );
}

public final function GetPotionBuffs() : array
{
return effectManager.GetPotionBuffs();
}

public final function RecalcPotionsDurations()
{
var i : int;
var buffs : array;

buffs = GetPotionBuffs();
for(i=0; i {
buffs[i].RecalcPotionDuration();
}
}

public function StartFrenzy()
{
var ratio, duration : float;
var skillLevel : int;

isInFrenzy = true;
skillLevel = GetSkillLevel(S_Alchemy_s16);
ratio = 0.48f - skillLevel * CalculateAttributeValue(GetSkillAttributeValue(S_Alchemy_s16, 'slowdown_ratio', false, true));
duration = skillLevel * CalculateAttributeValue(GetSkillAttributeValue(S_Alchemy_s16, 'slowdown_duration', false, true));

theGame.SetTimeScale(ratio, theGame.GetTimescaleSource(ETS_SkillFrenzy), theGame.GetTimescalePriority(ETS_SkillFrenzy) );
AddTimer('SkillFrenzyFinish', duration * ratio, , , , true);
}

timer function SkillFrenzyFinish(dt : float, optional id : int)
{
theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_SkillFrenzy) );
isInFrenzy = false;
}

public function GetToxicityDamageThreshold() : float
{
var ret : float;

ret = theGame.params.TOXICITY_DAMAGE_THRESHOLD;

if(CanUseSkill(S_Alchemy_s01))
ret += CalculateAttributeValue(GetSkillAttributeValue(S_Alchemy_s01, 'threshold', false, true)) * GetSkillLevel(S_Alchemy_s01);

return ret;
}



public final function AddToxicityOffset( val : float)
{
((W3PlayerAbilityManager)abilityManager).AddToxicityOffset(val);
}

public final function SetToxicityOffset( val : float)
{
((W3PlayerAbilityManager)abilityManager).SetToxicityOffset(val);
}

public final function RemoveToxicityOffset( val : float)
{
((W3PlayerAbilityManager)abilityManager).RemoveToxicityOffset(val);
}


public final function CalculatePotionDuration(item : SItemUniqueId, isMutagenPotion : bool, optional itemName : name) : float
{
var duration, skillPassiveMod, mutagenSkillMod : float;
var val, min, max : SAbilityAttributeValue;


if(inv.IsIdValid(item))
{
duration = CalculateAttributeValue(inv.GetItemAttributeValue(item, 'duration'));
}
else
{
theGame.GetDefinitionsManager().GetItemAttributeValueNoRandom(itemName, true, 'duration', min, max);
duration = CalculateAttributeValue(GetAttributeRandomizedValue(min, max));
}

skillPassiveMod = CalculateAttributeValue(GetAttributeValue('potion_duration'));

if(isMutagenPotion && CanUseSkill(S_Alchemy_s14))
{
val = GetSkillAttributeValue(S_Alchemy_s14, 'duration', false, true);
mutagenSkillMod = val.valueMultiplicative * GetSkillLevel(S_Alchemy_s14);
}

duration = duration * (1 + skillPassiveMod + mutagenSkillMod);

return duration;
}

public function ToxicityLowEnoughToDrinkPotion( slotid : EEquipmentSlots, optional itemId : SItemUniqueId ) : bool
{
var item : SItemUniqueId;
var maxTox : float;
var potionToxicity : float;
var toxicityOffset : float;
var effectType : EEffectType;
var customAbilityName : name;

if(itemId != GetInvalidUniqueId())
item = itemId;
else
item = itemSlots[slotid];

inv.GetPotionItemBuffData(item, effectType, customAbilityName);
maxTox = abilityManager.GetStatMax(BCS_Toxicity);
potionToxicity = CalculateAttributeValue(inv.GetItemAttributeValue(item, 'toxicity'));
toxicityOffset = CalculateAttributeValue(inv.GetItemAttributeValue(item, 'toxicity_offset'));

if(effectType != EET_WhiteHoney)
{
if(abilityManager.GetStat(BCS_Toxicity, false) + potionToxicity + toxicityOffset > maxTox )
{
return false;
}
}

return true;
}

public final function HasFreeToxicityToDrinkPotion( item : SItemUniqueId, effectType : EEffectType, out finalPotionToxicity : float ) : bool
{
var i : int;
var maxTox, toxicityOffset, adrenaline : float;
var costReduction : SAbilityAttributeValue;


if( effectType == EET_WhiteHoney )
{
return true;
}


maxTox = abilityManager.GetStatMax(BCS_Toxicity);
finalPotionToxicity = CalculateAttributeValue(inv.GetItemAttributeValue(item, 'toxicity'));
toxicityOffset = CalculateAttributeValue(inv.GetItemAttributeValue(item, 'toxicity_offset'));


if(CanUseSkill(S_Perk_13))
{
costReduction = GetSkillAttributeValue(S_Perk_13, 'cost_reduction', false, true);
adrenaline = FloorF(GetStat(BCS_Focus));
costReduction = costReduction * adrenaline;
finalPotionToxicity = (finalPotionToxicity - costReduction.valueBase) * (1 - costReduction.valueMultiplicative) - costReduction.valueAdditive;
finalPotionToxicity = MaxF(0.f, finalPotionToxicity);
}


if(abilityManager.GetStat(BCS_Toxicity, false) + finalPotionToxicity + toxicityOffset > maxTox )
{
return false;
}

return true;
}

public function DrinkPreparedPotion( slotid : EEquipmentSlots, optional itemId : SItemUniqueId )
{
var potParams : W3PotionParams;
var potionParams : SCustomEffectParams;
var factPotionParams : W3Potion_Fact_Params;
var adrenaline, hpGainValue, duration, finalPotionToxicity : float;
var ret : EEffectInteract;
var effectType : EEffectType;
var item : SItemUniqueId;
var customAbilityName, factId : name;
var atts : array;
var i : int;
var mutagenParams : W3MutagenBuffCustomParams;


if(itemId != GetInvalidUniqueId())
item = itemId;
else
item = itemSlots[slotid];


if(!inv.IsIdValid(item))
return;


if( inv.SingletonItemGetAmmo(item) == 0 )
return;


inv.GetPotionItemBuffData(item, effectType, customAbilityName);


if( !HasFreeToxicityToDrinkPotion( item, effectType, finalPotionToxicity ) )
{
return;
}


if(effectType == EET_Fact)
{
inv.GetItemAttributes(item, atts);

for(i=0; i {
if(StrBeginsWith(NameToString(atts[i]), "fact_"))
{
factId = atts[i];
break;
}
}

factPotionParams = new W3Potion_Fact_Params in theGame;
factPotionParams.factName = factId;
factPotionParams.potionItemName = inv.GetItemName(item);

potionParams.buffSpecificParams = factPotionParams;
}

else if(inv.ItemHasTag( item, 'Mutagen' ))
{
mutagenParams = new W3MutagenBuffCustomParams in theGame;
mutagenParams.toxicityOffset = CalculateAttributeValue(inv.GetItemAttributeValue(item, 'toxicity_offset'));
mutagenParams.potionItemName = inv.GetItemName(item);

potionParams.buffSpecificParams = mutagenParams;

if( IsMutationActive( EPMT_Mutation10 ) && !HasBuff( EET_Mutation10 ) )
{
AddEffectDefault( EET_Mutation10, this, "Mutation 10" );
}
}

else
{
potParams = new W3PotionParams in theGame;
potParams.potionItemName = inv.GetItemName(item);

potionParams.buffSpecificParams = potParams;
}


duration = CalculatePotionDuration(item, inv.ItemHasTag( item, 'Mutagen' ));


potionParams.effectType = effectType;
potionParams.creator = this;
potionParams.sourceName = "drank_potion";
potionParams.duration = duration;
potionParams.customAbilityName = customAbilityName;
ret = AddEffectCustom(potionParams);


if(factPotionParams)
delete factPotionParams;

if(mutagenParams)
delete mutagenParams;


inv.SingletonItemRemoveAmmo(item);


if(ret == EI_Pass || ret == EI_Override || ret == EI_Cumulate)
{
if( finalPotionToxicity > 0.f )
{
abilityManager.GainStat(BCS_Toxicity, finalPotionToxicity );
}


if(CanUseSkill(S_Perk_13))
{
abilityManager.DrainFocus(adrenaline);
}

if (!IsEffectActive('invisible'))
{
PlayEffect('use_potion');
}

if ( inv.ItemHasTag( item, 'Mutagen' ) )
{

theGame.GetGamerProfile().CheckTrialOfGrasses();


SetFailedFundamentalsFirstAchievementCondition(true);
}


if(CanUseSkill(S_Alchemy_s02))
{
hpGainValue = ClampF(GetStatMax(BCS_Vitality) * CalculateAttributeValue(GetSkillAttributeValue(S_Alchemy_s02, 'vitality_gain_perc', false, true)) * GetSkillLevel(S_Alchemy_s02), 0, GetStatMax(BCS_Vitality));
GainStat(BCS_Vitality, hpGainValue);
}


if(CanUseSkill(S_Alchemy_s04) && !skillBonusPotionEffect && (RandF() < CalculateAttributeValue(GetSkillAttributeValue(S_Alchemy_s04, 'apply_chance', false, true)) * GetSkillLevel(S_Alchemy_s04)))
{
AddRandomPotionEffectFromAlch4Skill( effectType );
}

theGame.GetGamerProfile().SetStat(ES_ActivePotions, effectManager.GetPotionBuffsCount());
}

theTelemetry.LogWithLabel(TE_ELIXIR_USED, inv.GetItemName(item));

if(ShouldProcessTutorial('TutorialPotionAmmo'))
{
FactsAdd("tut_used_potion");
}

SetFailedFundamentalsFirstAchievementCondition(true);
}


private final function AddRandomPotionEffectFromAlch4Skill( currentlyDrankPotion : EEffectType )
{
var randomPotions : array;
var currentPotion : CBaseGameplayEffect;
var effectsOld, effectsNew : array;
var i, ind : int;
var duration : float;
var params : SCustomEffectParams;
var ret : EEffectInteract;


randomPotions.PushBack( EET_BlackBlood );
randomPotions.PushBack( EET_Blizzard );
randomPotions.PushBack( EET_FullMoon );
randomPotions.PushBack( EET_GoldenOriole );
randomPotions.PushBack( EET_KillerWhale );
randomPotions.PushBack( EET_MariborForest );
randomPotions.PushBack( EET_PetriPhiltre );
randomPotions.PushBack( EET_Swallow );
randomPotions.PushBack( EET_TawnyOwl );
randomPotions.PushBack( EET_Thunderbolt );


randomPotions.Remove( currentlyDrankPotion );


ind = RandRange( randomPotions.Size() );


if( HasBuff( randomPotions[ ind ] ) )
{
currentPotion = GetBuff( randomPotions[ ind ] );
currentPotion.SetTimeLeft( currentPotion.GetInitialDurationAfterResists() );
}

else
{
duration = BonusPotionGetDurationFromXML( randomPotions[ ind ] );

if(duration > 0)
{
effectsOld = GetCurrentEffects();

params.effectType = randomPotions[ ind ];
params.creator = this;
params.sourceName = SkillEnumToName( S_Alchemy_s04 );
params.duration = duration;
ret = AddEffectCustom( params );


if( ret != EI_Undefined && ret != EI_Deny )
{
effectsNew = GetCurrentEffects();

ind = -1;
for( i=effectsNew.Size()-1; i>=0; i-=1)
{
if( !effectsOld.Contains( effectsNew[i] ) )
{
ind = i;
break;
}
}

if(ind > -1)
{
skillBonusPotionEffect = effectsNew[ind];
}
}
}
}
}


private function BonusPotionGetDurationFromXML(type : EEffectType) : float
{
var dm : CDefinitionsManagerAccessor;
var main, ingredients : SCustomNode;
var tmpName, typeName, itemName : name;
var abs : array;
var min, max : SAbilityAttributeValue;
var tmpInt : int;
var temp : array;
var i, temp2, temp3 : int;

dm = theGame.GetDefinitionsManager();
main = dm.GetCustomDefinition('alchemy_recipes');
typeName = EffectTypeToName(type);


for(i=0; i {
if(dm.GetCustomNodeAttributeValueName(main.subNodes[i], 'type_name', tmpName))
{

if(tmpName == typeName)
{
if(dm.GetCustomNodeAttributeValueInt(main.subNodes[i], 'level', tmpInt))
{

if(tmpInt == 1)
{
if(dm.GetCustomNodeAttributeValueName(main.subNodes[i], 'cookedItem_name', itemName))
{

if(IsNameValid(itemName))
{
break;
}
}
}
}
}
}
}

if(!IsNameValid(itemName))
return 0;


dm.GetItemAbilitiesWithWeights(itemName, true, abs, temp, temp2, temp3);
dm.GetAbilitiesAttributeValue(abs, 'duration', min, max);
return CalculateAttributeValue(GetAttributeRandomizedValue(min, max));
}

public function ClearSkillBonusPotionEffect()
{
skillBonusPotionEffect = NULL;
}

public function GetSkillBonusPotionEffect() : CBaseGameplayEffect
{
return skillBonusPotionEffect;
}







public final function HasRunewordActive(abilityName : name) : bool
{
var item : SItemUniqueId;
var hasRuneword : bool;

if(GetItemEquippedOnSlot(EES_SteelSword, item))
{
hasRuneword = inv.ItemHasAbility(item, abilityName);
}

if(!hasRuneword)
{
if(GetItemEquippedOnSlot(EES_SilverSword, item))
{
hasRuneword = inv.ItemHasAbility(item, abilityName);
}
}

return hasRuneword;
}

public final function GetShrineBuffs() : array
{
var null : array;

if(effectManager && effectManager.IsReady())
return effectManager.GetShrineBuffs();

return null;
}

public final function AddRepairObjectBuff(armor : bool, weapon : bool) : bool
{
var added : bool;

added = false;

if(weapon && (IsAnyItemEquippedOnSlot(EES_SilverSword) || IsAnyItemEquippedOnSlot(EES_SteelSword)) )
{
AddEffectDefault(EET_EnhancedWeapon, this, "repair_object", false);
added = true;
}

if(armor && (IsAnyItemEquippedOnSlot(EES_Armor) || IsAnyItemEquippedOnSlot(EES_Gloves) || IsAnyItemEquippedOnSlot(EES_Boots) || IsAnyItemEquippedOnSlot(EES_Pants)) )
{
AddEffectDefault(EET_EnhancedArmor, this, "repair_object", false);
added = true;
}

return added;
}


public function StartCSAnim(buff : CBaseGameplayEffect) : bool
{

if(IsAnyQuenActive() && (W3CriticalDOTEffect)buff)
return false;

return super.StartCSAnim(buff);
}

public function GetPotionBuffLevel(effectType : EEffectType) : int
{
if(effectManager && effectManager.IsReady())
return effectManager.GetPotionBuffLevel(effectType);

return 0;
}







event OnLevelGained(currentLevel : int, show : bool)
{
var i : int; // Added this
var itemN : array; // Added this
var isArmor : bool;
var isOther : bool;
var addArmor : bool;
var itemLevel : int;

var hud : CR4ScriptedHud;
hud = (CR4ScriptedHud)theGame.GetHud();

inv = thePlayer.GetInventory();

inv.GetAllItems(itemN); // Added this

for( i = 0; i < itemN.Size(); i += 1 ) // added this (Loops through every item in your inventory)
{
isArmor = false;
isOther = false;
addArmor = true;

if (thePlayer.inv.ItemHasTag(itemN[i], 'dlcArmor1') || thePlayer.inv.ItemHasTag(itemN[i], 'dlcArmor2'))
{
isArmor = true;
} else if (thePlayer.inv.ItemHasTag(itemN[i], 'dlcPants1') || thePlayer.inv.ItemHasTag(itemN[i], 'dlcPants2') || thePlayer.inv.ItemHasTag(itemN[i], 'dlcGloves1') || thePlayer.inv.ItemHasTag(itemN[i], 'dlcGloves2') || thePlayer.inv.ItemHasTag(itemN[i], 'dlcBoots1') || thePlayer.inv.ItemHasTag(itemN[i], 'dlcBoots2') )
{
isOther = true;
}
if( thePlayer.inv.ItemHasTag(itemN[i], 'ArmorMod') || thePlayer.inv.ItemHasTag(itemN[i], 'dlcModArmor') ) // Only ArmorMod items in your inventory
{
theGame.GameplayFactsSet("SignMod", 0);
itemLevel = thePlayer.GetInventory().GetItemLevel(itemN[i]); // Makes sure the Item Level is Re-Set on level up
if(isArmor || isOther)
{
if(itemLevel > thePlayer.GetLevel())
{
addArmor = false;
}
}
if(addArmor)
{
thePlayer.GetInventory().GetItemArmorTotal(itemN[i], true); // Add the new Armor Rating
}
}
} // End
if(abilityManager && abilityManager.IsInitialized())
{
((W3PlayerAbilityManager)abilityManager).OnLevelGained(currentLevel);
}

if ( theGame.GetDifficultyMode() != EDM_Hardcore )
{
Heal(GetStatMax(BCS_Vitality));
}


if(currentLevel >= 35)
{
theGame.GetGamerProfile().AddAchievement(EA_Immortal);
}

if ( hud && currentLevel < levelManager.GetMaxLevel() && FactsQuerySum( "DebugNoLevelUpUpdates" ) == 0 )
{
hud.OnLevelUpUpdate(currentLevel, show);
}

theGame.RequestAutoSave( "level gained", false );
}

public function GetSignStats(skill : ESkill, out damageType : name, out damageVal : float, out spellPower : SAbilityAttributeValue)
{
var i, size : int;
var dm : CDefinitionsManagerAccessor;
var attrs : array;

spellPower = GetPowerStatValue(CPS_SpellPower);

dm = theGame.GetDefinitionsManager();
dm.GetAbilityAttributes(GetSkillAbilityName(skill), attrs);
size = attrs.Size();

for( i = 0; i < size; i += 1 )
{
if( IsDamageTypeNameValid(attrs[i]) )
{
damageVal = CalculateAttributeValue(GetSkillAttributeValue(skill, attrs[i], false, true));
damageType = attrs[i];
break;
}
}
}


public function SetIgnorePainMaxVitality(val : float)
{
if(abilityManager && abilityManager.IsInitialized())
abilityManager.SetStatPointMax(BCS_Vitality, val);
}

event OnAnimEvent_ActionBlend( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if ( animEventType == AET_DurationStart && !disableActionBlend )
{
if ( this.IsCastingSign() )
ProcessSignEvent( 'cast_end' );


FindMoveTarget();
SetCanPlayHitAnim( true );
this.SetBIsCombatActionAllowed( true );

if ( this.GetFinisherVictim() && this.GetFinisherVictim().HasAbility( 'ForceFinisher' ) && !isInFinisher )
{
this.GetFinisherVictim().SignalGameplayEvent( 'Finisher' );
}
else if (this.BufferCombatAction != EBAT_EMPTY )
{



if ( !IsCombatMusicEnabled() )
{
SetCombatActionHeading( ProcessCombatActionHeading( this.BufferCombatAction ) );
FindTarget();
UpdateDisplayTarget( true );
}

if ( AllowAttack( GetTarget(), this.BufferCombatAction ) )
this.ProcessCombatActionBuffer();
}
else
{

ResumeStaminaRegen( 'InsideCombatAction' );



}
}
else if ( disableActionBlend )
{
disableActionBlend = false;
}
}


event OnAnimEvent_Sign( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if( animEventType == AET_Tick )
{
ProcessSignEvent( animEventName );
}
}

event OnAnimEvent_Throwable( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
var thrownEntity : CThrowable;

thrownEntity = (CThrowable)EntityHandleGet( thrownEntityHandle );

if ( inv.IsItemCrossbow( inv.GetItemFromSlot('l_weapon') ) && rangedWeapon.OnProcessThrowEvent( animEventName ) )
{
return true;
}
else if( thrownEntity && IsThrowingItem() && thrownEntity.OnProcessThrowEvent( animEventName ) )
{
return true;
}
}

event OnTaskSyncAnim( npc : CNewNPC, animNameLeft : name )
{
var tmpBool : bool;
var tmpName : name;
var damage, points, resistance : float;
var min, max : SAbilityAttributeValue;
var mc : EMonsterCategory;

super.OnTaskSyncAnim( npc, animNameLeft );

if( animNameLeft == 'BruxaBite' && IsMutationActive( EPMT_Mutation4 ) )
{
theGame.GetMonsterParamsForActor( npc, mc, tmpName, tmpBool, tmpBool, tmpBool );

if( mc == MC_Vampire )
{
GetResistValue( CDS_BleedingRes, points, resistance );

theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'BleedingEffect', 'DirectDamage', min, max );
damage = MaxF( 0.f, max.valueMultiplicative * GetMaxHealth() - points );

theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'BleedingEffect', 'duration', min, max );
damage *= min.valueAdditive * ( 1 - MinF( 1.f, resistance ) );

if( damage > 0.f )
{
npc.AddAbility( 'Mutation4BloodDebuff' );
ProcessActionMutation4ReturnedDamage( damage, npc, EAHA_ForceNo );
npc.AddTimer( 'RemoveMutation4BloodDebuff', 15.f, , , , , true );
}
}
}
}


public function ProcessActionMutation4ReturnedDamage( damageDealt : float, attacker : CActor, hitAnimationType : EActionHitAnim, optional action : W3DamageAction ) : bool
{
var customParams : SCustomEffectParams;
var currToxicity : float;
var min, max, customDamageValue : SAbilityAttributeValue;
var dm : CDefinitionsManagerAccessor;
var animAction : W3DamageAction;

if( damageDealt <= 0 )
{
return false;
}

if( action )
{
action.SetMutation4Triggered();
}

dm = theGame.GetDefinitionsManager();
currToxicity = GetStat( BCS_Toxicity );

dm.GetAbilityAttributeValue( 'AcidEffect', 'DirectDamage', min, max );
customDamageValue.valueAdditive = damageDealt * min.valueAdditive;

if( currToxicity > 0 )
{
customDamageValue.valueAdditive *= currToxicity;
}

dm.GetAbilityAttributeValue( 'AcidEffect', 'duration', min, max );
customDamageValue.valueAdditive /= min.valueAdditive;

customParams.effectType = EET_Acid;
customParams.effectValue = customDamageValue;
customParams.duration = min.valueAdditive;
customParams.creator = this;
customParams.sourceName = 'Mutation4';

attacker.AddEffectCustom( customParams );


animAction = new W3DamageAction in theGame;
animAction.Initialize( this, attacker, NULL, 'Mutation4', EHRT_Reflect, CPS_Undefined, true, false, false, false );
animAction.SetCannotReturnDamage( true );
animAction.SetCanPlayHitParticle( false );
animAction.SetHitAnimationPlayType( hitAnimationType );
theGame.damageMgr.ProcessAction( animAction );
delete animAction;

theGame.MutationHUDFeedback( MFT_PlayOnce );

return true;
}

event OnPlayerActionEnd()
{
var l_i : int;
var l_bed : W3WitcherBed;

l_i = (int)GetBehaviorVariable( 'playerExplorationAction' );

if( l_i == PEA_GoToSleep )
{
l_bed = (W3WitcherBed)theGame.GetEntityByTag( 'witcherBed' );
BlockAllActions( 'WitcherBed', false );
l_bed.ApplyAppearance( "collision" );
l_bed.GotoState( 'WakeUp' );
theGame.ReleaseNoSaveLock( l_bed.m_bedSaveLock );


substateManager.m_MovementCorrectorO.disallowRotWhenGoingToSleep = false;
}

super.OnPlayerActionEnd();
}

event OnPlayerActionStartFinished()
{
var l_initData : W3SingleMenuInitData;
var l_i : int;

l_i = (int)GetBehaviorVariable( 'playerExplorationAction' );

if( l_i == PEA_GoToSleep )
{
l_initData = new W3SingleMenuInitData in this;
l_initData.SetBlockOtherPanels( true );
l_initData.ignoreSaveSystem = true;
l_initData.ignoreMeditationCheck = true;
l_initData.setDefaultState( '' );
l_initData.isBonusMeditationAvailable = true;
l_initData.fixedMenuName = 'MeditationClockMenu';

theGame.RequestMenuWithBackground( 'MeditationClockMenu', 'CommonMenu', l_initData );
}

super.OnPlayerActionStartFinished();
}

public function IsInCombatAction_SpecialAttack() : bool
{
if ( IsInCombatAction() && ( GetCombatAction() == EBAT_SpecialAttack_Light || GetCombatAction() == EBAT_SpecialAttack_Heavy ) )
return true;
else
return false;
}

public function IsInCombatAction_SpecialAttackHeavy() : bool
{
if ( IsInCombatAction() && GetCombatAction() == EBAT_SpecialAttack_Heavy )
return true;
else
return false;
}

protected function WhenCombatActionIsFinished()
{
super.WhenCombatActionIsFinished();
RemoveTimer( 'ProcessAttackTimer' );
RemoveTimer( 'AttackTimerEnd' );
CastSignAbort();
specialAttackCamera = false;
this.OnPerformSpecialAttack( true, false );
}

event OnCombatActionEnd()
{
this.CleanCombatActionBuffer();
super.OnCombatActionEnd();

RemoveTemporarySkills();
}

event OnCombatActionFriendlyEnd()
{
if ( IsCastingSign() )
{
SetBehaviorVariable( 'IsCastingSign', 0 );
SetCurrentlyCastSign( ST_None, NULL );
LogChannel( 'ST_None', "ST_None" );
}

super.OnCombatActionFriendlyEnd();
}

public function GetPowerStatValue( stat : ECharacterPowerStats, optional ablName : name, optional ignoreDeath : bool ) : SAbilityAttributeValue
{
var result : SAbilityAttributeValue;


result = super.GetPowerStatValue( stat, ablName, ignoreDeath );
ApplyMutation10StatBoost( result );

return result;
}



timer function OpenRadialMenu( time: float, id : int )
{

if( GetBIsCombatActionAllowed() && !IsUITakeInput() )
{
bShowRadialMenu = true;
}

this.RemoveTimer('OpenRadialMenu');
}

public function OnAddRadialMenuOpenTimer( )
{





this.AddTimer('OpenRadialMenu', _HoldBeforeOpenRadialMenuTime * theGame.GetTimeScale() );

}

public function SetShowRadialMenuOpenFlag( bSet : bool )
{

bShowRadialMenu = bSet;
}

public function OnRemoveRadialMenuOpenTimer()
{

this.RemoveTimer('OpenRadialMenu');
}

public function ResetRadialMenuOpenTimer()
{

this.RemoveTimer('OpenRadialMenu');
if( GetBIsCombatActionAllowed() )
{


AddTimer('OpenRadialMenu', _HoldBeforeOpenRadialMenuTime * theGame.GetTimeScale() );
}
}



timer function ResendCompanionDisplayName(dt : float, id : int)
{
var hud : CR4ScriptedHud;
var companionModule : CR4HudModuleCompanion;

hud = (CR4ScriptedHud)theGame.GetHud();
if( hud )
{
companionModule = (CR4HudModuleCompanion)hud.GetHudModule("CompanionModule");
if( companionModule )
{
companionModule.ResendDisplayName();
}
}
}

timer function ResendCompanionDisplayNameSecond(dt : float, id : int)
{
var hud : CR4ScriptedHud;
var companionModule : CR4HudModuleCompanion;

hud = (CR4ScriptedHud)theGame.GetHud();
if( hud )
{
companionModule = (CR4HudModuleCompanion)hud.GetHudModule("CompanionModule");
if( companionModule )
{
companionModule.ResendDisplayNameSecond();
}
}
}

public function RemoveCompanionDisplayNameTimer()
{
this.RemoveTimer('ResendCompanionDisplayName');
}

public function RemoveCompanionDisplayNameTimerSecond()
{
this.RemoveTimer('ResendCompanionDisplayNameSecond');
}


public function GetCompanionNPCTag() : name
{
return companionNPCTag;
}

public function SetCompanionNPCTag( value : name )
{
companionNPCTag = value;
}

public function GetCompanionNPCTag2() : name
{
return companionNPCTag2;
}

public function SetCompanionNPCTag2( value : name )
{
companionNPCTag2 = value;
}

public function GetCompanionNPCIconPath() : string
{
return companionNPCIconPath;
}

public function SetCompanionNPCIconPath( value : string )
{
companionNPCIconPath = value;
}

public function GetCompanionNPCIconPath2() : string
{
return companionNPCIconPath2;
}

public function SetCompanionNPCIconPath2( value : string )
{
companionNPCIconPath2 = value;
}



public function ReactToBeingHit(damageAction : W3DamageAction, optional buffNotApplied : bool) : bool
{
var chance : float;
var procQuen : W3SignEntity;

if(!damageAction.IsDoTDamage() && damageAction.DealsAnyDamage())
{
if(inv.IsItemBomb(selectedItemId))
{
BombThrowAbort();
}
else
{

ThrowingAbort();
}
}


if(damageAction.IsActionRanged())
{
chance = CalculateAttributeValue(GetAttributeValue('quen_chance_on_projectile'));
if(chance > 0)
{
chance = ClampF(chance, 0, 1);

if(RandF() < chance)
{
procQuen = (W3SignEntity)theGame.CreateEntity(signs[ST_Quen].template, GetWorldPosition(), GetWorldRotation() );
procQuen.Init(signOwner, signs[ST_Quen].entity, true );
procQuen.OnStarted();
procQuen.OnThrowing();
procQuen.OnEnded();
}
}
}


if( !((W3Effect_Toxicity)damageAction.causer) )
MeditationForceAbort(true);


if(IsDoingSpecialAttack(false))
damageAction.SetHitAnimationPlayType(EAHA_ForceNo);

return super.ReactToBeingHit(damageAction, buffNotApplied);
}

protected function ShouldPauseHealthRegenOnHit() : bool
{

if( ( HasBuff( EET_Swallow ) && GetPotionBuffLevel( EET_Swallow ) >= 3 ) || HasBuff( EET_Runeword8 ) || HasBuff( EET_Mutation11Buff ) )
{
return false;
}

return true;
}

public function SetMappinToHighlight( mappinName : name, mappinState : bool )
{
var mappinDef : SHighlightMappin;
mappinDef.MappinName = mappinName;
mappinDef.MappinState = mappinState;
MappinToHighlight.PushBack(mappinDef);
}

public function ClearMappinToHighlight()
{
MappinToHighlight.Clear();
}

public function CastSignAbort()
{
if( currentlyCastSign != ST_None && signs[currentlyCastSign].entity)
{
signs[currentlyCastSign].entity.OnSignAborted();
}


}

event OnBlockingSceneStarted( scene: CStoryScene )
{
var med : W3PlayerWitcherStateMeditationWaiting;


med = (W3PlayerWitcherStateMeditationWaiting)GetCurrentState();
if(med)
{
med.StopRequested(true);
}


super.OnBlockingSceneStarted( scene );
}





public function GetHorseManager() : W3HorseManager
{
return (W3HorseManager)EntityHandleGet( horseManagerHandle );
}


public function HorseEquipItem(horsesItemId : SItemUniqueId) : bool
{
var man : W3HorseManager;

man = GetHorseManager();
if(man)
return man.EquipItem(horsesItemId) != GetInvalidUniqueId();

return false;
}


public function HorseUnequipItem(slot : EEquipmentSlots) : bool
{
var man : W3HorseManager;

man = GetHorseManager();
if(man)
return man.UnequipItem(slot) != GetInvalidUniqueId();

return false;
}


public final function HorseRemoveItemByName(itemName : name, quantity : int)
{
var man : W3HorseManager;

man = GetHorseManager();
if(man)
man.HorseRemoveItemByName(itemName, quantity);
}


public final function HorseRemoveItemByCategory(itemCategory : name, quantity : int)
{
var man : W3HorseManager;

man = GetHorseManager();
if(man)
man.HorseRemoveItemByCategory(itemCategory, quantity);
}


public final function HorseRemoveItemByTag(itemTag : name, quantity : int)
{
var man : W3HorseManager;

man = GetHorseManager();
if(man)
man.HorseRemoveItemByTag(itemTag, quantity);
}

public function GetAssociatedInventory() : CInventoryComponent
{
var man : W3HorseManager;

man = GetHorseManager();
if(man)
return man.GetInventoryComponent();

return NULL;
}





public final function TutorialMutagensUnequipPlayerSkills() : array
{
var pam : W3PlayerAbilityManager;

pam = (W3PlayerAbilityManager)abilityManager;
return pam.TutorialMutagensUnequipPlayerSkills();
}

public final function TutorialMutagensEquipOneGoodSkill()
{
var pam : W3PlayerAbilityManager;

pam = (W3PlayerAbilityManager)abilityManager;
pam.TutorialMutagensEquipOneGoodSkill();
}

public final function TutorialMutagensEquipOneGoodOneBadSkill()
{
var pam : W3PlayerAbilityManager;

pam = (W3PlayerAbilityManager)abilityManager;
if(pam)
pam.TutorialMutagensEquipOneGoodOneBadSkill();
}

public final function TutorialMutagensEquipThreeGoodSkills()
{
var pam : W3PlayerAbilityManager;

pam = (W3PlayerAbilityManager)abilityManager;
if(pam)
pam.TutorialMutagensEquipThreeGoodSkills();
}

public final function TutorialMutagensCleanupTempSkills(savedEquippedSkills : array)
{
var pam : W3PlayerAbilityManager;

pam = (W3PlayerAbilityManager)abilityManager;
return pam.TutorialMutagensCleanupTempSkills(savedEquippedSkills);
}





public final function CalculatedArmorStaminaRegenBonus() : float
{
var armorEq, glovesEq, pantsEq, bootsEq : bool;
var tempItem : SItemUniqueId;
var staminaRegenVal : float;
var armorRegenVal : SAbilityAttributeValue;

if( HasAbility( 'Glyphword 2 _Stats', true ) )
{
armorEq = inv.GetItemEquippedOnSlot( EES_Armor, tempItem );
glovesEq = inv.GetItemEquippedOnSlot( EES_Gloves, tempItem );
pantsEq = inv.GetItemEquippedOnSlot( EES_Pants, tempItem );
bootsEq = inv.GetItemEquippedOnSlot( EES_Boots, tempItem );

if ( armorEq )
staminaRegenVal += 0.1;
if ( glovesEq )
staminaRegenVal += 0.02;
if ( pantsEq )
staminaRegenVal += 0.1;
if ( bootsEq )
staminaRegenVal += 0.03;

}
else if( HasAbility( 'Glyphword 3 _Stats', true ) )
{
staminaRegenVal = 0;
}
else if( HasAbility( 'Glyphword 4 _Stats', true ) )
{
armorEq = inv.GetItemEquippedOnSlot( EES_Armor, tempItem );
glovesEq = inv.GetItemEquippedOnSlot( EES_Gloves, tempItem );
pantsEq = inv.GetItemEquippedOnSlot( EES_Pants, tempItem );
bootsEq = inv.GetItemEquippedOnSlot( EES_Boots, tempItem );

if ( armorEq )
staminaRegenVal -= 0.1;
if ( glovesEq )
staminaRegenVal -= 0.02;
if ( pantsEq )
staminaRegenVal -= 0.1;
if ( bootsEq )
staminaRegenVal -= 0.03;
}
else
{
armorRegenVal = GetAttributeValue('staminaRegen_armor_mod');
staminaRegenVal = armorRegenVal.valueMultiplicative;
}

return staminaRegenVal;
}

public function GetOffenseStatsList( optional hackMode : int ) : SPlayerOffenseStats
{
var playerOffenseStats:SPlayerOffenseStats;
var steelDmg, silverDmg, elementalSteel, elementalSilver : float;
var steelCritChance, steelCritDmg : float;
var silverCritChance, silverCritDmg : float;
var attackPower : SAbilityAttributeValue;
var fastCritChance, fastCritDmg : float;
var strongCritChance, strongCritDmg : float;
var fastAP, strongAP, min, max : SAbilityAttributeValue;
var item, crossbow : SItemUniqueId;
var value : SAbilityAttributeValue;
var mutagen : CBaseGameplayEffect;
var thunder : W3Potion_Thunderbolt;

if(!abilityManager || !abilityManager.IsInitialized())
return playerOffenseStats;

if (CanUseSkill(S_Sword_s21))
fastAP += GetSkillAttributeValue(S_Sword_s21, PowerStatEnumToName(CPS_AttackPower), false, true) * GetSkillLevel(S_Sword_s21);
if (CanUseSkill(S_Perk_05))
{
fastAP += GetAttributeValue('attack_power_fast_style');
fastCritDmg += CalculateAttributeValue(GetAttributeValue('critical_hit_chance_fast_style'));
strongCritDmg += CalculateAttributeValue(GetAttributeValue('critical_hit_chance_fast_style'));
}
if (CanUseSkill(S_Sword_s04))
strongAP += GetSkillAttributeValue(S_Sword_s04, PowerStatEnumToName(CPS_AttackPower), false, true) * GetSkillLevel(S_Sword_s04);
if (CanUseSkill(S_Perk_07))
strongAP += GetAttributeValue('attack_power_heavy_style');

if (CanUseSkill(S_Sword_s17))
{
fastCritChance += CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s17, theGame.params.CRITICAL_HIT_CHANCE, false, true)) * GetSkillLevel(S_Sword_s17);
fastCritDmg += CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s17, theGame.params.CRITICAL_HIT_DAMAGE_BONUS, false, true)) * GetSkillLevel(S_Sword_s17);
}

if (CanUseSkill(S_Sword_s08))
{
strongCritChance += CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s08, theGame.params.CRITICAL_HIT_CHANCE, false, true)) * GetSkillLevel(S_Sword_s08);
strongCritDmg += CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s08, theGame.params.CRITICAL_HIT_DAMAGE_BONUS, false, true)) * GetSkillLevel(S_Sword_s08);
}

if ( HasBuff(EET_Mutagen05) && (GetStat(BCS_Vitality) == GetStatMax(BCS_Vitality)) )
{
attackPower += GetAttributeValue('damageIncrease');
}

steelCritChance += CalculateAttributeValue(GetAttributeValue(theGame.params.CRITICAL_HIT_CHANCE));
silverCritChance += CalculateAttributeValue(GetAttributeValue(theGame.params.CRITICAL_HIT_CHANCE));
steelCritDmg += CalculateAttributeValue(GetAttributeValue(theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
silverCritDmg += CalculateAttributeValue(GetAttributeValue(theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
attackPower += GetPowerStatValue(CPS_AttackPower);

if (GetItemEquippedOnSlot(EES_SteelSword, item))
{
steelDmg = GetTotalWeaponDamage(item, theGame.params.DAMAGE_NAME_SLASHING, GetInvalidUniqueId());
steelDmg += GetTotalWeaponDamage(item, theGame.params.DAMAGE_NAME_PIERCING, GetInvalidUniqueId());
steelDmg += GetTotalWeaponDamage(item, theGame.params.DAMAGE_NAME_BLUDGEONING, GetInvalidUniqueId());
elementalSteel = CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_FIRE));
elementalSteel += CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_FROST));
if ( GetInventory().IsItemHeld(item) )
{
steelCritChance -= CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_CHANCE));
silverCritChance -= CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_CHANCE));
steelCritDmg -= CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
silverCritDmg -= CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
}
steelCritChance += CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_CHANCE));
steelCritDmg += CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_DAMAGE_BONUS));

thunder = (W3Potion_Thunderbolt)GetBuff(EET_Thunderbolt);
if(thunder && thunder.GetBuffLevel() == 3 && GetCurWeather() == EWE_Storm)
{
steelCritChance += 1.0f;
}
}
else
{
steelDmg += 0;
steelCritChance += 0;
steelCritDmg +=0;
}

if (GetItemEquippedOnSlot(EES_SilverSword, item))
{
silverDmg = GetTotalWeaponDamage(item, theGame.params.DAMAGE_NAME_SILVER, GetInvalidUniqueId());
elementalSilver = CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_FIRE));
elementalSilver += CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_FROST));
if ( GetInventory().IsItemHeld(item) )
{
steelCritChance -= CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_CHANCE));
silverCritChance -= CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_CHANCE));
steelCritDmg -= CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
silverCritDmg -= CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
}
silverCritChance += CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_CHANCE));
silverCritDmg += CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_DAMAGE_BONUS));

thunder = (W3Potion_Thunderbolt)GetBuff(EET_Thunderbolt);
if(thunder && thunder.GetBuffLevel() == 3 && GetCurWeather() == EWE_Storm)
{
silverCritChance += 1.0f;
}
}
else
{
silverDmg += 0;
silverCritChance += 0;
silverCritDmg +=0;
}

if ( HasAbility('Runeword 4 _Stats', true) )
{
steelDmg += steelDmg * (abilityManager.GetOverhealBonus() / GetStatMax(BCS_Vitality));
silverDmg += silverDmg * (abilityManager.GetOverhealBonus() / GetStatMax(BCS_Vitality));
}

fastAP += attackPower;
strongAP += attackPower;

playerOffenseStats.steelFastCritChance = (steelCritChance + fastCritChance) * 100;
playerOffenseStats.steelFastCritDmg = steelCritDmg + fastCritDmg;
if ( steelDmg != 0 )
{
playerOffenseStats.steelFastDmg = (steelDmg + fastAP.valueBase) * fastAP.valueMultiplicative + fastAP.valueAdditive + elementalSteel;
playerOffenseStats.steelFastCritDmg = (steelDmg + fastAP.valueBase) * (fastAP.valueMultiplicative + playerOffenseStats.steelFastCritDmg) + fastAP.valueAdditive + elementalSteel;
}
else
{
playerOffenseStats.steelFastDmg = 0;
playerOffenseStats.steelFastCritDmg = 0;
}
playerOffenseStats.steelFastDPS = (playerOffenseStats.steelFastDmg * (100 - playerOffenseStats.steelFastCritChance) + playerOffenseStats.steelFastCritDmg * playerOffenseStats.steelFastCritChance) / 100;
playerOffenseStats.steelFastDPS = playerOffenseStats.steelFastDPS / 0.6;


playerOffenseStats.steelStrongCritChance = (steelCritChance + strongCritChance) * 100;
playerOffenseStats.steelStrongCritDmg = steelCritDmg + strongCritDmg;
if ( steelDmg != 0 )
{
playerOffenseStats.steelStrongDmg = (steelDmg + strongAP.valueBase) * strongAP.valueMultiplicative + strongAP.valueAdditive + elementalSteel;
playerOffenseStats.steelStrongDmg *= 1.833f;
playerOffenseStats.steelStrongCritDmg = (steelDmg + strongAP.valueBase) * (strongAP.valueMultiplicative + playerOffenseStats.steelStrongCritDmg) + strongAP.valueAdditive + elementalSteel;
playerOffenseStats.steelStrongCritDmg *= 1.833f; }
else
{
playerOffenseStats.steelStrongDmg = 0;
playerOffenseStats.steelStrongCritDmg = 0;
}
playerOffenseStats.steelStrongDPS = (playerOffenseStats.steelStrongDmg * (100 - playerOffenseStats.steelStrongCritChance) + playerOffenseStats.steelStrongCritDmg * playerOffenseStats.steelStrongCritChance) / 100;
playerOffenseStats.steelStrongDPS = playerOffenseStats.steelStrongDPS / 1.1;



playerOffenseStats.silverFastCritChance = (silverCritChance + fastCritChance) * 100;
playerOffenseStats.silverFastCritDmg = silverCritDmg + fastCritDmg;
if ( silverDmg != 0 )
{
playerOffenseStats.silverFastDmg = (silverDmg + fastAP.valueBase) * fastAP.valueMultiplicative + fastAP.valueAdditive + elementalSilver;
playerOffenseStats.silverFastCritDmg = (silverDmg + fastAP.valueBase) * (fastAP.valueMultiplicative + playerOffenseStats.silverFastCritDmg) + fastAP.valueAdditive + elementalSilver;
}
else
{
playerOffenseStats.silverFastDmg = 0;
playerOffenseStats.silverFastCritDmg = 0;
}
playerOffenseStats.silverFastDPS = (playerOffenseStats.silverFastDmg * (100 - playerOffenseStats.silverFastCritChance) + playerOffenseStats.silverFastCritDmg * playerOffenseStats.silverFastCritChance) / 100;
playerOffenseStats.silverFastDPS = playerOffenseStats.silverFastDPS / 0.6;


playerOffenseStats.silverStrongCritChance = (silverCritChance + strongCritChance) * 100;
playerOffenseStats.silverStrongCritDmg = silverCritDmg + strongCritDmg;
if ( silverDmg != 0 )
{
playerOffenseStats.silverStrongDmg = (silverDmg + strongAP.valueBase) * strongAP.valueMultiplicative + strongAP.valueAdditive + elementalSilver;
playerOffenseStats.silverStrongDmg *= 1.833f;
playerOffenseStats.silverStrongCritDmg = (silverDmg + strongAP.valueBase) * (strongAP.valueMultiplicative + playerOffenseStats.silverStrongCritDmg) + strongAP.valueAdditive + elementalSilver;
playerOffenseStats.silverStrongCritDmg *= 1.833f;
}
else
{
playerOffenseStats.silverStrongDmg = 0;
playerOffenseStats.silverStrongCritDmg = 0;
}
playerOffenseStats.silverStrongDPS = (playerOffenseStats.silverStrongDmg * (100 - playerOffenseStats.silverStrongCritChance) + playerOffenseStats.silverStrongCritDmg * playerOffenseStats.silverStrongCritChance) / 100;
playerOffenseStats.silverStrongDPS = playerOffenseStats.silverStrongDPS / 1.1;


playerOffenseStats.crossbowCritChance = GetCriticalHitChance( false, false, NULL, MC_NotSet, true );


playerOffenseStats.crossbowSteelDmgType = theGame.params.DAMAGE_NAME_PIERCING;
if (GetItemEquippedOnSlot(EES_Bolt, item))
{


steelDmg = CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_FIRE));
if(steelDmg > 0)
{
playerOffenseStats.crossbowSteelDmg = steelDmg;

playerOffenseStats.crossbowSteelDmgType = theGame.params.DAMAGE_NAME_FIRE;
playerOffenseStats.crossbowSilverDmg = steelDmg;
}
else
{
playerOffenseStats.crossbowSilverDmg = CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_SILVER));

steelDmg = CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_PIERCING));
if(steelDmg > 0)
{
playerOffenseStats.crossbowSteelDmg = steelDmg;
playerOffenseStats.crossbowSteelDmgType = theGame.params.DAMAGE_NAME_PIERCING;
}
else
{
playerOffenseStats.crossbowSteelDmg = CalculateAttributeValue(GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_BLUDGEONING));
playerOffenseStats.crossbowSteelDmgType = theGame.params.DAMAGE_NAME_BLUDGEONING;
}
}
}

if (GetItemEquippedOnSlot(EES_RangedWeapon, item))
{
attackPower += GetInventory().GetItemAttributeValue(item, PowerStatEnumToName(CPS_AttackPower));
if(CanUseSkill(S_Perk_02))
{
attackPower += GetSkillAttributeValue(S_Perk_02, PowerStatEnumToName(CPS_AttackPower), false, true);
}


if( hackMode != 1 && ( IsMutationActive( EPMT_Mutation9 ) || hackMode == 2 ) )
{
theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation9', 'damage', min, max );
playerOffenseStats.crossbowSteelDmg += min.valueAdditive;
playerOffenseStats.crossbowSilverDmg += min.valueAdditive;
}

playerOffenseStats.crossbowSteelDmg = (playerOffenseStats.crossbowSteelDmg + attackPower.valueBase) * attackPower.valueMultiplicative + attackPower.valueAdditive;
playerOffenseStats.crossbowSilverDmg = (playerOffenseStats.crossbowSilverDmg + attackPower.valueBase) * attackPower.valueMultiplicative + attackPower.valueAdditive;
}
else
{
playerOffenseStats.crossbowSteelDmg = 0;
playerOffenseStats.crossbowSilverDmg = 0;
playerOffenseStats.crossbowSteelDmgType = theGame.params.DAMAGE_NAME_PIERCING;
}

return playerOffenseStats;
}

public function GetTotalWeaponDamage(weaponId : SItemUniqueId, damageTypeName : name, crossbowId : SItemUniqueId) : float
{
var damage, durRatio, durMod, itemMod : float;
var repairObjectBonus, min, max : SAbilityAttributeValue;

durMod = 0;
damage = super.GetTotalWeaponDamage(weaponId, damageTypeName, crossbowId);


if( IsMutationActive( EPMT_Mutation9 ) && inv.IsItemBolt( weaponId ) && IsDamageTypeAnyPhysicalType( damageTypeName ) )
{
theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation9', 'damage', min, max);
damage += min.valueAdditive;
}


if(IsPhysicalResistStat(GetResistForDamage(damageTypeName, false)))
{
repairObjectBonus = inv.GetItemAttributeValue(weaponId, theGame.params.REPAIR_OBJECT_BONUS);
durRatio = -1;

if(inv.IsIdValid(crossbowId) && inv.HasItemDurability(crossbowId))
{
durRatio = inv.GetItemDurabilityRatio(crossbowId);
}
else if(inv.IsIdValid(weaponId) && inv.HasItemDurability(weaponId))
{
durRatio = inv.GetItemDurabilityRatio(weaponId);
}


if(durRatio >= 0)
durMod = theGame.params.GetDurabilityMultiplier(durRatio, true);
else
durMod = 1;
}


if( damageTypeName == 'SilverDamage' && inv.ItemHasTag( weaponId, 'Aerondight' ) )
{
itemMod = inv.GetItemModifierFloat( weaponId, 'PermDamageBoost' );
if( itemMod > 0.f )
{
damage += itemMod;
}
}

return damage * (durMod + repairObjectBonus.valueMultiplicative);
}





public final function GetSkillPathType(skill : ESkill) : ESkillPath
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillPathType(skill);

return ESP_NotSet;
}

public function GetSkillLevel(s : ESkill) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillLevel(s);

return -1;
}

public function GetSkillMaxLevel(s : ESkill) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillMaxLevel(s);

return -1;
}

public function GetBoughtSkillLevel(s : ESkill) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetBoughtSkillLevel(s);

return -1;
}


public function GetAxiiLevel() : int
{
var level : int;

level = 1;

if(CanUseSkill(S_Magic_s17)) level += GetSkillLevel(S_Magic_s17);

return Clamp(level, 1, 4);
}

public function IsInFrenzy() : bool
{
return isInFrenzy;
}

public function HasRecentlyCountered() : bool
{
return hasRecentlyCountered;
}

public function SetRecentlyCountered(counter : bool)
{
hasRecentlyCountered = counter;
}

timer function CheckBlockedSkills(dt : float, id : int)
{
var nextCallTime : float;

nextCallTime = ((W3PlayerAbilityManager)abilityManager).CheckBlockedSkills(dt);
if(nextCallTime != -1)
AddTimer('CheckBlockedSkills', nextCallTime, , , , true);
}


public function RemoveTemporarySkills()
{
var i : int;
var pam : W3PlayerAbilityManager;

if(tempLearnedSignSkills.Size() > 0)
{
pam = (W3PlayerAbilityManager)abilityManager;
for(i=0; i {
pam.RemoveTemporarySkill(tempLearnedSignSkills[i]);
}

tempLearnedSignSkills.Clear();
}
RemoveAbilityAll(SkillEnumToName(S_Sword_s19));
}

public function RemoveTemporarySkill(skill : SSimpleSkill) : bool
{
var pam : W3PlayerAbilityManager;

pam = (W3PlayerAbilityManager)abilityManager;
if(pam && pam.IsInitialized())
return pam.RemoveTemporarySkill(skill);

return false;
}


private function AddTemporarySkills()
{
if(CanUseSkill(S_Sword_s19) && GetStat(BCS_Focus) >= 3)
{
tempLearnedSignSkills = ((W3PlayerAbilityManager)abilityManager).AddTempNonAlchemySkills();
DrainFocus(GetStat(BCS_Focus));
AddAbilityMultiple(SkillEnumToName(S_Sword_s19), GetSkillLevel(S_Sword_s19));
}
}



public function HasAlternateQuen() : bool
{
var quenEntity : W3QuenEntity;

quenEntity = (W3QuenEntity)GetCurrentSignEntity();
if(quenEntity)
{
return quenEntity.IsAlternateCast();
}

return false;
}





public function AddPoints(type : ESpendablePointType, amount : int, show : bool)
{
levelManager.AddPoints(type, amount, show);
}

public function GetLevel() : int {return levelManager.GetLevel();}
public function GetMaxLevel() : int {return levelManager.GetMaxLevel();}
public function GetTotalExpForNextLevel() : int {return levelManager.GetTotalExpForNextLevel();}
public function GetPointsTotal(type : ESpendablePointType) : int {return levelManager.GetPointsTotal(type);}
public function IsAutoLeveling() : bool {return autoLevel;}
public function SetAutoLeveling( b : bool ) {autoLevel = b;}

public function GetMissingExpForNextLevel() : int
{
return Max(0, GetTotalExpForNextLevel() - GetPointsTotal(EExperiencePoint));
}




private saved var runewordInfusionType : ESignType;
default runewordInfusionType = ST_None;

public final function GetRunewordInfusionType() : ESignType
{
return runewordInfusionType;
}


public function QuenImpulse( isAlternate : bool, signEntity : W3QuenEntity, source : string, optional forceSkillLevel : int )
{
var level, i, j : int;
var atts, damages : array;
var ents : array;
var action : W3DamageAction;
var dm : CDefinitionsManagerAccessor;
var skillAbilityName : name;
var dmg : float;
var min, max : SAbilityAttributeValue;
var pos : Vector;

if( forceSkillLevel > 0 )
{
level = forceSkillLevel;
}
else
{
level = GetSkillLevel(S_Magic_s13);
}

dm = theGame.GetDefinitionsManager();
skillAbilityName = GetSkillAbilityName(S_Magic_s13);

if(level >= 2)
{

dm.GetAbilityAttributes(skillAbilityName, atts);
for(i=0; i {
if(IsDamageTypeNameValid(atts[i]))
{
damages.PushBack(atts[i]);
}
}
}


pos = signEntity.GetWorldPosition();
FindGameplayEntitiesInSphere(ents, pos, 3, 1000, '', FLAG_OnlyAliveActors + FLAG_ExcludeTarget + FLAG_Attitude_Hostile + FLAG_Attitude_Neutral + FLAG_TestLineOfSight, this);


for(i=0; i {
action = new W3DamageAction in theGame;
action.Initialize(this, ents[i], signEntity, source, EHRT_Heavy, CPS_SpellPower, false, false, true, false);
action.SetSignSkill(S_Magic_s13);
action.SetCannotReturnDamage(true);
action.SetProcessBuffsIfNoDamage(true);


if(!isAlternate && level >= 2)
{
action.SetHitEffect('hit_electric_quen');
action.SetHitEffect('hit_electric_quen', true);
action.SetHitEffect('hit_electric_quen', false, true);
action.SetHitEffect('hit_electric_quen', true, true);
}

if(level >= 1)
{
action.AddEffectInfo(EET_Stagger);
}
if(level >= 2)
{
for(j=0; j {
dm.GetAbilityAttributeValue(skillAbilityName, damages[j], min, max);
dmg = CalculateAttributeValue(GetAttributeRandomizedValue(min, max));
if( IsSetBonusActive( EISB_Bear_2 ) )
{
dm.GetAbilityAttributeValue( GetSetBonusAbility( EISB_Bear_2 ), 'quen_dmg_boost', min, max );
dmg *= 1 + min.valueMultiplicative;
}
action.AddDamage(damages[j], dmg);
}
}
if(level == 3)
{
action.AddEffectInfo(EET_KnockdownTypeApplicator);
}

theGame.damageMgr.ProcessAction( action );
delete action;
}


if(isAlternate)
{
signEntity.PlayHitEffect('quen_impulse_explode', signEntity.GetWorldRotation());
signEntity.EraseFirstTimeStamp();


if(level >= 2)
{
if( !IsSetBonusActive( EISB_Bear_2 ) )
{
signEntity.PlayHitEffect('quen_electric_explode', signEntity.GetWorldRotation());
}
else
{
signEntity.PlayHitEffect('quen_electric_explode_bear_abl2', signEntity.GetWorldRotation());
}
}
}
else
{
signEntity.PlayEffect('lasting_shield_impulse');
}
}

public function OnSignCastPerformed(signType : ESignType, isAlternate : bool)
{
var items : array;
var weaponEnt : CEntity;
var fxName : name;
var pos : Vector;

super.OnSignCastPerformed(signType, isAlternate);

if(HasAbility('Runeword 1 _Stats', true) && GetStat(BCS_Focus) >= 1.0f)
{
DrainFocus(1.0f);
runewordInfusionType = signType;
items = inv.GetHeldWeapons();
weaponEnt = inv.GetItemEntityUnsafe(items[0]);


weaponEnt.StopEffect('runeword_aard');
weaponEnt.StopEffect('runeword_axii');
weaponEnt.StopEffect('runeword_igni');
weaponEnt.StopEffect('runeword_quen');
weaponEnt.StopEffect('runeword_yrden');


if(signType == ST_Aard)
fxName = 'runeword_aard';
else if(signType == ST_Axii)
fxName = 'runeword_axii';
else if(signType == ST_Igni)
fxName = 'runeword_igni';
else if(signType == ST_Quen)
fxName = 'runeword_quen';
else if(signType == ST_Yrden)
fxName = 'runeword_yrden';

weaponEnt.PlayEffect(fxName);
}


if( IsMutationActive( EPMT_Mutation6 ) && signType == ST_Aard && !isAlternate )
{
pos = GetWorldPosition() + GetWorldForward() * 2;

theGame.GetSurfacePostFX().AddSurfacePostFXGroup( pos, 0.f, 3.f, 2.f, 5.f, 0 );
}
}

public saved var savedQuenHealth, savedQuenDuration : float;

timer function HACK_QuenSaveStatus(dt : float, id : int)
{
var quenEntity : W3QuenEntity;

quenEntity = (W3QuenEntity)signs[ST_Quen].entity;
savedQuenHealth = quenEntity.GetShieldHealth();
savedQuenDuration = quenEntity.GetShieldRemainingDuration();
}

timer function DelayedRestoreQuen(dt : float, id : int)
{
RestoreQuen(savedQuenHealth, savedQuenDuration);
}

public final function OnBasicQuenFinishing()
{
RemoveTimer('HACK_QuenSaveStatus');
savedQuenHealth = 0.f;
savedQuenDuration = 0.f;
}

public final function IsAnyQuenActive() : bool
{
var quen : W3QuenEntity;

quen = (W3QuenEntity)GetSignEntity(ST_Quen);
if(quen)
return quen.IsAnyQuenActive();

return false;
}

public final function IsQuenActive(alternateMode : bool) : bool
{
if(IsAnyQuenActive() && GetSignEntity(ST_Quen).IsAlternateCast() == alternateMode)
return true;

return false;
}

public function FinishQuen( skipVisuals : bool, optional forceNoBearSetBonus : bool )
{
var quen : W3QuenEntity;

quen = (W3QuenEntity)GetSignEntity(ST_Quen);
if(quen)
quen.ForceFinishQuen( skipVisuals, forceNoBearSetBonus );
}


public function GetTotalSignSpellPower(signSkill : ESkill) : SAbilityAttributeValue
{
var sp : SAbilityAttributeValue;
var penalty : SAbilityAttributeValue;
var penaltyReduction : float;
var penaltyReductionLevel : int;


sp = GetSkillAttributeValue(signSkill, PowerStatEnumToName(CPS_SpellPower), true, true);


if ( signSkill == S_Magic_s01 )
{

penaltyReductionLevel = GetSkillLevel(S_Magic_s01) + 1;
if(penaltyReductionLevel > 0)
{
penaltyReduction = 1 - penaltyReductionLevel * CalculateAttributeValue(GetSkillAttributeValue(S_Magic_s01, 'spell_power_penalty_reduction', true, true));
penalty = GetSkillAttributeValue(S_Magic_s01, PowerStatEnumToName(CPS_SpellPower), false, false);
sp += penalty * penaltyReduction;
}
}


if(signSkill == S_Magic_1 || signSkill == S_Magic_s01)
{
sp += GetAttributeValue('spell_power_aard');
}
else if(signSkill == S_Magic_2 || signSkill == S_Magic_s02)
{
sp += GetAttributeValue('spell_power_igni');
}
else if(signSkill == S_Magic_3 || signSkill == S_Magic_s03)
{
sp += GetAttributeValue('spell_power_yrden');
}
else if(signSkill == S_Magic_4 || signSkill == S_Magic_s04)
{
sp += GetAttributeValue('spell_power_quen');
}
else if(signSkill == S_Magic_5 || signSkill == S_Magic_s05)
{
sp += GetAttributeValue('spell_power_axii');
}


ApplyMutation10StatBoost( sp );

return sp;
}





public final function GetGwentCardIndex( cardName : name ) : int
{
var dm : CDefinitionsManagerAccessor;

dm = theGame.GetDefinitionsManager();

if(dm.ItemHasTag( cardName , 'GwintCardLeader' ))
{
return theGame.GetGwintManager().GwentLeadersNametoInt( cardName );
}
else if(dm.ItemHasTag( cardName , 'GwintCardNrkd' ))
{
return theGame.GetGwintManager().GwentNrkdNameToInt( cardName );
}
else if(dm.ItemHasTag( cardName , 'GwintCardNlfg' ))
{
return theGame.GetGwintManager().GwentNlfgNameToInt( cardName );
}
else if(dm.ItemHasTag( cardName , 'GwintCardSctl' ))
{
return theGame.GetGwintManager().GwentSctlNameToInt( cardName );
}
else if(dm.ItemHasTag( cardName , 'GwintCardMstr' ))
{
return theGame.GetGwintManager().GwentMstrNameToInt( cardName );
}
else if(dm.ItemHasTag( cardName , 'GwintCardSke' ))
{
return theGame.GetGwintManager().GwentSkeNameToInt( cardName );
}
else if(dm.ItemHasTag( cardName , 'GwintCardNeutral' ))
{
return theGame.GetGwintManager().GwentNeutralNameToInt( cardName );
}
else if(dm.ItemHasTag( cardName , 'GwintCardSpcl' ))
{
return theGame.GetGwintManager().GwentSpecialNameToInt( cardName );
}

return -1;
}

public final function AddGwentCard(cardName : name, amount : int) : bool
{
var dm : CDefinitionsManagerAccessor;
var cardIndex, i : int;
var tut : STutorialMessage;
var gwintManager : CR4GwintManager;



if(FactsQuerySum("q001_nightmare_ended") > 0 && ShouldProcessTutorial('TutorialGwentDeckBuilder2'))
{
tut.type = ETMT_Hint;
tut.tutorialScriptTag = 'TutorialGwentDeckBuilder2';
tut.journalEntryName = 'TutorialGwentDeckBuilder2';
tut.hintPositionType = ETHPT_DefaultGlobal;
tut.markAsSeenOnShow = true;
tut.hintDurationType = ETHDT_Long;

theGame.GetTutorialSystem().DisplayTutorial(tut);
}

dm = theGame.GetDefinitionsManager();

cardIndex = GetGwentCardIndex(cardName);

if (cardIndex != -1)
{
FactsAdd("Gwint_Card_Looted");

for(i = 0; i < amount; i += 1)
{
theGame.GetGwintManager().AddCardToCollection( cardIndex );
}
}

if( dm.ItemHasTag( cardName, 'GwentTournament' ) )
{
if ( dm.ItemHasTag( cardName, 'GT1' ) )
{
FactsAdd( "GwentTournament", 1 );
}

else if ( dm.ItemHasTag( cardName, 'GT2' ) )
{
FactsAdd( "GwentTournament", 2 );
}

else if ( dm.ItemHasTag( cardName, 'GT3' ) )
{
FactsAdd( "GwentTournament", 3 );
}

else if ( dm.ItemHasTag( cardName, 'GT4' ) )
{
FactsAdd( "GwentTournament", 4 );
}

else if ( dm.ItemHasTag( cardName, 'GT5' ) )
{
FactsAdd( "GwentTournament", 5 );
}

else if ( dm.ItemHasTag( cardName, 'GT6' ) )
{
FactsAdd( "GwentTournament", 6 );
}

else if ( dm.ItemHasTag( cardName, 'GT7' ) )
{
FactsAdd( "GwentTournament", 7 );
}

CheckGwentTournamentDeck();
}

if( dm.ItemHasTag( cardName, 'EP2Tournament' ) )
{
if ( dm.ItemHasTag( cardName, 'GT1' ) )
{
FactsAdd( "EP2Tournament", 1 );
}

else if ( dm.ItemHasTag( cardName, 'GT2' ) )
{
FactsAdd( "EP2Tournament", 2 );
}

else if ( dm.ItemHasTag( cardName, 'GT3' ) )
{
FactsAdd( "EP2Tournament", 3 );
}

else if ( dm.ItemHasTag( cardName, 'GT4' ) )
{
FactsAdd( "EP2Tournament", 4 );
}

else if ( dm.ItemHasTag( cardName, 'GT5' ) )
{
FactsAdd( "EP2Tournament", 5 );
}

else if ( dm.ItemHasTag( cardName, 'GT6' ) )
{
FactsAdd( "EP2Tournament", 6 );
}

else if ( dm.ItemHasTag( cardName, 'GT7' ) )
{
FactsAdd( "EP2Tournament", 7 );
}

CheckEP2TournamentDeck();
}

gwintManager = theGame.GetGwintManager();
if( !gwintManager.IsDeckUnlocked( GwintFaction_Skellige ) &&
gwintManager.HasCardsOfFactionInCollection( GwintFaction_Skellige, false ) )
{
gwintManager.UnlockDeck( GwintFaction_Skellige );
}

return true;
}


public final function RemoveGwentCard(cardName : name, amount : int) : bool
{
var dm : CDefinitionsManagerAccessor;
var cardIndex, i : int;

dm = theGame.GetDefinitionsManager();

if(dm.ItemHasTag( cardName , 'GwintCardLeader' ))
{
cardIndex = theGame.GetGwintManager().GwentLeadersNametoInt( cardName );
for(i=0; i theGame.GetGwintManager().RemoveCardFromCollection( cardIndex );
}
else if(dm.ItemHasTag( cardName , 'GwintCardNrkd' ))
{
cardIndex = theGame.GetGwintManager().GwentNrkdNameToInt( cardName );
for(i=0; i theGame.GetGwintManager().RemoveCardFromCollection( cardIndex );
}
else if(dm.ItemHasTag( cardName , 'GwintCardNlfg' ))
{
cardIndex = theGame.GetGwintManager().GwentNlfgNameToInt( cardName );
for(i=0; i theGame.GetGwintManager().RemoveCardFromCollection( cardIndex );
}
else if(dm.ItemHasTag( cardName , 'GwintCardSctl' ))
{
cardIndex = theGame.GetGwintManager().GwentSctlNameToInt( cardName );
for(i=0; i theGame.GetGwintManager().RemoveCardFromCollection( cardIndex );
}
else if(dm.ItemHasTag( cardName , 'GwintCardMstr' ))
{
cardIndex = theGame.GetGwintManager().GwentMstrNameToInt( cardName );
for(i=0; i theGame.GetGwintManager().RemoveCardFromCollection( cardIndex );
}
else if(dm.ItemHasTag( cardName , 'GwintCardNeutral' ))
{
cardIndex = theGame.GetGwintManager().GwentNeutralNameToInt( cardName );
for(i=0; i theGame.GetGwintManager().RemoveCardFromCollection( cardIndex );
}
else if(dm.ItemHasTag( cardName , 'GwintCardSpcl' ))
{
cardIndex = theGame.GetGwintManager().GwentSpecialNameToInt( cardName );
for(i=0; i theGame.GetGwintManager().RemoveCardFromCollection( cardIndex );
}

if( dm.ItemHasTag( cardName, 'GwentTournament' ) )
{
if ( dm.ItemHasTag( cardName, 'GT1' ) )
{
FactsSubstract( "GwentTournament", 1 );
}

else if ( dm.ItemHasTag( cardName, 'GT2' ) )
{
FactsSubstract( "GwentTournament", 2 );
}

else if ( dm.ItemHasTag( cardName, 'GT3' ) )
{
FactsSubstract( "GwentTournament", 3 );
}

else if ( dm.ItemHasTag( cardName, 'GT4' ) )
{
FactsSubstract( "GwentTournament", 4 );
}

else if ( dm.ItemHasTag( cardName, 'GT5' ) )
{
FactsSubstract( "GwentTournament", 5 );
}

else if ( dm.ItemHasTag( cardName, 'GT6' ) )
{
FactsSubstract( "GwentTournament", 6 );
}

else if ( dm.ItemHasTag( cardName, 'GT7' ) )
{
FactsSubstract( "GwentTournament", 7 );
}

CheckGwentTournamentDeck();
}


if( dm.ItemHasTag( cardName, 'EP2Tournament' ) )
{
if ( dm.ItemHasTag( cardName, 'GT1' ) )
{
FactsSubstract( "EP2Tournament", 1 );
}

else if ( dm.ItemHasTag( cardName, 'GT2' ) )
{
FactsSubstract( "EP2Tournament", 2 );
}

else if ( dm.ItemHasTag( cardName, 'GT3' ) )
{
FactsSubstract( "EP2Tournament", 3 );
}

else if ( dm.ItemHasTag( cardName, 'GT4' ) )
{
FactsSubstract( "EP2Tournament", 4 );
}

else if ( dm.ItemHasTag( cardName, 'GT5' ) )
{
FactsSubstract( "EP2Tournament", 5 );
}

else if ( dm.ItemHasTag( cardName, 'GT6' ) )
{
FactsSubstract( "EP2Tournament", 6 );
}

else if ( dm.ItemHasTag( cardName, 'GT7' ) )
{
FactsSubstract( "EP2Tournament", 7 );
}

CheckEP2TournamentDeck();
}

return true;
}

function CheckGwentTournamentDeck()
{
var gwentPower : int;
var neededGwentPower : int;
var checkBreakpoint : int;

neededGwentPower = 70;

checkBreakpoint = neededGwentPower/5;
gwentPower = FactsQuerySum( "GwentTournament" );

if ( gwentPower >= neededGwentPower )
{
FactsAdd( "HasGwentTournamentDeck", 1 );
}
else
{
if( FactsDoesExist( "HasGwentTournamentDeck" ) )
{
FactsRemove( "HasGwentTournamentDeck" );
}

if ( gwentPower >= checkBreakpoint )
{
FactsAdd( "GwentTournamentObjective1", 1 );
}
else if ( FactsDoesExist( "GwentTournamentObjective1" ) )
{
FactsRemove( "GwentTournamentObjective1" );
}

if ( gwentPower >= checkBreakpoint*2 )
{
FactsAdd( "GwentTournamentObjective2", 1 );
}
else if ( FactsDoesExist( "GwentTournamentObjective2" ) )
{
FactsRemove( "GwentTournamentObjective2" );
}

if ( gwentPower >= checkBreakpoint*3 )
{
FactsAdd( "GwentTournamentObjective3", 1 );
}
else if ( FactsDoesExist( "GwentTournamentObjective3" ) )
{
FactsRemove( "GwentTournamentObjective3" );
}

if ( gwentPower >= checkBreakpoint*4 )
{
FactsAdd( "GwentTournamentObjective4", 1 );
}
else if ( FactsDoesExist( "GwentTournamentObjective4" ) )
{
FactsRemove( "GwentTournamentObjective4" );
}
}
}

function CheckEP2TournamentDeck()
{
var gwentPower : int;
var neededGwentPower : int;
var checkBreakpoint : int;

neededGwentPower = 24;

checkBreakpoint = neededGwentPower/5;
gwentPower = FactsQuerySum( "EP2Tournament" );

if ( gwentPower >= neededGwentPower )
{
if( FactsQuerySum( "HasEP2TournamentDeck") == 0 )
{
FactsAdd( "HasEP2TournamentDeck", 1 );
}

}
else
{
if( FactsDoesExist( "HasEP2TournamentDeck" ) )
{
FactsRemove( "HasEP2TournamentDeck" );
}

if ( gwentPower >= checkBreakpoint )
{
FactsAdd( "EP2TournamentObjective1", 1 );
}
else if ( FactsDoesExist( "EP2TournamentObjective1" ) )
{
FactsRemove( "EP2TournamentObjective1" );
}

if ( gwentPower >= checkBreakpoint*2 )
{
FactsAdd( "EP2TournamentObjective2", 1 );
}
else if ( FactsDoesExist( "EP2TournamentObjective2" ) )
{
FactsRemove( "EP2TournamentObjective2" );
}

if ( gwentPower >= checkBreakpoint*3 )
{
FactsAdd( "EP2TournamentObjective3", 1 );
}
else if ( FactsDoesExist( "EP2TournamentObjective3" ) )
{
FactsRemove( "EP2TournamentObjective3" );
}

if ( gwentPower >= checkBreakpoint*4 )
{
FactsAdd( "EP2TournamentObjective4", 1 );
}
else if ( FactsDoesExist( "EP2TournamentObjective4" ) )
{
FactsRemove( "EP2TournamentObjective4" );
}
}
}






public function SimulateBuffTimePassing(simulatedTime : float)
{
super.SimulateBuffTimePassing(simulatedTime);

FinishQuen(true);
}


public function CanMeditate() : bool
{
var currentStateName : name;

currentStateName = GetCurrentStateName();


if(currentStateName == 'Exploration' && !CanPerformPlayerAction())
return false;


if(GetCurrentStateName() != 'Exploration' && GetCurrentStateName() != 'Meditation' && GetCurrentStateName() != 'MeditationWaiting')
return false;


if(GetUsedVehicle())
return false;


return CanMeditateHere();
}


public final function CanMeditateWait(optional skipMeditationStateCheck : bool) : bool
{
var currState : name;

currState = GetCurrentStateName();



if(!skipMeditationStateCheck && currState != 'Meditation')
return false;


if(theGame.IsGameTimePaused())
return false;

if(!IsActionAllowed( EIAB_MeditationWaiting ))
return false;

return true;
}


public final function CanMeditateHere() : bool
{
var pos : Vector;

pos = GetWorldPosition();
if(pos.Z <= theGame.GetWorld().GetWaterLevel(pos, true) && IsInShallowWater())
return false;

if(IsThreatened())
return false;

return true;
}


public function Meditate() : bool
{
var medState : W3PlayerWitcherStateMeditation;
var stateName : name;

stateName = GetCurrentStateName();


if (!CanMeditate() || stateName == 'MeditationWaiting' )
return false;

GotoState('Meditation');
medState = (W3PlayerWitcherStateMeditation)GetState('Meditation');
medState.SetMeditationPointHeading(GetHeading());

return true;
}


public final function MeditationRestoring(simulatedTime : float)
{

if ( theGame.GetDifficultyMode() != EDM_Hard && theGame.GetDifficultyMode() != EDM_Hardcore )
{
Heal(GetStatMax(BCS_Vitality));
}


abilityManager.DrainToxicity( abilityManager.GetStat( BCS_Toxicity ) );
abilityManager.DrainFocus( abilityManager.GetStat( BCS_Focus ) );


inv.SingletonItemsRefillAmmo();


SimulateBuffTimePassing(simulatedTime);


ApplyWitcherHouseBuffs();
}

var clockMenu : CR4MeditationClockMenu;

public function MeditationClockStart(m : CR4MeditationClockMenu)
{
clockMenu = m;
AddTimer('UpdateClockTime',0.1,true);
}

public function MeditationClockStop()
{
clockMenu = NULL;
RemoveTimer('UpdateClockTime');
}

public timer function UpdateClockTime(dt : float, id : int)
{
if(clockMenu)
clockMenu.UpdateCurrentHours();
else
RemoveTimer('UpdateClockTime');
}

private var waitTimeHour : int;
public function SetWaitTargetHour(t : int)
{
waitTimeHour = t;
}
public function GetWaitTargetHour() : int
{
return waitTimeHour;
}

public function MeditationForceAbort(forceCloseUI : bool)
{
var waitt : W3PlayerWitcherStateMeditationWaiting;
var medd : W3PlayerWitcherStateMeditation;
var currentStateName : name;

currentStateName = GetCurrentStateName();

if(currentStateName == 'MeditationWaiting')
{
waitt = (W3PlayerWitcherStateMeditationWaiting)GetCurrentState();
if(waitt)
{
waitt.StopRequested(forceCloseUI);
}
}
else if(currentStateName == 'Meditation')
{
medd = (W3PlayerWitcherStateMeditation)GetCurrentState();
if(medd)
{
medd.StopRequested(forceCloseUI);
}
}



if(forceCloseUI && theGame.GetGuiManager().IsAnyMenu())
{
theGame.GetGuiManager().GetRootMenu().CloseMenu();
DisplayActionDisallowedHudMessage(EIAB_MeditationWaiting, false, false, true, false);
}
}

public function Runeword10Triggerred()
{
var min, max : SAbilityAttributeValue;

theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 10 _Stats', 'stamina', min, max );
GainStat(BCS_Stamina, min.valueMultiplicative * GetStatMax(BCS_Stamina));
PlayEffect('runeword_10_stamina');
}

public function Runeword12Triggerred()
{
var min, max : SAbilityAttributeValue;

theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 12 _Stats', 'focus', min, max );
GainStat(BCS_Focus, RandRangeF(max.valueAdditive, min.valueAdditive));
PlayEffect('runeword_20_adrenaline');
}

var runeword10TriggerredOnFinisher, runeword12TriggerredOnFinisher : bool;

event OnFinisherStart()
{
super.OnFinisherStart();

runeword10TriggerredOnFinisher = false;
runeword12TriggerredOnFinisher = false;
}

public function ApplyWitcherHouseBuffs()
{
var l_bed : W3WitcherBed;

if( FactsQuerySum( "PlayerInsideInnerWitcherHouse" ) > 0 )
{
l_bed = (W3WitcherBed)theGame.GetEntityByTag( 'witcherBed' );

if( l_bed.GetWasUsed() )
{
if( l_bed.GetBedLevel() != 0 )
{
AddEffectDefault( EET_WellRested, this, "Bed Buff" );
}

if( FactsQuerySum( "StablesExists" ) )
{
AddEffectDefault( EET_HorseStableBuff, this, "Stables" );
}

if( l_bed.GetWereItemsRefilled() )
{
theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_applied" ),, true );
l_bed.SetWereItemsRefilled( false );
}

AddEffectDefault( EET_BookshelfBuff, this, "Bookshelf" );

Heal( GetStatMax( BCS_Vitality ) );
}
}
}





public function CheatResurrect()
{
super.CheatResurrect();
theGame.ReleaseNoSaveLock(theGame.deathSaveLockId);
theInput.RestoreContext( 'Exploration', true );
}


public function Debug_EquipTestingSkills(equip : bool, force : bool)
{
var skills : array;
var i, slot : int;


((W3PlayerAbilityManager)abilityManager).OnLevelGained(36);

skills.PushBack(S_Magic_s01);
skills.PushBack(S_Magic_s02);
skills.PushBack(S_Magic_s03);
skills.PushBack(S_Magic_s04);
skills.PushBack(S_Magic_s05);
skills.PushBack(S_Sword_s01);
skills.PushBack(S_Sword_s02);


if(equip)
{
for(i=0; i {
if(!force && IsSkillEquipped(skills[i]))
continue;


if(GetSkillLevel(skills[i]) == 0)
AddSkill(skills[i]);


if(force)
slot = i+1;
else
slot = GetFreeSkillSlot();


EquipSkill(skills[i], slot);
}
}
else
{
for(i=0; i {
UnequipSkill(GetSkillSlotID(skills[i]));
}
}
}

public function Debug_ClearCharacterDevelopment(optional keepInv : bool)
{
var template : CEntityTemplate;
var entity : CEntity;
var invTesting : CInventoryComponent;
var i : int;
var items : array;
var abs : array;

delete abilityManager;
delete levelManager;
delete effectManager;


GetCharacterStats().GetAbilities(abs, false);
for(i=0; i RemoveAbility(abs[i]);


abs.Clear();
GetCharacterStatsParam(abs);
for(i=0; i AddAbility(abs[i]);


levelManager = new W3LevelManager in this;
levelManager.Initialize();
levelManager.PostInit(this, false, true);


AddAbility('GeraltSkills_Testing');
SetAbilityManager();
abilityManager.Init(this, GetCharacterStats(), false, theGame.GetDifficultyMode());

SetEffectManager();

abilityManager.PostInit();





if(!keepInv)
{
inv.RemoveAllItems();
}


template = (CEntityTemplate)LoadResource("geralt_inventory_release");
entity = theGame.CreateEntity(template, Vector(0,0,0));
invTesting = (CInventoryComponent)entity.GetComponentByClassName('CInventoryComponent');
invTesting.GiveAllItemsTo(inv, true);
entity.Destroy();


inv.GetAllItems(items);
for(i=0; i {
if(!inv.ItemHasTag(items[i], 'NoDrop'))
EquipItem(items[i]);
}


Debug_GiveTestingItems(0);
}

function Debug_BearSetBonusQuenSkills()
{
var skills : array;
var i, slot : int;

skills.PushBack(S_Magic_s04);
skills.PushBack(S_Magic_s14);

for(i=0; i {

if(GetSkillLevel(skills[i]) == 0)
{
AddSkill(skills[i]);
}

slot = GetFreeSkillSlot();


EquipSkill(skills[i], slot);
}
}

final function Debug_HAX_UnlockSkillSlot(slotIndex : int) : bool
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).Debug_HAX_UnlockSkillSlot(slotIndex);

return false;
}


public function GetLevelupAbility( id : int) : name
{
switch(id)
{
case 1: return 'Lvl1';
case 2: return 'Lvl2';
case 3: return 'Lvl3';
case 4: return 'Lvl4';
case 5: return 'Lvl5';
case 6: return 'Lvl6';
case 7: return 'Lvl7';
case 8: return 'Lvl8';
case 9: return 'Lvl9';
case 10: return 'Lvl10';
case 11: return 'Lvl11';
case 12: return 'Lvl12';
case 13: return 'Lvl13';
case 14: return 'Lvl14';
case 15: return 'Lvl15';
case 16: return 'Lvl16';
case 17: return 'Lvl17';
case 18: return 'Lvl18';
case 19: return 'Lvl19';
case 20: return 'Lvl20';
case 21: return 'Lvl21';
case 22: return 'Lvl22';
case 23: return 'Lvl23';
case 24: return 'Lvl24';
case 25: return 'Lvl25';
case 26: return 'Lvl26';
case 27: return 'Lvl27';
case 28: return 'Lvl28';
case 29: return 'Lvl29';
case 30: return 'Lvl30';
case 31: return 'Lvl31';
case 32: return 'Lvl32';
case 33: return 'Lvl33';
case 34: return 'Lvl34';
case 35: return 'Lvl35';
case 36: return 'Lvl36';
case 37: return 'Lvl37';
case 38: return 'Lvl38';
case 39: return 'Lvl39';
case 40: return 'Lvl40';
case 41: return 'Lvl41';
case 42: return 'Lvl42';
case 43: return 'Lvl43';
case 44: return 'Lvl44';
case 45: return 'Lvl45';
case 46: return 'Lvl46';
case 47: return 'Lvl47';
case 48: return 'Lvl48';
case 49: return 'Lvl49';
case 50: return 'Lvl50';

default: return '';
}

return '';
}

public function CanSprint( speed : float ) : bool
{
if( !super.CanSprint( speed ) )
{
return false;
}
if( rangedWeapon && rangedWeapon.GetCurrentStateName() != 'State_WeaponWait' )
{
if ( this.GetPlayerCombatStance() == PCS_AlertNear )
{
if ( IsSprintActionPressed() )
OnRangedForceHolster( true, false );
}
else
return false;
}
if( GetCurrentStateName() != 'Swimming' && GetStat(BCS_Stamina) <= 0 )
{
SetSprintActionPressed(false,true);
return false;
}

return true;
}

public function ManageSleeping()
{
thePlayer.RemoveBuffImmunity_AllCritical( 'Bed' );
thePlayer.RemoveBuffImmunity_AllNegative( 'Bed' );

thePlayer.PlayerStopAction( PEA_GoToSleep );
}



public function RestoreHorseManager() : bool
{
var horseTemplate : CEntityTemplate;
var horseManager : W3HorseManager;

if ( GetHorseManager() )
{
return false;
}

horseTemplate = (CEntityTemplate)LoadResource("horse_manager");
horseManager = (W3HorseManager)theGame.CreateEntity(horseTemplate, GetWorldPosition(),,,,,PM_Persist);
horseManager.CreateAttachment(this);
horseManager.OnCreated();
EntityHandleSet( horseManagerHandle, horseManager );

return true;
}






final function PerformParryCheck( parryInfo : SParryInfo ) : bool
{
if( super.PerformParryCheck( parryInfo ) )
{
GainAdrenalineFromPerk21( 'parry' );
return true;
}
return false;
}

protected final function PerformCounterCheck( parryInfo: SParryInfo ) : bool
{
var fistFightCheck, isInFistFight : bool;

if( super.PerformCounterCheck( parryInfo ) )
{
GainAdrenalineFromPerk21( 'counter' );

isInFistFight = FistFightCheck( parryInfo.target, parryInfo.attacker, fistFightCheck );

if( isInFistFight && fistFightCheck )
{
FactsAdd( "statistics_fist_fight_counter" );
AddTimer( 'FistFightCounterTimer', 0.5f, , , , true );
}

return true;
}
return false;
}

public function GainAdrenalineFromPerk21( n : name )
{
var perkStats, perkTime : SAbilityAttributeValue;
var targets : array;

targets = GetHostileEnemies();

if( !CanUseSkill( S_Perk_21 ) || targets.Size() == 0 )
{
return;
}

perkTime = GetSkillAttributeValue( S_Perk_21, 'perk21Time', false, false );

if( theGame.GetEngineTimeAsSeconds() >= timeForPerk21 + perkTime.valueAdditive )
{
perkStats = GetSkillAttributeValue( S_Perk_21, n , false, false );
GainStat( BCS_Focus, perkStats.valueAdditive );
timeForPerk21 = theGame.GetEngineTimeAsSeconds();

AddEffectDefault( EET_Perk21InternalCooldown, this, "Perk21", false );
}
}

timer function FistFightCounterTimer( dt : float, id : int )
{
FactsRemove( "statistics_fist_fight_counter" );
}

public final function IsSignBlocked(signType : ESignType) : bool
{
switch( signType )
{
case ST_Aard :
return IsRadialSlotBlocked ( 'Aard');
break;
case ST_Axii :
return IsRadialSlotBlocked ( 'Axii');
break;
case ST_Igni :
return IsRadialSlotBlocked ( 'Igni');
break;
case ST_Quen :
return IsRadialSlotBlocked ( 'Quen');
break;
case ST_Yrden :
return IsRadialSlotBlocked ( 'Yrden');
break;
default:
break;
}
return false;

}

public final function AddAnItemWithAutogenLevelAndQuality(itemName : name, desiredLevel : int, minQuality : int, optional equipItem : bool)
{
var itemLevel, quality : int;
var ids : array;
var attemptCounter : int;

itemLevel = 0;
quality = 0;
attemptCounter = 0;
while(itemLevel != desiredLevel || quality < minQuality)
{
attemptCounter += 1;
ids.Clear();
ids = inv.AddAnItem(itemName, 1, true);
itemLevel = inv.GetItemLevel(ids[0]);
quality = RoundMath(CalculateAttributeValue(inv.GetItemAttributeValue(ids[0], 'quality')));


if(attemptCounter >= 1000)
break;

if(itemLevel != desiredLevel || quality < minQuality)
inv.RemoveItem(ids[0]);
}

if(equipItem)
EquipItem(ids[0]);
}

public final function AddAnItemWithAutogenLevel(itemName : name, desiredLevel : int)
{
var itemLevel : int;
var ids : array;
var attemptCounter : int;

itemLevel = 0;
while(itemLevel != desiredLevel)
{
attemptCounter += 1;
ids.Clear();
ids = inv.AddAnItem(itemName, 1, true);
itemLevel = inv.GetItemLevel(ids[0]);


if(attemptCounter >= 1000)
break;

if(itemLevel != desiredLevel)
inv.RemoveItem(ids[0]);
}
}

public final function AddAnItemWithMinQuality(itemName : name, minQuality : int, optional equip : bool)
{
var quality : int;
var ids : array;
var attemptCounter : int;

quality = 0;
while(quality < minQuality)
{
attemptCounter += 1;
ids.Clear();
ids = inv.AddAnItem(itemName, 1, true);
quality = RoundMath(CalculateAttributeValue(inv.GetItemAttributeValue(ids[0], 'quality')));


if(attemptCounter >= 1000)
break;

if(quality < minQuality)
inv.RemoveItem(ids[0]);
}

if(equip)
EquipItem(ids[0]);
}






public function IsSetBonusActive( bonus : EItemSetBonus ) : bool
{
switch(bonus)
{
case EISB_Lynx_1: return amountOfSetPiecesEquipped[ EIST_Lynx ] >= theGame.params.ITEMS_REQUIRED_FOR_MINOR_SET_BONUS;
case EISB_Lynx_2: return amountOfSetPiecesEquipped[ EIST_Lynx ] >= theGame.params.ITEMS_REQUIRED_FOR_MAJOR_SET_BONUS;
case EISB_Gryphon_1: return amountOfSetPiecesEquipped[ EIST_Gryphon ] >= theGame.params.ITEMS_REQUIRED_FOR_MINOR_SET_BONUS;
case EISB_Gryphon_2: return amountOfSetPiecesEquipped[ EIST_Gryphon ] >= theGame.params.ITEMS_REQUIRED_FOR_MAJOR_SET_BONUS;
case EISB_Bear_1: return amountOfSetPiecesEquipped[ EIST_Bear ] >= theGame.params.ITEMS_REQUIRED_FOR_MINOR_SET_BONUS;
case EISB_Bear_2: return amountOfSetPiecesEquipped[ EIST_Bear ] >= theGame.params.ITEMS_REQUIRED_FOR_MAJOR_SET_BONUS;
case EISB_Wolf_1: return amountOfSetPiecesEquipped[ EIST_Wolf ] >= theGame.params.ITEMS_REQUIRED_FOR_MINOR_SET_BONUS;
case EISB_Wolf_2: return amountOfSetPiecesEquipped[ EIST_Wolf ] >= theGame.params.ITEMS_REQUIRED_FOR_MAJOR_SET_BONUS;
case EISB_RedWolf_1: return amountOfSetPiecesEquipped[ EIST_RedWolf ] >= theGame.params.ITEMS_REQUIRED_FOR_MINOR_SET_BONUS;
case EISB_RedWolf_2: return amountOfSetPiecesEquipped[ EIST_RedWolf ] >= theGame.params.ITEMS_REQUIRED_FOR_MAJOR_SET_BONUS;
case EISB_Vampire: return amountOfSetPiecesEquipped[ EIST_Vampire ] >= theGame.params.ITEMS_REQUIRED_FOR_MINOR_SET_BONUS;
default: return false;
}
}

public function GetSetPartsEquipped( setType : EItemSetType ) : int
{
return amountOfSetPiecesEquipped[ setType ];
}

protected function UpdateItemSetBonuses( item : SItemUniqueId, increment : bool )
{
var setType : EItemSetType;
var tutorialStateSets : W3TutorialManagerUIHandlerStateSetItemsUnlocked;
var id : SItemUniqueId;

if( !inv.IsIdValid( item ) || !inv.ItemHasTag(item, theGame.params.ITEM_SET_TAG_BONUS ) )
{

if( !IsSetBonusActive( EISB_Wolf_1 ) )
{
if( GetItemEquippedOnSlot( EES_SteelSword, id ) )
{
RemoveExtraOilsFromItem( id );
}
if( GetItemEquippedOnSlot( EES_SilverSword, id ) )
{
RemoveExtraOilsFromItem( id );
}
}

return;
}

setType = CheckSetType( item );

if( increment )
{
amountOfSetPiecesEquipped[ setType ] += 1;

if( amountOfSetPiecesEquipped[ setType ] >= theGame.params.ITEMS_REQUIRED_FOR_MINOR_SET_BONUS && ShouldProcessTutorial( 'TutorialSetBonusesUnlocked' ) && theGame.GetTutorialSystem().uiHandler && theGame.GetTutorialSystem().uiHandler.GetCurrentStateName() == 'SetItemsUnlocked' )
{
tutorialStateSets = ( W3TutorialManagerUIHandlerStateSetItemsUnlocked )theGame.GetTutorialSystem().uiHandler.GetCurrentState();
tutorialStateSets.OnSetBonusCompleted();
}
}
else
{
amountOfSetPiecesEquipped[ setType ] -= 1;
}


if( setType != EIST_Vampire && amountOfSetPiecesEquipped[ setType ] == theGame.params.ITEMS_REQUIRED_FOR_MAJOR_SET_BONUS )
{
theGame.GetGamerProfile().AddAchievement( EA_ReadyToRoll );
}


if( !IsSetBonusActive( EISB_Wolf_1 ) )
{
if( GetItemEquippedOnSlot( EES_SteelSword, id ) )
{
RemoveExtraOilsFromItem( id );
}
if( GetItemEquippedOnSlot( EES_SilverSword, id ) )
{
RemoveExtraOilsFromItem( id );
}
}

ManageActiveSetBonuses( setType );


ManageSetBonusesSoundbanks( setType );
}

public function ManageActiveSetBonuses( setType : EItemSetType )
{
var l_i : int;


if( setType == EIST_Lynx )
{

if( HasBuff( EET_LynxSetBonus ) && !IsSetBonusActive( EISB_Lynx_1 ) )
{
RemoveBuff( EET_LynxSetBonus );
}
}

else if( setType == EIST_Gryphon )
{

if( !IsSetBonusActive( EISB_Gryphon_1 ) )
{
RemoveBuff( EET_GryphonSetBonus );
}

if( IsSetBonusActive( EISB_Gryphon_2 ) && !HasBuff( EET_GryphonSetBonusYrden ) )
{
for( l_i = 0 ; l_i < yrdenEntities.Size() ; l_i += 1 )
{
if( yrdenEntities[ l_i ].GetIsPlayerInside() && !yrdenEntities[ l_i ].IsAlternateCast() )
{
AddEffectDefault( EET_GryphonSetBonusYrden, this, "GryphonSetBonusYrden" );
break;
}
}
}
else
{
RemoveBuff( EET_GryphonSetBonusYrden );
}
}
}

public function CheckSetTypeByName( itemName : name ) : EItemSetType
{
var dm : CDefinitionsManagerAccessor;

dm = theGame.GetDefinitionsManager();

if( dm.ItemHasTag( itemName, theGame.params.ITEM_SET_TAG_LYNX ) )
{
return EIST_Lynx;
}
else
if( dm.ItemHasTag( itemName, theGame.params.ITEM_SET_TAG_GRYPHON ) )
{
return EIST_Gryphon;
}
else
if( dm.ItemHasTag( itemName, theGame.params.ITEM_SET_TAG_BEAR ) )
{
return EIST_Bear;
}
else
if( dm.ItemHasTag( itemName, theGame.params.ITEM_SET_TAG_WOLF ) )
{
return EIST_Wolf;
}
else
if( dm.ItemHasTag( itemName, theGame.params.ITEM_SET_TAG_RED_WOLF ) )
{
return EIST_RedWolf;
}
else
if( dm.ItemHasTag( itemName, theGame.params.ITEM_SET_TAG_VAMPIRE ) )
{
return EIST_Vampire;
}
else
if( dm.ItemHasTag( itemName, theGame.params.ITEM_SET_TAG_VIPER ) )
{
return EIST_Viper;
}
else
{
return EIST_Undefined;
}
}

public function CheckSetType( item : SItemUniqueId ) : EItemSetType
{
var stopLoop : bool;
var tags : array;
var i : int;
var setType : EItemSetType;

stopLoop = false;

inv.GetItemTags( item, tags );


for( i=0; i {
switch( tags[i] )
{
case theGame.params.ITEM_SET_TAG_LYNX:
case theGame.params.ITEM_SET_TAG_GRYPHON:
case theGame.params.ITEM_SET_TAG_BEAR:
case theGame.params.ITEM_SET_TAG_WOLF:
case theGame.params.ITEM_SET_TAG_RED_WOLF:
case theGame.params.ITEM_SET_TAG_VAMPIRE:
case theGame.params.ITEM_SET_TAG_VIPER:
setType = SetItemNameToType( tags[i] );
stopLoop = true;
break;
}
if ( stopLoop )
{
break;
}
}

return setType;
}

public function GetSetBonusStatusByName( itemName : name, out desc1, desc2 : string, out isActive1, isActive2 : bool ) : EItemSetType
{
var setType : EItemSetType;

if( theGame.GetDLCManager().IsEP2Enabled() )
{
setType = CheckSetTypeByName( itemName );
SetBonusStatusByType( setType, desc1, desc2, isActive1, isActive2 );

return setType;
}
else
{
return EIST_Undefined;
}
}

public function GetSetBonusStatus( item : SItemUniqueId, out desc1, desc2 : string, out isActive1, isActive2 : bool ) : EItemSetType
{
var setType : EItemSetType;

if( theGame.GetDLCManager().IsEP2Enabled() )
{
setType = CheckSetType( item );
SetBonusStatusByType( setType, desc1, desc2, isActive1, isActive2 );

return setType;
}
else
{
return EIST_Undefined;
}
}

private function SetBonusStatusByType(setType : EItemSetType, out desc1, desc2 : string, out isActive1, isActive2 : bool):void
{
var setBonus : EItemSetBonus;

if( amountOfSetPiecesEquipped[ setType ] >= theGame.params.ITEMS_REQUIRED_FOR_MINOR_SET_BONUS )
{
isActive1 = true;
}

if( amountOfSetPiecesEquipped[ setType ] >= theGame.params.ITEMS_REQUIRED_FOR_MAJOR_SET_BONUS )
{
isActive2 = true;
}

setBonus = ItemSetTypeToItemSetBonus( setType, 1 );
desc1 = GetSetBonusTooltipDescription( setBonus );

setBonus = ItemSetTypeToItemSetBonus( setType, 2 );
desc2 = GetSetBonusTooltipDescription( setBonus );
}

public function ItemSetTypeToItemSetBonus( setType : EItemSetType, nr : int ) : EItemSetBonus
{
var setBonus : EItemSetBonus;

if( nr == 1 )
{
switch( setType )
{
case EIST_Lynx: setBonus = EISB_Lynx_1; break;
case EIST_Gryphon: setBonus = EISB_Gryphon_1; break;
case EIST_Bear: setBonus = EISB_Bear_1; break;
case EIST_Wolf: setBonus = EISB_Wolf_1; break;
case EIST_RedWolf: setBonus = EISB_RedWolf_1; break;
case EIST_Vampire: setBonus = EISB_Vampire; break;
}
}
else
{
switch( setType )
{
case EIST_Lynx: setBonus = EISB_Lynx_2; break;
case EIST_Gryphon: setBonus = EISB_Gryphon_2; break;
case EIST_Bear: setBonus = EISB_Bear_2; break;
case EIST_Wolf: setBonus = EISB_Wolf_2; break;
case EIST_RedWolf: setBonus = EISB_RedWolf_2; break;
case EIST_Vampire: setBonus = EISB_Undefined; break;
}
}

return setBonus;
}

public function GetSetBonusTooltipDescription( bonus : EItemSetBonus ) : string
{
var finalString : string;
var arrString : array;
var dm : CDefinitionsManagerAccessor;
var min, max : SAbilityAttributeValue;
var tempString : string;

switch( bonus )
{
case EISB_Lynx_1: tempString = "skill_desc_lynx_set_ability1"; break;
case EISB_Lynx_2: tempString = "skill_desc_lynx_set_ability2"; break;
case EISB_Gryphon_1: tempString = "skill_desc_gryphon_set_ability1"; break;
case EISB_Gryphon_2: tempString = "skill_desc_gryphon_set_ability2"; break;
case EISB_Bear_1: tempString = "skill_desc_bear_set_ability1"; break;
case EISB_Bear_2: tempString = "skill_desc_bear_set_ability2"; break;
case EISB_Wolf_1: tempString = "skill_desc_wolf_set_ability2"; break;
case EISB_Wolf_2: tempString = "skill_desc_wolf_set_ability1"; break;
case EISB_RedWolf_1: tempString = "skill_desc_red_wolf_set_ability1"; break;
case EISB_RedWolf_2: tempString = "skill_desc_red_wolf_set_ability2"; break;
case EISB_Vampire: tempString = "skill_desc_vampire_set_ability1"; break;
default: tempString = ""; break;
}

dm = theGame.GetDefinitionsManager();

switch( bonus )
{
case EISB_Lynx_1:
dm.GetAbilityAttributeValue( 'LynxSetBonusEffect', 'duration', min, max );
arrString.PushBack( FloatToString( min.valueAdditive ) );
dm.GetAbilityAttributeValue( 'LynxSetBonusEffect', 'lynx_dmg_boost', min, max );
arrString.PushBack( FloatToString( min.valueAdditive * 100 ) );
arrString.PushBack( FloatToString( min.valueAdditive * 100 * amountOfSetPiecesEquipped[ EIST_Lynx ] ) );
finalString = GetLocStringByKeyExtWithParams( tempString,,,arrString );
break;
case EISB_Lynx_2:
dm.GetAbilityAttributeValue( GetSetBonusAbility( EISB_Lynx_2 ), 'lynx_2_dmg_boost', min, max );
arrString.PushBack( FloatToString( min.valueAdditive * 100 ) );

dm.GetAbilityAttributeValue( GetSetBonusAbility( EISB_Lynx_2 ), 'lynx_2_adrenaline_cost', min, max );
arrString.PushBack( FloatToString( min.valueAdditive ) );

finalString = GetLocStringByKeyExtWithParams( tempString,,,arrString );
break;
case EISB_Gryphon_1:
dm.GetAbilityAttributeValue( 'GryphonSetBonusEffect', 'duration', min, max );
arrString.PushBack( FloatToString( min.valueAdditive ) );
finalString = GetLocStringByKeyExtWithParams( tempString,,,arrString );
break;
case EISB_Gryphon_2:
dm.GetAbilityAttributeValue( 'GryphonSetBonusYrdenEffect', 'trigger_scale', min, max );
arrString.PushBack( FloatToString( ( min.valueAdditive - 1 )* 100) );
dm.GetAbilityAttributeValue( 'GryphonSetBonusYrdenEffect', 'staminaRegen', min, max );
arrString.PushBack( FloatToString( min.valueMultiplicative * 100) );
dm.GetAbilityAttributeValue( 'GryphonSetBonusYrdenEffect', 'spell_power', min, max );
arrString.PushBack( FloatToString( min.valueMultiplicative * 100) );
dm.GetAbilityAttributeValue( 'GryphonSetBonusYrdenEffect', 'gryphon_set_bns_dmg_reduction', min, max );
arrString.PushBack( FloatToString( min.valueAdditive * 100) );
finalString = GetLocStringByKeyExtWithParams( tempString,,,arrString );
break;
case EISB_Bear_1:
dm.GetAbilityAttributeValue( 'setBonusAbilityBear_1', 'quen_reapply_chance', min, max );
arrString.PushBack( FloatToString( min.valueMultiplicative * 100 ) );

arrString.PushBack( FloatToString( min.valueMultiplicative * 100 * amountOfSetPiecesEquipped[ EIST_Bear ] ) );
finalString = GetLocStringByKeyExtWithParams( tempString,,,arrString );
break;
case EISB_Bear_2:
dm.GetAbilityAttributeValue( 'setBonusAbilityBear_2', 'quen_dmg_boost', min, max );
arrString.PushBack( FloatToString( min.valueMultiplicative * 100 ) );
finalString = GetLocStringByKeyExtWithParams( tempString,,,arrString );
break;
case EISB_RedWolf_2:
dm.GetAbilityAttributeValue( 'setBonusAbilityRedWolf_2', 'amount', min, max );
arrString.PushBack( FloatToString( min.valueAdditive ) );
finalString = GetLocStringByKeyExtWithParams( tempString,,,arrString );
break;
case EISB_Vampire:
dm.GetAbilityAttributeValue( 'setBonusAbilityVampire', 'life_percent', min, max );
arrString.PushBack( FloatToString( min.valueAdditive ) );
arrString.PushBack( FloatToString( min.valueAdditive * amountOfSetPiecesEquipped[ EIST_Vampire ] ) );
finalString = GetLocStringByKeyExtWithParams( tempString,,,arrString );
break;
default:
finalString = GetLocStringByKeyExtWithParams( tempString );
}

return finalString;
}

public function ManageSetBonusesSoundbanks( setType : EItemSetType )
{
if( amountOfSetPiecesEquipped[ setType ] >= theGame.params.ITEMS_REQUIRED_FOR_MINOR_SET_BONUS )
{
switch( setType )
{
case EIST_Lynx:
LoadSetBonusSoundBank( "ep2_setbonus_lynx.bnk" );
break;
case EIST_Gryphon:
LoadSetBonusSoundBank( "ep2_setbonus_gryphon.bnk" );
break;
case EIST_Bear:
LoadSetBonusSoundBank( "ep2_setbonus_bear.bnk" );
break;
}
}
else
{
switch( setType )
{
case EIST_Lynx:
UnloadSetBonusSoundBank( "ep2_setbonus_lynx.bnk" );
break;
case EIST_Gryphon:
UnloadSetBonusSoundBank( "ep2_setbonus_gryphon.bnk" );
break;
case EIST_Bear:
UnloadSetBonusSoundBank( "ep2_setbonus_bear.bnk" );
break;
}
}
}

public function VampiricSetAbilityRegeneration()
{
var healthMax : float;
var healthToReg : float;

healthMax = GetStatMax( BCS_Vitality );

healthToReg = ( amountOfSetPiecesEquipped[ EIST_Vampire ] * healthMax ) / 100;

PlayEffect('drain_energy_caretaker_shovel');
GainStat( BCS_Vitality, healthToReg );
}

private function LoadSetBonusSoundBank( bankName : string )
{
if( !theSound.SoundIsBankLoaded( bankName ) )
{
theSound.SoundLoadBank( bankName, true );
}
}

private function UnloadSetBonusSoundBank( bankName : string )
{
if( theSound.SoundIsBankLoaded( bankName ) )
{
theSound.SoundUnloadBank( bankName );
}
}

timer function BearSetBonusQuenReapply( dt : float, id : int )
{
var newQuen : W3QuenEntity;

newQuen = (W3QuenEntity)theGame.CreateEntity( GetSignTemplate( ST_Quen ), GetWorldPosition(), GetWorldRotation() );
newQuen.Init( signOwner, GetSignEntity( ST_Quen ), true );
newQuen.freeFromBearSetBonus = true;
newQuen.OnStarted();
newQuen.OnThrowing();
newQuen.OnEnded();

m_quenReappliedCount += 1;

RemoveTimer( 'BearSetBonusQuenReapply');
}

public final function StandaloneEp1_1()
{
var i, inc, quantityLow, randLow, quantityMedium, randMedium, quantityHigh, randHigh, startingMoney : int;
var pam : W3PlayerAbilityManager;
var ids : array;
var STARTING_LEVEL : int;

FactsAdd("StandAloneEP1", 1);


inv.RemoveAllItems();


inv.AddAnItem('Illusion Medallion', 1, true, true, false);
inv.AddAnItem('q103_safe_conduct', 1, true, true, false);


theGame.GetGamerProfile().ClearAllAchievementsForEP1();


STARTING_LEVEL = 32;
inc = STARTING_LEVEL - GetLevel();
for(i=0; i {
levelManager.AddPoints(EExperiencePoint, levelManager.GetTotalExpForNextLevel() - levelManager.GetPointsTotal(EExperiencePoint), false);
}


levelManager.ResetCharacterDev();
pam = (W3PlayerAbilityManager)abilityManager;
if(pam)
{
pam.ResetCharacterDev();
}
levelManager.SetFreeSkillPoints(levelManager.GetLevel() - 1 + 11);


inv.AddAnItem('Mutagen red', 4);
inv.AddAnItem('Mutagen green', 4);
inv.AddAnItem('Mutagen blue', 4);
inv.AddAnItem('Lesser mutagen red', 2);
inv.AddAnItem('Lesser mutagen green', 2);
inv.AddAnItem('Lesser mutagen blue', 2);
inv.AddAnItem('Greater mutagen green', 1);
inv.AddAnItem('Greater mutagen blue', 2);


startingMoney = 40000;
if(GetMoney() > startingMoney)
{
RemoveMoney(GetMoney() - startingMoney);
}
else
{
AddMoney( 40000 - GetMoney() );
}





ids.Clear();
ids = inv.AddAnItem('EP1 Standalone Starting Armor');
EquipItem(ids[0]);
ids.Clear();
ids = inv.AddAnItem('EP1 Standalone Starting Boots');
EquipItem(ids[0]);
ids.Clear();
ids = inv.AddAnItem('EP1 Standalone Starting Gloves');
EquipItem(ids[0]);
ids.Clear();
ids = inv.AddAnItem('EP1 Standalone Starting Pants');
EquipItem(ids[0]);


ids.Clear();
ids = inv.AddAnItem('EP1 Standalone Starting Steel Sword');
EquipItem(ids[0]);
ids.Clear();
ids = inv.AddAnItem('EP1 Standalone Starting Silver Sword');
EquipItem(ids[0]);


inv.AddAnItem('Torch', 1, true, true, false);


quantityLow = 1;
randLow = 3;
quantityMedium = 4;
randMedium = 4;
quantityHigh = 8;
randHigh = 6;

inv.AddAnItem('Alghoul bone marrow',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Amethyst dust',quantityLow+RandRange(randLow));
inv.AddAnItem('Arachas eyes',quantityLow+RandRange(randLow));
inv.AddAnItem('Arachas venom',quantityLow+RandRange(randLow));
inv.AddAnItem('Basilisk hide',quantityLow+RandRange(randLow));
inv.AddAnItem('Basilisk venom',quantityLow+RandRange(randLow));
inv.AddAnItem('Bear pelt',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Berserker pelt',quantityLow+RandRange(randLow));
inv.AddAnItem('Coal',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Cotton',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Dark iron ingot',quantityLow+RandRange(randLow));
inv.AddAnItem('Dark iron ore',quantityLow+RandRange(randLow));
inv.AddAnItem('Deer hide',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Diamond dust',quantityLow+RandRange(randLow));
inv.AddAnItem('Draconide leather',quantityLow+RandRange(randLow));
inv.AddAnItem('Drowned dead tongue',quantityLow+RandRange(randLow));
inv.AddAnItem('Drowner brain',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Dwimeryte ingot',quantityLow+RandRange(randLow));
inv.AddAnItem('Dwimeryte ore',quantityLow+RandRange(randLow));
inv.AddAnItem('Emerald dust',quantityLow+RandRange(randLow));
inv.AddAnItem('Endriag chitin plates',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Endriag embryo',quantityLow+RandRange(randLow));
inv.AddAnItem('Ghoul blood',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Goat hide',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Hag teeth',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Hardened leather',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Hardened timber',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Harpy feathers',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Horse hide',quantityLow+RandRange(randLow));
inv.AddAnItem('Iron ore',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Leather straps',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Leather',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Linen',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Meteorite ingot',quantityLow+RandRange(randLow));
inv.AddAnItem('Meteorite ore',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Necrophage skin',quantityLow+RandRange(randLow));
inv.AddAnItem('Nekker blood',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Nekker heart',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Oil',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Phosphorescent crystal',quantityLow+RandRange(randLow));
inv.AddAnItem('Pig hide',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Pure silver',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Rabbit pelt',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Rotfiend blood',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Sapphire dust',quantityLow+RandRange(randLow));
inv.AddAnItem('Silk',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Silver ingot',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Silver ore',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Specter dust',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Steel ingot',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Steel plate',quantityHigh+RandRange(randHigh));
inv.AddAnItem('String',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Thread',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Timber',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Twine',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Venom extract',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Water essence',quantityMedium+RandRange(randMedium));
inv.AddAnItem('Wolf liver',quantityHigh+RandRange(randHigh));
inv.AddAnItem('Wolf pelt',quantityMedium+RandRange(randMedium));

inv.AddAnItem('Alcohest', 5);
inv.AddAnItem('Dwarven spirit', 5);


ids.Clear();
ids = inv.AddAnItem('Crossbow 5');
EquipItem(ids[0]);
ids.Clear();
ids = inv.AddAnItem('Blunt Bolt', 100);
EquipItem(ids[0]);
inv.AddAnItem('Broadhead Bolt', 100);
inv.AddAnItem('Split Bolt', 100);


RemoveAllAlchemyRecipes();
RemoveAllCraftingSchematics();




AddAlchemyRecipe('Recipe for Cat 1');



AddAlchemyRecipe('Recipe for Maribor Forest 1');
AddAlchemyRecipe('Recipe for Petris Philtre 1');
AddAlchemyRecipe('Recipe for Swallow 1');
AddAlchemyRecipe('Recipe for Tawny Owl 1');

AddAlchemyRecipe('Recipe for White Gull 1');
AddAlchemyRecipe('Recipe for White Honey 1');
AddAlchemyRecipe('Recipe for White Raffards Decoction 1');



AddAlchemyRecipe('Recipe for Beast Oil 1');
AddAlchemyRecipe('Recipe for Cursed Oil 1');
AddAlchemyRecipe('Recipe for Hanged Man Venom 1');
AddAlchemyRecipe('Recipe for Hybrid Oil 1');
AddAlchemyRecipe('Recipe for Insectoid Oil 1');
AddAlchemyRecipe('Recipe for Magicals Oil 1');
AddAlchemyRecipe('Recipe for Necrophage Oil 1');
AddAlchemyRecipe('Recipe for Specter Oil 1');
AddAlchemyRecipe('Recipe for Vampire Oil 1');
AddAlchemyRecipe('Recipe for Draconide Oil 1');
AddAlchemyRecipe('Recipe for Ogre Oil 1');
AddAlchemyRecipe('Recipe for Relic Oil 1');
AddAlchemyRecipe('Recipe for Beast Oil 2');
AddAlchemyRecipe('Recipe for Cursed Oil 2');
AddAlchemyRecipe('Recipe for Hanged Man Venom 2');
AddAlchemyRecipe('Recipe for Hybrid Oil 2');
AddAlchemyRecipe('Recipe for Insectoid Oil 2');
AddAlchemyRecipe('Recipe for Magicals Oil 2');
AddAlchemyRecipe('Recipe for Necrophage Oil 2');
AddAlchemyRecipe('Recipe for Specter Oil 2');
AddAlchemyRecipe('Recipe for Vampire Oil 2');
AddAlchemyRecipe('Recipe for Draconide Oil 2');
AddAlchemyRecipe('Recipe for Ogre Oil 2');
AddAlchemyRecipe('Recipe for Relic Oil 2');


AddAlchemyRecipe('Recipe for Dancing Star 1');

AddAlchemyRecipe('Recipe for Dwimeritum Bomb 1');

AddAlchemyRecipe('Recipe for Grapeshot 1');
AddAlchemyRecipe('Recipe for Samum 1');

AddAlchemyRecipe('Recipe for White Frost 1');



AddAlchemyRecipe('Recipe for Dwarven spirit 1');
AddAlchemyRecipe('Recipe for Alcohest 1');
AddAlchemyRecipe('Recipe for White Gull 1');


AddStartingSchematics();


ids.Clear();
ids = inv.AddAnItem('Swallow 2');
EquipItem(ids[0]);
ids.Clear();
ids = inv.AddAnItem('Thunderbolt 2');
EquipItem(ids[0]);
ids.Clear();
ids = inv.AddAnItem('Tawny Owl 2');
EquipItem(ids[0]);
ids.Clear();

ids = inv.AddAnItem('Grapeshot 2');
EquipItem(ids[0]);
ids.Clear();
ids = inv.AddAnItem('Samum 2');
EquipItem(ids[0]);

inv.AddAnItem('Dwimeritum Bomb 1');
inv.AddAnItem('Dragons Dream 1');
inv.AddAnItem('Silver Dust Bomb 1');
inv.AddAnItem('White Frost 2');
inv.AddAnItem('Devils Puffball 2');
inv.AddAnItem('Dancing Star 2');
inv.AddAnItem('Beast Oil 1');
inv.AddAnItem('Cursed Oil 1');
inv.AddAnItem('Hanged Man Venom 2');
inv.AddAnItem('Hybrid Oil 1');
inv.AddAnItem('Insectoid Oil 1');
inv.AddAnItem('Magicals Oil 1');
inv.AddAnItem('Necrophage Oil 2');
inv.AddAnItem('Specter Oil 1');
inv.AddAnItem('Vampire Oil 1');
inv.AddAnItem('Draconide Oil 1');
inv.AddAnItem('Relic Oil 1');
inv.AddAnItem('Black Blood 1');
inv.AddAnItem('Blizzard 1');
inv.AddAnItem('Cat 2');
inv.AddAnItem('Full Moon 1');
inv.AddAnItem('Maribor Forest 1');
inv.AddAnItem('Petris Philtre 1');
inv.AddAnItem('White Gull 1', 3);
inv.AddAnItem('White Honey 2');
inv.AddAnItem('White Raffards Decoction 1');


inv.AddAnItem('Mutagen 17');
inv.AddAnItem('Mutagen 19');
inv.AddAnItem('Mutagen 27');
inv.AddAnItem('Mutagen 26');


inv.AddAnItem('weapon_repair_kit_1', 5);
inv.AddAnItem('weapon_repair_kit_2', 3);
inv.AddAnItem('armor_repair_kit_1', 5);
inv.AddAnItem('armor_repair_kit_2', 3);


quantityMedium = 2;
quantityLow = 1;
inv.AddAnItem('Rune stribog lesser', quantityMedium);
inv.AddAnItem('Rune stribog', quantityLow);
inv.AddAnItem('Rune dazhbog lesser', quantityMedium);
inv.AddAnItem('Rune dazhbog', quantityLow);
inv.AddAnItem('Rune devana lesser', quantityMedium);
inv.AddAnItem('Rune devana', quantityLow);
inv.AddAnItem('Rune zoria lesser', quantityMedium);
inv.AddAnItem('Rune zoria', quantityLow);
inv.AddAnItem('Rune morana lesser', quantityMedium);
inv.AddAnItem('Rune morana', quantityLow);
inv.AddAnItem('Rune triglav lesser', quantityMedium);
inv.AddAnItem('Rune triglav', quantityLow);
inv.AddAnItem('Rune svarog lesser', quantityMedium);
inv.AddAnItem('Rune svarog', quantityLow);
inv.AddAnItem('Rune veles lesser', quantityMedium);
inv.AddAnItem('Rune veles', quantityLow);
inv.AddAnItem('Rune perun lesser', quantityMedium);
inv.AddAnItem('Rune perun', quantityLow);
inv.AddAnItem('Rune elemental lesser', quantityMedium);
inv.AddAnItem('Rune elemental', quantityLow);

inv.AddAnItem('Glyph aard lesser', quantityMedium);
inv.AddAnItem('Glyph aard', quantityLow);
inv.AddAnItem('Glyph axii lesser', quantityMedium);
inv.AddAnItem('Glyph axii', quantityLow);
inv.AddAnItem('Glyph igni lesser', quantityMedium);
inv.AddAnItem('Glyph igni', quantityLow);
inv.AddAnItem('Glyph quen lesser', quantityMedium);
inv.AddAnItem('Glyph quen', quantityLow);
inv.AddAnItem('Glyph yrden lesser', quantityMedium);
inv.AddAnItem('Glyph yrden', quantityLow);


StandaloneEp1_2();
}

public final function StandaloneEp1_2()
{
var horseId : SItemUniqueId;
var ids : array;
var ents : array< CJournalBase >;
var i : int;
var manager : CWitcherJournalManager;


inv.AddAnItem( 'Cows milk', 20 );
ids.Clear();
ids = inv.AddAnItem( 'Dumpling', 44 );
EquipItem(ids[0]);


inv.AddAnItem('Clearing Potion', 2, true, false, false);


GetHorseManager().RemoveAllItems();

ids.Clear();
ids = inv.AddAnItem('Horse Bag 2');
horseId = GetHorseManager().MoveItemToHorse(ids[0]);
GetHorseManager().EquipItem(horseId);

ids.Clear();
ids = inv.AddAnItem('Horse Blinder 2');
horseId = GetHorseManager().MoveItemToHorse(ids[0]);
GetHorseManager().EquipItem(horseId);

ids.Clear();
ids = inv.AddAnItem('Horse Saddle 2');
horseId = GetHorseManager().MoveItemToHorse(ids[0]);
GetHorseManager().EquipItem(horseId);

manager = theGame.GetJournalManager();


manager.GetActivatedOfType( 'CJournalCreature', ents );
for(i=0; i {
manager.ActivateEntry(ents[i], JS_Inactive, false, true);
}


ents.Clear();
manager.GetActivatedOfType( 'CJournalCharacter', ents );
for(i=0; i {
manager.ActivateEntry(ents[i], JS_Inactive, false, true);
}


ents.Clear();
manager.GetActivatedOfType( 'CJournalQuest', ents );
for(i=0; i {

if( StrStartsWith(ents[i].baseName, "q60"))
continue;

manager.ActivateEntry(ents[i], JS_Inactive, false, true);
}


manager.ActivateEntryByScriptTag('TutorialAard', JS_Active);
manager.ActivateEntryByScriptTag('TutorialAdrenaline', JS_Active);
manager.ActivateEntryByScriptTag('TutorialAxii', JS_Active);
manager.ActivateEntryByScriptTag('TutorialAxiiDialog', JS_Active);
manager.ActivateEntryByScriptTag('TutorialCamera', JS_Active);
manager.ActivateEntryByScriptTag('TutorialCamera_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialCiriBlink', JS_Active);
manager.ActivateEntryByScriptTag('TutorialCiriCharge', JS_Active);
manager.ActivateEntryByScriptTag('TutorialCiriStamina', JS_Active);
manager.ActivateEntryByScriptTag('TutorialCounter', JS_Active);
manager.ActivateEntryByScriptTag('TutorialDialogClose', JS_Active);
manager.ActivateEntryByScriptTag('TutorialFallingRoll', JS_Active);
manager.ActivateEntryByScriptTag('TutorialFocus', JS_Active);
manager.ActivateEntryByScriptTag('TutorialFocusClues', JS_Active);
manager.ActivateEntryByScriptTag('TutorialFocusClues', JS_Active);
manager.ActivateEntryByScriptTag('TutorialHorseRoad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialHorseSpeed0', JS_Active);
manager.ActivateEntryByScriptTag('TutorialHorseSpeed0_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialHorseSpeed1', JS_Active);
manager.ActivateEntryByScriptTag('TutorialHorseSpeed2', JS_Active);
manager.ActivateEntryByScriptTag('TutorialHorseSummon', JS_Active);
manager.ActivateEntryByScriptTag('TutorialHorseSummon_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialIgni', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalAlternateSings', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalBoatDamage', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalBoatMount', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalBuffs', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalCharDevLeveling', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalCharDevSkills', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalCrafting', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalCrossbow', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalDialogGwint', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalDialogShop', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalDive', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalDodge', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalDodge_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalDrawWeapon', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalDrawWeapon_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalDurability', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalExplorations', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalExplorations_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalFastTravel', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalFocusRedObjects', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalGasClouds', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalHeavyAttacks', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalHorse', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalHorseStamina', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalJump', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalLightAttacks', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalLightAttacks_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalMeditation', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalMeditation_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalMonsterThreatLevels', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalMovement', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalMovement_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalMutagenIngredient', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalMutagenPotion', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalOils', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalPetards', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalPotions', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalPotions_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalQuestArea', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalRadial', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalRifts', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalRun', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalShopDescription', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalSignCast', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalSignCast_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalSpecialAttacks', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJournalStaminaExploration', JS_Active);
manager.ActivateEntryByScriptTag('TutorialJumpHang', JS_Active);
manager.ActivateEntryByScriptTag('TutorialLadder', JS_Active);
manager.ActivateEntryByScriptTag('TutorialLadderMove', JS_Active);
manager.ActivateEntryByScriptTag('TutorialLadderMove_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialObjectiveSwitching', JS_Active);
manager.ActivateEntryByScriptTag('TutorialOxygen', JS_Active);
manager.ActivateEntryByScriptTag('TutorialParry', JS_Active);
manager.ActivateEntryByScriptTag('TutorialPOIUncovered', JS_Active);
manager.ActivateEntryByScriptTag('TutorialQuen', JS_Active);
manager.ActivateEntryByScriptTag('TutorialRoll', JS_Active);
manager.ActivateEntryByScriptTag('TutorialRoll_pad', JS_Active);
manager.ActivateEntryByScriptTag('TutorialSpeedPairing', JS_Active);
manager.ActivateEntryByScriptTag('TutorialSprint', JS_Active);
manager.ActivateEntryByScriptTag('TutorialStaminaSigns', JS_Active);
manager.ActivateEntryByScriptTag('TutorialStealing', JS_Active);
manager.ActivateEntryByScriptTag('TutorialSwimmingSpeed', JS_Active);
manager.ActivateEntryByScriptTag('TutorialTimedChoiceDialog', JS_Active);
manager.ActivateEntryByScriptTag('TutorialYrden', JS_Active);


FactsAdd('kill_base_tutorials');


theGame.GetTutorialSystem().RemoveAllQueuedTutorials();


FactsAdd('standalone_ep1');
FactsRemove("StandAloneEP1");

theGame.GetJournalManager().ForceUntrackingQuestForEP1Savegame();
}

final function Debug_FocusBoyFocusGain()
{
var focusGain : float;

focusGain = FactsQuerySum( "debug_fact_focus_boy" ) ;
GainStat( BCS_Focus, focusGain );
}

public final function StandaloneEp2_1()
{
var i, inc, quantityLow, randLow, quantityMedium, randMedium, quantityHigh, randHigh, startingMoney : int;
var pam : W3PlayerAbilityManager;
var ids : array;
var STARTING_LEVEL : int;

FactsAdd( "StandAloneEP2", 1 );


inv.RemoveAllItems();


inv.AddAnItem( 'Illusion Medallion', 1, true, true, false );
inv.AddAnItem( 'q103_safe_conduct', 1, true, true, false );


theGame.GetGamerProfile().ClearAllAchievementsForEP2();


levelManager.Hack_EP2StandaloneLevelShrink( 35 );


levelManager.ResetCharacterDev();
pam = ( W3PlayerAbilityManager )abilityManager;
if( pam )
{
pam.ResetCharacterDev();
}
levelManager.SetFreeSkillPoints( levelManager.GetLevel() - 1 + 11 );


inv.AddAnItem( 'Mutagen red', 4 );
inv.AddAnItem( 'Mutagen green', 4 );
inv.AddAnItem( 'Mutagen blue', 4 );
inv.AddAnItem( 'Lesser mutagen red', 2 );
inv.AddAnItem( 'Lesser mutagen green', 2 );
inv.AddAnItem( 'Lesser mutagen blue', 2 );
inv.AddAnItem( 'Greater mutagen red', 2 );
inv.AddAnItem( 'Greater mutagen green', 2 );
inv.AddAnItem( 'Greater mutagen blue', 2 );


startingMoney = 20000;
if( GetMoney() > startingMoney )
{
RemoveMoney( GetMoney() - startingMoney );
}
else
{
AddMoney( 20000 - GetMoney() );
}


ids.Clear();
ids = inv.AddAnItem( 'EP2 Standalone Starting Armor' );
EquipItem( ids[0] );
ids.Clear();
ids = inv.AddAnItem( 'EP2 Standalone Starting Boots' );
EquipItem( ids[0] );
ids.Clear();
ids = inv.AddAnItem( 'EP2 Standalone Starting Gloves' );
EquipItem( ids[0] );
ids.Clear();
ids = inv.AddAnItem( 'EP2 Standalone Starting Pants' );
EquipItem( ids[0] );


ids.Clear();
ids = inv.AddAnItem( 'EP2 Standalone Starting Steel Sword' );
EquipItem( ids[0] );
ids.Clear();
ids = inv.AddAnItem( 'EP2 Standalone Starting Silver Sword' );
EquipItem( ids[0] );


inv.AddAnItem( 'Torch', 1, true, true, false );


quantityLow = 1;
randLow = 3;
quantityMedium = 4;
randMedium = 4;
quantityHigh = 8;
randHigh = 6;

inv.AddAnItem( 'Alghoul bone marrow',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Amethyst dust',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Arachas eyes',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Arachas venom',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Basilisk hide',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Basilisk venom',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Bear pelt',quantityHigh+RandRange( randHigh ) );
inv.AddAnItem( 'Berserker pelt',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Coal',quantityHigh+RandRange( randHigh ) );
inv.AddAnItem( 'Cotton',quantityHigh+RandRange( randHigh ) );


inv.AddAnItem( 'Deer hide',quantityHigh+RandRange( randHigh ) );
inv.AddAnItem( 'Diamond dust',quantityLow+RandRange( randLow ) );

inv.AddAnItem( 'Drowned dead tongue',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Drowner brain',quantityMedium+RandRange( randMedium ) );



inv.AddAnItem( 'Endriag chitin plates',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Endriag embryo',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Ghoul blood',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Goat hide',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Hag teeth',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Hardened leather',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Hardened timber',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Harpy feathers',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Horse hide',quantityLow+RandRange( randLow ) );






inv.AddAnItem( 'Necrophage skin',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Nekker blood',quantityHigh+RandRange( randHigh ) );
inv.AddAnItem( 'Nekker heart',quantityMedium+RandRange( randMedium ) );

inv.AddAnItem( 'Phosphorescent crystal',quantityLow+RandRange( randLow ) );
inv.AddAnItem( 'Pig hide',quantityMedium+RandRange( randMedium ) );

inv.AddAnItem( 'Rabbit pelt',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Rotfiend blood',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Sapphire dust',quantityLow+RandRange( randLow ) );



inv.AddAnItem( 'Specter dust',quantityMedium+RandRange( randMedium ) );







inv.AddAnItem( 'Water essence',quantityMedium+RandRange( randMedium ) );
inv.AddAnItem( 'Wolf liver',quantityHigh+RandRange( randHigh ) );
inv.AddAnItem( 'Wolf pelt',quantityMedium+RandRange( randMedium ) );

inv.AddAnItem( 'Alcohest', 5 );
inv.AddAnItem( 'Dwarven spirit', 5 );


ids.Clear();
ids = inv.AddAnItem( 'Crossbow 5' );
EquipItem( ids[0] );
ids.Clear();
ids = inv.AddAnItem( 'Blunt Bolt', 100 );
EquipItem( ids[0] );
inv.AddAnItem( 'Broadhead Bolt', 100 );
inv.AddAnItem( 'Split Bolt', 100 );


RemoveAllAlchemyRecipes();
RemoveAllCraftingSchematics();









AddAlchemyRecipe( 'Recipe for Petris Philtre 2' );
AddAlchemyRecipe( 'Recipe for Swallow 1' );
AddAlchemyRecipe( 'Recipe for Tawny Owl 1' );

AddAlchemyRecipe( 'Recipe for White Gull 1' );





AddAlchemyRecipe( 'Recipe for Beast Oil 1' );
AddAlchemyRecipe( 'Recipe for Cursed Oil 1' );
AddAlchemyRecipe( 'Recipe for Hanged Man Venom 1' );
AddAlchemyRecipe( 'Recipe for Hybrid Oil 1' );
AddAlchemyRecipe( 'Recipe for Insectoid Oil 2' );
AddAlchemyRecipe( 'Recipe for Magicals Oil 1' );
AddAlchemyRecipe( 'Recipe for Necrophage Oil 1' );
AddAlchemyRecipe( 'Recipe for Specter Oil 1' );
AddAlchemyRecipe( 'Recipe for Vampire Oil 2' );
AddAlchemyRecipe( 'Recipe for Draconide Oil 2' );
AddAlchemyRecipe( 'Recipe for Ogre Oil 1' );
AddAlchemyRecipe( 'Recipe for Relic Oil 1' );
AddAlchemyRecipe( 'Recipe for Beast Oil 2' );
AddAlchemyRecipe( 'Recipe for Cursed Oil 2' );
AddAlchemyRecipe( 'Recipe for Hanged Man Venom 2' );
AddAlchemyRecipe( 'Recipe for Hybrid Oil 2' );
AddAlchemyRecipe( 'Recipe for Insectoid Oil 2' );
AddAlchemyRecipe( 'Recipe for Magicals Oil 2' );
AddAlchemyRecipe( 'Recipe for Necrophage Oil 2' );
AddAlchemyRecipe( 'Recipe for Specter Oil 2' );
AddAlchemyRecipe( 'Recipe for Vampire Oil 2' );
AddAlchemyRecipe( 'Recipe for Draconide Oil 2' );
AddAlchemyRecipe( 'Recipe for Ogre Oil 2' );
AddAlchemyRecipe( 'Recipe for Relic Oil 2' );


AddAlchemyRecipe( 'Recipe for Dancing Star 1' );

AddAlchemyRecipe( 'Recipe for Dwimeritum Bomb 1' );

AddAlchemyRecipe( 'Recipe for Grapeshot 1' );
AddAlchemyRecipe( 'Recipe for Samum 1' );

AddAlchemyRecipe( 'Recipe for White Frost 1' );



AddAlchemyRecipe( 'Recipe for Dwarven spirit 1' );
AddAlchemyRecipe( 'Recipe for Alcohest 1' );
AddAlchemyRecipe( 'Recipe for White Gull 1' );


AddStartingSchematics();


ids.Clear();
ids = inv.AddAnItem( 'Swallow 2' );
EquipItem( ids[0] );
ids.Clear();
ids = inv.AddAnItem( 'Thunderbolt 2' );
EquipItem( ids[0] );
ids.Clear();
ids = inv.AddAnItem( 'Tawny Owl 2' );
EquipItem( ids[0] );
ids.Clear();

ids = inv.AddAnItem( 'Grapeshot 2' );
EquipItem( ids[0] );
ids.Clear();
ids = inv.AddAnItem( 'Samum 2' );
EquipItem( ids[0] );

inv.AddAnItem( 'Dwimeritum Bomb 1' );
inv.AddAnItem( 'Dragons Dream 1' );
inv.AddAnItem( 'Silver Dust Bomb 1' );
inv.AddAnItem( 'White Frost 2' );
inv.AddAnItem( 'Devils Puffball 2' );
inv.AddAnItem( 'Dancing Star 2' );
inv.AddAnItem( 'Beast Oil 1' );
inv.AddAnItem( 'Cursed Oil 1' );
inv.AddAnItem( 'Hanged Man Venom 2' );
inv.AddAnItem( 'Hybrid Oil 2' );
inv.AddAnItem( 'Insectoid Oil 2' );
inv.AddAnItem( 'Magicals Oil 1' );
inv.AddAnItem( 'Necrophage Oil 2' );
inv.AddAnItem( 'Ogre Oil 1' );
inv.AddAnItem( 'Specter Oil 1' );
inv.AddAnItem( 'Vampire Oil 2' );
inv.AddAnItem( 'Draconide Oil 2' );
inv.AddAnItem( 'Relic Oil 1' );
inv.AddAnItem( 'Black Blood 1' );
inv.AddAnItem( 'Blizzard 1' );
inv.AddAnItem( 'Cat 2' );
inv.AddAnItem( 'Full Moon 1' );
inv.AddAnItem( 'Golden Oriole 1' );
inv.AddAnItem( 'Killer Whale 1' );
inv.AddAnItem( 'Maribor Forest 1' );
inv.AddAnItem( 'Petris Philtre 2' );
inv.AddAnItem( 'White Gull 1', 3 );
inv.AddAnItem( 'White Honey 2' );
inv.AddAnItem( 'White Raffards Decoction 1' );


inv.AddAnItem( 'Mutagen 17' );
inv.AddAnItem( 'Mutagen 19' );
inv.AddAnItem( 'Mutagen 27' );
inv.AddAnItem( 'Mutagen 26' );


inv.AddAnItem( 'weapon_repair_kit_1', 5 );
inv.AddAnItem( 'weapon_repair_kit_2', 3 );
inv.AddAnItem( 'armor_repair_kit_1', 5 );
inv.AddAnItem( 'armor_repair_kit_2', 3 );


quantityMedium = 2;
quantityLow = 1;
inv.AddAnItem( 'Rune stribog lesser', quantityMedium );
inv.AddAnItem( 'Rune stribog', quantityLow );
inv.AddAnItem( 'Rune dazhbog lesser', quantityMedium );
inv.AddAnItem( 'Rune dazhbog', quantityLow );
inv.AddAnItem( 'Rune devana lesser', quantityMedium );
inv.AddAnItem( 'Rune devana', quantityLow );
inv.AddAnItem( 'Rune zoria lesser', quantityMedium );
inv.AddAnItem( 'Rune zoria', quantityLow );
inv.AddAnItem( 'Rune morana lesser', quantityMedium );
inv.AddAnItem( 'Rune morana', quantityLow );
inv.AddAnItem( 'Rune triglav lesser', quantityMedium );
inv.AddAnItem( 'Rune triglav', quantityLow );
inv.AddAnItem( 'Rune svarog lesser', quantityMedium );
inv.AddAnItem( 'Rune svarog', quantityLow );
inv.AddAnItem( 'Rune veles lesser', quantityMedium );
inv.AddAnItem( 'Rune veles', quantityLow );
inv.AddAnItem( 'Rune perun lesser', quantityMedium );
inv.AddAnItem( 'Rune perun', quantityLow );
inv.AddAnItem( 'Rune elemental lesser', quantityMedium );
inv.AddAnItem( 'Rune elemental', quantityLow );

inv.AddAnItem( 'Glyph aard lesser', quantityMedium );
inv.AddAnItem( 'Glyph aard', quantityLow );
inv.AddAnItem( 'Glyph axii lesser', quantityMedium );
inv.AddAnItem( 'Glyph axii', quantityLow );
inv.AddAnItem( 'Glyph igni lesser', quantityMedium );
inv.AddAnItem( 'Glyph igni', quantityLow );
inv.AddAnItem( 'Glyph quen lesser', quantityMedium );
inv.AddAnItem( 'Glyph quen', quantityLow );
inv.AddAnItem( 'Glyph yrden lesser', quantityMedium );
inv.AddAnItem( 'Glyph yrden', quantityLow );


StandaloneEp2_2();
}

public final function StandaloneEp2_2()
{
var horseId : SItemUniqueId;
var ids : array;
var ents : array< CJournalBase >;
var i : int;
var manager : CWitcherJournalManager;


inv.AddAnItem( 'Cows milk', 20 );
ids.Clear();
ids = inv.AddAnItem( 'Dumpling', 44 );
EquipItem( ids[0] );


inv.AddAnItem( 'Clearing Potion', 2, true, false, false );


GetHorseManager().RemoveAllItems();

ids.Clear();
ids = inv.AddAnItem( 'Horse Bag 2' );
horseId = GetHorseManager( ).MoveItemToHorse( ids[0] );
GetHorseManager().EquipItem( horseId );

ids.Clear();
ids = inv.AddAnItem( 'Horse Blinder 2' );
horseId = GetHorseManager().MoveItemToHorse( ids[0] );
GetHorseManager().EquipItem( horseId );

ids.Clear();
ids = inv.AddAnItem( 'Horse Saddle 2' );
horseId = GetHorseManager().MoveItemToHorse( ids[0] );
GetHorseManager().EquipItem( horseId );

manager = theGame.GetJournalManager();


manager.GetActivatedOfType( 'CJournalCreature', ents );
for(i=0; i {
manager.ActivateEntry( ents[i], JS_Inactive, false, true );
}


ents.Clear();
manager.GetActivatedOfType( 'CJournalCharacter', ents );
for(i=0; i {
manager.ActivateEntry( ents[i], JS_Inactive, false, true );
}


ents.Clear();
manager.GetActivatedOfType( 'CJournalQuest', ents );
for(i=0; i {

if( StrStartsWith( ents[i].baseName, "q60" ) )
continue;

manager.ActivateEntry( ents[i], JS_Inactive, false, true );
}


manager.ActivateEntryByScriptTag( 'TutorialAard', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialAdrenaline', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialAxii', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialAxiiDialog', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialCamera', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialCamera_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialCiriBlink', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialCiriCharge', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialCiriStamina', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialCounter', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialDialogClose', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialFallingRoll', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialFocus', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialFocusClues', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialFocusClues', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialHorseRoad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialHorseSpeed0', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialHorseSpeed0_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialHorseSpeed1', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialHorseSpeed2', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialHorseSummon', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialHorseSummon_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialIgni', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalAlternateSings', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalBoatDamage', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalBoatMount', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalBuffs', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalCharDevLeveling', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalCharDevSkills', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalCrafting', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalCrossbow', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalDialogGwint', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalDialogShop', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalDive', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalDodge', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalDodge_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalDrawWeapon', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalDrawWeapon_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalDurability', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalExplorations', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalExplorations_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalFastTravel', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalFocusRedObjects', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalGasClouds', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalHeavyAttacks', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalHorse', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalHorseStamina', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalJump', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalLightAttacks', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalLightAttacks_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalMeditation', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalMeditation_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalMonsterThreatLevels', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalMovement', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalMovement_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalMutagenIngredient', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalMutagenPotion', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalOils', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalPetards', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalPotions', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalPotions_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalQuestArea', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalRadial', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalRifts', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalRun', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalShopDescription', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalSignCast', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalSignCast_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalSpecialAttacks', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJournalStaminaExploration', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialJumpHang', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialLadder', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialLadderMove', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialLadderMove_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialObjectiveSwitching', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialOxygen', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialParry', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialPOIUncovered', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialQuen', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialRoll', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialRoll_pad', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialSpeedPairing', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialSprint', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialStaminaSigns', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialStealing', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialSwimmingSpeed', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialTimedChoiceDialog', JS_Active );
manager.ActivateEntryByScriptTag( 'TutorialYrden', JS_Active );

inv.AddAnItem( 'Geralt Shirt', 1 );
inv.AddAnItem( 'Thread', 13 );
inv.AddAnItem( 'String', 9 );
inv.AddAnItem( 'Linen', 4 );
inv.AddAnItem( 'Silk', 6 );
inv.AddAnItem( 'Nigredo', 3 );
inv.AddAnItem( 'Albedo', 1 );
inv.AddAnItem( 'Rubedo', 1 );
inv.AddAnItem( 'Rebis', 1 );
inv.AddAnItem( 'Dog tallow', 4 );
inv.AddAnItem( 'Lunar shards', 3 );
inv.AddAnItem( 'Quicksilver solution', 5 );
inv.AddAnItem( 'Aether', 1 );
inv.AddAnItem( 'Optima mater', 3 );
inv.AddAnItem( 'Fifth essence', 2 );
inv.AddAnItem( 'Hardened timber', 6 );
inv.AddAnItem( 'Fur square', 1 );
inv.AddAnItem( 'Leather straps', 11 );
inv.AddAnItem( 'Leather squares', 6 );
inv.AddAnItem( 'Leather', 3 );
inv.AddAnItem( 'Hardened leather', 14 );
inv.AddAnItem( 'Chitin scale', 8 );
inv.AddAnItem( 'Draconide leather', 5 );
inv.AddAnItem( 'Infused draconide leather', 0 );
inv.AddAnItem( 'Steel ingot', 5 );
inv.AddAnItem( 'Dark iron ore', 2 );
inv.AddAnItem( 'Dark iron ingot', 3 );
inv.AddAnItem( 'Dark iron plate', 1 );
inv.AddAnItem( 'Dark steel ingot', 10 );
inv.AddAnItem( 'Dark steel plate', 6 );
inv.AddAnItem( 'Silver ore', 2 );
inv.AddAnItem( 'Silver ingot', 6 );
inv.AddAnItem( 'Meteorite ore', 3 );
inv.AddAnItem( 'Meteorite ingot', 3 );
inv.AddAnItem( 'Meteorite plate', 2 );
inv.AddAnItem( 'Meteorite silver ingot', 6 );
inv.AddAnItem( 'Meteorite silver plate', 5 );
inv.AddAnItem( 'Orichalcum ingot', 0 );
inv.AddAnItem( 'Orichalcum plate', 1 );
inv.AddAnItem( 'Dwimeryte ingot', 6 );
inv.AddAnItem( 'Dwimeryte plate', 5 );
inv.AddAnItem( 'Dwimeryte enriched ingot', 0 );
inv.AddAnItem( 'Dwimeryte enriched plate', 0 );
inv.AddAnItem( 'Emerald dust', 0 );
inv.AddAnItem( 'Ruby dust', 4 );
inv.AddAnItem( 'Ruby', 2 );
inv.AddAnItem( 'Ruby flawless', 1 );
inv.AddAnItem( 'Sapphire dust', 0 );
inv.AddAnItem( 'Sapphire', 0 );
inv.AddAnItem( 'Monstrous brain', 8 );
inv.AddAnItem( 'Monstrous blood', 14 );
inv.AddAnItem( 'Monstrous bone', 9 );
inv.AddAnItem( 'Monstrous claw', 14 );
inv.AddAnItem( 'Monstrous dust', 9 );
inv.AddAnItem( 'Monstrous ear', 5 );
inv.AddAnItem( 'Monstrous egg', 1 );
inv.AddAnItem( 'Monstrous eye', 10 );
inv.AddAnItem( 'Monstrous essence', 7 );
inv.AddAnItem( 'Monstrous feather', 8 );
inv.AddAnItem( 'Monstrous hair', 12 );
inv.AddAnItem( 'Monstrous heart', 7 );
inv.AddAnItem( 'Monstrous hide', 4 );
inv.AddAnItem( 'Monstrous liver', 5 );
inv.AddAnItem( 'Monstrous plate', 1 );
inv.AddAnItem( 'Monstrous saliva', 6 );
inv.AddAnItem( 'Monstrous stomach', 3 );
inv.AddAnItem( 'Monstrous tongue', 5 );
inv.AddAnItem( 'Monstrous tooth', 9 );
inv.AddAnItem( 'Venom extract', 0 );
inv.AddAnItem( 'Siren vocal cords', 1 );


SelectQuickslotItem( EES_RangedWeapon );


FactsAdd( 'kill_base_tutorials' );


theGame.GetTutorialSystem().RemoveAllQueuedTutorials();


FactsAdd( 'standalone_ep2' );
FactsRemove( "StandAloneEP2" );

theGame.GetJournalManager().ForceUntrackingQuestForEP1Savegame();
}

//zur13
public function SSS_GetEquippedMutationType() : EPlayerMutationType
{
//return first equipped mutation
var equippedMutations : array< EPlayerMutationType >;
equippedMutations = GetEquippedMutationType();

if(equippedMutations.Size()>0)
{
return equippedMutations[0];
}
return EPMT_None;
}
}

exec function fuqfep1()
{
theGame.GetJournalManager().ForceUntrackingQuestForEP1Savegame();
}





function GetWitcherPlayer() : W3PlayerWitcher
{
return (W3PlayerWitcher)thePlayer;
}();>();>();>();>();>();>;>();>();>();>();>();>();>();>;>;>;>;>;>;>;>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>();>;>();>();>();>();>

[/spoiler] 

[spoiler]r4player:
statemachine abstract import class CR4Player extends CPlayer
{
// BEHAVIOR INITIALIZATION
protected var pcGamePlayInitialized : bool; // MS: hack variable to fix Tpose when initially spawning Geralt (Consult Tomsin)

// PC Controls
private var pcMode : bool; // MS: Use control/camera modifications for keyboard/mouse
default pcMode = true;

// COMBAT MECHANICS
protected saved var weaponHolster : WeaponHolster; // Makes Geralt holster and unholster the swords
public var rangedWeapon : Crossbow; // Handles ranged weapons
public var crossbowDontPopStateHack : bool; default crossbowDontPopStateHack = false;

private var hitReactTransScale : float; //dynamic scale for npc's hitreaction animation translation to force CloseCombat

private var bIsCombatActionAllowed : bool;
private var currentCombatAction : EBufferActionType;

private var uninterruptedHitsCount : int; //amount of uninterrupted hints performed by the player (gets reset when we get hit or stop attacking etc.)
private var uninterruptedHitsCameraStarted : bool; //set to true once we enable the uninterrupted hits camera effect
private var uninterruptedHitsCurrentCameraEffect : name; //currently used camera blurr effect for uninterrupted hits

private var counterTimestamps : array; //times when player pressed counter attack button - we check it later to prevent spamming

private var hitReactionEffect : bool; //blurr

private var lookAtPosition : Vector; //Position that Geralt is looking at, also where he will shoot
private var orientationTarget : EOrientationTarget;
private var customOrientationTarget : EOrientationTarget;
protected var customOrientationStack : array;

public var delayOrientationChange : bool;
protected var delayCameraOrientationChange : bool;
private var actionType : int; // 0 = sign, 1 = guard, 2 = specialAttack, 3 = throwItem
private var customOrientationStackIndex : int; //Used by Player only: will disable the previous combat action's orientation target and add to the stack everytime he performs a new combat action

private var emptyMoveTargetTimer : float;

private var onlyOneEnemyLeft : bool;

public var isInFinisher : bool;
private var finisherTarget : CGameplayEntity;

private var combatStance : EPlayerCombatStance;

public var approachAttack : int; //Enable/Disable approach attack prototype, 0 = enabled, 1 = disabled with no far attack limit, 2 = disabled with far attack limit
default approachAttack = 1;
protected var specialAttackCamera : bool;

private var specialAttackTimeRatio : float;

public saved var itemsPerLevel : array;
public var itemsPerLevelGiven : array;

private var playerTickTimerPhase : int;
default playerTickTimerPhase = 0;

protected var evadeHeading : float;

public var vehicleCbtMgrAiming : bool; //MS: hack variable to pass vehicleCbtMgr aiming variable to UseGenericVehicle

public var specialHeavyChargeDuration : float; //duration of charge-up event
public var specialHeavyStartEngineTime : EngineTime; //timestamp of when the charge-up started
public var playedSpecialAttackMissingResourceSound : bool; //if missing resource sound was played or not (used in loop)
public function SetPlayedSpecialAttackMissingResourceSound(b : bool) {playedSpecialAttackMissingResourceSound = b;}

public var counterCollisionGroupNames : array;

public saved var lastInstantKillTime : GameTime;

// Save locks
private var noSaveLockCombatActionName : string; default noSaveLockCombatActionName = 'combat_action';
private var noSaveLockCombatAction : int;
private var deathNoSaveLock : int;
private var noSaveLock : int;

//new game plus
protected saved var newGamePlusInitialized : bool;
default newGamePlusInitialized = false;

// action buffer
protected var BufferAllSteps : bool;
protected var BufferCombatAction : EBufferActionType;
protected var BufferButtonStage : EButtonStage;

default BufferAllSteps = false;
default customOrientationTarget = OT_None;
default hitReactionEffect = true;
default uninterruptedHitsCount = 0;
default uninterruptedHitsCameraStarted = false;
default customOrientationStackIndex = -1;

// CRITICAL STATES
private var keepRequestingCriticalAnimStart : bool; //set to true while we are trying to start critical anim

default keepRequestingCriticalAnimStart = false;

// EXPLORATION
private var currentCustomAction : EPlayerExplorationAction;
public var substateManager : CExplorationStateManager;
protected var isOnBoat : bool; //set to true if player is on boat (but not necessarily sailing, but e.g. standing)
protected var isInShallowWater : bool;
public var medallion : W3MedallionFX;
protected var lastMedallionEffect : float;
private var isInRunAnimation : bool;
public var interiorTracker :CPlayerInteriorTracker;
public var m_SettlementBlockCanter : int;

// FISTFIGHT MINIGAME
private var fistFightMinigameEnabled : bool;
private var isFFMinigameToTheDeath : bool;
private var FFMinigameEndsithBS : bool;
public var fistFightTeleportNode : CNode;
public var isStartingFistFightMinigame : bool;
public var GeraltMaxHealth : float;
public var fistsItems : array< SItemUniqueId >;

default FFMinigameEndsithBS = false;
default fistFightMinigameEnabled = false;
default isFFMinigameToTheDeath = false;

// GWINT MINIGAME
private var gwintAiDifficulty : EGwintDifficultyMode; default gwintAiDifficulty = EGDM_Easy;
private var gwintAiAggression : EGwintAggressionMode; default gwintAiAggression = EGAM_Defensive;
private var gwintMinigameState : EMinigameState; default gwintMinigameState = EMS_None;

// HORSE
import private var horseWithInventory : EntityHandle; // if spawned handle is valid ( horse with inventory )
private var currentlyMountedHorse : CNewNPC;
private var horseSummonTimeStamp : float;
private saved var isHorseRacing : bool;
private var horseCombatSlowMo : bool;
default isHorseRacing = false;
default horseCombatSlowMo = true;

// HUD FIXME - shouldn't this all be in hud / ui rather than player?
private var HudMessages : array ; //#B change to struct with message type, message duration etc
protected var fShowToLowStaminaIndication : float;
public var showTooLowAdrenaline : bool;
private var HAXE3Container : W3Container; //#B temp for E3
private var HAXE3bAutoLoot: bool; //#B temp for E3
private var bShowHud : bool;
private var dodgeFeedbackTarget : CActor;

default HAXE3bAutoLoot = false;
default fShowToLowStaminaIndication = 0.0f;
default bShowHud = true;

saved var displayedQuestsGUID : array< CGUID >; // #B moved here because saved in journal doesn't work.
saved var rewardsMultiplier : array< SRewardMultiplier >; // #B moved here because saved in journal doesn't work.s
saved var glossaryImageOverride : array< SGlossaryImageOverride >; // #B moved here because saved in journal doesn't work.s

// INPUT
private var prevRawLeftJoyRot : float;
protected var explorationInputContext : name;
protected var combatInputContext : name;
protected var combatFistsInputContext : name;

// INTERACTIONS
private var isInsideInteraction : bool; //set to true when player is inside any interaction range, used to prioritize input
private var isInsideHorseInteraction : bool;
public var horseInteractionSource : CEntity;
public var nearbyLockedContainersNoKey : array; //to update tooltip if player is close to a locked container and is THEN given a key

// MOVEMENT
private var bMoveTargetChangeAllowed : bool; default bMoveTargetChangeAllowed = true;
private var moveAdj : CMovementAdjustor;
private var defaultLocomotionController : CR4LocomotionPlayerControllerScript;
//private var isFollowing : bool;
//private var followingStartTime : float;
private var canFollowNpc : bool;
private var actorToFollow : CActor;
public var terrainPitch : float;
public var steepSlopeNormalPitch : float; default steepSlopeNormalPitch = 65.f;
public var disableSprintTerrainPitch : float; default disableSprintTerrainPitch = 54.f;
private var submergeDepth : float;

private var m_useSelectedItemIfSpawned : bool; default m_useSelectedItemIfSpawned = false; // Used only in WaitForItemSpawnAndProccesTask


var navQuery : CNavigationReachabilityQueryInterface;

// BARBER
public saved var rememberedCustomHead : name;

// EPISODE1
public saved var proudWalk : bool;
private var etherealCount : int;
default etherealCount = 0;

// PHANTOM WEAPON
private var phantomWeaponMgr : CPhantomWeaponManager;

/*public var bonePositionCam : Vector;

public function SetBonePositionCam( pos : Vector )
{
bonePositionCam = pos;
}*/

function EnablePCMode( flag : bool )
{
pcMode = flag;
}

public function IsPCModeEnabled() : bool
{
return pcMode && theInput.LastUsedPCInput();
}

public function ShouldUsePCModeTargeting() : bool
{
return IsPCModeEnabled() && !lastAxisInputIsMovement;
}

public function SetDodgeFeedbackTarget( target : CActor )
{
dodgeFeedbackTarget = target;
}

public function GetDodgeFeedbackTarget() : CActor
{
return dodgeFeedbackTarget;
}

public function SetSubmergeDepth( depth : float )
{
submergeDepth = depth;
}

public function GetSubmergeDepth() : float
{
return submergeDepth;
}

// ONELINERS
editable var delayBetweenIllusionOneliners : float;

hint delayBetweenIllusionOneliners = "delay in secs between oneliners about illusionary objects";

default delayBetweenIllusionOneliners = 5;

// Battlecry
private var battlecry_timeForNext : float;
private var battlecry_delayMin : float; default battlecry_delayMin = 15;
private var battlecry_delayMax : float; default battlecry_delayMax = 60;
private var battlecry_lastTry : name;

// Weather
private var previousWeather : name;
private var previousRainStrength : float;

//OTHER
protected var receivedDamageInCombat : bool; //set when you got hit
protected var prevDayNightIsNight : bool; //Day-Night cycle check - value of previous check
public var failedFundamentalsFirstAchievementCondition : bool; //achievement

private var spawnedTime : float;

public var currentMonsterHuntInvestigationArea : W3MonsterHuntInvestigationArea;

private var isPerformingPhaseChangeAnimation : bool; // flag for suppressing game camera update during synced animation in eredin fight
default isPerformingPhaseChangeAnimation = false;

default receivedDamageInCombat = false;

// PLAYER MODE
public var playerMode : W3PlayerMode;

// QUICKSLOTS
protected saved var selectedItemId : SItemUniqueId; //id of item selected from quickslots
protected saved var blockedRadialSlots : array < SRadialSlotDef >; // radial menu slots blocked by different sources

// SOFT LOCK TARGETING
public var enemyCollectionDist : float;
public var findMoveTargetDistMin : float; //distance from player to get softlocked targets
public var findMoveTargetDistMax : float; //distance from player that target gets disengaged from soft lock
private var findMoveTargetScaledFrame : float; //xaxis scale to find non-hostile targets when stationary
public var interactDist : float; //distance from player to attack or interact with a non-hostile npc
protected var bCanFindTarget : bool;
private var bIsConfirmingEmptyTarget : bool;
private var displayTarget : CGameplayEntity; //entity to show health bar on hud;
private var isShootingFriendly : bool;

default findMoveTargetDistMax = 18.f;
default findMoveTargetScaledFrame = 0.5f;
default interactDist = 3.5f;

//Target Selection
private var currentSelectedTarget : CActor;
private var selectedTargetToConfirm : CActor;
private var bConfirmTargetTimerIsEnabled : bool;

// THROWABLES
public saved var thrownEntityHandle : EntityHandle; //entity of currently thrown item (in aiming)
private var isThrowingItemWithAim : bool;
private saved var isThrowingItem : bool; //used for aim mode to check if we're in throwing logic
private var isThrowHoldPressed : bool;

// CROSSBOW
private var isAimingCrossbow : bool;

default isThrowingItemWithAim = false;

// AIMING MODE
public var playerAiming : PlayerAiming;

// DISMEMBERMENT
public var forceDismember : bool;
public var forceDismemberName : name;
public var forceDismemberChance : int;
public var forceDismemberExplosion : bool;

// FINISHER
private var finisherVictim : CActor;
public var forceFinisher : bool;
public var forceFinisherAnimName : name;
public var forceFinisherChance : int;
public var forcedStance : bool;

// WEAPON COLLISION FX
private var m_WeaponFXCollisionGroupNames : array ;
private var m_CollisionEffect : CEntity;
private var m_LastWeaponTipPos : Vector;
private var m_CollisionFxTemplate : CEntityTemplate;
private var m_RefreshWeaponFXType : bool;
private var m_PlayWoodenFX : bool;

// POSTERS
private var m_activePoster : W3Poster;

public function SetActivePoster ( poster : W3Poster )
{
m_activePoster = poster;
}

public function RemoveActivePoster ()
{
m_activePoster = NULL;
}

public function GetActivePoster () : W3Poster
{
return m_activePoster;
}
// SAVE / LOAD
//private saved var safePositionStored: bool; default safePositionStored = false;
//private saved var lastSafePosition : Vector;
//private saved var lastSafeRotation : EulerAngles;

public var horseOnNavMesh : bool;
default horseOnNavMesh = true;

public function SetHorseNav( val : bool ) { horseOnNavMesh = val; }

// TEST
public var testAdjustRequestedMovementDirection : bool; // TEST
default testAdjustRequestedMovementDirection = false;

// State
default autoState = 'Exploration';

///////////////////////////////////////////////////////////////////////////
/////////////////// IMPORTED C++ FUNCTIONS //////////////////////////////
///////////////////////////////////////////////////////////////////////////

// All following functions give cached data from previous frame
import final function GetEnemiesInRange( out enemies : array< CActor > );
import final function GetVisibleEnemies( out enemies : array< CActor > );
import final function IsEnemyVisible( enemy : CActor ) : bool;

// Set this up in order to use above functions and get the proper data
import final function SetupEnemiesCollection( range, heightTolerance : float,
maxEnemies : int,
optional tag : name,
optional flags : int ); // please combine EScriptQueryFlags - FLAG_ExcludePlayer is always on

import final function IsInInterior() : bool;
import final function IsInSettlement() : bool;
import final function EnterSettlement( isEntering : bool );
import final function ActionDirectControl( controller : CR4LocomotionDirectController ) : bool;
import final function SetPlayerTarget( target : CActor );
import final function SetPlayerCombatTarget( target : CActor );
import final function ObtainTicketFromCombatTarget( ticketName : CName, ticketsCount : int );
import final function FreeTicketAtCombatTarget();
import final function SetScriptMoveTarget( target : CActor );
import final function GetRiderData() : CAIStorageRiderData;
import final function SetIsInCombat( inCombat : bool );
import final function SaveLastMountedHorse( mountedHorse : CActor );

import final function SetBacklightFromHealth( healthPercentage : float );
import private final function SetBacklightColor( color : Vector );

import final function GetCombatDataComponent() : CCombatDataComponent;

import final function GetTemplatePathAndAppearance( out templatePath : string, out appearance : name );

import final function HACK_BoatDismountPositionCorrection( slotPos : Vector );

import final function HACK_ForceGetBonePosition( boneIndex : int ) : Vector;


public function GetLevel() : int
{
return 0;
}

///////////////////////////////////////////////////////////////////////////
// (new) targeting

var targeting : CR4PlayerTargeting;
var targetingPrecalcs : SR4PlayerTargetingPrecalcs;
var targetingIn : SR4PlayerTargetingIn;
var targetingOut : SR4PlayerTargetingOut;
var useNativeTargeting : bool;
default useNativeTargeting = true;

var visibleActors : array< CActor >;
var visibleActorsTime : array< float >;

///////////////////////////////////////////////////////////////////////////

event OnSpawned( spawnData : SEntitySpawnData )
{
var atts : array;
var skill : ESkill;
var i : int;
var item : SItemUniqueId;

AddAnimEventCallback('ThrowHoldTest', 'OnAnimEvent_ThrowHoldTest');
AddAnimEventCallback('OnWeaponDrawReady', 'OnAnimEvent_OnWeaponDrawReady');
AddAnimEventCallback('OnWeaponHolsterReady', 'OnAnimEvent_OnWeaponHolsterReady');
AddAnimEventCallback('AllowTempLookAt', 'OnAnimEvent_AllowTempLookAt');
AddAnimEventCallback('SlideToTarget', 'OnAnimEvent_SlideToTarget');
AddAnimEventCallback('PlayFinisherBlood', 'OnAnimEvent_PlayFinisherBlood');
AddAnimEventCallback('SlowMo', 'OnAnimEvent_SlowMo');
AddAnimEventCallback('BloodTrailForced', 'OnAnimEvent_BloodTrailForced');
AddAnimEventCallback('FadeOut', 'OnAnimEvent_FadeOut');
AddAnimEventCallback('FadeIn', 'OnAnimEvent_FadeIn');
AddAnimEventCallback('DisallowHitAnim', 'OnAnimEvent_DisallowHitAnim');
AddAnimEventCallback('AllowFall', 'OnAnimEvent_AllowFall');
AddAnimEventCallback('AllowFall2', 'OnAnimEvent_AllowFall2');
AddAnimEventCallback('DettachGround', 'OnAnimEvent_DettachGround');
AddAnimEventCallback('KillWithRagdoll', 'OnAnimEvent_KillWithRagdoll');
AddAnimEventCallback('pad_vibration', 'OnAnimEvent_pad_vibration');
AddAnimEventCallback('pad_vibration_light', 'OnAnimEvent_pad_vibration_light');
AddAnimEventCallback('RemoveBurning', 'OnAnimEvent_RemoveBurning');
AddAnimEventCallback('RemoveTangled', 'OnAnimEvent_RemoveTangled');

AddItemPerLevelList();

enemyCollectionDist = findMoveTargetDistMax;

//give items
if(!spawnData.restored && !((W3ReplacerCiri)this) )
{
AddTimer('GiveStartingItems', 0.00001, true, , , true);

if(!theGame.IsFinalBuild())
{
//unlock skills for testing purposes
AddAbility('GeraltSkills_Testing');
AddTimer('Debug_GiveTestingItems',0.0001,true);
}
}

InitTargeting();

// After load
if( spawnData.restored )
{
// ED this line was not called before, because of extra if conditions regarding "safe position stored" but it was uncommented
//OnUseSelectedItem();
}


// Create the sword holster (it is a saved property, there is no need of re-creating it when playing from save)
if ( !weaponHolster )
{
weaponHolster = new WeaponHolster in this;
}
// temp workaround of not saving states:
weaponHolster.Initialize( this, spawnData.restored );

if ( !interiorTracker )
{
interiorTracker = new CPlayerInteriorTracker in this;
}
interiorTracker.Init( spawnData.restored );


super.OnSpawned( spawnData );

// Create medallion
medallion = new W3MedallionFX in this;

playerMode = new W3PlayerMode in this;
playerMode.Initialize( this );

// Initialize Aiming Mode
playerAiming = new PlayerAiming in this;
playerAiming.Initialize( this );

// Initialize reachability query
navQuery = new CNavigationReachabilityQueryInterface in this;

// Start looking for soft-lock targets
EnableFindTarget( true );
AddTimer( 'CombatCheck', 0.2f, true );

// Get the exploration state manager component
substateManager = ( CExplorationStateManager ) GetComponentByClassName( 'CExplorationStateManager' );

findMoveTargetDist = findMoveTargetDistMax;

SetupEnemiesCollection( enemyCollectionDist, findMoveTargetDist, 10, 'None', FLAG_Attitude_Neutral + FLAG_Attitude_Hostile + FLAG_Attitude_Friendly + FLAG_OnlyAliveActors );

//for geralt-replacer switching
inputHandler.RemoveLocksOnSpawn();

// Player has the lowest push priority
((CActor) this ).SetInteractionPriority( IP_Prio_0 );

prevDayNightIsNight = theGame.envMgr.IsNight();
CheckDayNightCycle();

// Debug
EnableVisualDebug( SHOW_AI, true );

//oneliners delay
FactsRemove("blocked_illusion_oneliner");

SetFailedFundamentalsFirstAchievementCondition(false);
m_CollisionFxTemplate = (CEntityTemplate) LoadResource( 'sword_colision_fx' );
if( m_WeaponFXCollisionGroupNames.Size() == 0 )
{
m_WeaponFXCollisionGroupNames.PushBack('Static');
m_WeaponFXCollisionGroupNames.PushBack('Foliage');
m_WeaponFXCollisionGroupNames.PushBack('Fence');
m_WeaponFXCollisionGroupNames.PushBack('BoatSide');
m_WeaponFXCollisionGroupNames.PushBack('Door');
m_WeaponFXCollisionGroupNames.PushBack('RigidBody');
m_WeaponFXCollisionGroupNames.PushBack('Dynamic');
m_WeaponFXCollisionGroupNames.PushBack('Destructible');
}

if ( counterCollisionGroupNames.Size() == 0 )
{
counterCollisionGroupNames.PushBack('Static');
counterCollisionGroupNames.PushBack('Foliage');
counterCollisionGroupNames.PushBack('Fence');
counterCollisionGroupNames.PushBack('Terrain');
counterCollisionGroupNames.PushBack('Door');
counterCollisionGroupNames.PushBack('RigidBody');
counterCollisionGroupNames.PushBack('Dynamic');
counterCollisionGroupNames.PushBack('Destructible');
}

//ps4 pad backlight color
ResetPadBacklightColor();

if( spawnData.restored )
{
if (IsCurrentlyUsingItemL())
{
if (inv.HasItemById( currentlyEquipedItemL ))
{
OnUseSelectedItem();
}
else
{
HideUsableItem(true);
}
}
if ( GetCurrentMeleeWeaponType() == PW_Steel || GetCurrentMeleeWeaponType() == PW_Silver )
{
OnEquipMeleeWeapon(GetCurrentMeleeWeaponType(), true, true);
}

AddTimer( 'UnmountCrossbowTimer', 0.01, true );

ClearBlockedSlots();
}

((CR4PlayerStateSwimming)this.GetState('Swimming')).OnParentSpawned();

//hack for possible immortality from finishers
SetImmortalityMode( AIM_None, AIC_SyncedAnim );

//disable Dimeritium Bomb skill locks after load
theGame.GetDefinitionsManager().GetContainedAbilities('DwimeritiumBomb_3', atts);
for(i=0; i {
skill = SkillNameToEnum(atts[i]);
if(skill != S_SUndefined)
BlockSkill(skill, false);
}

// phantom weapon manager
this.GetInventory().GetItemEquippedOnSlot( EES_SteelSword, item );
if( this.GetInventory().ItemHasTag( item, 'PhantomWeapon' ) )
{
this.InitPhantomWeaponMgr();
}

//retoractive fix
if(FactsQuerySum("mq3036_fact_done") > 0)
BlockAllActions('mq3036', false);

spawnedTime = theGame.GetEngineTimeAsSeconds();

if ( theGame.GetInGameConfigWrapper().GetVarValue('Gameplay', 'EnableUberMovement' ) == "1" )
theGame.EnableUberMovement( true );
else
theGame.EnableUberMovement( false );

// Initial level for Gwint Difficulty (Normal)
if ( !FactsDoesExist("gwent_difficulty") )
FactsAdd("gwent_difficulty", 2);
}

public function GetTimeSinceSpawned() : float
{
return theGame.GetEngineTimeAsSeconds() - spawnedTime;
}

timer function UnmountCrossbowTimer( dt : float, id : int )
{
var itemId : SItemUniqueId;

itemId = this.inv.GetItemFromSlot( 'l_weapon' );
if ( inv.IsIdValid( itemId ) && inv.IsItemCrossbow( itemId ) )
{
rangedWeapon = (Crossbow)( inv.GetItemEntityUnsafe( itemId ) );

if (rangedWeapon)
{
rangedWeapon.Initialize( (CActor)( rangedWeapon.GetParentEntity() ) );
OnRangedForceHolster( true, true );
RemoveTimer( 'UnmountCrossbowTimer' );
}
}
else
RemoveTimer( 'UnmountCrossbowTimer' );
}

event OnDestroyed()
{
playerAiming.RemoveAimingSloMo();

if(rangedWeapon)
rangedWeapon.ClearDeployedEntity(true);

ResetPadBacklightColor();

//remove combat mode no-save lock
theGame.ReleaseNoSaveLock( noSaveLock );
}

/////////////////////////////////////////////////////////////////////
////////////////////////Radial Menu//////////////////////////////////
////////////////////////////////////////////////////////////////////

public function GetBlockedSlots () : array < SRadialSlotDef >
{
return blockedRadialSlots;
}

public function ClearBlockedSlots()
{
var i : int;
//var blockedSigns : array;
//var playerWitcher : W3PlayerWitcher;

for ( i = 0; i < blockedRadialSlots.Size(); i+=1 )
{
if( !IsSwimming() )
{
if ( EnableRadialSlot(blockedRadialSlots[i].slotName, 'swimming'))
{
i-=1;
continue;
}
}
if (!IsUsingVehicle())
{
if ( EnableRadialSlot(blockedRadialSlots[i].slotName, 'useVehicle'))
{
i-=1;
continue;
}
}
if ( !IsCurrentlyUsingItemL() || !IsUsableItemLBlocked() )
{
if ( EnableRadialSlot(blockedRadialSlots[i].slotName, 'usableItemL'))
{
i-=1;
continue;
}
}
if ( !IsThrowingItem() )
{
if ( EnableRadialSlot(blockedRadialSlots[i].slotName, 'throwBomb'))
{
i-=1;
continue;
}
}
}
// this is a hack that had to be added because someone ignored existing functionality of blocking radial slots propely and created BlockSignSelection. Unfortunately to keep the backwawrd compatibility I had to hack it.
/*playerWitcher = (W3PlayerWitcher)this;

if ( playerWitcher )
{
blockedSigns = playerWitcher.GetBlockedSigns();

i = 0;
for ( i = 0; i < blockedSigns.Size(); i+=1 )
{
switch( blockedSigns[i] )
{
case ST_Aard :
if ( !IsRadialSlotBlocked ( 'Aard') )
{
playerWitcher.BlockSignSelection(ST_Aard, false);
}
break;
case ST_Axii :
if ( !IsRadialSlotBlocked ( 'Axii') )
{
playerWitcher.BlockSignSelection(ST_Axii, false );
}
break;
case ST_Igni :
if ( !IsRadialSlotBlocked ( 'Igni') )
{
playerWitcher.BlockSignSelection(ST_Igni, false );
}
break;
case ST_Quen :
if ( !IsRadialSlotBlocked ( 'Quen') )
{
playerWitcher.BlockSignSelection(ST_Quen, false );
}
break;
case ST_Yrden :
if ( !IsRadialSlotBlocked ( 'Yrden') )
{
playerWitcher.BlockSignSelection(ST_Yrden, false );
}
break;
default:
break;
}
}
}*/

}

public function RestoreBlockedSlots ()
{
var i : int;
var slotsToBlock : array;

for ( i = 0; i < blockedRadialSlots.Size(); i+=1 )
{
slotsToBlock.PushBack ( blockedRadialSlots[i].slotName );
}
if ( slotsToBlock.Size() > 0 )
{
EnableRadialSlots ( false, slotsToBlock );
}
}
private function DisableRadialSlot ( slotName : name, sourceName : name ) : bool
{
var i : int;
var k : int;
var slotsToBlock : array;

var blockedRadialSlotEntry : SRadialSlotDef;

slotsToBlock.PushBack ( slotName );

for ( i = 0; i < blockedRadialSlots.Size(); i+=1 )
{
if ( blockedRadialSlots[i].slotName == slotName )
{
if ( sourceName != '' )
{
for ( k = 0; k < blockedRadialSlots[i].disabledBySources.Size(); k += 1 )
{
if ( blockedRadialSlots[i].disabledBySources[k] == sourceName )
{
return false;
}
}
blockedRadialSlots[i].disabledBySources.PushBack ( sourceName );
return false;
}

return false;
}
}

blockedRadialSlotEntry = InitBlockedRadialSlotEntry ( slotName );

if ( sourceName != '' )
{
blockedRadialSlotEntry.disabledBySources.PushBack ( sourceName );
}
blockedRadialSlots.PushBack ( blockedRadialSlotEntry );
EnableRadialSlots ( false, slotsToBlock );
return true;
}

public function EnableRadialSlot ( slotName : name, sourceName : name ) : bool
{
var i : int;
var k : int;

var slotsToBlock : array;

slotsToBlock.PushBack ( slotName );

for ( i = 0; i < blockedRadialSlots.Size(); i+=1 )
{
if ( blockedRadialSlots[i].slotName == slotName )
{

if ( sourceName != '' )
{
for ( k = 0; k < blockedRadialSlots[i].disabledBySources.Size(); k += 1 )
{
if ( blockedRadialSlots[i].disabledBySources[k] == sourceName )
{
blockedRadialSlots[i].disabledBySources.Remove ( blockedRadialSlots[i].disabledBySources[k] );
}
}
}
if ( blockedRadialSlots[i].disabledBySources.Size() <= 0 )
{
blockedRadialSlots.Remove( blockedRadialSlots[i] );
EnableRadialSlots ( true, slotsToBlock );
return true;
}
return false;
}
}
return false;

}

private function InitBlockedRadialSlotEntry ( slotName : name ) : SRadialSlotDef
{
var blockedRadialSlotEntry : SRadialSlotDef;

blockedRadialSlotEntry.slotName = slotName;

return blockedRadialSlotEntry;

}

public function EnableRadialSlotsWithSource ( enable : bool, slotsToBlock : array < name >, sourceName : name )
{
var i : int;

for ( i = 0; i < slotsToBlock.Size(); i+=1 )
{
if ( enable )
{
EnableRadialSlot ( slotsToBlock[i], sourceName );
}
else
{
DisableRadialSlot ( slotsToBlock[i], sourceName );
}
}
if ( blockedRadialSlots.Size() <= 0 )
{
blockedRadialSlots.Clear();
}
}

public function IsRadialSlotBlocked ( slotName : name ) : bool
{
var i : int;

for ( i = 0; i < blockedRadialSlots.Size(); i+=1 )
{
if ( blockedRadialSlots[i].slotName == slotName )
{
return true;
}
}
return false;
}


/////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
/////////////////////// @Reapir Kits ////////////////////////////////////
////////////////////////////////////////////////////////////////////
public function RepairItem ( rapairKitId : SItemUniqueId, usedOnItem : SItemUniqueId );
public function HasRepairAbleGearEquiped () : bool;
public function HasRepairAbleWaponEquiped () : bool;
public function IsItemRepairAble ( item : SItemUniqueId ) : bool;

/////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
/////////////////////// @OILS ////////////////////////////////////
////////////////////////////////////////////////////////////////////
public function ApplyOil( oilId : SItemUniqueId, usedOnItem : SItemUniqueId );
public function IsEquippedSwordUpgradedWithOil(steel : bool, optional oilName : name) : bool;
public function GetOilAppliedOnSword(steel : bool) : name;

public function CanApplyOilOnItem(oilId : SItemUniqueId, usedOnItem : SItemUniqueId) : bool
{
if(inv.ItemHasTag(oilId, theGame.params.TAG_STEEL_OIL) && inv.IsItemSteelSwordUsableByPlayer(usedOnItem))
return true;

if(inv.ItemHasTag(oilId, theGame.params.TAG_SILVER_OIL) && inv.IsItemSilverSwordUsableByPlayer(usedOnItem))
return true;

return false;
}
////////////////////////////////////////////////////////////////////

public final function DidFailFundamentalsFirstAchievementCondition() : bool
{
return failedFundamentalsFirstAchievementCondition;
}

public final function SetFailedFundamentalsFirstAchievementCondition(b : bool)
{
var i : int;
var npc : CNewNPC;

failedFundamentalsFirstAchievementCondition = b;

//save info in enemy since we might run away from combat and return, triggering new combat encounter
if(failedFundamentalsFirstAchievementCondition)
{
for(i=0; i {
if(hostileEnemies[i].HasTag(theGame.params.MONSTER_HUNT_ACTOR_TAG))
{
npc = (CNewNPC)hostileEnemies[i];
npc.AddTag('failedFundamentalsAchievement');
npc.AddTimer('FundamentalsAchFailTimer', 30*60, , , , true, true);
}
}
}
}

public function IsInCombatFist() : bool
{
return this.GetCurrentStateName() == 'CombatFists';
}

public function IsInitialized() : bool;

public function IsCiri() : bool
{
return ((W3ReplacerCiri)this);
}

protected function WouldLikeToMove() : bool
{
var speedVec : Vector;
var speed, speedMult : float;

// Get speed from input
speedVec.X = theInput.GetActionValue( 'GI_AxisLeftX' ); //player.mainInput.aLeftJoyX;
speedVec.Y = theInput.GetActionValue( 'GI_AxisLeftY' );//player.mainInput.aLeftJoyY;
speed = VecLength2D( speedVec );

return speed > 0.1f;
}

function HandleMovement( deltaTime : float )
{
// just to see if player would like to move if there would be possibility
// example of use: movement is blocked when in critical state, but it can end earlier only if it would be desired by player
// and this is nothing but desire to move
// note: for some reason, when doing WouldLikeToMove()? 1.0f : 0.0f it just doesn't care and gives 0.0f
if (WouldLikeToMove())
SetBehaviorVariable( 'playerWouldLikeToMove', 1.0f);
else
SetBehaviorVariable( 'playerWouldLikeToMove', 0.0f);

super.HandleMovement( deltaTime );
}

function BattleCryIsReady( ) : bool
{
var l_currentTime : float;

l_currentTime = theGame.GetEngineTimeAsSeconds();

if( l_currentTime >= battlecry_timeForNext )
{
return true;
}
return false;
}

function PlayBattleCry( _BattleCry : name , _Chance : float, optional _IgnoreDelay, ignoreRepeatCheck : bool )
{
var l_randValue : float;
var fact : int;

fact = FactsQuerySum("force_stance_normal");

if( IsSwimming()
|| theGame.IsDialogOrCutscenePlaying()
|| IsInNonGameplayCutscene()
|| IsInGameplayScene()
|| theGame.IsCurrentlyPlayingNonGameplayScene()
|| theGame.IsFading()
|| theGame.IsBlackscreen()
|| FactsQuerySum("force_stance_normal") > 0 )
{
return;
}

// To avoid calling too often the same type of battle cry
if ( !ignoreRepeatCheck )
{
if( battlecry_lastTry == _BattleCry )
return;
}

battlecry_lastTry = _BattleCry;

l_randValue = RandF();

// Either use delay or chance
if( l_randValue < _Chance && ( _IgnoreDelay || BattleCryIsReady() ) )
{
thePlayer.PlayVoiceset( 90, _BattleCry );
// Restart counter
battlecry_timeForNext = theGame.GetEngineTimeAsSeconds() + RandRangeF( battlecry_delayMax, battlecry_delayMin );
}

}

public final function OnWeatherChanged()
{
if( IsInInterior()
|| GetCurrentStateName() != 'Exploration'
|| theGame.IsDialogOrCutscenePlaying()
|| IsInNonGameplayCutscene()
|| IsInGameplayScene()
|| theGame.IsCurrentlyPlayingNonGameplayScene()
|| theGame.IsFading()
|| theGame.IsBlackscreen()
|| GetTimeSinceSpawned() < 60 )
{
return;
}

AddTimer( 'CommentOnWeather', 1 );
}

public final timer function CommentOnWeather( _Delta : float, _Id : int )
{
var l_weather : name;
var l_currentArea : EAreaName;
var l_rand : float;

l_weather = GetWeatherConditionName();

l_currentArea = theGame.GetCommonMapManager().GetCurrentArea();

switch ( l_weather )
{
case 'WT_Clear':

l_rand = RandF();

if( l_rand > 0.66f && !AreaIsCold() && theGame.envMgr.IsDay() )
{
thePlayer.PlayVoiceset( 90, 'WeatherHot' );
}
else if ( l_rand > 0.33f )
{
thePlayer.PlayVoiceset( 90, 'WeatherClearingUp' );
}
break;

case 'WT_Rain_Storm':
thePlayer.PlayVoiceset( 90, 'WeatherStormy' );
break;

case 'WT_Light_Clouds':
if( previousRainStrength < GetRainStrength() )
{
thePlayer.PlayVoiceset( 90, 'WeatherLooksLikeRain' );
}
else if( AreaIsCold() && previousWeather == 'WT_Clear' )
{
thePlayer.PlayVoiceset( 90, 'WeatherCold' );
}
break;

case 'WT_Mid_Clouds':
if( previousRainStrength < GetRainStrength() )
{
thePlayer.PlayVoiceset( 90, 'WeatherRaining' );
}
else if( AreaIsCold() && previousWeather == 'WT_Clear' )
{
thePlayer.PlayVoiceset( 90, 'WeatherCold' );
}
break;

case 'WT_Mid_Clouds_Dark':
if( previousWeather != 'WT_Heavy_Clouds' && previousWeather != 'WT_Heavy_Clouds_Dark' )
thePlayer.PlayVoiceset( 90, 'WeatherWindy' );
break;

case 'WT_Heavy_Clouds':
if( previousWeather != 'WT_Mid_Clouds_Dark' && previousWeather != 'WT_Heavy_Clouds_Dark' )
thePlayer.PlayVoiceset( 90, 'WeatherWindy' );
break;

case 'WT_Heavy_Clouds_Dark':
if( thePlayer.IsOnBoat() )
{
thePlayer.PlayVoiceset( 90, 'WeatherSeaWillStorm' );
}
else if( previousRainStrength < GetRainStrength() )
{
thePlayer.PlayVoiceset( 90, 'WeatherLooksLikeRain' );
}
else
{
thePlayer.PlayVoiceset( 90, 'WeatherWindy' );
}
break;

case 'WT_Snow':
if( RandF() > 0.5f )
thePlayer.PlayVoiceset( 90, 'WeatherSnowy' );
else
thePlayer.PlayVoiceset( 90, 'WeatherCold' );
break;
}

previousRainStrength = GetRainStrength();
previousWeather = l_weather;
}

function CanUpdateMovement() : bool
{
if ( rangedWeapon
&& GetBehaviorVariable( 'fullBodyAnimWeight' ) >= 1.f
&& rangedWeapon.GetCurrentStateName() != 'State_WeaponWait' )
return false;

return true;
}

public function SetDefaultLocomotionController()
{
if( !defaultLocomotionController )
{
defaultLocomotionController = new CR4LocomotionPlayerControllerScript in this;
}

ActionDirectControl( defaultLocomotionController );
}

event OnPlayerTickTimer( deltaTime : float )
{
var focusModeController : CFocusModeController;
var cnt : int;

super.OnPlayerTickTimer( deltaTime );

HandleMovement( deltaTime );

if ( playerAiming.GetCurrentStateName() == 'Aiming' )
{
FindTarget();
FindNonActorTarget( false );
UpdateDisplayTarget();
UpdateLookAtTarget();
}
else
{
if( playerTickTimerPhase == 0 )
{
FindTarget();
}
else if( playerTickTimerPhase == 1 )
{
FindNonActorTarget( false );
}
else if ( playerTickTimerPhase == 2 )
{
UpdateDisplayTarget();
UpdateLookAtTarget();
}
}

//CombatModeDebug();

playerTickTimerPhase = ( playerTickTimerPhase + 1 ) % 3;

focusModeController = theGame.GetFocusModeController();
focusModeController.UpdateFocusInteractions( deltaTime );

//some behavior hack for critical states, moved from effectsManager.PerformUpdate() since it does not tick continuously anymore
cnt = (int)( effectManager.GetCriticalBuffsCount() > 0 );
SetBehaviorVariable('hasCriticalBuff', cnt);
}

event OnDeath( damageAction : W3DamageAction )
{
super.OnDeath( damageAction );

RemoveTimer('RequestCriticalAnimStart');
//theInput.SetContext('Death');
EnableFindTarget( false );
BlockAllActions('Death', true);

EnableHardLock( false );

theGame.CreateNoSaveLock( 'player_death', deathNoSaveLock, false, false );
theGame.SetDeathSaveLockId( deathNoSaveLock );

ClearHostileEnemiesList();
RemoveReactions();
SetPlayerCombatTarget(NULL);
OnEnableAimingMode( false );
}

// Called when the actor gets out of unconscious state
function OnRevived()
{
super.OnRevived();
BlockAllActions('Death', false);

theGame.ReleaseNoSaveLock(deathNoSaveLock);

this.RestartReactionsIfNeeded();
}

public function CanStartTalk() : bool
{
if ( beingWarnedBy.Size() > 0 )
return false;

return super.CanStartTalk();
}

///////////////////////////////////////////////////////////////////////////
// @Counters
///////////////////////////////////////////////////////////////////////////

//caches timestamp of counter use (button press)
public function AddCounterTimeStamp(time : EngineTime) {counterTimestamps.PushBack(time);}

/*
This function checks if we have performed a counter
It checks timestamps of moments when we pressed the parry/counter button in order
to determine if the player was spamming the button. If so then this is not a counter.

Returns true if the counter is valid
*/
public function CheckCounterSpamming(attacker : CActor) : bool
{
var counterWindowStartTime : EngineTime; //the time when the counter window (in anim) started
var i, spamCounter : int;
var reflexAction : bool;
var testEngineTime : EngineTime;

if(!attacker)
return false;

counterWindowStartTime = ((CNewNPC)attacker).GetCounterWindowStartTime();
spamCounter = 0;
reflexAction = false;

//if counterWindowStartTime was never set return false - PF
if ( counterWindowStartTime == testEngineTime )
{
return false;
}

for(i = counterTimestamps.Size() - 1; i>=0; i-=1)
{
//log number of button presses since 0.4 seconds before the counter timewindow
if(counterTimestamps[i] >= (counterWindowStartTime - EngineTimeFromFloat(0.4)) )
{
//spamCounter += 1; Original Code - Legendary Counter modded this line
spamCounter = 1;
}
//and at the same time remove all outdated data on the fly
else
{
counterTimestamps.Remove(counterTimestamps[i]);
continue;
}

//set info that we have a potential parry if this press was after the counter timewindow started
if(!reflexAction && (counterTimestamps[i] >= counterWindowStartTime))
reflexAction = true;
}

/*
If reflexAction is set then we have at least 1 button press within the counter timewindow.

//if(spamCounter == 1 && reflexAction) Original Code - Legendary Counter modded this line
if(spamCounter == 1 || reflexAction)
1 means exactly one button press - a potential counter (if reflexAction is set as well)
>1 means spamming
*/
if(spamCounter == 1 && reflexAction)
return true;

return false;
}

protected function PerformCounterCheck(parryInfo: SParryInfo) : bool
{
var mult : float;
var parryType : EParryType;
var validCounter, useKnockdown : bool;
var slideDistance, duration : float;
var playerToTargetRot : EulerAngles;
var zDifference : float;
var effectType : EEffectType;
var repelType : EPlayerRepelType = PRT_Random;
var params : SCustomEffectParams;
var thisPos, attackerPos : Vector;
var fistFightCheck : bool;
var fistFightCounter : bool;
var attackerInventory : CInventoryComponent;
var weaponId : SItemUniqueId;
var weaponTags : array;
var playerToAttackerVector : Vector;
var tracePosStart : Vector;
var tracePosEnd : Vector;
var hitPos : Vector;
var hitNormal : Vector;

if(ShouldProcessTutorial('TutorialDodge') || ShouldProcessTutorial('TutorialCounter'))
{
theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_TutorialFight) );
FactsRemove("tut_fight_slomo_ON");
}

if ( !parryInfo.canBeParried || parryInfo.attacker.HasAbility( 'CannotBeCountered' ) )
return false;

fistFightCheck = FistFightCheck( parryInfo.target, parryInfo.attacker, fistFightCounter );

if( ParryCounterCheck() && parryInfo.targetToAttackerAngleAbs < theGame.params.PARRY_HALF_ANGLE && fistFightCheck )
{
//check if this is a valid counter
validCounter = CheckCounterSpamming(parryInfo.attacker);

if(validCounter)
{
if ( IsInCombatActionFriendly() )
RaiseEvent('CombatActionFriendlyEnd');

SetBehaviorVariable( 'parryType', ChooseParryTypeIndex( parryInfo ) );
SetBehaviorVariable( 'counter', (float)validCounter); //1/true when the parry is a counter/reflex_parry

//PPPP counter success sound
//SoundEvent("global_machines_lift_wood1_mechanism_stop" );
SetBehaviorVariable( 'parryType', ChooseParryTypeIndex( parryInfo ) );
SetBehaviorVariable( 'counter', (float)validCounter); //1/true when the parry is a counter/reflex_parry
this.SetBehaviorVariable( 'combatActionType', (int)CAT_Parry );


if ( !fistFightCounter )
{
attackerInventory = parryInfo.attacker.GetInventory();
weaponId = attackerInventory.GetItemFromSlot('r_weapon');
attackerInventory.GetItemTags( weaponId , weaponTags );

/*if( parryInfo.attacker.HasTag( 'olgierd_gpl' ) && parryInfo.attackActionName == 'attack_heavy' )
{
//DealCounterDamageToOlgierd();
GetTarget().AddAbility( 'HitCounterEnabled', false );
GetTarget().AddTimer( 'DisableHitCounterAfter', 3.0 );
}*/

//don't look at me like that. It is NOT a hack... follow the white rabbit...
if ( parryInfo.attacker.HasAbility('mon_gravehag') )
{
repelType = PRT_Slash;
parryInfo.attacker.AddEffectDefault(EET_CounterStrikeHit, this, 'ReflexParryPerformed');
//parryInfo.attacker.RemoveAbility('TongueAttack');
}
else if ( (CNewNPC)parryInfo.attacker && !((CNewNPC)parryInfo.attacker).IsHuman() )
{
repelType = PRT_SideStepSlash;
}
else if ( weaponTags.Contains('spear2h') )
{
repelType = PRT_SideStepSlash;
parryInfo.attacker.AddEffectDefault(EET_CounterStrikeHit, this, "ReflexParryPerformed");
parryInfo.attacker.SignalGameplayEvent( 'SpearDestruction');
}
else
{
//-----pitch check------
thisPos = this.GetWorldPosition();
attackerPos = parryInfo.attacker.GetWorldPosition();
playerToTargetRot = VecToRotation( thisPos - attackerPos );
zDifference = thisPos.Z - attackerPos.Z;

if ( playerToTargetRot.Pitch < -5.f && zDifference > 0.35 )
{
repelType = PRT_Kick;
//Pass attacker to the timer so that he ragdolls after a delay
ragdollTarget = parryInfo.attacker;
AddTimer( 'ApplyCounterRagdollTimer', 0.3 );
}
else
{
useKnockdown = false;
if ( CanUseSkill(S_Sword_s11) )
{
if( GetSkillLevel(S_Sword_s11) > 1 && RandF() < GetWitcherPlayer().GetStat(BCS_Focus) )//CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s11, 'chance', false, true)) )
{
duration = CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s11, 'duration', false, true));
useKnockdown = true;
}
}
else if ( parryInfo.attacker.IsHuman() )
{
//Apply knockdown if npc is countered on ledge
tracePosStart = parryInfo.attacker.GetWorldPosition();
tracePosStart.Z += 1.f;
playerToAttackerVector = VecNormalize( parryInfo.attacker.GetWorldPosition() - parryInfo.target.GetWorldPosition() );
tracePosEnd = ( playerToAttackerVector * 0.75f ) + ( playerToAttackerVector * parryInfo.attacker.GetRadius() ) + parryInfo.attacker.GetWorldPosition();
tracePosEnd.Z += 1.f;

if ( !theGame.GetWorld().StaticTrace( tracePosStart, tracePosEnd, hitPos, hitNormal, counterCollisionGroupNames ) )
{
tracePosStart = tracePosEnd;
tracePosEnd -= 3.f;

if ( !theGame.GetWorld().StaticTrace( tracePosStart, tracePosEnd, hitPos, hitNormal, counterCollisionGroupNames ) )
useKnockdown = true;
}
}

if(useKnockdown && (!parryInfo.attacker.IsImmuneToBuff(EET_HeavyKnockdown) || !parryInfo.attacker.IsImmuneToBuff(EET_Knockdown)))
{
if(!parryInfo.attacker.IsImmuneToBuff(EET_HeavyKnockdown))
{
params.effectType = EET_HeavyKnockdown;
}
else
{
params.effectType = EET_Knockdown;
}

repelType = PRT_Kick;
params.creator = this;
params.sourceName = "ReflexParryPerformed";
params.duration = duration;

parryInfo.attacker.AddEffectCustom(params);
}
else
{
parryInfo.attacker.AddEffectDefault(EET_CounterStrikeHit, this, "ReflexParryPerformed");
}
}
}

parryInfo.attacker.GetInventory().PlayItemEffect(parryInfo.attackerWeaponId, 'counterattack');

//by default repelType is PRT_Random
if ( repelType == PRT_Random )
if ( RandRange(100) > 50 )
repelType = PRT_Bash;
else
repelType = PRT_Kick;

this.SetBehaviorVariable( 'repelType', (int)repelType );
parryInfo.attacker.SetBehaviorVariable( 'repelType', (int)repelType );
}
else
{
parryInfo.attacker.AddEffectDefault(EET_CounterStrikeHit, this, "ReflexParryPerformed");
}

//SetCustomOrientationTargetForCombatActions( OT_None );
SetParryTarget ( parryInfo.attacker );
SetSlideTarget( parryInfo.attacker );
if ( !IsActorLockedToTarget() )
SetMoveTarget( parryInfo.attacker );

if ( RaiseForceEvent( 'PerformCounter' ) )
OnCombatActionStart();

SetCustomRotation( 'Counter', VecHeading( parryInfo.attacker.GetWorldPosition() - this.GetWorldPosition() ), 0.0f, 0.2f, false );
AddTimer( 'UpdateCounterRotation', 0.4f, true );
AddTimer( 'SetCounterRotation', 0.2f );

IncreaseUninterruptedHitsCount(); //counters also count as uninterrupted hits

//drain stamina
if(IsHeavyAttack(parryInfo.attackActionName))
mult = theGame.params.HEAVY_STRIKE_COST_MULTIPLIER;

DrainStamina(ESAT_Counterattack, 0, 0, '', 0, mult);

theGame.GetGamerProfile().IncStat(ES_CounterattackChain);

}
else
{
ResetUninterruptedHitsCount();
}
return validCounter;
}

return false;
}

timer function UpdateCounterRotation( dt : float, id : int )
{
UpdateCustomRotationHeading( 'Counter', VecHeading( parryTarget.GetWorldPosition() - this.GetWorldPosition() ) );
}

timer function SetCounterRotation( dt : float, id : int )
{
SetCustomRotation( 'Counter', VecHeading( parryTarget.GetWorldPosition() - this.GetWorldPosition() ), 360.f, 0.2f, false );
}

private var parryTarget : CActor;
private function SetParryTarget( t : CActor )
{
parryTarget = t;
}

private var ragdollTarget : CActor;
timer function ApplyCounterRagdollTimer( time : float , id : int)
{
var actor : CActor;

actor = (CActor)ragdollTarget;

if(actor)
{
actor.AddEffectDefault(EET_HeavyKnockdown, this, 'ReflexParryPerformed');
}
}

///////////////////////////////////////////////////////////////////////////
// Player Mode

public function EnableMode( mode : EPlayerMode, enable : bool )
{
playerMode.EnableMode( mode, enable );
}

public function GetPlayerMode() : W3PlayerMode
{
return playerMode;
}

private function GetClosestIncomingAttacker() : CActor
{
var i, size : int;
var attackerToPlayerDistances : array< float >;
var closestAttackerIndex : int;
var incomingAttackers : array;

//incomingAttackers = this.combatManager.SendTicketOwners( CTT_Attack );
if(playerMode && playerMode.combatDataComponent)
{
if ( incomingAttackers.Size() <= 0 )
this.playerMode.combatDataComponent.GetTicketSourceOwners( incomingAttackers, 'TICKET_Charge' );

if ( incomingAttackers.Size() <= 0 )
this.playerMode.combatDataComponent.GetTicketSourceOwners( incomingAttackers, 'TICKET_Melee' );

if ( incomingAttackers.Size() <= 0 )
this.playerMode.combatDataComponent.GetTicketSourceOwners( incomingAttackers, 'TICKET_Range' );
}

size = incomingAttackers.Size();
attackerToPlayerDistances.Resize( size );

if ( size > 0 )
{
for ( i = incomingAttackers.Size()-1; i >= 0; i -= 1)
{
if ( !IsEnemyVisible( incomingAttackers[i] ) )
{
incomingAttackers.EraseFast( i );
}
}
}

if ( size > 0 )
{
for ( i = 0; i < size; i += 1 )
{
attackerToPlayerDistances[i] = VecDistance( incomingAttackers[i].GetWorldPosition(), this.GetWorldPosition() );
}
closestAttackerIndex = ArrayFindMinF( attackerToPlayerDistances );
return incomingAttackers[ closestAttackerIndex ];
}
else
{
return NULL;
}
}

// Combat Timer
timer function CombatCheck( time : float , id : int)
{
var i : int;
var strLevel, temp : string;
var enemies : array;

UpdateFinishableEnemyList();
FindMoveTarget();
playerMode.UpdateCombatMode();

if( GetPlayerCombatStance() == PCS_Guarded )
{
if( GetTarget().GetHealthPercents() > 0.25f )
{
PlayBattleCry( 'BattleCryTaunt', 0.2f );
}
else
{
if( GetTarget().IsHuman() )
PlayBattleCry( 'BattleCryHumansEnd', 0.3f );
else
PlayBattleCry( 'BattleCryMonstersEnd', 0.3f );
}
}

if(IsThreatened() && ShouldProcessTutorial('TutorialMonsterThreatLevels') && FactsQuerySum("q001_nightmare_ended") > 0)
{
GetEnemiesInRange(enemies);
for(i=0; i {
strLevel = ((CNewNPC)enemies[i]).GetExperienceDifferenceLevelName(temp);
if(strLevel == "deadlyLevel" || strLevel == "highLevel")
{
FactsAdd("tut_high_threat_monster");
break;
}
}
}
}

public function ReceivedDamageInCombat() : bool
{
return receivedDamageInCombat;
}

//called when combat starts
event OnCombatStart()
{
var weaponType : EPlayerWeapon;

theGame.CreateNoSaveLock( 'combat', noSaveLock );

//cerberus achievement
FactsRemove("statistics_cerberus_sign");
FactsRemove("statistics_cerberus_petard");
FactsRemove("statistics_cerberus_bolt");
FactsRemove("statistics_cerberus_fists");
FactsRemove("statistics_cerberus_melee");
FactsRemove("statistics_cerberus_environment");

BlockAction(EIAB_OpenMeditation, 'InCombat');
BlockAction(EIAB_HighlightObjective, 'InCombat');

if ( !this.IsUsingBoat() && GetTarget().GetAttitude(this) == AIA_Hostile )
{
weaponType = GetMostConvenientMeleeWeapon( GetTarget() );

if ( weaponType == PW_Steel || weaponType == PW_Silver )
this.OnEquipMeleeWeapon( weaponType, false );
}
}

//called when combat finishes
event OnCombatFinished()
{
var cnt : int;

reevaluateCurrentWeapon = false;

thePlayer.HardLockToTarget( false );

receivedDamageInCombat = false;

//cerberus achievement
cnt = 0;
if(FactsQuerySum("statistics_cerberus_sign") > 0)
cnt += 1;
if(FactsQuerySum("statistics_cerberus_petard") > 0)
cnt += 1;
if(FactsQuerySum("statistics_cerberus_bolt") > 0)
cnt += 1;
if(FactsQuerySum("statistics_cerberus_fists") > 0)
cnt += 1;
if(FactsQuerySum("statistics_cerberus_melee") > 0)
cnt += 1;
if(FactsQuerySum("statistics_cerberus_environment") > 0)
cnt += 1;

//failsafe
FactsRemove("statistics_cerberus_sign");
FactsRemove("statistics_cerberus_petard");
FactsRemove("statistics_cerberus_bolt");
FactsRemove("statistics_cerberus_fists");
FactsRemove("statistics_cerberus_melee");
FactsRemove("statistics_cerberus_environment");

if(cnt >= 3)
theGame.GetGamerProfile().AddAchievement(EA_Cerberus);
//end of cerberus

if(theGame.GetTutorialSystem() && FactsQuerySum("TutorialShowSilver") > 0)
{
FactsAdd("tut_show_silver_sword", 1);
FactsRemove("TutorialShowSilver");
}
this.SetBehaviorVariable('isInCombatForOverlay',0.f);
GoToExplorationIfNeeded();
theGame.ReleaseNoSaveLock( noSaveLock );
LogChannel( 'OnCombatFinished', "OnCombatFinished: ReleaseNoSaveLock" );

SetFailedFundamentalsFirstAchievementCondition(false);

UnblockAction(EIAB_OpenMeditation, 'InCombat');
UnblockAction(EIAB_HighlightObjective, 'InCombat');
}

event OnReactToBeingHit( damageAction : W3DamageAction )
{
var weaponType : EPlayerWeapon;

super.OnReactToBeingHit(damageAction);

if ( IsInCombat() && damageAction.attacker && damageAction.attacker == GetTarget() && !( this.IsUsingVehicle() && this.IsOnBoat() ) )
{
weaponType = GetMostConvenientMeleeWeapon( GetTarget() );
if ( weaponType != PW_Fists && weaponType != PW_None && weaponType != this.GetCurrentMeleeWeaponType() )
OnEquipMeleeWeapon( weaponType, false );
}
}

//called when player receives damage in combat(except for toxicity)
public function ReceivedCombatDamage()
{
receivedDamageInCombat = true;
}

///////////////////////////////////////////////////////////////////////////
// @Uninterrupted hits
///////////////////////////////////////////////////////////////////////////


timer function UninterruptedHitsResetOnIdle(dt : float, id : int)
{
ResetUninterruptedHitsCount();
}

public function ResetUninterruptedHitsCount()
{
uninterruptedHitsCount = 0;
LogUnitAtt("Uninterrupted attacks reset!!!!");
}

public function IncreaseUninterruptedHitsCount()
{
uninterruptedHitsCount += 1;
LogUnitAtt("Uninterrupted attacks count increased to " + uninterruptedHitsCount);

if(uninterruptedHitsCount == 4)
AddTimer('StartUninterruptedBlurr', 1, false);

//idle turn off timer
AddTimer('UninterruptedHitsResetOnIdle', 4.f, false);
}

timer function StartUninterruptedBlurr(dt : float, id : int)
{
var changed : bool;
var movingAgent : CMovingPhysicalAgentComponent;
var target : CActor;

//check if the timer is to be turned off
if(uninterruptedHitsCount < 4)
{
LogUnitAtt("Stopping camera effect");
thePlayer.StopEffect(uninterruptedHitsCurrentCameraEffect);
uninterruptedHitsCurrentCameraEffect = '';
uninterruptedHitsCameraStarted = false;
RemoveTimer('StartUninterruptedBlurr');
}
else //still valid
{
target = GetTarget();

if( target )
{
movingAgent = ( (CMovingPhysicalAgentComponent) (target.GetMovingAgentComponent()) );
}

if(!uninterruptedHitsCameraStarted)
{
LogUnitAtt("Starting camera effect");
AddTimer('StartUninterruptedBlurr', 0.001, true); //need to update per tick
if(movingAgent && movingAgent.GetCapsuleHeight() > 2)
uninterruptedHitsCurrentCameraEffect = theGame.params.UNINTERRUPTED_HITS_CAMERA_EFFECT_BIG_ENEMY;
else
uninterruptedHitsCurrentCameraEffect = theGame.params.UNINTERRUPTED_HITS_CAMERA_EFFECT_REGULAR_ENEMY;
thePlayer.PlayEffect(uninterruptedHitsCurrentCameraEffect);
uninterruptedHitsCameraStarted = true;
}
else
{
changed = false;
if(movingAgent && movingAgent.GetCapsuleHeight() > 2 && uninterruptedHitsCurrentCameraEffect != theGame.params.UNINTERRUPTED_HITS_CAMERA_EFFECT_BIG_ENEMY)
changed = true;
else if(!movingAgent || ( movingAgent.GetCapsuleHeight() <= 2 && uninterruptedHitsCurrentCameraEffect != theGame.params.UNINTERRUPTED_HITS_CAMERA_EFFECT_REGULAR_ENEMY) )
changed = true;

//if the target's height has changed then swap the camera effect
if(changed)
{
//stop current effect
thePlayer.StopEffect(uninterruptedHitsCurrentCameraEffect);

//change mode
if(uninterruptedHitsCurrentCameraEffect == theGame.params.UNINTERRUPTED_HITS_CAMERA_EFFECT_BIG_ENEMY)
uninterruptedHitsCurrentCameraEffect = theGame.params.UNINTERRUPTED_HITS_CAMERA_EFFECT_REGULAR_ENEMY;
else
uninterruptedHitsCurrentCameraEffect = theGame.params.UNINTERRUPTED_HITS_CAMERA_EFFECT_BIG_ENEMY;

//turn new camera effect on
thePlayer.PlayEffect(uninterruptedHitsCurrentCameraEffect);
}
}
}
}

///////////////////////////////////////////////////////////////////////////
// Exploration Actions
///////////////////////////////////////////////////////////////////////////

private var playerActionEventListeners : array;
private var playerActionEventBlockingListeners : array;

private function PlayerActionBlockGameplayActions( sourceName : name, lock : bool, isFromPlace : bool )
{
if ( lock )
{
thePlayer.BlockAction( EIAB_Signs, sourceName, false, false, isFromPlace );
thePlayer.BlockAction( EIAB_DrawWeapon, sourceName, false, false, isFromPlace );
thePlayer.BlockAction( EIAB_CallHorse, sourceName, false, false, isFromPlace );
thePlayer.BlockAction( EIAB_FastTravel, sourceName, false, false, isFromPlace );
thePlayer.BlockAction( EIAB_Fists, sourceName, false, false, isFromPlace );
thePlayer.BlockAction( EIAB_InteractionAction, sourceName, false, false, isFromPlace );
thePlayer.DisableCombatState();
}
else
{
thePlayer.UnblockAction( EIAB_Signs, sourceName );
thePlayer.UnblockAction( EIAB_DrawWeapon, sourceName );
thePlayer.UnblockAction( EIAB_CallHorse, sourceName );
thePlayer.UnblockAction( EIAB_FastTravel, sourceName );
thePlayer.UnblockAction( EIAB_Fists, sourceName );
thePlayer.UnblockAction( EIAB_InteractionAction, sourceName );
}
}

public function GetPlayerActionEventListeners() : array
{
return playerActionEventListeners;
}

//Registers for event + blocks GameplayActions
public function RegisterForPlayerAction( listener : CGameplayEntity, isLockedByPlace : bool )
{
if ( !playerActionEventListeners.Contains( listener ) )
{
playerActionEventListeners.PushBack( listener );
}
if ( listener.ShouldBlockGameplayActionsOnInteraction() )
{
if ( !playerActionEventBlockingListeners.Contains( listener ) )
{
playerActionEventBlockingListeners.PushBack( listener );
}
if ( playerActionEventBlockingListeners.Size() == 1 )
{
PlayerActionBlockGameplayActions( 'PlayerAction', true, isLockedByPlace );
}
}
}

//Unregisters for event + unblocks GameplayActions
public function UnregisterForPlayerAction( listener : CGameplayEntity, isLockedByPlace : bool )
{
playerActionEventListeners.Remove( listener );
playerActionEventBlockingListeners.Remove( listener );
if ( playerActionEventBlockingListeners.Size() == 0 )
{
PlayerActionBlockGameplayActions( 'PlayerAction', false, isLockedByPlace );
}
}

event OnPlayerActionStart()
{
//MS: Only used for ProudWalk
thePlayer.SetBehaviorVariable( 'inJumpState', 1.f );
}

event OnPlayerActionEnd()
{
var i : int;
for ( i = playerActionEventListeners.Size() - 1; i >= 0; i-=1 )
{
playerActionEventListeners[i].OnPlayerActionEnd();
}
currentCustomAction = PEA_None;

//MS: Only used for ProudWalk
thePlayer.SetBehaviorVariable( 'inJumpState', 0.f );
}

event OnPlayerActionStartFinished()
{
var i : int;
for ( i = playerActionEventListeners.Size() - 1; i >= 0; i-=1 )
{
playerActionEventListeners[i].OnPlayerActionStartFinished();
}
}

function PlayerStartAction( playerAction : EPlayerExplorationAction, optional animName : name ) : bool
{
if ( playerAction == PEA_SlotAnimation && !IsNameValid(animName) )
{
return false;
}

SetBehaviorVariable( 'playerStopAction', 0.0);
SetBehaviorVariable( 'playerExplorationAction', (float)(int)playerAction);

/*if ( playerAction == PEA_SlotAnimation )
{
if ( !this.ActionPlaySlotAnimationAsync('PLAYER_ACTION_SLOT',animName) )
return false;
}*/

if ( RaiseForceEvent('playerActionStart') )
{
currentCustomAction = playerAction;
if ( playerAction == PEA_SlotAnimation )
{
playerActionSlotAnimName = animName;
AddTimer('PlayActionAnimWorkaround',0,false);
}
return true;
}
return false;
}

private var playerActionSlotAnimName : name;

timer function PlayActionAnimWorkaround( dt : float , id : int)
{
this.ActionPlaySlotAnimationAsync('PLAYER_ACTION_SLOT',playerActionSlotAnimName, 0.2, 0.2, true);
}

function PlayerStopAction( playerAction : EPlayerExplorationAction )
{
SetBehaviorVariable( 'playerExplorationAction', (float)(int)playerAction);
SetBehaviorVariable( 'playerStopAction', 1.0);
currentCustomAction = PEA_None;
}

function GetPlayerAction() : EPlayerExplorationAction
{
return currentCustomAction;
}

function MedallionPing()
{
var currTime : float = theGame.GetEngineTimeAsSeconds();

if ( lastMedallionEffect < currTime )
{
lastMedallionEffect = theGame.GetEngineTimeAsSeconds() + medallion.effectDuration;
medallion.TriggerMedallionFX();
}
}

///////////////////////////////////////////////////////////////////////////
// @INTERACTIONS
///////////////////////////////////////////////////////////////////////////

public function CanPerformPlayerAction(optional alsoOutsideExplorationState : bool) : bool
{
//if in exploration or in any state and flag set
if(!alsoOutsideExplorationState && GetCurrentStateName() != 'Exploration')
return false;

if( isInAir || (substateManager && !substateManager.CanInteract()) || IsInCombatAction() || GetCriticalBuffsCount() > 0)
return false;

return true;
}

//called when we receive an item
event OnItemGiven(data : SItemChangedData)
{
var keyName : name;
var i : int;
var hud : CR4ScriptedHud;
var message : string;
var inve : CInventoryComponent;

if(data.informGui)
{
hud = (CR4ScriptedHud)theGame.GetHud();
if(hud)
{
message = GetLocStringByKeyExt("panel_common_item_received") + ": " + GetLocStringByKeyExt(inv.GetItemLocalizedNameByUniqueID(data.ids[0]));
if(data.quantity > 1)
message += " x" + data.quantity;
hud.HudConsoleMsg(message);
}
}

inve = GetInventory(); //OnItemGiven can be called before we cache inventory component

//key - check if we're next to a lock that uses this key and update interaction if needed
if(inve.ItemHasTag(data.ids[0], 'key'))
{
keyName = inve.GetItemName(data.ids[0]);
for(i=nearbyLockedContainersNoKey.Size()-1; i>=0; i-=1)
{
if(nearbyLockedContainersNoKey[i].GetKeyName() == keyName && nearbyLockedContainersNoKey[i].IsEnabled())
{
nearbyLockedContainersNoKey[i].UpdateComponents("Unlock");
nearbyLockedContainersNoKey.Remove(nearbyLockedContainersNoKey[i]);
}
}
}

//alchemy level 3 items
if(inve.IsItemAlchemyItem(data.ids[0]))
{
UpgradeAlchemyItem(data.ids[0], CanUseSkill(S_Perk_08));
}

if(inve.ItemHasTag(data.ids[0], theGame.params.TAG_OFIR_SET))
CheckOfirSetAchievement();
}

private final function CheckOfirSetAchievement()
{
var hasArmor, hasBoots, hasGloves, hasPants, hasSword, hasSaddle, hasBag, hasBlinders : bool;

//check player items
CheckOfirItems(GetInventory(), hasArmor, hasBoots, hasGloves, hasPants, hasSword, hasSaddle, hasBag, hasBlinders);

//check stash items
CheckOfirItems(GetWitcherPlayer().GetHorseManager().GetInventoryComponent(), hasArmor, hasBoots, hasGloves, hasPants, hasSword, hasSaddle, hasBag, hasBlinders);

if(hasArmor && hasBoots && hasGloves && hasPants && hasSword && hasSaddle && hasBag && hasBlinders)
theGame.GetGamerProfile().AddAchievement(EA_LatestFashion);
}

private final function CheckOfirItems(inv : CInventoryComponent, out hasArmor : bool, out hasBoots : bool, out hasGloves : bool, out hasPants : bool, out hasSword : bool, out hasSaddle : bool, out hasBag : bool, out hasBlinders : bool)
{
var ofirs : array;
var i : int;

ofirs = inv.GetItemsByTag(theGame.params.TAG_OFIR_SET);
for(i=0; i {
if(inv.IsItemChestArmor(ofirs[i]))
{
hasArmor = true;
continue;
}
else if(inv.IsItemBoots(ofirs[i]))
{
hasBoots = true;
continue;
}
else if(inv.IsItemGloves(ofirs[i]))
{
hasGloves = true;
continue;
}
else if(inv.IsItemPants(ofirs[i]))
{
hasPants = true;
continue;
}
else if(inv.IsItemSteelSwordUsableByPlayer(ofirs[i]))
{
hasSword = true;
continue;
}
else if(inv.IsItemSilverSwordUsableByPlayer(ofirs[i]))
{
hasSword = true;
continue;
}
else if(inv.IsItemSaddle(ofirs[i]))
{
hasSaddle = true;
continue;
}
else if(inv.IsItemHorseBag(ofirs[i]))
{
hasBag = true;
continue;
}
else if(inv.IsItemBlinders(ofirs[i]))
{
hasBlinders = true;
continue;
}
}
}

//changes all alchemy items of level 3 abilities from level 2 to 3 (if upgrade) or from 3 to 2 (if not upgrading)
public function ChangeAlchemyItemsAbilities(upgrade : bool)
{
var i : int;
var dm : CDefinitionsManagerAccessor;
var items : array;

inv.GetAllItems(items);
dm = theGame.GetDefinitionsManager();

for(i=0; i if(inv.IsItemAlchemyItem(items[i]))
UpgradeAlchemyItem(items[i], upgrade);
}

//changes all alchemy items of level 3 abilities from level 2 to 3 (if upgrade) or from 3 to 2 (if not upgrading)
public function UpgradeAlchemyItem(itemID : SItemUniqueId, upgrade : bool)
{
var j, currLevel, otherLevel : int;
var dm : CDefinitionsManagerAccessor;
var abs, currAbilities, otherAbilities : array;
var min, max : SAbilityAttributeValue;

if(!inv.IsItemAlchemyItem(itemID))
return;

//get current level
currLevel = (int)CalculateAttributeValue(inv.GetItemAttributeValue(itemID, 'level'));

//if level ok then exit
if(currLevel == 3 || currLevel == 2 || currLevel < 2 || currLevel > 3)
return;

//get current ability name
currAbilities = inv.GetItemAbilitiesWithAttribute(itemID, 'level', currLevel);

//get other ability name
inv.GetItemContainedAbilities(itemID, abs);
dm = theGame.GetDefinitionsManager();
for(j=0; j {
dm.GetAbilityAttributeValue(abs[j], 'level', min, max);
otherLevel = (int)CalculateAttributeValue(GetAttributeRandomizedValue(min, max));
if( (otherLevel == 2 || otherLevel == 3) && otherLevel != currLevel)
otherAbilities.PushBack(abs[j]);
}

//swap abilities
if(otherAbilities.Size() == 0)
{
LogAssert(false, "CR4Player.UpgradeAlchemyItem: cannot find ability to swap to from <<" + currAbilities[0] + ">> on item <<" + inv.GetItemName(itemID) + ">> !!!");
}
else
{
for(j=0; j inv.RemoveItemBaseAbility(itemID, currAbilities[j]);

for(j=0; j inv.AddItemBaseAbility(itemID, otherAbilities[j]);
}
}

///////////////////////////////////////////////////////////////////////////
// Movement adjustment helper functions
///////////////////////////////////////////////////////////////////////////

public function MovAdjRotateToTarget( ticket : SMovementAdjustmentRequestTicket )
{
var movementAdjustor : CMovementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
var localOrientationTarget : EOrientationTarget = GetOrientationTarget();

if ( localOrientationTarget == OT_CustomHeading )
{
movementAdjustor.RotateTo( ticket, GetOrientationTargetCustomHeading() );
}
else if ( localOrientationTarget == OT_Actor )
{
/*if ( parryTarget && IsGuarded() )
movementAdjustor.RotateTowards( ticket, parryTarget );
else*/ if ( slideTarget )
movementAdjustor.RotateTowards( ticket, slideTarget );
else if ( lAxisReleasedAfterCounter )
movementAdjustor.RotateTo( ticket, GetHeading() );
else
movementAdjustor.RotateTo( ticket, GetCombatActionHeading() );//rawPlayerHeading );
}
else if ( localOrientationTarget == OT_Player )
{
if ( bLAxisReleased )
movementAdjustor.RotateTo( ticket, GetHeading() );
else
movementAdjustor.RotateTo( ticket, rawPlayerHeading );//GetCombatActionHeading() );
}
else if ( localOrientationTarget == OT_CameraOffset )
{
//movementAdjustor.RotateTo( ticket, VecHeading( cachedCameraVector ) );//rawCameraHeading - oTCameraOffset );
movementAdjustor.RotateTo( ticket, VecHeading( theCamera.GetCameraDirection() ) );//rawCameraHeading );
}
else
{
// default to camera
movementAdjustor.RotateTo( ticket, rawCameraHeading );
}
// never rotate to player
}

////////////////////////////////////////////////////////////////////////////////////
// Look at targets - moved here from movables
////////////////////////////////////////////////////////////////////////////////////
//var cachedCameraVector : Vector;
public function UpdateLookAtTarget()
{
var localOrientationTarget : EOrientationTarget;
var playerRot : EulerAngles;
var lookAtActive : Float;
var lookAtTarget : Vector;
var headBoneIdx : int;
var tempComponent : CDrawableComponent;
var entityHeight : float;
var useTorsoBone : bool;

var angles : EulerAngles;
var dir : Vector;
var camZ : float;

var target : CActor;

lookAtActive = 0.0f;

localOrientationTarget = GetOrientationTarget();

if ( localOrientationTarget == OT_Player || localOrientationTarget == OT_CustomHeading )
{
/*headBoneIdx = GetTorsoBoneIndex();
if ( headBoneIdx >= 0 )
{
lookAtTarget = MatrixGetTranslation( GetBoneWorldMatrixByIndex( headBoneIdx ) );
}*/

//lookAtTarget = GetHeadingVector() * 30.f + this.GetWorldPosition();// + lookAtTarget;

if ( localOrientationTarget == OT_Player )
angles = VecToRotation( GetHeadingVector() );
else if ( customOrientationInfoStack.Size() > 0 )
angles = VecToRotation( VecFromHeading( customOrientationInfoStack[ customOrientationInfoStack.Size() - 1 ].customHeading ) );
else
angles = VecToRotation( GetHeadingVector() );

//angles.Pitch = oTCameraPitchOffset;
dir = RotForward( angles );
lookAtTarget = dir * 30.f + this.GetWorldPosition();// + lookAtTarget;
lookAtTarget.Z += 1.6f;
lookAtActive = 1.0f;
}
else if ( localOrientationTarget == OT_Camera )
{
headBoneIdx = GetHeadBoneIndex();
if ( headBoneIdx >= 0 )
{
lookAtTarget = MatrixGetTranslation( GetBoneWorldMatrixByIndex( headBoneIdx ) );
}
else
{
lookAtTarget = GetWorldPosition();
lookAtTarget.Z += 1.6f; // fake head?
}
lookAtTarget += theCamera.GetCameraDirection() * 100.f;
lookAtActive = 1.0f;
}
else if ( localOrientationTarget == OT_CameraOffset )
{
/*lookAtTarget = GetWorldPosition();
lookAtTarget.Z += 1.6f; // fake head?
camDir = theCamera.GetCameraDirection();
camZ = camDir.Z;// + 0.1;
camDir = VecFromHeading( VecHeading( theCamera.GetCameraDirection() ) - oTCameraOffset ) * VecLength2D( camDir );
camDir.Z = camZ;*/

dir = theCamera.GetCameraDirection();
angles = VecToRotation( dir );
angles.Pitch = -angles.Pitch + oTCameraPitchOffset;
angles.Yaw -= oTCameraOffset;
dir = RotForward( angles );

lookAtTarget = dir * 30.f + this.GetWorldPosition();// + lookAtTarget;
lookAtTarget.Z += 1.6f;
lookAtActive = 1.0f;
}
else if ( localOrientationTarget == OT_Actor )
{
if ( IsInCombatAction() )
{
if ( ( ( ( W3PlayerWitcher )this ).GetCurrentlyCastSign() != ST_None && GetBehaviorVariable( 'combatActionType' ) == (int)CAT_CastSign )
|| GetBehaviorVariable( 'combatActionType' ) == (int)CAT_ItemThrow )
//|| GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Crossbow )
useTorsoBone = true;
}

if ( rangedWeapon && rangedWeapon.GetCurrentStateName() != 'State_WeaponWait' )
useTorsoBone = true;

if ( tempLookAtTarget && (CActor)(tempLookAtTarget) )
{
lookAtTarget = ProcessLookAtTargetPosition( tempLookAtTarget, useTorsoBone );
lookAtActive = 1.0f;
}

if ( GetDisplayTarget() && IsDisplayTargetTargetable() )
{
lookAtTarget = ProcessLookAtTargetPosition( GetDisplayTarget(), useTorsoBone );
lookAtActive = 1.0f;
}
else
{
//FAIL SAFE in case the displayTarget disappears for some reason

if ( slideTarget )
{
lookAtTarget = ProcessLookAtTargetPosition( slideTarget, useTorsoBone );
}
else
{
target = GetTarget();
if ( target )
{
lookAtTarget = ProcessLookAtTargetPosition( target, useTorsoBone );
}
}

lookAtActive = 1.0f;
}

if ( !slideTarget && !IsUsingVehicle() )
{
// TODO maybe just get axis from head?
playerRot = GetWorldRotation();
lookAtTarget = GetWorldPosition() + VecFromHeading( playerRot.Yaw ) * 100.0f;
lookAtActive = 0.0f;
}

if ( useTorsoBone )
lookAtTarget.Z += 0.2f;
}


//lookAtTarget = player.GetHeadingVector() * 30.f + this.GetWorldPosition();// + lookAtTarget;
//lookAtActive = 1.0f;
GetVisualDebug().AddSphere('lookAtTarget', 1.f, lookAtTarget, true, Color(255,0,0), 3.0f );
SetLookAtPosition( lookAtTarget );
UpdateLookAtVariables( lookAtActive, lookAtTarget );
}

private function ProcessLookAtTargetPosition( ent : CGameplayEntity, useTorsoBone : bool ) : Vector
{
var boneIdx : int;
var actor : CActor;
var lookAtTarget : Vector;
var tempComponent : CDrawableComponent;
var box : Box;
var entityHeight : float;
var entityPos : Vector;
var predictedPos : Vector;
var z : float;
var entMat : Matrix;

actor = (CActor)(ent);
entityPos = ent.GetWorldPosition();
lookAtTarget = entityPos;

if ( actor )
{
if ( useTorsoBone )
boneIdx = actor.GetTorsoBoneIndex();
else
boneIdx = actor.GetHeadBoneIndex();
}
else
boneIdx = -1;

if ( !( ent.aimVector.X == 0 && ent.aimVector.Y == 0 && ent.aimVector.Z == 0 ) )
{
entMat = ent.GetLocalToWorld();
lookAtTarget = VecTransform( entMat, ent.aimVector );
}
else if ( boneIdx >= 0 )
{
lookAtTarget = MatrixGetTranslation( ent.GetBoneWorldMatrixByIndex( boneIdx ) );
}
else
{
if ( actor )
lookAtTarget.Z += ( ((CMovingPhysicalAgentComponent)actor.GetMovingAgentComponent()).GetCapsuleHeight() * 0.5 ); // fake head?
else
{
tempComponent = (CDrawableComponent)( ent.GetComponentByClassName('CDrawableComponent') );
if ( tempComponent.GetObjectBoundingVolume( box ) )
{
entityHeight = box.Max.Z - box.Min.Z;
lookAtTarget = lookAtTarget + Vector(0,0,entityHeight/2);
}
}
}
z = ((CMovingPhysicalAgentComponent)actor.GetMovingAgentComponent()).GetCapsuleHeight();
if ( actor )
{
if ( PredictLookAtTargetPosition( actor, lookAtTarget.Z - entityPos.Z, predictedPos ) )
lookAtTarget = predictedPos;
}

return lookAtTarget;
}


private function PredictLookAtTargetPosition( targetActor : CActor, zOffSet : float, out predictedPos : Vector ) : bool
{
var virtualPos : Vector;
var i : int;
var dist : float;
var deltaTime : float;
var projSpeed : float;
var projSpeedInt : Vector;
var projAngle : float;

var e3Hack : bool;
var currentTimeInCurve : float;
e3Hack = false;

if ( rangedWeapon
&& rangedWeapon.GetDeployedEntity()
&& ( rangedWeapon.GetCurrentStateName() == 'State_WeaponAim' || rangedWeapon.GetCurrentStateName() == 'State_WeaponShoot' ) )
{
projSpeed = rangedWeapon.GetDeployedEntity().projSpeed;

virtualPos = targetActor.GetWorldPosition();

if ( e3Hack && targetActor.HasTag( 'e3_griffin' ) )
{
for ( i = 0; i < 10; i += 1 )
{
dist = VecDistance( rangedWeapon.GetDeployedEntity().GetWorldPosition(), virtualPos );
deltaTime = dist/projSpeed;
virtualPos = targetActor.PredictWorldPosition( deltaTime );
}
}
else
return false;

virtualPos.Z += zOffSet;
predictedPos = virtualPos;
GetVisualDebug().AddSphere('CrossbowPredictedPos', 1.0f, virtualPos , true, Color(255,50,50), 5.0f );
return true;
}
return false;
}

public function SetLookAtPosition( vec : Vector )
{
lookAtPosition = vec;
}

public function GetLookAtPosition() : Vector
{
return lookAtPosition;
}

////////////////////////////////////////////////////////////////////////////////////
// Scene
////////////////////////////////////////////////////////////////////////////////////

event OnBlockingSceneEnded( optional output : CStorySceneOutput)
{
//hack for possible immortality from finishers
SetImmortalityMode( AIM_None, AIC_SyncedAnim );
super.OnBlockingSceneEnded(output);
}

////////////////////////////////////////////////////////////////////////////////////
// New combat / exploration and weapon drawing
////////////////////////////////////////////////////////////////////////////////////

function GetCurrentMeleeWeaponName() : name
{
return weaponHolster.GetCurrentMeleeWeaponName();
}

public function GetCurrentMeleeWeaponType() : EPlayerWeapon
{
return weaponHolster.GetCurrentMeleeWeapon();
}

public function OnMeleeForceHolster(ignoreActionLock : bool)
{
weaponHolster.HolsterWeapon(ignoreActionLock, true);
}

event OnForcedHolsterWeapon()
{
weaponHolster.OnForcedHolsterWeapon();
}

event OnEquippedItem( category : name, slotName : name )
{
var weaponType : EPlayerWeapon;

if ( slotName == 'r_weapon' )
{
switch ( category )
{
case 'None' :
weaponType = PW_None;
break;
case 'fist' :
weaponType = PW_Fists;
break;
case 'steelsword' :
weaponType = PW_Steel;
break;
case 'silversword' :
weaponType = PW_Silver;
break;
default :
return true;
}

weaponHolster.OnEquippedMeleeWeapon( weaponType );
}
}

private var isHoldingDeadlySword : bool;
public function ProcessIsHoldingDeadlySword()
{
isHoldingDeadlySword = IsDeadlySwordHeld();
}

public function IsHoldingDeadlySword() : bool
{
return isHoldingDeadlySword;
}

event OnHolsteredItem( category : name, slotName : name )
{
var weaponType : EPlayerWeapon;

if ( slotName == 'r_weapon' )
{
weaponType = weaponHolster.GetCurrentMeleeWeapon();
switch ( category )
{
case 'fist' :
if ( weaponType == PW_Fists )
weaponHolster.OnEquippedMeleeWeapon( PW_None );
return true;
case 'steelsword' :
if ( weaponType == PW_Steel )
weaponHolster.OnEquippedMeleeWeapon( PW_None );
return true;
case 'silversword' :
if ( weaponType == PW_Silver )
weaponHolster.OnEquippedMeleeWeapon( PW_None );
return true;
default :
return true;
}
}
}

event OnEquipMeleeWeapon( weaponType : EPlayerWeapon, ignoreActionLock : bool, optional sheatheIfAlreadyEquipped : bool )
{
RemoveTimer( 'DelayedSheathSword' );

weaponHolster.OnEquipMeleeWeapon( weaponType, ignoreActionLock, sheatheIfAlreadyEquipped );

/*// Check if we want to go to combat or exploration
if( weaponHolster.GetCurrentMeleeWeapon() == PW_None )
{
GoToExplorationIfNeeded( );
}
else
{
GoToCombatIfNeeded( );
}*/

m_RefreshWeaponFXType = true;
}

event OnHolsterLeftHandItem()
{
weaponHolster.OnHolsterLeftHandItem();
}

timer function DelayedSheathSword( dt: float, id : int )
{
if ( !IsCombatMusicEnabled() )
{
if ( IsInCombatAction() || !IsActionAllowed( EIAB_DrawWeapon ) )
{
LogChannel( 'OnCombatFinished', "DelayedSheathSword: Sheath pushed to buffer" );
PushCombatActionOnBuffer(EBAT_Sheathe_Sword,BS_Pressed);
}
else
{
LogChannel( 'OnCombatFinished', "DelayedSheathSword: Sheath successful" );
OnEquipMeleeWeapon( PW_None, false );
}
}
}

protected function ShouldAutoSheathSwordInstantly() : bool
{
var enemies : array;
var i : int;

GetEnemiesInRange( enemies );

for ( i = 0; i < enemies.Size(); i += 1 )
{
if ( IsThreat( enemies[i] ) &&
VecDistance( enemies[i].GetWorldPosition(), this.GetWorldPosition() ) <= findMoveTargetDist )
{
return false;
}
}

return true;
}

public function PrepareToAttack( optional target : CActor, optional action : EBufferActionType )
{
var weaponType : EPlayerWeapon;

if( IsInAir() || !GetBIsCombatActionAllowed() )
{
return ;
}

if( !target )
{
target = (CActor)displayTarget;
}
if( !target && IsCombatMusicEnabled() )
{
target = moveTarget;
}
if( !target )
{
if ( this.GetCurrentStateName() == 'Exploration' )
{
SetCombatActionHeading( ProcessCombatActionHeading( action ) );
thePlayer.CanAttackWhenNotInCombat( action, false, target );
}
}

weaponHolster.TryToPrepareMeleeWeaponToAttack();

//if ( this.GetCurrentStateName() == 'Exploration' ) //PF - commenting this because Geralt won't switch to proper state when you sheathe sword while mashing attack
{
weaponType = GetCurrentMeleeWeaponType();

if ( weaponType == PW_None )
{
// Get the weapon we have to use
weaponType = GetMostConvenientMeleeWeapon( target );
}

// Can't go to combat if we are in not a proper state
if( !OnStateCanGoToCombat() )
{
return;
}

GoToCombat( weaponType );
}
}

public function DisplayCannotAttackMessage( actor : CActor ) : bool
{
if ( actor && ( actor.GetMovingAgentComponent().GetName() == "child_base" || ((CNewNPC)actor).GetNPCType() == ENGT_Quest ) )
{
DisplayHudMessage(GetLocStringByKeyExt("panel_hud_message_cant_attack_this_target"));
return true;
}

return false;
}

public function GetMostConvenientMeleeWeapon( targetToDrawAgainst : CActor, optional ignoreActionLock : bool ) : EPlayerWeapon
{
return weaponHolster.GetMostConvenientMeleeWeapon( targetToDrawAgainst, ignoreActionLock );
}

private var reevaluateCurrentWeapon : bool;

event OnTargetWeaponDrawn()
{
var weaponType : EPlayerWeapon = this.GetCurrentMeleeWeaponType();
if ( weaponType == PW_Fists )
reevaluateCurrentWeapon = true;
}

public function GoToCombatIfNeeded( optional enemy : CActor ) : bool
{
var weaponType : EPlayerWeapon;
var target : CActor;

if( !enemy && IsInCombat() )
{
target = GetTarget();

if ( target )
enemy = target;
else
enemy = moveTarget;
}

// Should we fight
if( !ShouldGoToCombat( enemy ) )
{
return false;
}

weaponType = this.GetCurrentMeleeWeaponType();

if ( weaponType == PW_None || ( reevaluateCurrentWeapon && weaponType == PW_Fists ) || ( !IsInCombat() && weaponHolster.IsOnTheMiddleOfHolstering() ) )
{
// Get the weapon we have to use
weaponType = weaponHolster.GetMostConvenientMeleeWeapon( enemy );
reevaluateCurrentWeapon = false;
}

// Change the state+
GoToCombat( weaponType );


return true;
}

public function GoToCombatIfWanted( ) : bool
{
var weaponType : EPlayerWeapon;
var target : CActor;
var enemy : CActor;


if( !IsInCombat() )
{
return false;
}

target = GetTarget();

if ( target )
enemy = target;
else
enemy = moveTarget;

weaponType = this.GetCurrentMeleeWeaponType();

if ( weaponType == PW_None || ( !IsInCombat() && weaponHolster.IsOnTheMiddleOfHolstering() ) )
{
// Get the weapon we have to use
weaponType = weaponHolster.GetMostConvenientMeleeWeapon( enemy );
}

// Change the state+
GoToCombat( weaponType );


return true;
}

public function GoToExplorationIfNeeded() : bool
{
/*
if( GetCurrentStateName() == 'Exploration' )
{
return false;
}
*/

if( ! IsInCombatState() )
{
return false;
}

if( !ShouldGoToExploration() )
{
return false;
}

// Change fists weapon to none
weaponHolster.EndedCombat();

// Change the state
GotoState( 'Exploration' );
return true;
}

event OnStateCanGoToCombat()
{
return false;
}

event OnStateCanUpdateExplorationSubstates()
{
return false;
}

private function ShouldGoToCombat( optional enemy : CActor ) : bool
{
// TODO If we don't have a specific enemy, let's just check if there are hostiles to fight
if ( !enemy )
{
//return isFightingHostiles;
return false;
}

// Can't go to combat if we are in not a proper state
if( !OnStateCanGoToCombat() )
{
return false;
}

// See if we should be fighting this enemy
/*if ( !IsEnemyVisible( enemy ) )
{
return false;
}*/
/*if ( !WasVisibleInScaledFrame( enemy, 1.f, 1.f ) )
{
return false;
}*/

if ( this.GetCurrentStateName() == 'AimThrow' )
{
return false;
}

if ( this.GetCurrentStateName() == 'Swimming' )
{
return false;
}

if ( this.GetCurrentStateName() == 'TraverseExploration' )
{
return false;
}

// TODO: Reenable or find somethingbetter
// Temporaryly disabled cause it does not work on some terrain
/*
if ( !theGame.GetWorld().NavigationLineTest( GetWorldPosition(), enemy.GetWorldPosition(), 0.4 ) )
{
return false;
}
*/

return true;
}

private function ShouldGoToExploration() : bool
{
if ( IsInCombat() )//moveTarget && IsThreat( moveTarget ) )
{
return false;
}
/*if( IsGuarded() )
{
return false;
}*/
if ( rangedWeapon && rangedWeapon.GetCurrentStateName() != 'State_WeaponWait' )
{
return false;
}
if( IsFistFightMinigameEnabled() )
{
return false;
}
if( IsKnockedUnconscious() )
{
return false;
}
if( IsInCombatAction() )
{
return false;
}
if( GetCriticalBuffsCount() > 0 )
{
return false;
}

return true;
}

private function GoToCombat( weaponType : EPlayerWeapon, optional initialAction : EInitialAction )
{
// Set up and change state
switch( weaponType )
{
case PW_Silver:
((W3PlayerWitcherStateCombatSilver) GetState('CombatSilver')).SetupState( initialAction );
GoToStateIfNew( 'CombatSilver' );
break;
case PW_Steel:
((W3PlayerWitcherStateCombatSteel) GetState('CombatSteel')).SetupState( initialAction );
GoToStateIfNew( 'CombatSteel' );
break;
case PW_Fists:
case PW_None:
default :
((W3PlayerWitcherStateCombatFists) GetState('CombatFists')).SetupState( initialAction );
GoToStateIfNew( 'CombatFists' );
break;
}
}

public function GoToStateIfNew( newState : name, optional keepStack : bool, optional forceEvents : bool )
{
if( newState != GetCurrentStateName() )
{
GotoState( newState, keepStack, forceEvents );
}
}

// So we can debug and control what is changing the state
public function GotoState( newState : name, optional keepStack : bool, optional forceEvents : bool )
{
/*if( newState == 'Exploration' )
{
newState = newState;
}*/

super.GotoState( newState, keepStack, forceEvents );
//PushState( newState );
}
/*
public function PushState( newState : name )
{
if( newState == 'Exploration' )
{
newState = newState;
}
super.PushState( newState );
}

public function PopState( optional popAll : bool )
{
super.PopState( popAll );
}
*/
public function IsThisACombatSuperState( stateName : name ) : bool
{
return stateName == 'Combat' || stateName == 'CombatSteel' || stateName == 'CombatSilver' || stateName == 'CombatFists';
}

public function GetWeaponHolster() : WeaponHolster
{
return weaponHolster;
}

public function AbortSign()
{
var playerWitcher : W3PlayerWitcher;
var sign : W3SignEntity;

playerWitcher = (W3PlayerWitcher)this;

if(playerWitcher)
{
sign = (W3SignEntity)playerWitcher.GetCurrentSignEntity();
if (sign)
{
sign.OnSignAborted();
}
}
}

///////////////////////////////////////////////////////////////////////////
// Animation event handlers
///////////////////////////////////////////////////////////////////////////
protected var disableActionBlend : bool;

//KonradSuperDodgeHACK: To make dodge more responsive during NORMAL ATTACKS, dodge will fire immediately when hit animation can be played.
//When hit anim is disabled, then the action will be cached and will be processed at the END of DisallowHitAnim event.
//During all other actions, however, it will use the normal check of inputAllowed and combatActionAllowed. This is a super hack. And we will all go to hell for this.
event OnAnimEvent_DisallowHitAnim( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if ( animEventType == AET_DurationEnd )
{
if ( ( BufferCombatAction == EBAT_Dodge || BufferCombatAction == EBAT_Roll )
&& IsInCombatAction()
&& GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack )
{
//LogChannel('combatActionAllowed',"BufferCombatAction != EBAT_EMPTY");
( (CR4Player)this ).ProcessCombatActionBuffer();
disableActionBlend = true;
}
}
else if ( IsInCombatAction() && GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Dodge && animEventType == AET_DurationStart )
{
disableActionBlend = false;
}

super.OnAnimEvent_DisallowHitAnim( animEventName, animEventType, animInfo );
}


event OnAnimEvent_FadeOut( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
theGame.FadeOutAsync( 0.2, Color( 0, 0, 0, 1 ) );
}

event OnAnimEvent_FadeIn( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
theGame.FadeInAsync( 0.4 );
}

event OnAnimEvent_BloodTrailForced( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
var bloodTrailParam : CBloodTrailEffect;
var weaponId : SItemUniqueId;

if ( isInFinisher )
{
bloodTrailParam = (CBloodTrailEffect)(GetFinisherVictim()).GetGameplayEntityParam( 'CBloodTrailEffect' );
weaponId = this.inv.GetItemFromSlot('r_weapon');
if ( bloodTrailParam )
thePlayer.inv.PlayItemEffect( weaponId, bloodTrailParam.GetEffectName() );
}
}

event OnAnimEvent_SlowMo( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if ( isInFinisher && DisableManualCameraControlStackHasSource( 'Finisher' ) )
{
if( animEventType != AET_DurationEnd )
theGame.SetTimeScale( 0.1f, 'AnimEventSlomoMo', 1000, true );
else
theGame.RemoveTimeScale( 'AnimEventSlomoMo' );
}
}

event OnAnimEvent_PlayFinisherBlood( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if ( isInFinisher )
{
SpawnFinisherBlood();
}
}

event OnAnimEvent_OnWeaponDrawReady( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
weaponHolster.OnWeaponDrawReady();
}

event OnAnimEvent_OnWeaponHolsterReady( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
weaponHolster.OnWeaponHolsterReady();
}

event OnAnimEvent_ThrowHoldTest( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
var thrownEntity : CThrowable;

thrownEntity = (CThrowable)EntityHandleGet( thrownEntityHandle );

if( IsThrowHold() )
{
SetBehaviorVariable( 'throwStage', (int)TS_Loop );
PushState( 'AimThrow' );
thrownEntity.StartAiming();
}
else
{
BombThrowRelease();
SetCombatIdleStance( 1.f );
}
}

event OnAnimEvent_AllowTempLookAt( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if( animEventType == AET_DurationStart )
SetTempLookAtTarget( slideTarget );
else if( animEventType == AET_DurationEnd )
SetTempLookAtTarget( NULL );
}

protected var slideNPC : CNewNPC;
protected var minSlideDistance : float;
protected var slideTicket : SMovementAdjustmentRequestTicket;

event OnAnimEvent_SlideToTarget( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
var movementAdjustor : CMovementAdjustor;

if ( animEventType == AET_DurationStart )
slideNPC = (CNewNPC)slideTarget;

if(!slideNPC)
return false;

if ( animEventType == AET_DurationStart && slideNPC.GetGameplayVisibility() )
{
movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
slideTicket = movementAdjustor.GetRequest( 'SlideToTarget' );
movementAdjustor.CancelByName( 'SlideToTarget' );
slideTicket = movementAdjustor.CreateNewRequest( 'SlideToTarget' );
movementAdjustor.BindToEventAnimInfo( slideTicket, animInfo );
//movementAdjustor.Continuous(slideTicket);
movementAdjustor.MaxLocationAdjustmentSpeed( slideTicket, 1000000 );
movementAdjustor.ScaleAnimation( slideTicket );
minSlideDistance = ((CMovingPhysicalAgentComponent)this.GetMovingAgentComponent()).GetCapsuleRadius()+((CMovingPhysicalAgentComponent)slideNPC.GetMovingAgentComponent()).GetCapsuleRadius();
movementAdjustor.SlideTowards( slideTicket, slideTarget, minSlideDistance, minSlideDistance );
}
else if ( !slideNPC.GetGameplayVisibility() )
{
movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
movementAdjustor.CancelByName( 'SlideToTarget' );
slideNPC = NULL;
}
else
{
movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
movementAdjustor.SlideTowards( slideTicket, slideTarget, minSlideDistance, minSlideDistance );
}
}

event OnAnimEvent_ActionBlend( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
}
/*
event OnAnimEvent_Throwable( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
var thrownEntity : CThrowable;

thrownEntity = (CThrowable)EntityHandleGet( thrownEntityHandle );

if ( inv.IsItemCrossbow( inv.GetItemFromSlot('l_weapon') ) && rangedWeapon.OnProcessThrowEvent( animEventName ) )
{
return true;
}
else if( thrownEntity && IsThrowingItem() && thrownEntity.OnProcessThrowEvent( animEventName ) )
{
return true;
}
}*/

event OnAnimEvent_SubstateManager( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
// Notify the exploration manager
substateManager.OnAnimEvent( animEventName, animEventType, animInfo );
}

event OnAnimEvent_AllowFall( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if ( !substateManager.m_OwnerMAC.IsOnGround() )
{
substateManager.m_SharedDataO.SetFallFromCritical( true );
substateManager.m_MoverO.SetVelocity( -6.0f * GetWorldForward() );
substateManager.QueueStateExternal( 'Jump' );
RemoveBuff( EET_Knockdown, true );
RemoveBuff( EET_HeavyKnockdown, true );
return true;
}
return false;
}

event OnAnimEvent_AllowFall2( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if ( !substateManager.m_OwnerMAC.IsOnGround() )
{
//substateManager.m_SharedDataO.m_FromCriticalB = true;
//substateManager.m_MoverO.SetVelocity( -6.0f * GetWorldForward() );
substateManager.QueueStateExternal( 'Jump' );
RemoveBuff( EET_Knockdown, true );
RemoveBuff( EET_HeavyKnockdown, true );
}
if( substateManager.StateWantsAndCanEnter( 'Slide' ) )
{
substateManager.QueueStateExternal( 'Slide' );
}
}

event OnAnimEvent_DettachGround( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
//substateManager.m_MoverO.SetManualMovement( true );
}

//pad vibration for finishers
event OnAnimEvent_pad_vibration( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
var witcher : W3PlayerWitcher;

theGame.VibrateControllerHard();

//delayed FX for runeword 10 & 12
witcher = GetWitcherPlayer();
if(isInFinisher && witcher)
{
if(HasAbility('Runeword 10 _Stats', true) && !witcher.runeword10TriggerredOnFinisher && ((bool)theGame.GetInGameConfigWrapper().GetVarValue('Gameplay', 'AutomaticFinishersEnabled')) == true)
{
witcher.Runeword10Triggerred();
witcher.runeword10TriggerredOnFinisher = true;
}
else if(HasAbility('Runeword 12 _Stats', true) && !witcher.runeword12TriggerredOnFinisher)
{
witcher.Runeword12Triggerred();
witcher.runeword12TriggerredOnFinisher = true;
}
}
}

//pad vibration light
event OnAnimEvent_pad_vibration_light( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
//theGame.VibrateControllerLight(); //draw & sheathe weapon
}

event OnAnimEvent_KillWithRagdoll( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
//thePlayer.SetKinematic( false );
//thePlayer.Kill();
}

event OnAnimEvent_RemoveBurning( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
thePlayer.AddBuffImmunity(EET_Burning, 'AnimEvent_RemoveBurning', true);
}

event OnAnimEvent_RemoveTangled( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if ( this.HasBuff( EET_Tangled ) )
{
this.StopEffect('black_spider_web');
this.PlayEffectSingle('black_spider_web_break');
}
}
///////////////////////////////////////////////////////////////////////////

event OnBehaviorGraphNotification( notificationName : name, stateName : name )
{
substateManager.OnBehaviorGraphNotification( notificationName, stateName );

if( notificationName == 'PlayerRunActivate' )
{
isInRunAnimation = true;
}
else if( notificationName == 'PlayerRunDeactivate' )
{
isInRunAnimation = false;
}
}

event OnEnumAnimEvent( animEventName : name, variant : SEnumVariant, animEventType : EAnimationEventType, animEventDuration : float, animInfo : SAnimationEventAnimInfo )
{
var movementAdjustor : CMovementAdjustor;
var ticket : SMovementAdjustmentRequestTicket;
var rotationRate : ERotationRate;

if ( animEventName == 'RotateToTarget' )
{
/**
* Rotate player to target
*/
rotationRate = GetRotationRateFromAnimEvent( variant.enumValue );

movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
if ( animEventType == AET_DurationStart || animEventType == AET_DurationStartInTheMiddle )
{
// when it starts (also in the middle - it may mean that we switch between events)
// create request if there isn't any and always setup rotation rate
if (! movementAdjustor.IsRequestActive( movementAdjustor.GetRequest( 'RotateToTarget' ) ) )
{
// start rotation adjustment
ticket = movementAdjustor.CreateNewRequest( 'RotateToTarget' );

// use adjustment duration only when RR_0 is selected, otherwise use continuous to match desired rotation as fast as possible
if ((int)rotationRate == 0)
movementAdjustor.AdjustmentDuration( ticket, animEventDuration );
else
{
movementAdjustor.Continuous( ticket );
movementAdjustor.BindToEvent( ticket, 'RotateToTarget' );
}

movementAdjustor.DontUseSourceAnimation( ticket ); // do not use source anim as it will use delta seconds from event
movementAdjustor.ReplaceRotation( ticket );
}
else
{
// get existing ticket to update rotation rate
ticket = movementAdjustor.GetRequest( 'RotateToTarget' );
}
MovAdjRotateToTarget( ticket );
// update rotationRate
if ((int)rotationRate > 0)
{
movementAdjustor.MaxRotationAdjustmentSpeed( ticket, (float)((int)rotationRate) );
}
}
else if ( animEventType == AET_DurationEnd )
{
// it will end if there's no event, but sometimes one event could end and be followed by another
// and we want to have that continuity kept, that's why we won't end request manually
}
else
{
// continuous update (makes more sense when there is no target and we want to rotate towards camera)
ticket = movementAdjustor.GetRequest( 'RotateToTarget' );
MovAdjRotateToTarget( ticket );
}
}
super.OnEnumAnimEvent(animEventName, variant, animEventType, animEventDuration, animInfo);
}

event OnTeleported()
{
if( substateManager )
{
substateManager.OnTeleported();
}
}

/*public function CaptureSafePosition()
{
lastSafePosition = GetWorldPosition();
lastSafeRotation = GetWorldRotation();
safePositionStored = true;
}*/

///////////////////////////////////////////////////////////////////////////
// FISTFIGHT
///////////////////////////////////////////////////////////////////////////
event OnStartFistfightMinigame()
{
super.OnStartFistfightMinigame();

//Goto state CombatFist
SetFistFightMinigameEnabled( true );
FistFightHealthChange( true );
thePlayer.GetPlayerMode().ForceCombatMode( FCMR_QuestFunction );
SetImmortalityMode(AIM_Unconscious, AIC_Fistfight);
thePlayer.SetBehaviorVariable( 'playerWeaponLatent', (int)PW_Fists );
GotoCombatStateWithAction( IA_None );
((CMovingAgentComponent)this.GetMovingAgentComponent()).SnapToNavigableSpace( true );
EquipGeraltFistfightWeapon( true );
BlockAction( EIAB_RadialMenu, 'FistfightMinigame' ,,true);
BlockAction( EIAB_Signs, 'FistfightMinigame' ,,true);
BlockAction( EIAB_ThrowBomb, 'FistfightMinigame' ,,true);
BlockAction( EIAB_UsableItem, 'FistfightMinigame' ,,true);
BlockAction( EIAB_Crossbow, 'FistfightMinigame' ,,true);
BlockAction( EIAB_DrawWeapon, 'FistfightMinigame' ,,true);
BlockAction( EIAB_RunAndSprint, 'FistfightMinigame' ,,true);
BlockAction( EIAB_SwordAttack, 'FistfightMinigame' ,,true);
BlockAction( EIAB_CallHorse, 'FistfightMinigame' ,,true);
BlockAction( EIAB_Roll, 'FistfightMinigame' ,,true);
BlockAction( EIAB_Interactions, 'FistfightMinigame' ,,true);
BlockAction( EIAB_Explorations, 'FistfightMinigame' ,,true);
BlockAction( EIAB_OpenInventory, 'FistfightMinigame' ,,true);
BlockAction( EIAB_QuickSlots, 'FistfightMinigame' ,,true);
BlockAction( EIAB_OpenCharacterPanel, 'FistfightMinigame' ,,true);
}

event OnEndFistfightMinigame()
{
((CMovingAgentComponent)this.GetMovingAgentComponent()).SnapToNavigableSpace( false );
FistFightHealthChange( false );
thePlayer.GetPlayerMode().ReleaseForceCombatMode( FCMR_QuestFunction );
EquipGeraltFistfightWeapon( false );
SetFistFightMinigameEnabled( false );
SetImmortalityMode(AIM_None, AIC_Fistfight);
BlockAllActions('FistfightMinigame',false);

super.OnEndFistfightMinigame();
}

public function GetFistFightFinisher( out masterAnimName, slaveAnimIndex : name )
{
var index : int;

index = RandRange(1);
switch ( index )
{
case 0 : masterAnimName = 'man_fistfight_finisher_1_win'; slaveAnimIndex = 'man_fistfight_finisher_1_looser';
}
}

public function SetFistFightMinigameEnabled( flag : bool )
{
fistFightMinigameEnabled = flag;
}

public function SetFistFightParams( toDeath : bool, endsWithBS : bool )
{
isFFMinigameToTheDeath = toDeath;
FFMinigameEndsithBS = endsWithBS;
}

public function IsFistFightMinigameEnabled() : bool
{
return fistFightMinigameEnabled;
}

public function IsFistFightMinigameToTheDeath() : bool
{
return isFFMinigameToTheDeath;
}

public function FistFightHealthChange( val : bool )
{
if( val == true )
{
GeraltMaxHealth = thePlayer.GetStatMax(BCS_Vitality);
ClampGeraltMaxHealth( 2000 );
SetHealthPerc( 100 );
}
else
{
ClampGeraltMaxHealth( GeraltMaxHealth );
SetHealthPerc( 100 );
}

}

function ClampGeraltMaxHealth( val : float )
{
thePlayer.abilityManager.SetStatPointMax( BCS_Vitality, val );
}

function EquipGeraltFistfightWeapon( val : bool )
{
if ( val )
{
fistsItems = thePlayer.GetInventory().AddAnItem( 'Geralt Fistfight Fists', 1, true, true );
thePlayer.GetInventory().MountItem( fistsItems[0] , true );
}
else
{
thePlayer.GetInventory().DropItem( fistsItems[0], true );
}
}

///////////////////////////////////////////////////////////////////////////
// GWINT
///////////////////////////////////////////////////////////////////////////
public function GetGwintAiDifficulty() : EGwintDifficultyMode
{
return gwintAiDifficulty;
}

public function SetGwintAiDifficulty( difficulty : EGwintDifficultyMode )
{
gwintAiDifficulty = difficulty;
}

public function GetGwintAiAggression() : EGwintAggressionMode
{
return gwintAiAggression;
}

public function SetGwintAiAggression( aggression : EGwintAggressionMode )
{
gwintAiAggression = aggression;
}

public function GetGwintMinigameState() : EMinigameState
{
return gwintMinigameState;
}

public function SetGwintMinigameState( minigameState : EMinigameState )
{
gwintMinigameState = minigameState;
}

public function OnGwintGameRequested( deckName : name )
{
var gwintManager:CR4GwintManager;
gwintManager = theGame.GetGwintManager();

gwintMinigameState = EMS_None;

gwintManager.SetEnemyDeckByName(deckName);

if (gwintManager.GetHasDoneTutorial() || !theGame.GetTutorialSystem().AreMessagesEnabled())
{
gwintManager.gameRequested = true;
theGame.RequestMenu( 'DeckBuilder' );
}
else
{
theGame.RequestMenu( 'GwintGame' );
}
}

private var gwintCardNumbersArray : array;

public function InitGwintCardNumbersArray( arr : array )
{
gwintCardNumbersArray.Clear();
gwintCardNumbersArray = arr;
}

public function GetCardNumbersArray() : array
{
return gwintCardNumbersArray;
}
///////////////////////////////////////////////////////////////////////////
// COMBAT CAMERA
///////////////////////////////////////////////////////////////////////////

protected var customCameraStack : array;

public function AddCustomCamToStack( customCameraParams : SCustomCameraParams ) : int
{
if( customCameraParams.useCustomCamera )
{
if ( customCameraParams.cameraParams.enums[0].enumType != 'ECustomCameraType' )
{
LogChannel( 'CustomCamera', "ERROR: Selected enum is not a custom camera!!!" );
return -1;
}
else
{
customCameraStack.PushBack( customCameraParams );
return ( customCameraStack.Size() - 1 );
}
}

return 0;
}

public function DisableCustomCamInStack( customCameraStackIndex : int )
{
if ( customCameraStackIndex != -1 )
customCameraStack[customCameraStackIndex].useCustomCamera = false;
else
LogChannel( 'CustomCamera', "ERROR: Custom camera to disable does not exist!!!" );
}

event OnInteriorStateChanged( inInterior : bool )
{
interiorCamera = inInterior;
}

event OnModifyPlayerSpeed( flag : bool )
{
modifyPlayerSpeed = flag;
SetBehaviorVariable( 'modifyPlayerSpeed', (float)modifyPlayerSpeed );
}

event OnGameCameraTick( out moveData : SCameraMovementData, dt : float )
{
var targetRotation : EulerAngles;
/*var dist : float;

if( thePlayer.IsInCombat() )
{
dist = VecDistance2D( thePlayer.GetWorldPosition(), thePlayer.GetTarget().GetWorldPosition() );
thePlayer.GetVisualDebug().AddText( 'dbg', dist, thePlayer.GetWorldPosition() + Vector( 0.f,0.f,2.f ), true, , Color( 0, 255, 0 ) );
}*/

if ( isStartingFistFightMinigame )
{
moveData.pivotRotationValue = fistFightTeleportNode.GetWorldRotation();
isStartingFistFightMinigame = false;
}

// Specific substate
if( substateManager.UpdateCameraIfNeeded( moveData, dt ) )
{
return true;
}

// focusMode camera
if ( theGame.IsFocusModeActive() )
{
theGame.GetGameCamera().ChangePivotRotationController( 'Exploration' );
theGame.GetGameCamera().ChangePivotDistanceController( 'Default' );
theGame.GetGameCamera().ChangePivotPositionController( 'Default' );

// HACK
moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController();
moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController();
moveData.pivotPositionController = theGame.GetGameCamera().GetActivePivotPositionController();
// END HACK


moveData.pivotPositionController.SetDesiredPosition( thePlayer.GetWorldPosition() );

moveData.pivotRotationController.SetDesiredPitch( -10.0f );
moveData.pivotRotationController.maxPitch = 50.0;

moveData.pivotDistanceController.SetDesiredDistance( 3.5f );

if ( !interiorCamera )
{
moveData.pivotPositionController.offsetZ = 1.5f;
DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( 0.5f, 2.0f, 0.3f ), 0.20f, dt );
}
else
{
moveData.pivotPositionController.offsetZ = 1.3f;
DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( 0.5f, 2.3f, 0.5f ), 0.3f, dt );
}

return true;
}



// HACK: Target heading ( Made for ladder )
if( substateManager.m_SharedDataO.IsForceHeading( targetRotation ) )
{
moveData.pivotRotationController.SetDesiredHeading( targetRotation.Yaw );
moveData.pivotRotationController.SetDesiredPitch( targetRotation.Pitch );
moveData.pivotRotationValue.Yaw = LerpAngleF( 2.1f * dt, moveData.pivotRotationValue.Yaw, targetRotation.Yaw );
moveData.pivotRotationValue.Pitch = LerpAngleF( 1.0f * dt, moveData.pivotRotationValue.Pitch, targetRotation.Pitch );
//return true;
}


if( customCameraStack.Size() > 0 )
{
// HANDLE CUSTOM CAMERAS HERE
// IF HANDLED - RETURN TRUE
}

return false;
}

private var questCameraRequest : SQuestCameraRequest;
private var cameraRequestTimeStamp : float;

public function RequestQuestCamera( camera : SQuestCameraRequest )
{
questCameraRequest = camera;
questCameraRequest.requestTimeStamp = theGame.GetEngineTimeAsSeconds();
}

public function ResetQuestCameraRequest()
{
var cameraRequest : SQuestCameraRequest;

questCameraRequest = cameraRequest;
}

event OnGameCameraPostTick( out moveData : SCameraMovementData, dt : float )
{
var ent : CEntity;
var playerPos : Vector;
var angles : EulerAngles;

var distance : float;

/*if( thePlayer.IsInCombat() )
{
distance = VecDistance2D( thePlayer.GetWorldPosition(), thePlayer.GetTarget().GetWorldPosition() );
}

thePlayer.GetVisualDebug().AddText( 'Distance', "Distance form target: " + distance, thePlayer.GetWorldPosition() + Vector( 0.f,0.f,2.f ), true, , Color( 0, 255, 0 ) );
*/

if ( questCameraRequest.requestTimeStamp > 0 )
{
if ( questCameraRequest.duration > 0 && questCameraRequest.requestTimeStamp + questCameraRequest.duration < theGame.GetEngineTimeAsSeconds() )
{
ResetQuestCameraRequest();
return false;
}

if( questCameraRequest.lookAtTag )
{
ent = theGame.GetEntityByTag( questCameraRequest.lookAtTag );
playerPos = GetWorldPosition();
playerPos.Z += 1.8f;

angles = VecToRotation( ent.GetWorldPosition() - playerPos );

moveData.pivotRotationController.SetDesiredHeading( angles.Yaw );
moveData.pivotRotationController.SetDesiredPitch( -angles.Pitch );
}
else
{
if( questCameraRequest.requestYaw )
{
angles = GetWorldRotation();
moveData.pivotRotationController.SetDesiredHeading( angles.Yaw + questCameraRequest.yaw );
}

if( questCameraRequest.requestPitch )
{
moveData.pivotRotationController.SetDesiredPitch( questCameraRequest.pitch );
}
}
}
}

var wasRunning : bool;
var vel : float;
var smoothTime : float;

var constDamper : ConstDamper;
var rotMultVel : float;

public function UpdateCameraInterior( out moveData : SCameraMovementData, timeDelta : float )
{
var camDist : float;
var camOffset : float;
var rotMultDest : float;
var rotMult : float;
var angles : EulerAngles;

theGame.GetGameCamera().ChangePivotRotationController( 'ExplorationInterior' );
theGame.GetGameCamera().ChangePivotDistanceController( 'Default' );
theGame.GetGameCamera().ChangePivotPositionController( 'Default' );

// HACK
moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController();
moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController();
moveData.pivotPositionController = theGame.GetGameCamera().GetActivePivotPositionController();
// END HACK

moveData.pivotPositionController.SetDesiredPosition( GetWorldPosition(), 15.f );

if ( !constDamper )
{
constDamper = new ConstDamper in this;
constDamper.SetDamp( 0.35f );
}

if ( rawPlayerSpeed <= 0 || AbsF( AngleDistance( rawPlayerHeading, GetHeading() ) ) > 135 )
constDamper.Reset();
else if ( theGame.IsUberMovementEnabled() )
rotMult = 0.5f;
else
rotMult = 1.f;

rotMult = constDamper.UpdateAndGet( timeDelta, rotMult );

//DampFloatSpring( rotMult, rotMultVel, rotMultDest, 4.f, timeDelta );

if ( AbsF( AngleDistance( GetHeading(), moveData.pivotRotationValue.Yaw ) ) < 135.f && rawPlayerSpeed > 0 )
moveData.pivotRotationController.SetDesiredHeading( GetHeading(), rotMult );
else
moveData.pivotRotationController.SetDesiredHeading( moveData.pivotRotationValue.Yaw );

moveData.pivotDistanceController.SetDesiredDistance( 1.5f );

angles = VecToRotation( GetMovingAgentComponent().GetVelocity() );
if ( AbsF( angles.Pitch ) < 8.f || bLAxisReleased )
moveData.pivotRotationController.SetDesiredPitch( -10.f );
else
moveData.pivotRotationController.SetDesiredPitch( -angles.Pitch - 18.f );

if ( IsGuarded() )
moveData.pivotPositionController.offsetZ = 1.0f;
else
moveData.pivotPositionController.offsetZ = 1.3f;

//if ( movementLockType == PMLT_NoSprint )
//{
if ( playerMoveType >= PMT_Run )
{
//camDist = 0.3f;
camDist = -0.5f;
camOffset = 0.25;

if ( !wasRunning )
{
smoothTime = 1.f;
wasRunning = true;
}
DampFloatSpring( smoothTime, vel, 0.1, 0.5, timeDelta );
}
else
{
//camDist = -0.6f;
camDist = 0.f;
camOffset = 0.4f;
smoothTime = 0.2f;
wasRunning = false;
}

//camDist = theGame.GetGameplayConfigFloatValue( 'debugA' );

DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( 0.3f, camDist, 0.3f ), smoothTime, timeDelta );
//DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( 0.5, camDist, camOffset ), smoothTime, timeDelta );
//}
//else
// DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( theGame.GetGameplayConfigFloatValue( 'debugA' ),theGame.GetGameplayConfigFloatValue( 'debugB' ),theGame.GetGameplayConfigFloatValue( 'debugC' ) ), 0.4f, timeDelta );
//DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( 0.7f, 0.f, 0.3 ), 0.4f, timeDelta );
}


var wasBRAxisPushed : bool;
protected function UpdateCameraChanneledSign( out moveData : SCameraMovementData, timeDelta : float ) : bool
{
var screenSpaceOffset : float;
var screenSpaceOffsetFwd : float;
var screenSpaceOffsetUp : float;
var heading : float;
var pitch : float;
var playerToTargetRot : EulerAngles;
var rightOffset : float = -20.f;
var leftOffset : float = 15.f;
var angles : EulerAngles;

var vec : Vector;

if( this.IsCurrentSignChanneled() && this.GetCurrentlyCastSign() != ST_Quen && this.GetCurrentlyCastSign() != ST_Yrden )
{
theGame.GetGameCamera().ChangePivotRotationController( 'SignChannel' );
theGame.GetGameCamera().ChangePivotDistanceController( 'SignChannel' );
// HACK
moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController();
moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController();
// END HACK

if ( GetCurrentlyCastSign() == ST_Axii )
leftOffset = 32.f;

if ( oTCameraOffset != leftOffset && oTCameraOffset != rightOffset )
{
if( ( interiorCamera && !moveTarget )
|| ( AngleDistance( GetHeading(), moveData.pivotRotationValue.Yaw ) < 0 ) )
oTCameraOffset = leftOffset;
else
oTCameraOffset = rightOffset;
}

if ( oTCameraOffset == leftOffset )
{
screenSpaceOffset = 0.65f;
oTCameraPitchOffset = 13.f;
//moveData.pivotDistanceController.SetDesiredDistance( 0.5f, 3.f );
}
else if ( oTCameraOffset == rightOffset )
{
screenSpaceOffset = -0.65f;
oTCameraPitchOffset = 13.f;
//moveData.pivotDistanceController.SetDesiredDistance( 0.5f, 3.f );
}

moveData.pivotPositionController.offsetZ = 1.3f;

if ( !delayCameraOrientationChange )
{
if ( GetOrientationTarget() == OT_Camera || GetOrientationTarget() == OT_CameraOffset )
{
if ( bRAxisReleased )
{
heading = moveData.pivotRotationValue.Yaw;
pitch = moveData.pivotRotationValue.Pitch;
}
else
{
heading = moveData.pivotRotationValue.Yaw + oTCameraOffset;
pitch = moveData.pivotRotationValue.Pitch; //+ oTCameraPitchOffset;
}
}
else if ( GetOrientationTarget() == OT_Actor )
{
if ( GetDisplayTarget() )
vec = GetDisplayTarget().GetWorldPosition() - GetWorldPosition();
else if ( slideTarget )
vec = slideTarget.GetWorldPosition() - GetWorldPosition();
else if ( GetTarget() )
vec = GetTarget().GetWorldPosition() - GetWorldPosition();
else
vec = GetHeadingVector();

angles = VecToRotation( vec );
heading = angles.Yaw + oTCameraOffset;
pitch = -angles.Pitch - oTCameraPitchOffset;//-angles.Pitch;
}
else
{
angles = VecToRotation( GetHeadingVector() );
heading = angles.Yaw + oTCameraOffset;
pitch = -angles.Pitch - oTCameraPitchOffset;//-angles.Pitch;
}

if ( !wasBRAxisPushed && ( !bRAxisReleased ) )//|| !lastAxisInputIsMovement ) )
wasBRAxisPushed = true;

moveData.pivotRotationController.SetDesiredHeading( heading , 2.f );
moveData.pivotRotationController.SetDesiredPitch( pitch );
}
else
{
moveData.pivotRotationController.SetDesiredHeading( moveData.pivotRotationValue.Yaw, 1.f );
moveData.pivotRotationController.SetDesiredPitch( -oTCameraPitchOffset );
}

if ( moveData.pivotRotationValue.Pitch <= 5.f && moveData.pivotRotationValue.Pitch >= -15.f )
{
screenSpaceOffsetFwd = 1.8;
screenSpaceOffsetUp = 0.4;
}
else if ( moveData.pivotRotationValue.Pitch > 0 )
{
screenSpaceOffsetFwd = moveData.pivotRotationValue.Pitch*0.00727 + 1.275f;
screenSpaceOffsetFwd = ClampF( screenSpaceOffsetFwd, 1.5, 2.2 );

screenSpaceOffsetUp = -moveData.pivotRotationValue.Pitch*0.00727 + 0.4363f;
screenSpaceOffsetUp = ClampF( screenSpaceOffsetUp, 0, 0.3 );
}
else
{
if ( GetCurrentlyCastSign() == ST_Axii )
{
screenSpaceOffsetFwd = -moveData.pivotRotationValue.Pitch*0.0425 + 0.8625f;
screenSpaceOffsetFwd = ClampF( screenSpaceOffsetFwd, 1.5, 2.3 );
}
else
{
screenSpaceOffsetFwd = -moveData.pivotRotationValue.Pitch*0.035 + 0.75f;
screenSpaceOffsetFwd = ClampF( screenSpaceOffsetFwd, 1.5, 2.6 );
}
screenSpaceOffsetUp = -moveData.pivotRotationValue.Pitch*0.005 + 0.325f;
screenSpaceOffsetUp = ClampF( screenSpaceOffsetUp, 0.4, 0.5 );
}

DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( screenSpaceOffset, screenSpaceOffsetFwd, screenSpaceOffsetUp ), 0.25f, timeDelta );//1.5,0.4
moveData.pivotDistanceController.SetDesiredDistance( 2.8f, 5.f );
moveData.pivotPositionController.SetDesiredPosition( GetWorldPosition() );

return true;
}
else
{
this.wasBRAxisPushed = false;

return false;
}
}

protected function UpdateCameraForSpecialAttack( out moveData : SCameraMovementData, timeDelta : float ) : bool
{
var screenSpaceOffset : float;
var tempHeading : float;
var cameraOffsetLeft : float;
var cameraOffsetRight : float;

if ( !specialAttackCamera )
return false;

theGame.GetGameCamera().ForceManualControlHorTimeout();
theGame.GetGameCamera().ForceManualControlVerTimeout();
//if ( parent.delayCameraOrientationChange || parent.delayOrientationChange )
//{
cameraOffsetLeft = 30.f;
cameraOffsetRight = -30.f;
//}
//else
//{
// cameraOffsetLeft = 2.f;
// cameraOffsetRight = -2.f;
//}

theGame.GetGameCamera().ChangePivotRotationController( 'SignChannel' );
theGame.GetGameCamera().ChangePivotDistanceController( 'SignChannel' );
// HACK
moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController();
moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController();

if ( slideTarget )
tempHeading = VecHeading( slideTarget.GetWorldPosition() - GetWorldPosition() );
else
tempHeading = GetHeading();

oTCameraPitchOffset = 0.f;

if( ( interiorCamera && !moveTarget )
|| ( AngleDistance( tempHeading, moveData.pivotRotationValue.Yaw ) < 0 ) )
oTCameraOffset = cameraOffsetLeft;
else
oTCameraOffset = cameraOffsetRight;

if ( oTCameraOffset == cameraOffsetLeft )
{
if ( delayCameraOrientationChange || delayOrientationChange )
{
screenSpaceOffset = 0.75f;
moveData.pivotDistanceController.SetDesiredDistance( 1.6f, 3.f );
moveData.pivotPositionController.offsetZ = 1.4f;
moveData.pivotRotationController.SetDesiredPitch( -15.f );
}
else
{
screenSpaceOffset = 0.7f;
moveData.pivotDistanceController.SetDesiredDistance( 3.25f );
moveData.pivotPositionController.offsetZ = 1.2f;
moveData.pivotRotationController.SetDesiredPitch( -10.f );
}
}
else if ( oTCameraOffset == cameraOffsetRight )
{
if ( delayCameraOrientationChange || delayOrientationChange )
{
screenSpaceOffset = -0.85f;
moveData.pivotDistanceController.SetDesiredDistance( 1.6f, 3.f );
moveData.pivotPositionController.offsetZ = 1.4f;
moveData.pivotRotationController.SetDesiredPitch( -15.f );
}
else
{
screenSpaceOffset = -0.8f;
moveData.pivotDistanceController.SetDesiredDistance( 3.25f );
moveData.pivotPositionController.offsetZ = 1.2f;
moveData.pivotRotationController.SetDesiredPitch( -10.f );
}
}
else
{
moveData.pivotDistanceController.SetDesiredDistance( 1.25f, 3.f );
moveData.pivotPositionController.offsetZ = 1.3f;
moveData.pivotRotationController.SetDesiredPitch( -5.5f );
}

DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( screenSpaceOffset, 0.f, 0.f ), 1.f, timeDelta );

if ( !delayCameraOrientationChange )
{
if ( moveTarget )
moveData.pivotRotationController.SetDesiredHeading( GetHeading() + oTCameraOffset, 0.5f );
else
moveData.pivotRotationController.SetDesiredHeading( GetHeading() + oTCameraOffset, 1.f );
}
else
moveData.pivotRotationController.SetDesiredHeading( moveData.pivotRotationValue.Yaw, 1.f );

moveData.pivotPositionController.SetDesiredPosition( GetWorldPosition() );

return true;
}


private var fovVel : float;
private var sprintOffset : Vector;
private var previousOffset : bool;
private var previousRotationVelocity : float;
private var pivotRotationTimeStamp : float;
protected function UpdateCameraSprint( out moveData : SCameraMovementData, timeDelta : float )
{
var angleDiff : float;
var camOffsetVector : Vector;
var smoothSpeed : float;
var camera : CCustomCamera;
var camAngularSpeed : float;

var playerToCamAngle : float;
var useExplorationSprintCam : bool;

camera = theGame.GetGameCamera();
if( camera )
{
if ( sprintingCamera )
{
//theGame.GetGameCamera().ForceManualControlHorTimeout();
theGame.GetGameCamera().ForceManualControlVerTimeout();

playerToCamAngle = AbsF( AngleDistance( GetHeading(), moveData.pivotRotationValue.Yaw ) );

/*if ( theGame.GetGameplayConfigFloatValue( 'debugE' ) > 0.1f )
useExplorationSprintCam = !IsInCombat() || ( moveTarget && VecDistance( moveTarget.GetWorldPosition(), GetWorldPosition() ) > findMoveTargetDistMax );
else*/
useExplorationSprintCam = false;// !IsInCombat() || ( moveTarget && VecDistance( moveTarget.GetWorldPosition(), GetWorldPosition() ) > findMoveTargetDistMax );

if ( useExplorationSprintCam )
{
if ( playerToCamAngle <= 45 )
{
theGame.GetGameCamera().ChangePivotRotationController( 'Sprint' );
// HACK
moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController();

moveData.pivotRotationController.SetDesiredHeading( GetHeading(), 0.25f );
moveData.pivotRotationController.SetDesiredPitch( -3.5f, 0.5f );
thePlayer.EnableManualCameraControl( true, 'Sprint' );
}
else
{
thePlayer.EnableManualCameraControl( false, 'Sprint' );
}
}
else
{
if ( theGame.IsUberMovementEnabled() )
moveData.pivotRotationController.SetDesiredHeading( GetHeading(), 0.35f );

thePlayer.EnableManualCameraControl( true, 'Sprint' );
}

if ( bRAxisReleased )
{
if ( AbsF( rawLeftJoyRot ) > 25 )
angleDiff = AngleDistance( GetHeading(), moveData.pivotRotationValue.Yaw );

pivotRotationTimeStamp = theGame.GetEngineTimeAsSeconds();
previousRotationVelocity = 0.f;
}
else
{
if ( previousRotationVelocity <= 0 && AbsF( moveData.pivotRotationVelocity.Yaw ) > 250 )
{
pivotRotationTimeStamp = theGame.GetEngineTimeAsSeconds();
previousRotationVelocity = AbsF( moveData.pivotRotationVelocity.Yaw );
}
}

if ( pivotRotationTimeStamp + 0.4f <= theGame.GetEngineTimeAsSeconds() && AbsF( moveData.pivotRotationVelocity.Yaw ) > 250 )
angleDiff = VecHeading( rawRightJoyVec );

if ( useExplorationSprintCam )
{
if ( playerToCamAngle > 90 )
{
camOffsetVector.X = 0.f;
smoothSpeed = 1.f;
}
else if ( angleDiff > 15.f )
{
camOffsetVector.X = -0.8;
smoothSpeed = 1.f;
previousOffset = true;
}
else if ( angleDiff < -15.f )
{
camOffsetVector.X = 0.475f;
smoothSpeed = 1.5f;
previousOffset = false;
}
else
{
if ( previousOffset )
{
camOffsetVector.X = -0.8;
smoothSpeed = 1.5f;
}
else
{
camOffsetVector.X = 0.475f;
smoothSpeed = 1.5f;
}
}

camOffsetVector.Y = 1.4f;
camOffsetVector.Z = 0.275f;
}
else
{
/*camOffsetVector.X = 0.f;
camOffsetVector.Y = 0.4f;
camOffsetVector.Z = 0.2f;*/
smoothSpeed = 0.75f;

camOffsetVector.X = 0.f;
camOffsetVector.Y = 1.f;
camOffsetVector.Z = 0.2f;
moveData.pivotRotationController.SetDesiredPitch( -10.f, 0.5f );
}

DampVectorConst( sprintOffset, camOffsetVector, smoothSpeed, timeDelta );

moveData.cameraLocalSpaceOffset = sprintOffset;

DampFloatSpring( camera.fov, fovVel, 70.f, 1.0, timeDelta );
}
else
{
sprintOffset = moveData.cameraLocalSpaceOffset;
DampFloatSpring( camera.fov, fovVel, 60.f, 1.0, timeDelta );
previousOffset = false;
}
}
}

function EnableSprintingCamera( flag : bool )
{
if( !theGame.IsUberMovementEnabled() && !useSprintingCameraAnim )
{
return;
}

super.EnableSprintingCamera( flag );

if ( !flag )
{
thePlayer.EnableManualCameraControl( true, 'Sprint' );
}
}

protected function UpdateCameraCombatActionButNotInCombat( out moveData : SCameraMovementData, timeDelta : float )
{
var vel : Vector;
var heading : float;
var pitch : float;
var headingMult : float;
var pitchMult : float;
var camOffset : Vector;
var buff : CBaseGameplayEffect;
var runningAndAlertNear : bool;
var desiredDist : float;

if ( ( !IsCurrentSignChanneled() || GetCurrentlyCastSign() == ST_Quen || GetCurrentlyCastSign() == ST_Yrden ) && !specialAttackCamera && !IsInCombatActionFriendly() )
{
buff = GetCurrentlyAnimatedCS();
runningAndAlertNear = GetPlayerCombatStance() == PCS_AlertNear && playerMoveType == PMT_Run && !GetDisplayTarget();
if ( runningAndAlertNear ||
( GetPlayerCombatStance() == PCS_AlertFar && !IsInCombatAction() && !buff ) )
{
camOffset.X = 0.f;
camOffset.Y = 0.f;
camOffset.Z = -0.1f;

if ( runningAndAlertNear )
{
moveData.pivotDistanceController.SetDesiredDistance( 4.f );
moveData.pivotPositionController.offsetZ = 1.5f;
}
}
else
{
camOffset.X = 0.f;
camOffset.Y = -1.5f;
camOffset.Z = -0.2f;
}

DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( camOffset.X, camOffset.Y, camOffset.Z ), 0.4f, timeDelta );
sprintOffset = moveData.cameraLocalSpaceOffset;
heading = moveData.pivotRotationValue.Yaw;

if ( GetOrientationTarget() == OT_Camera || GetOrientationTarget() == OT_CameraOffset )
pitch = moveData.pivotRotationValue.Pitch;
else if ( lastAxisInputIsMovement
|| GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack
|| GetBehaviorVariable( 'combatActionType' ) == (int)CAT_SpecialAttack
|| ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_CastSign && !IsCurrentSignChanneled() && GetCurrentlyCastSign() == ST_Quen ) )
{
theGame.GetGameCamera().ForceManualControlVerTimeout();
pitch = -20.f;
}
else
pitch = moveData.pivotRotationValue.Pitch;

headingMult = 1.f;
pitchMult = 1.f;

//if( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack )
if( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_CastSign
&& ( GetEquippedSign() == ST_Aard || GetEquippedSign() == ST_Yrden )
&& GetBehaviorVariable( 'alternateSignCast' ) == 1 )
{
//theGame.GetGameCamera().ForceManualControlHorTimeout();
theGame.GetGameCamera().ForceManualControlVerTimeout();
pitch = -20.f;

//DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( theGame.GetGameplayConfigFloatValue( 'debugA' ), theGame.GetGameplayConfigFloatValue( 'debugB' ), theGame.GetGameplayConfigFloatValue( 'debugC' ) ), 0.4f, timeDelta );
}

//vel = GetMovingAgentComponent().GetVelocity();
//if ( VecLength( vel ) > 0 && GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Dodge )
//{
/*theGame.GetGameCamera().ForceManualControlHorTimeout();
heading = GetHeading();
headingMult = 0.5f;*/
//}

if ( IsCurrentSignChanneled() && GetCurrentlyCastSign() == ST_Quen )
{
pitch = moveData.pivotRotationValue.Pitch;
}

moveData.pivotRotationController.SetDesiredHeading( heading, );
moveData.pivotRotationController.SetDesiredPitch( pitch );
}
}

/*public function UpdateCameraForSpecialAttack( out moveData : SCameraMovementData, timeDelta : float ) : bool
{
return false;
}*/
//------------------------------------------------------------------------------------------------------------------
event OnGameCameraExplorationRotCtrlChange()
{
if( substateManager )
{
return substateManager.OnGameCameraExplorationRotCtrlChange( );
}

return false;
}

///////////////////////////////////////////////////////////////////////////
// COMBAT MOVEMENT ORIENTATION
///////////////////////////////////////////////////////////////////////////

//Rotation
function SetCustomRotation( customRotationName : name, rotHeading : float, rotSpeed : float, activeTime : float, rotateExistingDeltaLocation : bool )
{
var movementAdjustor : CMovementAdjustor;
var ticket : SMovementAdjustmentRequestTicket;

movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
ticket = movementAdjustor.GetRequest( customRotationName );
movementAdjustor.Cancel( ticket );
ticket = movementAdjustor.CreateNewRequest( customRotationName );
movementAdjustor.Continuous( ticket );
movementAdjustor.ReplaceRotation( ticket );
movementAdjustor.RotateTo( ticket, rotHeading );
movementAdjustor.MaxRotationAdjustmentSpeed( ticket, rotSpeed );
if (rotSpeed == 0.0f)
{
movementAdjustor.AdjustmentDuration( ticket, activeTime );
}
movementAdjustor.KeepActiveFor( ticket, activeTime );
movementAdjustor.RotateExistingDeltaLocation( ticket, rotateExistingDeltaLocation );
}

function UpdateCustomRotationHeading( customRotationName : name, rotHeading : float )
{
var movementAdjustor : CMovementAdjustor;
var ticket : SMovementAdjustmentRequestTicket;

movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
ticket = movementAdjustor.GetRequest( customRotationName );
movementAdjustor.RotateTo( ticket, rotHeading );
}

function SetCustomRotationTowards( customRotationName : name, target : CActor, rotSpeed : float, optional activeTime : float )
{
var movementAdjustor : CMovementAdjustor;
var ticket : SMovementAdjustmentRequestTicket;

movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
ticket = movementAdjustor.GetRequest( customRotationName );
movementAdjustor.Cancel( ticket );
ticket = movementAdjustor.CreateNewRequest( customRotationName );
movementAdjustor.Continuous( ticket );
movementAdjustor.ReplaceRotation( ticket );
movementAdjustor.RotateTowards( ticket, target );
movementAdjustor.MaxRotationAdjustmentSpeed( ticket, rotSpeed );
if (activeTime > 0.0f)
{
movementAdjustor.KeepActiveFor( ticket, activeTime );
}
else
{
movementAdjustor.DontEnd( ticket );
}
}

//lock movement in dir
function CustomLockMovement( customMovementName : name, heading : float )
{
var movementAdjustor : CMovementAdjustor;
var ticket : SMovementAdjustmentRequestTicket;

movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
ticket = movementAdjustor.GetRequest( customMovementName );
movementAdjustor.Cancel( ticket );
ticket = movementAdjustor.CreateNewRequest( customMovementName );
movementAdjustor.Continuous( ticket );
movementAdjustor.DontEnd( ticket );
movementAdjustor.LockMovementInDirection( ticket, heading );
}

function BindMovementAdjustmentToEvent( customRotationName : name, eventName : CName )
{
var movementAdjustor : CMovementAdjustor;
var ticket : SMovementAdjustmentRequestTicket;

movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
ticket = movementAdjustor.GetRequest( customRotationName );
movementAdjustor.BindToEvent( ticket, eventName );
}

function UpdateCustomLockMovementHeading( customMovementName : name, heading : float )
{
var movementAdjustor : CMovementAdjustor;
var ticket : SMovementAdjustmentRequestTicket;

movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
ticket = movementAdjustor.GetRequest( customMovementName );
movementAdjustor.LockMovementInDirection( ticket, heading );
}

function CustomLockDistance( customMovementName : name, maintainDistanceTo : CNode, minDist, maxDist : float )
{
var movementAdjustor : CMovementAdjustor;
var ticket : SMovementAdjustmentRequestTicket;

movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
ticket = movementAdjustor.GetRequest( customMovementName );
movementAdjustor.Cancel( ticket );
ticket = movementAdjustor.CreateNewRequest( customMovementName );
movementAdjustor.Continuous( ticket );
movementAdjustor.SlideTowards( ticket, maintainDistanceTo, minDist, maxDist );
}

function UpdateCustomLockDistance( customMovementName : name, maintainDistanceTo : CNode, minDist, maxDist : float )
{
var movementAdjustor : CMovementAdjustor;
var ticket : SMovementAdjustmentRequestTicket;

movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor();
ticket = movementAdjustor.GetRequest( customMovementName );
movementAdjustor.SlideTowards( ticket, maintainDistanceTo, minDist, maxDist );
}

private var disableManualCameraControlStack : array;
public function EnableManualCameraControl( enable : bool, sourceName : name )
{
if ( !enable )
{
if ( !disableManualCameraControlStack.Contains( sourceName ) )
{
disableManualCameraControlStack.PushBack( sourceName );
}
}
else
{
disableManualCameraControlStack.Remove( sourceName );
}

if ( disableManualCameraControlStack.Size() > 0 )
theGame.GetGameCamera().EnableManualControl( false );
else
theGame.GetGameCamera().EnableManualControl( true );
}

public function IsCameraControlDisabled( optional disabledBySourceName : name ) : bool
{
if ( disabledBySourceName )
return disableManualCameraControlStack.Contains( disabledBySourceName );
else
return disableManualCameraControlStack.Size() > 0;
}

public function DisableManualCameraControlStackHasSource( sourceName : name ) : bool
{
return disableManualCameraControlStack.Contains( sourceName );
}

public function ClearDisableManualCameraControlStack()
{
disableManualCameraControlStack.Clear();
theGame.GetGameCamera().EnableManualControl( true );
}

function SetOrientationTarget( target : EOrientationTarget )
{
if ( IsPCModeEnabled() && target == OT_Player )
{
target = OT_Camera;
}

orientationTarget = target;
}

function GetOrientationTarget() : EOrientationTarget
{
return orientationTarget;
}

var customOrientationInfoStack : array;
public function AddCustomOrientationTarget( orientationTarget : EOrientationTarget, sourceName : name )
{
var customOrientationInfo : SCustomOrientationInfo;
var i : int;

if ( customOrientationInfoStack.Size() > 0 )
{
for( i = customOrientationInfoStack.Size()-1; i>=0; i-=1 )
{
if ( customOrientationInfoStack[i].sourceName == sourceName )
customOrientationInfoStack.Erase(i);
}
}

customOrientationInfo.sourceName = sourceName;
customOrientationInfo.orientationTarget = orientationTarget;
customOrientationInfoStack.PushBack( customOrientationInfo );
SetOrientationTarget( orientationTarget );
}

public function RemoveCustomOrientationTarget( sourceName : name )
{
var customOrientationInfo : SCustomOrientationInfo;
var i : int;

if ( customOrientationInfoStack.Size() > 0 )
{
for( i = customOrientationInfoStack.Size()-1; i>=0; i-=1 )
{
if ( customOrientationInfoStack[i].sourceName == sourceName )
customOrientationInfoStack.Erase(i);
}
}
else
LogChannel( 'CustomOrienatation', "ERROR: Custom orientation cannot be removed, stack is already empty!!!" );
}

protected function ClearCustomOrientationInfoStack()
{
customOrientationInfoStack.Clear();
}

protected function GetCustomOrientationTarget( out infoStack : SCustomOrientationInfo ) : bool
{
var size : int;

size = customOrientationInfoStack.Size();

if ( size <= 0 )
return false;
else
{
infoStack = customOrientationInfoStack[ size - 1 ];
return true;
}
}

public function SetOrientationTargetCustomHeading( heading : float, sourceName : name ) : bool
{
var i : int;
if ( customOrientationInfoStack.Size() > 0 )
{
for( i = customOrientationInfoStack.Size()-1; i>=0; i-=1 )
{
if ( customOrientationInfoStack[i].sourceName == sourceName )
{
customOrientationInfoStack[i].customHeading = heading;
return true;
}
}
}

LogChannel( 'SetOrientationTargetCustomHeading', "ERROR: Cannot set customHeading because stack is empty or sourceName is not found!!!" );
return false;
}

// returns the topmost OT_CustomHeading in stack
public function GetOrientationTargetCustomHeading() : float
{
var i : int;
if ( customOrientationInfoStack.Size() > 0 )
{
for( i = customOrientationInfoStack.Size()-1; i>=0; i-=1 )
{
if ( customOrientationInfoStack[i].orientationTarget == OT_CustomHeading )
{
return customOrientationInfoStack[i].customHeading;
}
}
}

LogChannel( 'SetOrientationTargetCustomHeading', "ERROR: Cannot get customHeading because stack is empty or no OT_CustomHeading in stack!!!" );
return -1.f;
}

public function GetCombatActionOrientationTarget( combatActionType : ECombatActionType ) : EOrientationTarget
{
var newCustomOrientationTarget : EOrientationTarget;
var targetEnt : CGameplayEntity;
var targetActor : CActor;

if ( GetCurrentStateName() == 'AimThrow' )
newCustomOrientationTarget = OT_CameraOffset;
else
{
targetEnt = GetDisplayTarget();
targetActor = (CActor)targetEnt;

if ( targetEnt )
{
if ( targetActor )
{
if ( moveTarget )
newCustomOrientationTarget = OT_Actor;
else
{
if ( this.IsSwimming() )
newCustomOrientationTarget = OT_Camera;
else if ( lastAxisInputIsMovement )
newCustomOrientationTarget = OT_Player;
else
newCustomOrientationTarget = OT_Actor;
}
}
else
{
if ( combatActionType == CAT_Crossbow && targetEnt.HasTag( 'softLock_Bolt' ) )
newCustomOrientationTarget = OT_Actor;
else
{
if ( this.IsSwimming() )
newCustomOrientationTarget = OT_Camera;
else if ( lastAxisInputIsMovement )
newCustomOrientationTarget = OT_Player;
else
newCustomOrientationTarget = OT_Camera;

}
}
}
else
{
if ( IsUsingVehicle() )// || this.IsSwimming() )
newCustomOrientationTarget = OT_Camera;
else if ( lastAxisInputIsMovement )
{
if ( this.IsSwimming() )
{
//if ( !bRAxisReleased
// || ( GetOrientationTarget() == OT_Camera && ( this.rangedWeapon.GetCurrentStateName() == 'State_WeaponAim' || this.rangedWeapon.GetCurrentStateName() == 'State_WeaponShoot' ) ) )
newCustomOrientationTarget = OT_Camera;
//else
// newCustomOrientationTarget = OT_CustomHeading;
}
else
newCustomOrientationTarget = OT_Player;

}
else
newCustomOrientationTarget = OT_Camera;
}
}

return newCustomOrientationTarget;
}

public function GetOrientationTargetHeading( orientationTarget : EOrientationTarget ) : float
{
var heading : float;

if( orientationTarget == OT_Camera )
heading = VecHeading( theCamera.GetCameraDirection() );
else if( orientationTarget == OT_CameraOffset )
heading = VecHeading( theCamera.GetCameraDirection() ) - oTCameraOffset;
else if( orientationTarget == OT_CustomHeading )
heading = GetOrientationTargetCustomHeading();
else if ( GetDisplayTarget() && orientationTarget == OT_Actor )
{
if ( (CActor)( GetDisplayTarget() ) )
{
//if ( GetPlayerCombatStance() == PCS_AlertNear )
heading = VecHeading( GetDisplayTarget().GetWorldPosition() - GetWorldPosition() );
//else
// heading = GetHeading();
}
else
{
if ( GetDisplayTarget().HasTag( 'softLock_Bolt' ) )
heading = VecHeading( GetDisplayTarget().GetWorldPosition() - GetWorldPosition() );
else
heading = GetHeading();
}
}
else
heading = GetHeading();

return heading;
}

event OnDelayOrientationChange()
{
var delayOrientation : bool;
var delayCameraRotation : bool;
var moveData : SCameraMovementData;
var time : float;

time = 0.01f;

if ( theInput.GetActionValue( 'CastSignHold' ) == 1.f )
{
actionType = 0;
if ( moveTarget )
delayOrientation = true;
else
{
if ( !GetBIsCombatActionAllowed() )
delayOrientation = true;
}


}
else if ( theInput.GetActionValue( 'ThrowItemHold' ) == 1.f )
{
actionType = 3;
delayOrientation = true;
}
else if ( theInput.GetActionValue( 'SpecialAttackHeavy' ) == 1.f )
{
actionType = 2;
if ( !slideTarget )
delayOrientation = true;
else
delayOrientation = true;
}
else if ( IsGuarded() && !moveTarget )
{
actionType = 1;
delayOrientation = true;
}

if ( delayOrientation )
{
delayOrientationChange = true;
theGame.GetGameCamera().ForceManualControlHorTimeout();
theGame.GetGameCamera().ForceManualControlVerTimeout();
AddTimer( 'DelayOrientationChangeTimer', time, true );
}

if ( delayCameraRotation )
{
delayCameraOrientationChange = true;
theGame.GetGameCamera().ForceManualControlHorTimeout();
theGame.GetGameCamera().ForceManualControlVerTimeout();
AddTimer( 'DelayOrientationChangeTimer', time, true );
}
}

//This is also called from behgraph (e.g. SpecialHeavyAttack)
event OnDelayOrientationChangeOff()
{
delayOrientationChange = false;
delayCameraOrientationChange = false;
RemoveTimer( 'DelayOrientationChangeTimer' );

//if ( !IsCameraLockedToTarget() )
// theGame.GetGameCamera().EnableManualControl( true );
}

timer function DelayOrientationChangeTimer( time : float , id : int)
{
if ( ( actionType == 0 && theInput.GetActionValue( 'CastSignHold' ) == 0.f )
|| ( actionType == 2 && theInput.GetActionValue( 'SpecialAttackHeavy' ) == 0.f )
|| ( actionType == 3 && theInput.GetActionValue( 'ThrowItemHold' ) == 0.f )
|| ( actionType == 1 && !IsGuarded() )
|| ( VecLength( rawRightJoyVec ) > 0.f ) )//&& !( slideTarget && IsInCombatAction() && GetBehaviorVariable( 'combatActionType') == (int)CAT_CastSign && GetCurrentlyCastSign() == ST_Axii ) ) )
{
OnDelayOrientationChangeOff();
}
}

public function SetCombatActionHeading( heading : float )
{
combatActionHeading = heading;
}

public function GetCombatActionHeading() : float
{
return combatActionHeading;
}

protected function EnableCloseCombatCharacterRadius( flag : bool )
{
var actor : CActor;

actor = (CActor)slideTarget;
if ( flag )
{
this.GetMovingAgentComponent().SetVirtualRadius( 'CloseCombatCharacterRadius' );
if(actor)
actor.GetMovingAgentComponent().SetVirtualRadius( 'CloseCombatCharacterRadius' );
}
else
{
if ( this.IsInCombat() )
{
GetMovingAgentComponent().SetVirtualRadius( 'CombatCharacterRadius' );
if(actor)
actor.GetMovingAgentComponent().SetVirtualRadius( 'CombatCharacterRadius' );
}
else
{
this.GetMovingAgentComponent().ResetVirtualRadius();
if(actor)
actor.GetMovingAgentComponent().ResetVirtualRadius();
}
}
}

///////////////////////////////////////////////////////////////////////////
// Soft Lock Logic



private var isSnappedToNavMesh : bool;
private var snapToNavMeshCachedFlag : bool;
public function SnapToNavMesh( flag : bool )
{
var comp : CMovingAgentComponent;

comp = (CMovingAgentComponent)this.GetMovingAgentComponent();

if ( comp )
{
comp.SnapToNavigableSpace( flag );
isSnappedToNavMesh = flag;
}
else
{
snapToNavMeshCachedFlag = flag;
AddTimer( 'DelayedSnapToNavMesh', 0.2f );
}
}

public final function PlayRuneword4FX(optional weaponType : EPlayerWeapon)
{
var hasSwordDrawn : bool;
var sword : SItemUniqueId;

//we show fx only if overheal is greater than 1% - otherwise if we have a DoT and regen at the same time the health
//jumps back and forth between 100% and 99.99% stating and stopping the fx over and over
//needs to have sword drawn
if(abilityManager.GetOverhealBonus() > (0.005 * GetStatMax(BCS_Vitality)))
{
hasSwordDrawn = HasAbility('Runeword 4 _Stats', true);

if(!hasSwordDrawn && GetWitcherPlayer())
{
if(weaponType == PW_Steel)
{
if(GetWitcherPlayer().GetItemEquippedOnSlot(EES_SteelSword, sword))
hasSwordDrawn = inv.ItemHasAbility(sword, 'Runeword 4 _Stats');
}
else if(weaponType == PW_Silver)
{
if(GetWitcherPlayer().GetItemEquippedOnSlot(EES_SilverSword, sword))
hasSwordDrawn = inv.ItemHasAbility(sword, 'Runeword 4 _Stats');
}
}

if(hasSwordDrawn)
{
if(!IsEffectActive('runeword_4', true))
PlayEffect('runeword_4');
}
}
}

timer function DelayedSnapToNavMesh( dt : float, id : int)
{
SnapToNavMesh( snapToNavMeshCachedFlag );
}

saved var navMeshSnapInfoStack : array;
public function EnableSnapToNavMesh( source : name, enable : bool )
{
if ( enable )
{
if ( !navMeshSnapInfoStack.Contains( source ) )
navMeshSnapInfoStack.PushBack( source );
}
else
{
if ( navMeshSnapInfoStack.Contains( source ) )
navMeshSnapInfoStack.Remove( source );
}

if ( navMeshSnapInfoStack.Size() > 0 )
SnapToNavMesh( true );
else
SnapToNavMesh( false );
}

public function ForceRemoveAllNavMeshSnaps()
{
navMeshSnapInfoStack.Clear();
SnapToNavMesh( false );
}

public function CanSprint( speed : float ) : bool
{
if( speed <= 0.8f )
{
return false;
}

if ( thePlayer.GetIsSprintToggled() )
{
}
else if ( !sprintActionPressed )
{
return false;
}
else if( !theInput.IsActionPressed('Sprint') || ( theInput.LastUsedGamepad() && IsInsideInteraction() && GetHowLongSprintButtonWasPressed() < 0.12 ) )
{
return false;
}

if ( thePlayer.HasBuff( EET_OverEncumbered ) )
{
return false;
}
if ( !IsSwimming() )
{
if ( ShouldUseStaminaWhileSprinting() && !GetIsSprinting() && !IsInCombat() && GetStatPercents(BCS_Stamina) <= 0.9 )
{
return false;
}
if( ( !IsCombatMusicEnabled() || IsInFistFightMiniGame() ) && ( !IsActionAllowed(EIAB_RunAndSprint) || !IsActionAllowed(EIAB_Sprint) ) )
{
return false;
}
if( IsTerrainTooSteepToRunUp() )
{
return false;
}
if( IsInCombatAction() )
{
return false;
}
if( IsInAir() )
{
return false;
}
}
if( theGame.IsFocusModeActive() )
{
return false;
}

return true;
}


public function SetTerrainPitch( pitch : float )
{
terrainPitch = pitch;
}

public function IsTerrainTooSteepToRunUp() : bool
{
return terrainPitch <= disableSprintTerrainPitch;
}

public function SetTempLookAtTarget( actor : CGameplayEntity )
{
tempLookAtTarget = actor;
}

private var beingWarnedBy : array;

event OnBeingWarnedStart( sender : CActor )
{
if ( !beingWarnedBy.Contains(sender) )
beingWarnedBy.PushBack(sender);
}
event OnBeingWarnedStop( sender : CActor )
{
beingWarnedBy.Remove(sender);
}

event OnCanFindPath( sender : CActor )
{
AddCanFindPathEnemyToList(sender,true);
}
event OnCannotFindPath( sender : CActor )
{
AddCanFindPathEnemyToList(sender,false);
}
event OnBecomeAwareAndCanAttack( sender : CActor )
{
AddEnemyToHostileEnemiesList( sender, true );
OnApproachAttack( sender );
}
event OnBecomeUnawareOrCannotAttack( sender : CActor )
{
AddEnemyToHostileEnemiesList( sender, false );
OnApproachAttackEnd( sender );
OnCannotFindPath(sender);
}
event OnApproachAttack( sender : CActor )
{
AddEnemyToHostileEnemiesList( sender, true );
super.OnApproachAttack( sender );
}
event OnApproachAttackEnd( sender : CActor )
{
AddEnemyToHostileEnemiesList( sender, false );
super.OnApproachAttackEnd( sender );
}
event OnAttack( sender : CActor )
{
super.OnAttack( sender );
}
event OnAttackEnd( sender : CActor )
{
super.OnAttackEnd( sender );
}

event OnHitCeiling()
{
substateManager.ReactOnHitCeiling();
}

protected var hostileEnemies : array; //all enemies that are actively engaged in combat with the player (may or may not be visible by Geralt)
private var hostileMonsters : array; // subgroup from hostileEnemies containing only monsters for sound system
function AddEnemyToHostileEnemiesList( actor : CActor, add : bool )
{
if ( add )
{
RemoveTimer( 'RemoveEnemyFromHostileEnemiesListTimer' );
if ( !hostileEnemies.Contains( actor ) )
{
hostileEnemies.PushBack( actor );

if( !actor.IsHuman() )
hostileMonsters.PushBack( actor );
}
}
else
{
if ( hostileEnemies.Size() == 1 )
{
if ( !actor.IsAlive() || actor.IsKnockedUnconscious() )
{
hostileEnemies.Remove( actor );
if( !actor.IsHuman() )
hostileMonsters.Remove( actor );
}
else
{
// If we already waiting to remove an entity
if( hostileEnemyToRemove )
{
hostileEnemies.Remove( hostileEnemyToRemove );
if( !hostileEnemyToRemove.IsHuman() )
hostileMonsters.Remove( hostileEnemyToRemove );
}
hostileEnemyToRemove = actor;
AddTimer( 'RemoveEnemyFromHostileEnemiesListTimer', 3.f );
}
}
else
{
hostileEnemies.Remove( actor );
if( !actor.IsHuman() )
hostileMonsters.Remove( actor );
}
}
}



public function ShouldEnableCombatMusic() : bool
{
var moveTargetNPC : CNewNPC;

if ( thePlayer.GetPlayerMode().GetForceCombatMode() )
return true;
else if ( !IsCombatMusicEnabled() )
{
if ( IsInCombat() )
return true;
else if ( IsThreatened() )
{
moveTargetNPC = (CNewNPC)moveTarget;
if ( moveTargetNPC.IsRanged() && hostileEnemies.Contains( moveTargetNPC ) )
return true;
else
return false;
}
else
return false;
}
else if ( ( thePlayer.IsThreatened() && ( hostileEnemies.Size() > 0 || thePlayer.GetPlayerCombatStance() == PCS_AlertNear ) )
|| IsInCombat()
|| finishableEnemiesList.Size() > 0
|| isInFinisher )
return true;
else
return false;

}

public var canFindPathEnemiesList : array;
public var disablecanFindPathEnemiesListUpdate : bool;
private var lastCanFindPathEnemy : CActor;
private var cachedMoveTarget : CActor;
private var reachabilityTestId : int;
private var reachabilityTestId2 : int;
function AddCanFindPathEnemyToList( actor : CActor, add : bool )
{
if ( disablecanFindPathEnemiesListUpdate )
return;

if ( add && !canFindPathEnemiesList.Contains( actor ) )
{
canFindPathEnemiesList.PushBack(actor);
}
else if ( !add )
{
canFindPathEnemiesList.Remove(actor);

if ( canFindPathEnemiesList.Size() <= 0 )
playerMode.UpdateCombatMode();
}
}

public function ClearCanFindPathEnemiesList( dt : float, id : int )
{
canFindPathEnemiesList.Clear();
}

public var finishableEnemiesList : array;
function AddToFinishableEnemyList( actor : CActor, add : bool )
{
if ( add && !finishableEnemiesList.Contains( actor ) )
{
finishableEnemiesList.PushBack(actor);
}
else if ( !add )
{
finishableEnemiesList.Remove(actor);
}
}

private function UpdateFinishableEnemyList()
{
var i : int;
i = 0;
while ( i < finishableEnemiesList.Size() )
{
if ( !finishableEnemiesList[ i ] )
{
finishableEnemiesList.EraseFast( i );
}
else
{
i += 1;
}
}
}

private timer function ClearFinishableEnemyList( dt : float, id : int )
{
finishableEnemiesList.Clear();
}

private var hostileEnemyToRemove : CActor;
private timer function RemoveEnemyFromHostileEnemiesListTimer( time : float , id : int)
{
hostileEnemies.Remove( hostileEnemyToRemove );

if( hostileEnemyToRemove.IsMonster() )
hostileMonsters.Remove( hostileEnemyToRemove );

hostileEnemyToRemove = NULL;
}

private function ClearHostileEnemiesList()
{
hostileEnemies.Clear();
hostileMonsters.Clear();
canFindPathEnemiesList.Clear();
}

private var moveTargets : array; //all hostileEnemies that Geralt is aware of.
public function GetMoveTargets() : array { return moveTargets; }
public function GetNumberOfMoveTargets() : int { return moveTargets.Size(); }

protected var enableStrafe : bool;


public function FindMoveTarget()
{
var moveTargetDists : array;
var moveTargetCanPathFinds : array;
var aPotentialMoveTargetCanFindPath : bool;

var newMoveTarget : CActor;
var actors : array;
var currentHeading : float;
var size, i : int;
var playerToNewMoveTargetDist : float;
var playerToMoveTargetDist : float;
var confirmEmptyMoveTarget : bool;
var newEmptyMoveTargetTimer : float;
var wasVisibleInFullFrame : bool;
var setIsThreatened : bool;

var enemysTarget : CActor;
var isEnemyInCombat : bool;
var potentialMoveTargets : array;
var onlyThreatTargets : bool;

thePlayer.SetupEnemiesCollection( enemyCollectionDist, enemyCollectionDist, 10, 'None', FLAG_Attitude_Neutral + FLAG_Attitude_Hostile + FLAG_Attitude_Friendly + FLAG_OnlyAliveActors );

//if ( moveTarget )
// cachedMoveTarget = moveTarget;

if ( GetCurrentStateName() != 'PlayerDialogScene' && IsAlive() )//&& !IsInCombatAction() )//GetBIsCombatActionAllowed() )
{
GetVisibleEnemies( actors );

//Include enemies that geralt cannot see, but is hostile to him
if ( hostileEnemies.Size() > 0 )
{
for( i=0; i < hostileEnemies.Size() ; i+=1 )
{
if ( !actors.Contains( hostileEnemies[i] ) )
actors.PushBack( hostileEnemies[i] );
}
}

//Include enemies that are technically dead, but can be finished off
if ( finishableEnemiesList.Size() > 0 )
{
for( i=0; i < finishableEnemiesList.Size() ; i+=1 )
{
if ( !actors.Contains( finishableEnemiesList[i] ) )
actors.PushBack( finishableEnemiesList[i] );
}
}

//Check the last moveTarget for situation where enemy targets an ally when you round a corner
if ( moveTarget && !actors.Contains( moveTarget ) )
actors.PushBack( moveTarget );

FilterActors( actors, onlyThreatTargets, false );

//Determine whether Player should be threatened
if ( actors.Size() > 0 )
{
setIsThreatened = false;

if ( onlyThreatTargets )
{
setIsThreatened = true;
}
else
{
for( i=0; i < actors.Size() ; i+=1 )
{
if ( IsThreat( actors[i] ) )
{
setIsThreatened = true;
break;
}
else
{
enemysTarget = actors[i].GetTarget();
isEnemyInCombat = actors[i].IsInCombat();
if ( isEnemyInCombat && enemysTarget && GetAttitudeBetween( enemysTarget, this ) == AIA_Friendly && enemysTarget.isPlayerFollower )
{
setIsThreatened = true;
break;
}
}
}
}

//After filtering you will only have either all hostile or all neutral npcs
for( i = actors.Size()-1; i>=0; i-=1 )
{
if ( ( !actors[i].IsAlive() && !finishableEnemiesList.Contains( actors[i] ) )
|| actors[i].IsKnockedUnconscious()
|| this.GetUsedVehicle() == actors[i]
|| !actors[i].CanBeTargeted() )
{
actors.EraseFast(i);
}
else if ( !IsThreatened() )
{
if ( !WasVisibleInScaledFrame( actors[i], 1.f, 1.f ) )
actors.EraseFast(i);
}
}
}
else if ( moveTarget && IsThreat( moveTarget ) )
setIsThreatened = true;
//SetIsThreatened( true );
else
setIsThreatened = false;
//SetIsThreatened( false );

if ( setIsThreatened )
{
enemyCollectionDist = 50.f;
SetIsThreatened( true );
}
else
{
if ( IsThreatened() )
AddTimer( 'finishableEnemiesList', 1.f );

enemyCollectionDist = findMoveTargetDistMax;
SetIsThreatened( false );
}

moveTargets = actors;
potentialMoveTargets = moveTargets;

//MS: By default Geralt will not play PCS_AlertNear unless there is one guy among the hostile npcs that canBeStrafed
if ( !moveTarget )
enableStrafe = false;

if ( potentialMoveTargets.Size() > 0 )
{
for ( i = 0; i < potentialMoveTargets.Size(); i += 1 )
{
if ( potentialMoveTargets[i].CanBeStrafed() )
enableStrafe = true;

if ( !potentialMoveTargets[i].GetGameplayVisibility() )
moveTargetDists.PushBack( 100.f ); //Put invisible enemies as the last choice for moveTarget
else
moveTargetDists.PushBack( VecDistance( potentialMoveTargets[i].GetNearestPointInPersonalSpace( GetWorldPosition() ), GetWorldPosition() ) );

if ( canFindPathEnemiesList.Contains( potentialMoveTargets[i] ) )
{
moveTargetCanPathFinds.PushBack( true );
aPotentialMoveTargetCanFindPath = true;
}
else
{
moveTargetCanPathFinds.PushBack( false );
}
}

if ( aPotentialMoveTargetCanFindPath )
{
for ( i = moveTargetCanPathFinds.Size()-1 ; i >= 0; i-=1 )
{
if ( !moveTargetCanPathFinds[i] )
{
moveTargetCanPathFinds.EraseFast(i);
potentialMoveTargets.EraseFast(i);
moveTargetDists.EraseFast(i);
}
}
}

if ( moveTargetDists.Size() > 0 )
newMoveTarget = potentialMoveTargets[ ArrayFindMinF( moveTargetDists ) ];
}

if ( newMoveTarget && newMoveTarget != moveTarget )
{
if ( moveTarget )
{
playerToNewMoveTargetDist = VecDistance( newMoveTarget.GetNearestPointInPersonalSpace( GetWorldPosition() ), GetWorldPosition() );
playerToMoveTargetDist = VecDistance( moveTarget.GetNearestPointInPersonalSpace( GetWorldPosition() ), GetWorldPosition() );
wasVisibleInFullFrame = WasVisibleInScaledFrame( moveTarget, 1.f, 1.f ) ;

if ( !IsThreat( moveTarget )
|| !wasVisibleInFullFrame
|| !IsEnemyVisible( moveTarget )
|| ( !moveTarget.IsAlive() && !finishableEnemiesList.Contains( moveTarget ) )
|| !moveTarget.GetGameplayVisibility()
|| ( moveTarget.IsAlive() && moveTarget.IsKnockedUnconscious() )
|| ( wasVisibleInFullFrame && IsEnemyVisible( moveTarget ) && playerToNewMoveTargetDist < playerToMoveTargetDist - 0.25f ) )
{
SetMoveTarget( newMoveTarget );
}
}
else
SetMoveTarget( newMoveTarget );
}


if ( !IsThreatened() )
{
if ( moveTarget
&& ( ( !moveTarget.IsAlive() && !finishableEnemiesList.Contains( moveTarget ) ) || !WasVisibleInScaledFrame( moveTarget, 0.8f, 1.f ) || VecDistance( moveTarget.GetWorldPosition(), this.GetWorldPosition() ) > theGame.params.MAX_THROW_RANGE ) )
{
confirmEmptyMoveTarget = true;
newEmptyMoveTargetTimer = 0.f;
}
}
/*else if ( moveTarget
&& ( moveTarget.IsAlive() || finishableEnemiesList.Contains( moveTarget ) )
//&& moveTarget.GetGameplayVisibility()
&& hostileEnemies.Contains( moveTarget ) )
*/
else if ( moveTarget && ( IsThreat( moveTarget ) || finishableEnemiesList.Contains( moveTarget ) ) )
{
if ( !IsEnemyVisible( moveTarget ) )
{
confirmEmptyMoveTarget = true;
newEmptyMoveTargetTimer = 5.f;
}
else
SetMoveTarget( moveTarget );
}
else if ( IsInCombat() )
{
confirmEmptyMoveTarget = true;
newEmptyMoveTargetTimer = 1.0f;
}

if ( confirmEmptyMoveTarget )
{
if ( newEmptyMoveTargetTimer < emptyMoveTargetTimer )
{
bIsConfirmingEmptyTarget = false;
emptyMoveTargetTimer = newEmptyMoveTargetTimer;
}

ConfirmEmptyMoveTarget( newEmptyMoveTargetTimer );
}
}
else
SetIsThreatened( false );

//reactionsSystem
if ( IsThreatened() && !IsInFistFightMiniGame() )
theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'CombatNearbyAction', 5.0, 18.0f, -1.f, -1, true ); //reactionSystemSearch
else
theGame.GetBehTreeReactionManager().RemoveReactionEvent( this, 'CombatNearbyAction'); //reactionSystemSearch

// sending nearby monsters count as parameter to sound system
theSound.SoundParameter( "monster_count", hostileMonsters.Size() );
}

private function ConfirmEmptyMoveTarget( timeDelta : float )
{
if ( !bIsConfirmingEmptyTarget )
{
bIsConfirmingEmptyTarget = true;
AddTimer( 'ConfirmEmptyTargetTimer', timeDelta );
}
}

private timer function ConfirmEmptyTargetTimer( time : float , id : int)
{
SetMoveTarget( NULL );
}


var isInCombatReason : int;
var canFindPathToEnemy : bool;
var combatModeEnt : CEntity;
var navDist : float;
var directDist : float;
var reachableEnemyWasTooFar : bool;
var reachableEnemyWasTooFarTimeStamp : float;
var reachablilityFailed : bool;
var reachablilityFailedTimeStamp : float;
public function ShouldEnableCombat( out unableToPathFind : bool, forceCombatMode : bool ) : bool
{
var shouldFindPathToNPCs : bool;
var playerToTargetDist : float;
var canFindPathToTarget : bool;
var moveTargetNPC : CNewNPC;
var currentTime : float;
var currentTime2 : float;
var isReachableEnemyTooFar : bool;
var reachableEnemyWasTooFarTimeStampDelta : float;
var reachablilityFailedTimeStampDelta : float;
var currentTimeTemp : float;

/*if ( GetIsSprinting() )
{
unableToPathFind = true;
isInCombatReason = 0;
return false;
}*/

if ( forceCombatMode && isSnappedToNavMesh )
return true;

if ( !IsThreatened() )
{
reachableEnemyWasTooFar = false;
reachablilityFailed = false;
isInCombatReason = 0;
return false;
}

if( thePlayer.substateManager.GetStateCur() != 'CombatExploration' && !thePlayer.substateManager.CanChangeToState( 'CombatExploration' )
&& thePlayer.substateManager.GetStateCur() != 'Ragdoll' ) //&& !thePlayer.substateManager.CanChangeToState( 'Ragdoll' ) ) )
{
reachableEnemyWasTooFar = false;
reachablilityFailed = false;
isInCombatReason = 0;
return false;
}

if ( moveTarget )
{
canFindPathToEnemy = CanFindPathToTarget( unableToPathFind );
currentTimeTemp = EngineTimeToFloat( theGame.GetEngineTime() );

if ( canFindPathToEnemy )
isReachableEnemyTooFar = IsReachableEnemyTooFar();

if ( IsInCombat() )
{
if ( canFindPathToEnemy )
{
if ( forceCombatMode )
return true;

reachablilityFailed = false;
reachablilityFailedTimeStamp = currentTimeTemp;

if ( reachableEnemyWasTooFar )
{
if ( isReachableEnemyTooFar )
{
currentTime = currentTimeTemp;

if ( GetIsSprinting() )
reachableEnemyWasTooFarTimeStampDelta = 0.f;
else
reachableEnemyWasTooFarTimeStampDelta = 3.f;

if ( currentTime > reachableEnemyWasTooFarTimeStamp + reachableEnemyWasTooFarTimeStampDelta )
{
isInCombatReason = 0;
unableToPathFind = true;
return false;
}
}
else
reachableEnemyWasTooFar = false;
}
else
{
if ( isReachableEnemyTooFar )
{
reachableEnemyWasTooFar = true;
reachableEnemyWasTooFarTimeStamp = currentTimeTemp;
}
else
reachableEnemyWasTooFar = false;
}

return true;
}
else
{
reachableEnemyWasTooFar = false;
reachableEnemyWasTooFarTimeStamp = currentTimeTemp;

if ( reachablilityFailed )
{
if ( IsEnemyTooHighToReach() )
reachablilityFailedTimeStampDelta = 1.f;
else
reachablilityFailedTimeStampDelta = 5.f;

currentTime2 = currentTimeTemp;
if ( currentTime2 > reachablilityFailedTimeStamp + reachablilityFailedTimeStampDelta )
{
unableToPathFind = true;
return false;
}
}
else
{
reachablilityFailed = true;
reachablilityFailedTimeStamp = currentTimeTemp;
}

return true;
}
}
else if ( canFindPathToEnemy )
{
if ( forceCombatMode )
{
reachableEnemyWasTooFar = false;
return true;
}

reachablilityFailed = false;
reachablilityFailedTimeStamp = currentTimeTemp;

moveTargetNPC = (CNewNPC)moveTarget;
playerToTargetDist = VecDistance( moveTarget.GetWorldPosition(), this.GetWorldPosition() );

/*if ( !theGame.GetWorld().NavigationLineTest( this.GetWorldPosition(), moveTarget.GetWorldPosition(), 0.4f ) )
{
isInCombatReason = 0;
return false;
}
else*/ if ( reachableEnemyWasTooFar
&& ( isReachableEnemyTooFar || !theGame.GetWorld().NavigationLineTest( this.GetWorldPosition(), moveTarget.GetWorldPosition(), 0.4f ) ) )
{
isInCombatReason = 0;
return false;
}
else if ( playerToTargetDist <= findMoveTargetDistMin )
isInCombatReason = 1;
else if ( ( moveTargetNPC.GetCurrentStance() == NS_Fly || moveTargetNPC.IsRanged() ) && hostileEnemies.Contains( moveTarget ) )
isInCombatReason = 2;
else
{
isInCombatReason = 0;
return false;
}

reachableEnemyWasTooFar = false;
return true;
}
}
else
{
reachableEnemyWasTooFar = false;
reachablilityFailed = false;
}

isInCombatReason = 0;
return false;
}

private function CanFindPathToTarget( out unableToPathFind : bool, optional forcedTarget : CNewNPC ) : bool
{
var moveTargetNPC : CNewNPC;
var moveTargetsTemp : array;
var i : int;
var safeSpotTolerance : float;
var ent : CEntity;

moveTargetsTemp = moveTargets;

for ( i = 0; i < moveTargetsTemp.Size(); i += 1 )
{
moveTargetNPC = (CNewNPC)moveTargetsTemp[i];

if ( moveTargetNPC && moveTargetNPC.GetCurrentStance() == NS_Fly )
{
isInCombatReason = 2;
return true;
}
}

switch ( navQuery.GetLastOutput( 0.4 ) )
{
case EAsyncTastResult_Failure:
{
isInCombatReason = 0;
return false;
}
case EAsyncTastResult_Success:
{
ent = navQuery.GetOutputClosestEntity();

if ( ent )
combatModeEnt = moveTarget;

navDist = navQuery.GetOutputClosestDistance();

isInCombatReason = 1;
return true;
}
case EAsyncTastResult_Pending:
{
return canFindPathToEnemy;
}
case EAsyncTastResult_Invalidated:
{
if ( IsInCombat() )
{
if ( IsEnemyTooHighToReach() )
safeSpotTolerance = 0.f;
else
safeSpotTolerance = 3.f;
}
else
safeSpotTolerance = 0.f;

switch( navQuery.TestActorsList( ENavigationReachability_Any, this, moveTargetsTemp, safeSpotTolerance, 75.0 ) )
{
case EAsyncTastResult_Failure:
{
isInCombatReason = 0;
return false;
}
case EAsyncTastResult_Success:
{
ent = navQuery.GetOutputClosestEntity();

if ( ent )
combatModeEnt = moveTarget;

navDist = navQuery.GetOutputClosestDistance();

isInCombatReason = 1;
return true;
}
case EAsyncTastResult_Pending:
{
return canFindPathToEnemy;
}
case EAsyncTastResult_Invalidated:
{
if ( IsInCombat() )
return true;
else
return false;
}
}
}
}
}

private function IsReachableEnemyTooFar() : bool
{
//var navDistFailMax : float = 100.f;
var navDistLimit : float = findMoveTargetDist; //25.f;
var navDistDivisor : float = 2.f;
var playerToTargetVector : Vector;

directDist = VecDistance( combatModeEnt.GetWorldPosition(), thePlayer.GetWorldPosition() );
playerToTargetVector = this.GetWorldPosition() - combatModeEnt.GetWorldPosition();

if ( playerMode.GetForceCombatMode() || isInCombatReason == 2 )
return false;

if ( ( playerToTargetVector.Z < 0.5 && navDist > navDistLimit && directDist < navDist/navDistDivisor ) )
return true;
else
return false;
}

private function IsEnemyTooHighToReach() : bool
{
var playerToTargetVector : Vector;

playerToTargetVector = this.GetWorldPosition() - combatModeEnt.GetWorldPosition();

if ( playerToTargetVector.Z < -0.5f && !theGame.GetWorld().NavigationLineTest( this.GetWorldPosition(), combatModeEnt.GetWorldPosition(), 0.4f ) )
return true;
else
return false;
}

//Force Geralt to face an enemy for a moment before changing to another enemy
public function LockToMoveTarget( lockTime : float )
{
/*if ( IsMoveTargetChangeAllowed() )
{
bMoveTargetChangeAllowed = false;
AddTimer( 'DisableLockToMoveTargetTimer', lockTime );
}*/
}

private timer function DisableLockToMoveTargetTimer( time : float , id : int)
{
if ( !this.IsActorLockedToTarget() )
{
SetMoveTargetChangeAllowed( true );
}
}

public function SetMoveTargetChangeAllowed( flag : bool )
{
//bMoveTargetChangeAllowed = flag;
}

public function IsMoveTargetChangeAllowed() : bool
{
return bMoveTargetChangeAllowed;
}

public function SetMoveTarget( actor : CActor )
{
if ( !actor && ForceCombatModeOverride() )
return;

if ( IsMoveTargetChangeAllowed()
&& moveTarget != actor )
{
moveTarget = actor;
bIsConfirmingEmptyTarget = false;
RemoveTimer( 'ConfirmEmptyTargetTimer' );

if ( !moveTarget )
SetScriptMoveTarget( moveTarget );
}
}

private var isThreatened : bool;
protected function SetIsThreatened( flag : bool )
{
var allowSetIsThreatened : bool;

allowSetIsThreatened = true;
if ( ForceCombatModeOverride() )
{
if ( flag || !moveTarget )
allowSetIsThreatened = true;
else
allowSetIsThreatened = false;
}

if ( allowSetIsThreatened )
{
isThreatened = flag;
}
}

public function ForceCombatModeOverride() : bool
{
if( this.GetPlayerMode().GetForceCombatMode()
&& canFindPathToEnemy
&& theGame.GetGlobalAttitude( GetBaseAttitudeGroup(), moveTarget.GetBaseAttitudeGroup() ) == AIA_Hostile )
return true;
else
return false;
}

public function IsThreatened() : bool { return isThreatened; }

public function EnableFindTarget( flag : bool )
{
var target : CActor;

if( IsActorLockedToTarget() )
{
target = GetTarget();

if ( target && target.IsAlive() )
bCanFindTarget = flag;
else
bCanFindTarget = true;
}
else
bCanFindTarget = flag;
}

public function UpdateDisplayTarget( optional forceUpdate : bool, optional forceNullActor : bool )
{
var hud : CR4ScriptedHud;
var tempTarget : CGameplayEntity;
var angleDist1 : float;
var angleDist2 : float;
var nonActorTargetMult : float;
var combatActionType : int;
var currTarget : CActor;
var interactionTarget : CInteractionComponent;

var heading : float;

if(theGame.IsDialogOrCutscenePlaying())
{
currentSelectedDisplayTarget = NULL;

if ( displayTarget )
ConfirmDisplayTarget( NULL );

return;
}

if ( forceNullActor )
currTarget = NULL;
else
currTarget = GetTarget();

currentSelectedDisplayTarget = currTarget;

if ( currTarget && !currTarget.IsTargetableByPlayer() )
{
currentSelectedDisplayTarget = NULL;
ConfirmDisplayTarget( currentSelectedDisplayTarget );
return;
}
//Setting multiplier that increases non actor target priority
nonActorTargetMult = 1.25;

//Update the interaction icon
hud = (CR4ScriptedHud)theGame.GetHud();

if ( !IsThreatened() )
{
if ( !bLAxisReleased || lastAxisInputIsMovement )
{
if ( currTarget )
angleDist1 = AbsF( AngleDistance( this.GetHeading(), VecHeading( currTarget.GetWorldPosition() - this.GetWorldPosition() ) ) );
else
angleDist1 = 360;

if ( nonActorTarget )
angleDist2 = AbsF( AngleDistance( this.GetHeading(), VecHeading( nonActorTarget.GetWorldPosition() - this.GetWorldPosition() ) ) );
else
angleDist2 = 360;
}
else
{
if ( currTarget )
angleDist1 = AbsF( AngleDistance( theCamera.GetCameraHeading(), VecHeading( currTarget.GetWorldPosition() - theCamera.GetCameraPosition() ) ) );
else
angleDist1 = 360;

if ( nonActorTarget )
angleDist2 = AbsF( AngleDistance( theCamera.GetCameraHeading(), VecHeading( nonActorTarget.GetWorldPosition() - theCamera.GetCameraPosition() ) ) );
else
angleDist2 = 360;
}
}

else
{
if ( !bLAxisReleased )
{
if ( ShouldUsePCModeTargeting() )
{
if ( currTarget )
angleDist1 = AbsF( AngleDistance( theCamera.GetCameraHeading(), VecHeading( currTarget.GetWorldPosition() - theCamera.GetCameraPosition() ) ) );
else
angleDist1 = 360;

if ( nonActorTarget && IsInCombatAction() )
{
angleDist2 = nonActorTargetMult * AbsF( AngleDistance( theCamera.GetCameraHeading(), VecHeading( nonActorTarget.GetWorldPosition() - theCamera.GetCameraPosition() ) ) );
}
else
angleDist2 = 360;
}
else
{
if ( currTarget )
angleDist1 = AbsF( AngleDistance( rawPlayerHeading, VecHeading( currTarget.GetWorldPosition() - this.GetWorldPosition() ) ) );
else
angleDist1 = 360;

if ( nonActorTarget && IsInCombatAction() )
{
angleDist2 = nonActorTargetMult * AbsF( AngleDistance( rawPlayerHeading, VecHeading( nonActorTarget.GetWorldPosition() - this.GetWorldPosition() ) ) );
}
else
angleDist2 = 360;
}
}
else
{
angleDist1 = 0;
angleDist2 = 360;
}
}


if ( angleDist1 < angleDist2 )
tempTarget = currTarget;
else
tempTarget = nonActorTarget;


if ( slideTarget && IsInCombatAction() )
{
combatActionType = (int)this.GetBehaviorVariable( 'combatActionType' );
if ( combatActionType == (int)CAT_Attack
|| ( combatActionType == (int)CAT_SpecialAttack && this.GetBehaviorVariable( 'playerAttackType' ) == 1.f )
|| ( combatActionType == (int)CAT_ItemThrow )
|| ( combatActionType == (int)CAT_CastSign && !IsCurrentSignChanneled() )
|| ( combatActionType == (int)CAT_CastSign && IsCurrentSignChanneled() && GetCurrentlyCastSign() == ST_Axii )
|| ( combatActionType == (int)CAT_CastSign && IsCurrentSignChanneled() && GetCurrentlyCastSign() == ST_Igni )
|| combatActionType == (int)CAT_Dodge
|| combatActionType == (int)CAT_Roll )
{
if ( combatActionType == (int)CAT_CastSign && GetCurrentlyCastSign() == ST_Igni && !IsCombatMusicEnabled() )
currentSelectedDisplayTarget = tempTarget;
else
currentSelectedDisplayTarget = slideTarget;
}
else
currentSelectedDisplayTarget = tempTarget;
}
else if ( slideTarget
&& this.rangedWeapon
&& this.rangedWeapon.GetCurrentStateName() != 'State_WeaponWait'
&& this.playerAiming.GetCurrentStateName() == 'Waiting' ) //( this.rangedWeapon.GetCurrentStateName() == 'State_WeaponShoot' || this.rangedWeapon.GetCurrentStateName() == 'State_WeaponAim' ) )
currentSelectedDisplayTarget = slideTarget;
else
currentSelectedDisplayTarget = tempTarget;

interactionTarget = theGame.GetInteractionsManager().GetActiveInteraction();
if ( interactionTarget && !IsThreatened() && !( this.IsCastingSign() && this.IsCurrentSignChanneled() ) )
{
tempTarget = (CGameplayEntity)interactionTarget.GetEntity();
if ( tempTarget && tempTarget != this.GetUsedVehicle() )
{
currentSelectedDisplayTarget = tempTarget;
SetDisplayTarget( currentSelectedDisplayTarget );
}
}

// disabling display for invisible targets
if ( (CActor)currentSelectedDisplayTarget && !((CActor)currentSelectedDisplayTarget).GetGameplayVisibility() )
{
currentSelectedDisplayTarget = NULL;
}

if ( displayTarget != currentSelectedDisplayTarget )
{
if ( forceUpdate )
SetDisplayTarget( currentSelectedDisplayTarget );
else
ConfirmDisplayTarget( currentSelectedDisplayTarget );
}
}

private var bConfirmDisplayTargetTimerEnabled : bool;
private var displayTargetToConfirm : CGameplayEntity;
private var currentSelectedDisplayTarget : CGameplayEntity;

private function ConfirmDisplayTarget( targetToConfirm : CGameplayEntity )
{
if ( targetToConfirm != displayTarget )
{
displayTargetToConfirm = targetToConfirm;
if( !bConfirmDisplayTargetTimerEnabled )
{
bConfirmDisplayTargetTimerEnabled = true;

if ( targetToConfirm )
AddTimer( 'ConfirmDisplayTargetTimer', 0.1f );
else
AddTimer( 'ConfirmDisplayTargetTimer', 0.f );
}
}
}

private timer function ConfirmDisplayTargetTimer( time : float, optional id : int)
{
if ( displayTargetToConfirm == currentSelectedDisplayTarget )
SetDisplayTarget( displayTargetToConfirm );

bConfirmDisplayTargetTimerEnabled = false;
}


protected function SetDisplayTarget( e : CGameplayEntity )
{
var displayTargetActor : CActor;

if ( e != displayTarget )
{
displayTarget = e;
displayTargetActor = (CActor)displayTarget;
SetPlayerCombatTarget( displayTargetActor );

if ( displayTargetActor && !displayTargetActor.IsTargetableByPlayer())
{
isDisplayTargetTargetable = false;
}
else if ( !displayTargetActor && displayTarget != nonActorTarget )
{
isDisplayTargetTargetable = false;
}
else
{
isDisplayTargetTargetable = true;
}
}
}

public function GetDisplayTarget() : CGameplayEntity { return displayTarget; }

private var isDisplayTargetTargetable : bool;
public function IsDisplayTargetTargetable() : bool
{
return isDisplayTargetTargetable;
}

public var radialSlots : array;
public function EnableRadialSlots( enable : bool, slotNames : array )
{
var hud : CR4ScriptedHud;
var module : CR4HudModuleRadialMenu;
var i : int;

hud = (CR4ScriptedHud)theGame.GetHud();
module = (CR4HudModuleRadialMenu)hud.GetHudModule("RadialMenuModule");

for(i=0; i {
module.SetDesaturated( !enable, slotNames[i] );
}
}

public function IsEnemyInCone( source : CActor, coneHeading : Vector, coneDist, coneAngle : float, out newLockTarget : CActor ) : bool
{
var targets : array;
var sourceToTargetDists : array;
var i : int;
var targetingInfo : STargetingInfo;

//GetVisibleEnemies( targets );
//targets = FilterActors( targets );
targets = GetMoveTargets();

if ( targets.Size() > 0 )
{
targetingInfo.source = this;
targetingInfo.canBeTargetedCheck = true;
targetingInfo.coneCheck = true;
targetingInfo.coneHalfAngleCos = CosF( Deg2Rad( coneAngle * 0.5f ) );
targetingInfo.coneDist = coneDist;
targetingInfo.coneHeadingVector = coneHeading;
targetingInfo.distCheck = true;
targetingInfo.invisibleCheck = true;
targetingInfo.navMeshCheck = true;
targetingInfo.inFrameCheck = false;
targetingInfo.frameScaleX = 1.f;
targetingInfo.frameScaleY = 1.f;
targetingInfo.knockDownCheck = false;
targetingInfo.knockDownCheckDist = 1.5f;
targetingInfo.rsHeadingCheck = false;
targetingInfo.rsHeadingLimitCos = 1.0f;

for( i = targets.Size() - 1; i >= 0; i -= 1 )
{
targetingInfo.targetEntity = targets[i];
if ( !IsEntityTargetable( targetingInfo ) )
targets.Erase( i );
}

for ( i = 0; i < targets.Size(); i += 1 )
sourceToTargetDists.PushBack( VecDistance( source.GetWorldPosition(), targets[i].GetWorldPosition() ) );

if(sourceToTargetDists.Size() > 0)
newLockTarget = targets[ ArrayFindMinF( sourceToTargetDists ) ];
else
newLockTarget = NULL;
}

return targets.Size() > 0;
}

public function GetScreenSpaceLockTarget( sourceEnt : CGameplayEntity, coneAngle, coneDist, coneHeading : float, optional inFrameCheck : bool ) : CActor
{
var source : CActor;
var sourcePos, targetPos : Vector;
var targets : array;
var sourceToTargetDists : array;
var sourceCoord : Vector;
var targetCoord : Vector;
var i : int;
var angleDiff : float;
var sourceToTargetHeading : float;
var sourceToTargetDist : float;
var size : float;
var targetingDist : float;
var targetingInfo : STargetingInfo;

var temp : int;

// MAREK TODO : Need to use cached values of screenspace coords instead of calculating again
//GetVisibleEnemies( targets );
//targets = FilterActors( targets );
source = (CActor)sourceEnt;

targets = GetMoveTargets();

if ( this.IsPCModeEnabled() )
{
if ( ( coneHeading > -45.f && coneHeading < 45.f )
|| coneHeading > 135.f
|| coneHeading < -135.f )
{
if ( coneHeading > 0 )
coneHeading = 180 - coneHeading;
else
coneHeading = 180 + coneHeading;
}
}

/*if ( IsCombatMusicEnabled() || hostileEnemies.Size() > 0 )
{
if ( targets[0] && !IsThreat( targets[0] ) )
targets.Clear();
}*/

for( i = targets.Size() - 1; i >= 0; i -= 1 )
{
if ( ( !targets[i].GetGameplayVisibility() || !IsThreat( targets[i] ) || !IsEnemyVisible( targets[i] ) || !this.CanBeTargetedIfSwimming( targets[i] ) )
&& ( !IsCastingSign() || GetCurrentlyCastSign() != ST_Axii ) )
targets.Erase(i);
}

if ( source )
{
temp = source.GetTorsoBoneIndex();

if ( temp < 0 )
sourcePos = source.GetWorldPosition();
else
sourcePos = MatrixGetTranslation( source.GetBoneWorldMatrixByIndex( source.GetTorsoBoneIndex() ) );
}
else
sourcePos = sourceEnt.GetWorldPosition();

theCamera.WorldVectorToViewRatio( sourcePos, sourceCoord.X , sourceCoord.Y );

/*if ( !IsUsingVehicle() )
targetingDist = softLockDist;
else*/
targetingDist = softLockDistVehicle;

if ( targets.Size() > 0 )
{
targetingInfo.source = this;
targetingInfo.canBeTargetedCheck = true;
targetingInfo.coneCheck = false;
targetingInfo.coneHalfAngleCos = 0.86602540378f; // = CosF( Deg2Rad( 60.0f * 0.5f ) )
targetingInfo.coneDist = targetingDist;
targetingInfo.coneHeadingVector = Vector( 0.0f, 1.0f, 0.0f );
targetingInfo.distCheck = true;
targetingInfo.invisibleCheck = true;
targetingInfo.navMeshCheck = false;

if ( inFrameCheck )
targetingInfo.inFrameCheck = true;
else
targetingInfo.inFrameCheck = false;

targetingInfo.frameScaleX = 1.f;
targetingInfo.frameScaleY = 1.f;
targetingInfo.knockDownCheck = false;
targetingInfo.knockDownCheckDist = softLockDist;
if ( bRAxisReleased )
targetingInfo.rsHeadingCheck = false;
else
targetingInfo.rsHeadingCheck = true;
targetingInfo.rsHeadingLimitCos = -0.5f; // = CosF( Deg2Rad( 120.0f ) );

for( i = targets.Size() - 1; i >= 0; i -= 1 )
{
temp = targets[i].GetTorsoBoneIndex();

if ( temp < 0 )
targetPos = targets[i].GetWorldPosition();
else
targetPos = MatrixGetTranslation( targets[i].GetBoneWorldMatrixByIndex( targets[i].GetTorsoBoneIndex() ) );

theCamera.WorldVectorToViewRatio( targetPos, targetCoord.X, targetCoord.Y );
sourceToTargetHeading = VecHeading( targetCoord - sourceCoord );
angleDiff = AbsF( AngleDistance( coneHeading, sourceToTargetHeading ) );

targetingInfo.targetEntity = targets[i];
if ( !IsEntityTargetable( targetingInfo ) )
targets.Erase( i );
else if ( !bRAxisReleased && angleDiff > ( coneAngle * 0.5 ) )
targets.Erase( i );
else if ( targets[i] == sourceEnt )
targets.Erase( i );

/*if ( GetDisplayTarget() && IsInCombatAction() && GetBehaviorVariable( 'combatActionType') == (int)CAT_CastSign && GetCurrentlyCastSign() == ST_Igni )
{

}
else
{
targetingInfo.rsHeadingCheck = false;
if ( !IsEntityTargetable( targetingInfo )
|| angleDiff > ( coneAngle * 0.5 )
|| targets[i] == sourceEnt )
targets.Erase( i );
}*/
}
}

size = targets.Size();
if ( size > 0 )
{
for ( i = 0; i < targets.Size(); i += 1 )
{
temp = targets[i].GetTorsoBoneIndex();

if ( temp < 0 )
targetPos = targets[i].GetWorldPosition();
else
targetPos = MatrixGetTranslation( targets[i].GetBoneWorldMatrixByIndex( targets[i].GetTorsoBoneIndex() ) );

theCamera.WorldVectorToViewRatio( targetPos, targetCoord.X, targetCoord.Y );
sourceToTargetHeading = AbsF( VecHeading( targetCoord - sourceCoord ) );
angleDiff = AngleDistance( 180, sourceToTargetHeading );
sourceToTargetDist = VecDistance2D( sourceCoord, targetCoord );

sourceToTargetDists.PushBack( SinF( Deg2Rad( angleDiff ) ) * sourceToTargetDist );
}
}

if ( targets.Size() > 0 )//GetDisplayTarget() )
return targets[ ArrayFindMinF( sourceToTargetDists ) ];
else
return NULL;
}

public function IsEntityTargetable( out info : STargetingInfo, optional usePrecalcs : bool ) : bool
{
var playerHasBlockingBuffs : bool;
var sourceActor : CActor;
var targetEntity : CEntity;
var targetActor : CActor;
var targetNPC : CNewNPC;
var sourcePosition : Vector;
var targetPosition : Vector;
var direction : Vector;
var sourceToTargetDist : float;
var sourceCapsuleRadius : float;
var mpac : CMovingPhysicalAgentComponent;

var coneDistSq : float;
var knockDownCheckDistSq : float;
var sourceToTargetAngleDist : float;
var b : bool;
var infoSourceWorldPos : Vector;
var infoTargetWorldPos : Vector;
var finishEnabled : bool;

if ( usePrecalcs )
{
playerHasBlockingBuffs = targetingIn.playerHasBlockingBuffs;
}
else
{
playerHasBlockingBuffs = thePlayer.HasBuff( EET_Confusion ) || thePlayer.HasBuff( EET_Hypnotized ) || thePlayer.HasBuff( EET_Blindness ) || thePlayer.HasBuff( EET_WraithBlindness );
}
if ( playerHasBlockingBuffs )
{
return false;
}

sourceActor = info.source;
targetEntity = info.targetEntity;
if ( !sourceActor || !targetEntity )
{
return false;
}

targetActor = (CActor)targetEntity;

// "can be targeted" check
if ( info.canBeTargetedCheck && !targetActor.CanBeTargeted() )
{
return false;
}

// visibility check
if ( info.invisibleCheck && !targetActor.GetGameplayVisibility() )
{
return false;
}

sourcePosition = sourceActor.GetWorldPosition();
targetPosition = targetEntity.GetWorldPosition();

if ( targetActor )
{
{ // do not target mounted horses
targetNPC = (CNewNPC)targetActor;
if ( targetNPC )
{
if ( targetNPC.IsHorse() && !targetNPC.GetHorseComponent().IsDismounted() )
{
return false;
}
}
}
}

if ( info.distCheck || info.knockDownCheck )
{
if ( usePrecalcs )
{
if ( targetActor )
{
// radius is taken form the first actor
sourceToTargetDist = Distance2DBetweenCapsuleAndPoint( targetActor, sourceActor ) - targetingPrecalcs.playerRadius;
}
else
{
sourceToTargetDist = VecDistance2D( sourcePosition, targetPosition ) - targetingPrecalcs.playerRadius;
}
}
else
{
if ( targetActor )
{
sourceToTargetDist = Distance2DBetweenCapsules( sourceActor, targetActor );
}
else
{
sourceToTargetDist = Distance2DBetweenCapsuleAndPoint( sourceActor, targetEntity );
}
}
}

// distance check
if ( info.distCheck )
{
if ( sourceToTargetDist >= info.coneDist )
{
return false;
}
}

// prepare source to target direction if needed
if ( info.coneCheck || info.rsHeadingCheck )
{
direction = VecNormalize2D( targetPosition - sourcePosition );
}

// cone check
if ( info.coneCheck )
{
if ( VecDot2D( direction, info.coneHeadingVector ) < info.coneHalfAngleCos )
{
return false;
}
}

// heading cone check
if ( info.rsHeadingCheck )
{
if ( usePrecalcs )
{
if ( VecDot2D( direction, targetingIn.lookAtDirection ) < info.rsHeadingLimitCos )
{
return false;
}
}
else
{
if ( VecDot2D( direction, VecNormalize2D( GetLookAtPosition() - sourcePosition ) ) < info.rsHeadingLimitCos )
{
return false;
}
}
}

// "in frame" check
if ( info.inFrameCheck && !WasVisibleInScaledFrame( targetEntity, info.frameScaleX, info.frameScaleY ) )
{
return false;
}

// navmesh check
if ( info.navMeshCheck && !IsSwimming() )
{
sourceCapsuleRadius = 0.1f;
if ( usePrecalcs )
{
sourceCapsuleRadius = targetingPrecalcs.playerRadius;
}
else
{
mpac = (CMovingPhysicalAgentComponent)sourceActor.GetMovingAgentComponent();
if ( mpac )
{
sourceCapsuleRadius = mpac.GetCapsuleRadius();
}
}
if ( !theGame.GetWorld().NavigationLineTest( sourcePosition, targetPosition, sourceCapsuleRadius ) )
{
return false;
}
}

// knockdown check
if ( info.knockDownCheck )
{
// if actor is not alive
if ( targetActor && !targetActor.IsAlive() )
{
// and contains enabled "Finish" interaction
finishEnabled = targetActor.GetComponent( 'Finish' ).IsEnabled();
if ( finishEnabled )
{
// and is contained in finishable enemies list
if ( finishableEnemiesList.Contains( targetActor ) )
{
// and is too far to "finish" -> we cannot target it
if ( sourceToTargetDist >= info.knockDownCheckDist )
{
return false;
}
}
}
}
}

return true;
}

public function CanBeTargetedIfSwimming( actor : CActor, optional usePrecalcs : bool ) : bool
{
var subDepth : float;
var isDiving : bool;

if ( !actor )
{
return false;
}

if ( usePrecalcs )
{
isDiving = targetingIn.isDiving;
}
else
{
isDiving = IsSwimming() && OnCheckDiving();
}

subDepth = ((CMovingPhysicalAgentComponent)actor.GetMovingAgentComponent()).GetSubmergeDepth();

if ( isDiving )
{
return ( subDepth < -1.0f );
}
else
{
return ( subDepth >= -1.0f );
}
}

/*
public function IsEntityTargetable( source : CActor, targetEntity : CGameplayEntity, coneCheck : bool, coneAngle, coneDist, coneHeading : float, distCheck, invisibleCheck, navMeshCheck : bool, inFrameCheck : bool, frameScaleX : float, frameScaleY : float, knockDownCheck : bool, knockDownCheckDist : float, rsHeadingCheck : bool, rsHeading : float, rsHeadingLimit : float) : bool
{
var targetActor : CActor;
var targetNPC : CNewNPC;
var direction : Vector;
var sourceToTargetDist : float;
var coneDistSq : float;
var sourceCapsuleRadius : float;
var knockDownCheckDistSq : float;
var sourceToTargetAngleDist : float;
var b : bool;
var targetsHorse : W3HorseComponent;

direction = VecNormalize2D( targetEntity.GetWorldPosition() - source.GetWorldPosition() );
targetActor = (CActor)targetEntity;

if ( distCheck )
{
if ( targetActor )
sourceToTargetDist = VecDistanceSquared( source.GetWorldPosition(), targetActor.GetNearestPointInBothPersonalSpaces( source.GetWorldPosition() ) );
else
sourceToTargetDist = VecDistanceSquared( source.GetWorldPosition(), targetEntity.GetWorldPosition() );

coneDistSq = coneDist * coneDist;
}

if ( knockDownCheck && targetActor )
knockDownCheckDistSq = knockDownCheckDist * knockDownCheckDist;

if ( navMeshCheck && targetActor )
sourceCapsuleRadius = ((CMovingPhysicalAgentComponent)source.GetMovingAgentComponent()).GetCapsuleRadius();

if ( rsHeadingCheck )
sourceToTargetAngleDist = AngleDistance( VecHeading( GetLookAtPosition() - source.GetWorldPosition() ), VecHeading( targetEntity.GetWorldPosition() - source.GetWorldPosition() ) );

// do not target mounted horses
if(targetActor)
{
targetNPC = (CNewNPC)targetActor;
if(targetNPC)
{
targetsHorse = (W3HorseComponent)targetNPC.GetHorseComponent();
if(targetsHorse && targetsHorse.IsNotBeingUsed() )
return false;
}
}

b = !coneCheck || AbsF( AngleDistance( coneHeading, VecHeading( direction ) ) ) < ( coneAngle * 0.5 );
b = b && ( !distCheck || sourceToTargetDist < coneDistSq );
b = b && ( !invisibleCheck || targetActor.GetGameplayVisibility() );
b = b && ( !navMeshCheck || (!IsSwimming() && theGame.GetWorld().NavigationLineTest( source.GetWorldPosition(), targetActor.GetWorldPosition(), sourceCapsuleRadius ) ) );
b = b && ( !inFrameCheck || WasVisibleInScaledFrame( targetEntity, frameScaleX, frameScaleY ) );
b = b && ( !rsHeadingCheck || ( rsHeading >= 0 && sourceToTargetAngleDist < 0 && sourceToTargetAngleDist >= ( rsHeadingLimit * -1 ) ) || ( rsHeading < 0 && sourceToTargetAngleDist >= 0 && sourceToTargetAngleDist <= rsHeadingLimit ) );
b = b && ( !knockDownCheck || !targetActor.GetComponent( 'Finish' ).IsEnabled() || ( targetActor.GetComponent( 'Finish' ).IsEnabled() && sourceToTargetDist < knockDownCheckDistSq ) );

if ( b )
return true;
else
return false;
}
*/
private function FilterActors( out targets : array, out onlyThreatsReturned : bool, optional usePrecalcs : bool )
{
var i : int;
var size : int;
var foundThreat : bool;
var foundNonThreat : bool;
var threatsCount : int;
var tmpActor : CActor;

foundThreat = false;
foundNonThreat = false;

size = targets.Size();
i = 0;
threatsCount = 0;

// after that loop first "threatsCount" targets will be "threat"
for ( i = 0; i < size; i+=1 )
{
if( IsThreat( targets[ i ], usePrecalcs ) )
{
foundThreat = true;
if ( i != threatsCount )
{
tmpActor = targets[ i ];
targets[ i ] = targets[ threatsCount ];
targets[ threatsCount ] = tmpActor;
}
threatsCount += 1;
}
else
{
foundNonThreat = true;
}
}

if ( foundThreat )
{
onlyThreatsReturned = true;
if ( foundNonThreat )
{
targets.Resize( threatsCount );
}
}
}

private function InternalFindTargetsInCone( out targets : array< CActor >, out outHeadingVector : Vector, optional usePrecalcs : bool )
{
var size, i : int;
var coneHalfAngleDot : float;
var coneHeading : float;
var coneHeadingVector : Vector;
var position : Vector;
var direction : Vector;
var onlyThreatTargetsFound : bool;

targets.Clear();
GetVisibleEnemies( targets );

//Include enemies that are technically dead, but can be finished off
for( i = 0; i < finishableEnemiesList.Size() ; i+=1 )
{
if ( !targets.Contains( finishableEnemiesList[i] ) )
{
targets.PushBack( finishableEnemiesList[i] );
}
}

onlyThreatTargetsFound = false;
FilterActors( targets, onlyThreatTargetsFound, true );

if ( IsCombatMusicEnabled() && targets.Size() > 0 && !onlyThreatTargetsFound && !IsThreat( targets[0], usePrecalcs ) )
{
targets.Clear();
}

coneHeading = 0.0f;
coneHalfAngleDot = 0.0f;
if ( ( orientationTarget == OT_Camera ) || ( orientationTarget == OT_CameraOffset ) )
{
if ( usePrecalcs )
{
coneHeading = targetingPrecalcs.cameraHeading;
}
else
{
coneHeading = theGame.GetGameCamera().GetHeading();
}
coneHalfAngleDot = 0.5f; // = CosF( Deg2Rad( 120.f * 0.5f ) ); - Just use calculator... why not? this is constant.
}
else
{
if ( IsSwimming() )
{
if ( usePrecalcs )
{
coneHeading = targetingPrecalcs.cameraHeading;
}
else
{
coneHeading = theGame.GetGameCamera().GetHeading();
}
coneHalfAngleDot = 0.17364817766f; // = CosF( Deg2Rad( 160.f * 0.5f ) );
}
else if ( bLAxisReleased )
{
if( IsInCombatAction() )
{
coneHeading = GetCombatActionHeading();
}
else
{
if ( ShouldUsePCModeTargeting() )
coneHeading = theGame.GetGameCamera().GetHeading();
else
coneHeading = cachedRawPlayerHeading;
}

if ( IsInCombat() )
{
if ( ShouldUsePCModeTargeting() )
coneHalfAngleDot = -1; // = CosF( Deg2Rad( 360.0f * 0.5f ) )
else
coneHalfAngleDot = 0.17364817766f; // = CosF( Deg2Rad( 160.f * 0.5f ) );
}
else
{
coneHalfAngleDot = -1.0f;
}
}
else
{
if( IsInCombatAction() )
{
coneHeading = GetCombatActionHeading();
}
else
{
if ( ShouldUsePCModeTargeting() )
coneHeading = theGame.GetGameCamera().GetHeading();
else
coneHeading = cachedRawPlayerHeading;
}

if ( ShouldUsePCModeTargeting() )
coneHalfAngleDot = -1; // = CosF( Deg2Rad( 360.0f * 0.5f ) )
else
coneHalfAngleDot = 0.17364817766f; // = CosF( Deg2Rad( 160.f * 0.5f ) );
}

coneHeadingVector = VecFromHeading( coneHeading );
position = this.GetWorldPosition();

for ( i = targets.Size() - 1; i >= 0; i -= 1 )
{
if ( !targets[i] )
{
targets.EraseFast(i);
continue;
}

direction = VecNormalize2D( targets[i].GetWorldPosition() - position );

if ( VecDot2D( coneHeadingVector, direction ) < coneHalfAngleDot )
{
targets.EraseFast( i );
}
}
}

outHeadingVector = coneHeadingVector;
}

///////////////////////////////////////////////////////////////////////////
// (new) targeting

function InitTargeting()
{
var consts : SR4PlayerTargetingConsts;

if ( !targeting )
{
targeting = new CR4PlayerTargeting in this;
}
if ( targeting )
{
consts.softLockDistance = this.softLockDist;
consts.softLockFrameSize = this.softLockFrameSize;
targeting.SetConsts( consts );
}
}

function PrepareTargetingIn( actionCheck : bool, bufferActionType : EBufferActionType, actionInput : bool )
{
var coneDist : float;

if ( actionCheck && bufferActionType == EBAT_ItemUse )
{
coneDist = findMoveTargetDist;
}
else if ( IsSwimming() )
{
coneDist = theGame.params.MAX_THROW_RANGE;
}
else if ( ( GetPlayerCombatStance() == PCS_AlertNear ) && ( ( playerMoveType == PMT_Walk ) || ( playerMoveType == PMT_Idle ) ) )
{
coneDist = softLockDist;
}
else
{
coneDist = findMoveTargetDist;
}

targetingIn.canFindTarget = this.bCanFindTarget;
targetingIn.playerHasBlockingBuffs = thePlayer.HasBuff( EET_Confusion ) || thePlayer.HasBuff( EET_Hypnotized ) || thePlayer.HasBuff( EET_Blindness ) || thePlayer.HasBuff( EET_WraithBlindness );
targetingIn.isHardLockedToTarget = this.IsHardLockEnabled();
targetingIn.isActorLockedToTarget = this.IsActorLockedToTarget();
targetingIn.isCameraLockedToTarget = this.IsCameraLockedToTarget();
targetingIn.actionCheck = actionCheck;
targetingIn.actionInput = actionInput;
targetingIn.isInCombatAction = this.IsInCombatAction();
targetingIn.isLAxisReleased = this.bLAxisReleased;
targetingIn.isLAxisReleasedAfterCounter = this.lAxisReleasedAfterCounter;
targetingIn.isLAxisReleasedAfterCounterNoCA = this.lAxisReleasedAfterCounterNoCA;
targetingIn.lastAxisInputIsMovement = this.lastAxisInputIsMovement;
targetingIn.isAiming = this.playerAiming.GetCurrentStateName() == 'Aiming';
targetingIn.isSwimming = this.IsSwimming();
targetingIn.isDiving = this.IsSwimming() && OnCheckDiving();
targetingIn.isThreatened = this.IsThreatened();
targetingIn.isCombatMusicEnabled = this.IsCombatMusicEnabled();
targetingIn.isPcModeEnabled = this.IsPCModeEnabled();
targetingIn.isInParryOrCounter = this.isInParryOrCounter;
targetingIn.shouldUsePcModeTargeting = this.ShouldUsePCModeTargeting();
targetingIn.bufferActionType = bufferActionType;
targetingIn.orientationTarget = this.GetOrientationTarget();
targetingIn.coneDist = coneDist; // computed few lines above
targetingIn.findMoveTargetDist = this.findMoveTargetDist;
targetingIn.cachedRawPlayerHeading = this.cachedRawPlayerHeading;
targetingIn.combatActionHeading = this.GetCombatActionHeading();
targetingIn.rawPlayerHeadingVector = VecFromHeading( this.rawPlayerHeading );
targetingIn.lookAtDirection = VecNormalize2D( this.GetLookAtPosition() - GetWorldPosition() );
targetingIn.moveTarget = this.moveTarget;
targetingIn.aimingTarget = this.playerAiming.GetAimedTarget();
targetingIn.displayTarget = (CActor)this.displayTarget;
targetingIn.finishableEnemies = this.finishableEnemiesList;
targetingIn.hostileEnemies = this.hostileEnemies;
targetingIn.defaultSelectionWeights = ProcessSelectionWeights();
}

function ResetTargetingOut()
{
targetingOut.target = NULL;
targetingOut.result = false;
targetingOut.confirmNewTarget = false;
targetingOut.forceDisableUpdatePosition = false;
}

function MakeFindTargetPrecalcs()
{
var mpac : CMovingPhysicalAgentComponent;

targetingPrecalcs.playerPosition = thePlayer.GetWorldPosition();
targetingPrecalcs.playerHeading = thePlayer.GetHeading();
targetingPrecalcs.playerHeadingVector = thePlayer.GetHeadingVector();
targetingPrecalcs.playerHeadingVector.Z = 0;
targetingPrecalcs.playerHeadingVector = VecNormalize2D( targetingPrecalcs.playerHeadingVector );

targetingPrecalcs.playerRadius = 0.5f;
mpac = (CMovingPhysicalAgentComponent)thePlayer.GetMovingAgentComponent();
if ( mpac )
{
targetingPrecalcs.playerRadius = mpac.GetCapsuleRadius();
}

targetingPrecalcs.cameraPosition = theCamera.GetCameraPosition();
targetingPrecalcs.cameraDirection = theCamera.GetCameraDirection();
targetingPrecalcs.cameraHeadingVector = targetingPrecalcs.cameraDirection;
targetingPrecalcs.cameraHeadingVector.Z = 0;
targetingPrecalcs.cameraHeadingVector = VecNormalize2D( targetingPrecalcs.cameraHeadingVector );
targetingPrecalcs.cameraHeading = VecHeading( targetingPrecalcs.cameraHeadingVector );
}

public function GetForceDisableUpdatePosition() : bool
{
return targetingOut.forceDisableUpdatePosition;
}

public function SetUseNativeTargeting( use : bool )
{
useNativeTargeting = use;
}

protected function FindTarget( optional actionCheck : bool, optional action : EBufferActionType, optional actionInput : bool ) : CActor
{
if ( IsCombatMusicEnabled() && !IsInCombat() && reachableEnemyWasTooFar )
{
playerMode.UpdateCombatMode();
}

PrepareTargetingIn( actionCheck, action, actionInput );
if ( useNativeTargeting )
{
targeting.BeginFindTarget( targetingIn );
targeting.FindTarget();
targeting.EndFindTarget( targetingOut );
}
else
{
UpdateVisibleActors();
MakeFindTargetPrecalcs();
ResetTargetingOut();
FindTarget_Scripted();
}
if ( targetingOut.result )
{
if ( targetingOut.confirmNewTarget )
{
ConfirmNewTarget( targetingOut.target );
}
return targetingOut.target;
}
return NULL;
}

protected function FindTarget_Scripted()
{
var currentTarget : CActor;
var newTarget : CActor;
var selectedTarget : CActor;
var displayTargetActor : CActor;
var playerPosition : Vector;
var playerHeadingVector : Vector;
var cameraPosition : Vector;
var cameraHeadingVector : Vector;
var selectionHeadingVector : Vector;
var targetingInfo : STargetingInfo;
var selectionWeights : STargetSelectionWeights;
var targets : array< CActor >;
var isMoveTargetTargetable : bool;
var targetChangeFromActionInput : bool;
var retainCurrentTarget : bool;

// caching data

playerPosition = this.GetWorldPosition();
playerHeadingVector = targetingPrecalcs.playerHeadingVector;
cameraPosition = theCamera.GetCameraPosition();
cameraHeadingVector = targetingPrecalcs.cameraHeadingVector;

currentTarget = GetTarget();
if ( currentTarget )
{
if ( IsHardLockEnabled() && currentTarget.IsAlive() && !currentTarget.IsKnockedUnconscious() )
{
if ( VecDistanceSquared( playerPosition, currentTarget.GetWorldPosition() ) > 50.f * 50.0f )
{
HardLockToTarget( false );
}
else
{
targetingOut.target = currentTarget;
targetingOut.result = true;
return;
}
}
GetVisualDebug().AddSphere('target', 1.0f, currentTarget.GetWorldPosition(), true, Color( 255, 255, 0 ), 1.0f );
}

if ( bCanFindTarget && !IsActorLockedToTarget() )
{
if ( !targetingIn.playerHasBlockingBuffs )
{
InternalFindTargetsInCone( targets, selectionHeadingVector, true );
}

targetingInfo.source = this;
targetingInfo.canBeTargetedCheck = true;
targetingInfo.coneCheck = false;
targetingInfo.coneHalfAngleCos = 1.0f;
targetingInfo.coneDist = targetingIn.coneDist;
targetingInfo.distCheck = true;
targetingInfo.invisibleCheck = true;
targetingInfo.navMeshCheck = false; //true;

if ( ShouldUsePCModeTargeting() )
targetingInfo.inFrameCheck = false;
else
targetingInfo.inFrameCheck = true;

targetingInfo.frameScaleX = 1.0f;
targetingInfo.frameScaleY = 1.0f;
targetingInfo.knockDownCheck = false;
targetingInfo.knockDownCheckDist = 1.5f;
targetingInfo.rsHeadingCheck = false;
targetingInfo.rsHeadingLimitCos = 1.0f;

if ( currentTarget )
{
targetingInfo.targetEntity = currentTarget;
if ( !IsEntityTargetable( targetingInfo, true ) )
{
currentTarget = NULL;
}
if ( currentTarget && !CanBeTargetedIfSwimming( currentTarget, true ) )
{
currentTarget = NULL;
}
}

isMoveTargetTargetable = false;
if ( moveTarget )
{
if ( CanBeTargetedIfSwimming( moveTarget, true ) )
{
targetingInfo.targetEntity = moveTarget;
targetingInfo.coneDist = findMoveTargetDist;
targetingInfo.inFrameCheck = false;
if ( IsEntityTargetable( targetingInfo, true ) )
{
isMoveTargetTargetable = true;
}
}
}

// checking "standard" cone dist again
targetingInfo.coneDist = targetingIn.coneDist;

if ( !targetingIn.playerHasBlockingBuffs )
{
RemoveNonTargetable( targets, targetingInfo, selectionHeadingVector );
}

newTarget = NULL;
if ( this.playerAiming.GetCurrentStateName() == 'Aiming' )
{
newTarget = this.playerAiming.GetAimedTarget();
if ( !newTarget )
{
selectionWeights.angleWeight = 1.f;
selectionWeights.distanceWeight = 0.f;
selectionWeights.distanceRingWeight = 0.f;

selectedTarget = SelectTarget( targets, false, cameraPosition, cameraHeadingVector, selectionWeights, true );
newTarget = selectedTarget;
}
}
else if ( IsSwimming() )
{
selectionWeights.angleWeight = 0.9f;
selectionWeights.distanceWeight = 0.1f;
selectionWeights.distanceRingWeight = 0.f;

selectedTarget = SelectTarget( targets, true, cameraPosition, cameraHeadingVector, selectionWeights, true );
newTarget = selectedTarget;
}
else if ( IsThreatened() )
{
// Change locked enemy when the current one becomes invisible
if ( IsCameraLockedToTarget() )
{
if ( currentTarget && !currentTarget.GetGameplayVisibility() )
{
ForceSelectLockTarget();
}
}

displayTargetActor = (CActor)displayTarget;
selectedTarget = SelectTarget( targets, true, playerPosition, selectionHeadingVector, targetingIn.defaultSelectionWeights, true );

if ( !selectedTarget )
{
targetingOut.forceDisableUpdatePosition = true;
}

targetChangeFromActionInput = targetingIn.actionInput && !lAxisReleasedAfterCounter;
if ( selectedTarget &&
( !IsThreat( currentTarget, true ) || ShouldUsePCModeTargeting() || ( !IsInCombatAction() && !lAxisReleasedAfterCounterNoCA ) || targetChangeFromActionInput ) )
{
newTarget = selectedTarget;
}
else if ( displayTargetActor &&
( ( bLAxisReleased && !ShouldUsePCModeTargeting() )|| IsInCombatAction() ) &&
( displayTargetActor.IsAlive() || finishableEnemiesList.Contains( displayTargetActor ) ) &&
displayTargetActor.GetGameplayVisibility() &&
( IsEnemyVisible( displayTargetActor ) || finishableEnemiesList.Contains( displayTargetActor ) ) &&
this.CanBeTargetedIfSwimming( displayTargetActor, true ) &&
IsThreat( displayTargetActor, true ) &&
WasVisibleInScaledFrame( displayTargetActor, 1.f, 1.f ) )
{
newTarget = displayTargetActor;
}
// target closest enemy immediately when transitioning from running/sprint to walk/idle,
// but when you are already in walk/idle player should hit air after he kills his target, he should only target closest enemy when that enmy is within his field of vision
else if ( moveTarget &&
isMoveTargetTargetable &&
( !IsInCombatAction() || isInParryOrCounter || GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Dodge || GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Roll ) )
{
newTarget = moveTarget;
}
else
{
newTarget = NULL;
}
}
else
{
retainCurrentTarget = false;
if ( lAxisReleasedAfterCounterNoCA )
{
if ( lastAxisInputIsMovement && !this.IsSwimming())
{
selectionWeights.angleWeight = 0.375f;
selectionWeights.distanceWeight = 0.275f;
selectionWeights.distanceRingWeight = 0.35f;
selectedTarget = SelectTarget( targets, false, playerPosition, playerHeadingVector, selectionWeights, true );

if ( currentTarget != selectedTarget )
{
targetingInfo.targetEntity = currentTarget;
if ( IsEntityTargetable( targetingInfo, true ) && currentTarget.IsAlive() )
{
retainCurrentTarget = true;
}
}
}
else
{
selectionWeights.angleWeight = 0.75f;
selectionWeights.distanceWeight = 0.125f;
selectionWeights.distanceRingWeight = 0.125f;
selectedTarget = SelectTarget( targets, false, cameraPosition, cameraHeadingVector, selectionWeights, true );
}
}
else
{
selectionWeights.angleWeight = 0.6f;
selectionWeights.distanceWeight = 0.4f;
selectionWeights.distanceRingWeight = 0.f;
selectedTarget = SelectTarget( targets, true, playerPosition, targetingIn.rawPlayerHeadingVector, selectionWeights, true );
}

if ( retainCurrentTarget )
{
newTarget = currentTarget;
}
else if ( IsInCombatAction() && GetBehaviorVariable( 'isPerformingSpecialAttack' ) == 1.0f )
{
newTarget = moveTarget;
}
else if ( selectedTarget )
{
newTarget = selectedTarget;
}
else
{
newTarget = NULL;
}
}

targetingOut.confirmNewTarget = true;
}
else
{
newTarget = NULL;
}

targetingOut.result = true;
targetingOut.target = newTarget;
}

function UpdateVisibleActors()
{
var i : int;
var now : float;

now = theGame.GetEngineTimeAsSeconds();
for ( i = visibleActors.Size() - 1; i >= 0; i-=1 )
{
// wasn't visible for more than 1 second
if ( ( now - visibleActorsTime[i] ) > 1.0f )
{
visibleActors.EraseFast( i );
visibleActorsTime.EraseFast( i );
}
}
}

function RemoveNonTargetable( out targets : array< CActor >, out info : STargetingInfo, selectionHeadingVector : Vector )
{
var i : int;
var cameraPosition : Vector;
var cameraDirection : Vector;
var nonCombatCheck : bool;
var playerToCamPlaneDist : float;
var targetToCamPlaneDist : float;

if ( targets.Size() == 0 )
{
return;
}

nonCombatCheck = bLAxisReleased && !IsInCombat();

// first, let's prepare targeting info (so that we don't need to do it in each loop step)
if ( nonCombatCheck )
{
info.coneHeadingVector = targetingPrecalcs.playerHeadingVector;
if ( lastAxisInputIsMovement )
{
info.coneHeadingVector = selectionHeadingVector;
info.invisibleCheck = false;
info.coneCheck = true;
info.coneHalfAngleCos = 0.76604444311f; // = CosF( Deg2Rad( 80.0f * 0.5f ) )
}
else
{
info.invisibleCheck = false;
info.frameScaleX = 0.9f;
info.frameScaleY = 0.9f;
}
}
else
{
info.coneHeadingVector = Vector( 0.0f, 0.0f, 0.0f );

//MS: ConeCheck is false because it's already been filtered by InternalFindTargetsInCone
if ( IsInCombat() )
{
info.inFrameCheck = false;
}
else
{
if ( !bLAxisReleased )
{
info.coneCheck = true;

if ( this.IsSwimming() )
info.coneHalfAngleCos = -1; // = CosF( Deg2Rad( 360.0f * 0.5f ) )
else
info.coneHalfAngleCos = 0.86602540378f; // = CosF( Deg2Rad( 60.0f * 0.5f ) )

info.coneHeadingVector = targetingIn.rawPlayerHeadingVector;
}
}
}

cameraPosition = theCamera.GetCameraPosition();
cameraDirection = targetingPrecalcs.cameraDirection;
playerToCamPlaneDist = VecDot2D( cameraDirection, this.GetWorldPosition() - cameraPosition );

// then, using prepared info let's filter out invalid targets
for( i = targets.Size() - 1; i >= 0; i -= 1 )
{
info.targetEntity = targets[i];

if ( !CanBeTargetedIfSwimming( targets[i], true ) )
{
targets.EraseFast( i );
}
else if ( !IsEntityTargetable( info, true ) )
{
targets.EraseFast( i );
}
else
{
if ( nonCombatCheck && !lastAxisInputIsMovement )
{
// removing targets between camera and player
targetToCamPlaneDist = VecDot2D( cameraDirection, targets[i].GetWorldPosition() - cameraPosition );
if ( targetToCamPlaneDist < playerToCamPlaneDist )
{
targets.EraseFast( i );
}
}
}
}
}

var combatModeColor : Color;
public function CombatModeDebug()
{
var visualDebug : CVisualDebug = GetVisualDebug();

var naviQueryMsg : string;
var naviQueryMsg1 : string;
var naviQueryMsg2 : string;

var navSnapMsg : string;
var i : int;

if ( IsCombatMusicEnabled() )
visualDebug.AddText( 'CombatMusic', "CombatMusic : On", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.7f ), true, , Color( 255, 255, 255 ) );
else
visualDebug.AddText( 'CombatMusic', "CombatMusic : Off", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.7f ), true, , Color( 0, 0, 0 ) );

if ( GetPlayerMode().GetForceCombatMode() )
visualDebug.AddText( 'ForcedCombatMode', "ForcedCombatMode : TRUE", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.6f ), true, , Color( 255, 255, 255 ) );
else
visualDebug.AddText( 'ForcedCombatMode', "ForcedCombatMode : FALSE", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.6f ), true, , Color( 0, 0, 0 ) );


if ( IsThreatened() )
{
if ( IsInCombat() )
visualDebug.AddText( 'CombatMode', "CombatMode : AlertNear/Far", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.5f ), true, , Color( 255, 0, 0 ) );
else
visualDebug.AddText( 'CombatMode', "CombatMode : CombatExploration", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.5f ), true, , Color( 255, 255, 0 ) );
}
else
visualDebug.AddText( 'CombatMode', "CombatMode : NormalExploration", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.5f ), true, , Color( 0, 255, 0 ) );

visualDebug.AddText( 'NaviQuery', naviQueryMsg, combatModeEnt.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery1', naviQueryMsg1, thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery2', naviQueryMsg2, thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.2f ), true, , combatModeColor );

if ( isInCombatReason == 0 )
visualDebug.AddText( 'CombatModeReason', "CombatModeReason : ", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.4f ), true, , Color( 125, 125, 125 ) );
else if ( isInCombatReason == 1 )
visualDebug.AddText( 'CombatModeReason', "CombatModeReason : Geralt CAN pathfind to NPC", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.4f ), true, , Color( 255, 0, 0 ) );
else if ( isInCombatReason == 2 )
visualDebug.AddText( 'CombatModeReason', "CombatModeReason : An NPC is flying or ranged", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.4f ), true, , Color( 255, 0, 0 ) );
else if ( isInCombatReason == 2 )
visualDebug.AddText( 'CombatModeReason', "CombatModeReason : Forced Combat Mode", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.4f ), true, , Color( 255, 0, 0 ) );

if ( reachableEnemyWasTooFar )
{
combatModeColor.Red = 255;
combatModeColor.Green = 255;
combatModeColor.Blue = 0;
}
else
{
combatModeColor.Red = 0;
combatModeColor.Green = 255;
combatModeColor.Blue = 0;
}

if ( IsThreatened() )
{
switch ( navQuery.GetLastOutput( 2.0 ) )
{
case EAsyncTastResult_Failure:
{
if ( this.playerMode.GetForceCombatMode() )
{
if ( isSnappedToNavMesh )
{
visualDebug.AddText( 'NaviQuery', "", combatModeEnt.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery1', "Naviquery : Snapped So no need for query", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery2', "Naviquery : Snapped So no need for query", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.2f ), true, , combatModeColor );
}
else
{
visualDebug.AddText( 'NaviQuery', "", combatModeEnt.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery1', "Naviquery : Failed", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery2', "Naviquery : Failed", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.2f ), true, , combatModeColor );
}
}
else
{
visualDebug.AddText( 'NaviQuery', "", combatModeEnt.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery1', "Naviquery : Failed", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery2', "Naviquery : Failed", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.2f ), true, , combatModeColor );
}
break;
}
case EAsyncTastResult_Success:
{
visualDebug.AddText( 'NaviQuery', combatModeEnt.GetName(), combatModeEnt.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery1', "Naviquery : Success (navDist: " + navDist + ")", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery2', "Naviquery : Success (directDist: " + directDist + ")", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.2f ), true, , combatModeColor );
break;
}
case EAsyncTastResult_Pending:
{
visualDebug.AddText( 'NaviQuery', combatModeEnt.GetName(), combatModeEnt.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery1', "Naviquery : Pending (navDist: " + navDist + ")", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery2', "Naviquery : Pending (directDist: " + directDist + ")", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.2f ), true, , combatModeColor );
break;
}
case EAsyncTastResult_Invalidated:
{
visualDebug.AddText( 'NaviQuery', "", combatModeEnt.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery1', "Naviquery : Invalidated", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery2', "Naviquery : Invalidated", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.2f ), true, , combatModeColor );
break;
}
}
}
else
{
visualDebug.AddText( 'NaviQuery', "", combatModeEnt.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery1', "", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.3f ), true, , combatModeColor );
visualDebug.AddText( 'NaviQuery2', "", thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.2f ), true, , combatModeColor );
}

if ( navMeshSnapInfoStack.Size() > 0 )
{
for ( i = navMeshSnapInfoStack.Size()-1; i >= 0; i -= 1 )
{
navSnapMsg = navSnapMsg + navMeshSnapInfoStack[i] + " ";
}

visualDebug.AddText( 'NavMeshSnap', "NavMeshSnap: Enabled, Sources : " + navSnapMsg, thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.1f ), true, , Color( 255, 255, 255 ) );
}
else
visualDebug.AddText( 'NavMeshSnap', "NavMeshSnap: Disabled" , thePlayer.GetWorldPosition() + Vector( 0.f,0.f,1.1f ), true, , Color( 0, 0, 0 ) );

}

function IsCombatMusicEnabled() : bool
{
if ( theSound.GetCurrentGameState() == ESGS_UnderwaterCombat
|| theSound.GetCurrentGameState() == ESGS_Combat
|| theSound.GetCurrentGameState() == ESGS_CombatMonsterHunt
|| theSound.GetCurrentGameState() == ESGS_FocusUnderwaterCombat )
return true;
else
return false;
}

function IsSoundStateCombatMusic( gameState : ESoundGameState ) : bool
{
if ( gameState == ESGS_UnderwaterCombat
|| gameState == ESGS_Combat
|| gameState == ESGS_CombatMonsterHunt
|| gameState == ESGS_FocusUnderwaterCombat )
return true;
else
return false;
}

private function ConfirmNewTarget( actorToConfirm : CActor )
{
var leftJoyRotLimit : float = 1.f;

var target : CActor;

target = GetTarget();

//MS: When Player pushes stick in npcs direction, he needs to push the stick beyond leftJoyRotLimit in order to change targets
if ( !target
|| !moveTarget
|| ( target && ( !IsThreat( target ) || !target.IsAlive() ) )
|| VecLength( rawLeftJoyVec ) < 0.7f
|| ( IsInCombatAction() && ( ( GetBehaviorVariable( 'combatActionType') == (int)CAT_Dodge ) || ( VecLength( rawLeftJoyVec ) >= 0.7f && ( prevRawLeftJoyRot >= ( rawLeftJoyRot + leftJoyRotLimit ) || prevRawLeftJoyRot <= ( rawLeftJoyRot - leftJoyRotLimit ) || AbsF( AngleDistance( cachedRawPlayerHeading, VecHeading( GetDisplayTarget().GetWorldPosition() - this.GetWorldPosition() ) ) ) > 60 ) ) ) )
|| ( !IsInCombatAction() && ( !rangedWeapon || ( rangedWeapon.GetCurrentStateName() != 'State_WeaponHolster' ) ) ))//&& rangedWeapon.GetCurrentStateName() != 'State_WeaponShoot' ) && rangedWeapon.GetCurrentStateName() != 'State_WeaponAim' ) )
{
SetPrevRawLeftJoyRot();

if ( actorToConfirm != target )
{
SetTarget( actorToConfirm );
}
}
}

protected function SelectTarget( targets : array< CActor >, useVisibilityCheck : bool, sourcePosition : Vector, headingVector : Vector, selectionWeights : STargetSelectionWeights, optional usePrecalcs : bool ) : CActor
{
var i : int;
var target : CActor;
var selectedTarget : CActor;
var currentTarget : CActor;
var playerPosition : Vector;
var distanceToPlayer : float;
var priority : float;
var maxPriority : float;
var now : float;
var remove : bool;
var visibleActorIndex : int;

if ( useVisibilityCheck )
{
currentTarget = this.GetTarget();
playerPosition = this.GetWorldPosition();
now = theGame.GetEngineTimeAsSeconds();

for ( i = targets.Size() - 1; i >= 0; i-=1 )
{
target = targets[ i ];
if ( target != currentTarget && ( !IsPCModeEnabled() && !WasVisibleInScaledFrame( target, softLockFrameSize, softLockFrameSize ) ) )
{
remove = true;
visibleActorIndex = visibleActors.FindFirst( target );
if ( visibleActorIndex != -1 )
{
if ( usePrecalcs )
{
distanceToPlayer = Distance2DBetweenCapsuleAndPoint( target, this ) - targetingPrecalcs.playerRadius;
}
else
{
distanceToPlayer = Distance2DBetweenCapsules( this, target );
}
// if within soft lock distance and soft lock visibility duration -> don't remove yet
if ( distanceToPlayer < this.softLockDist && ( now - visibleActorsTime[ i ] ) < 1.0f )
{
remove = false;
}
}
if ( remove )
{
targets.EraseFast( i );
}
}
else
{
visibleActorIndex = visibleActors.FindFirst( target );
if ( visibleActorIndex == -1 )
{
visibleActors.PushBack( target );
visibleActorsTime.PushBack( now );
}
else
{
visibleActorsTime[ visibleActorIndex ] = now;
}
}
}
}

selectedTarget = NULL;
maxPriority = -1.0f;
for( i = targets.Size() - 1; i >= 0; i-=1 )
{
priority = CalcSelectionPriority( targets[ i ], selectionWeights, sourcePosition, headingVector );
if ( priority > maxPriority )
{
maxPriority = priority;
selectedTarget = targets[ i ];
}
}

//LogChannel( 'selectedTarget', selectedTarget );
return selectedTarget;
}

function Distance2DBetweenCapsuleAndPoint( actor : CActor, entity : CEntity ) : float
{
var distance : float;
var mpac : CMovingPhysicalAgentComponent;

distance = VecDistance2D( actor.GetWorldPosition(), entity.GetWorldPosition() );

mpac = (CMovingPhysicalAgentComponent)actor.GetMovingAgentComponent();
if ( mpac )
{
distance -= mpac.GetCapsuleRadius();
}

return distance;
}


function Distance2DBetweenCapsules( actor1 : CActor, actor2 : CActor ) : float
{
var distance : float;
var mpac : CMovingPhysicalAgentComponent;

distance = VecDistance2D( actor1.GetWorldPosition(), actor2.GetWorldPosition() );

mpac = (CMovingPhysicalAgentComponent)actor1.GetMovingAgentComponent();
if ( mpac )
{
distance -= mpac.GetCapsuleRadius();
}

mpac = (CMovingPhysicalAgentComponent)actor2.GetMovingAgentComponent();
if ( mpac )
{
distance -= mpac.GetCapsuleRadius();
}

return distance;
}

protected function ProcessSelectionWeights() : STargetSelectionWeights
{
var selectionWeights : STargetSelectionWeights;

if ( ShouldUsePCModeTargeting() )
{
selectionWeights.angleWeight = 0.75f;
selectionWeights.distanceWeight = 0.25f;
selectionWeights.distanceRingWeight = 0.f;
return selectionWeights;
}

if ( IsInCombatAction() && ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Dodge || GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Roll ) )
{
selectionWeights.angleWeight = 0.575f;
selectionWeights.distanceWeight = 0.175f;
selectionWeights.distanceRingWeight = 0.25f;
}
if ( !lAxisReleasedAfterCounter || IsInCombatAction() ) // !bLAxisReleased ||
{
if ( theInput.GetActionValue( 'ThrowItem' ) == 1.f || ( rangedWeapon && rangedWeapon.GetCurrentStateName() != 'State_WeaponWait' ) )
{
selectionWeights.angleWeight = 1.f;
selectionWeights.distanceWeight = 0.f;
selectionWeights.distanceRingWeight = 0.f;
}
else if ( !lAxisReleasedAfterCounter ) // !bLAxisReleased )
{
selectionWeights.angleWeight = 0.55f;//0.75f;
selectionWeights.distanceWeight = 0.45f;//0.25f;
selectionWeights.distanceRingWeight = 0.f;//0.3f;
}
else
{
selectionWeights.angleWeight = 0.75f;
selectionWeights.distanceWeight = 0.25f;
selectionWeights.distanceRingWeight = 0.f;//0.3f;
}
}
else if( !IsCurrentSignChanneled() )
{
selectionWeights.angleWeight = 0.35f;
selectionWeights.distanceWeight = 0.65f;
selectionWeights.distanceRingWeight = 0.f;
}
else
{
selectionWeights.angleWeight = 0.275f;
selectionWeights.distanceWeight = 0.375f;
selectionWeights.distanceRingWeight = 0.35f;
}

return selectionWeights;
}

protected function CalcSelectionPriority( target : CEntity, selectionWeights : STargetSelectionWeights, sourcePosition : Vector, headingVector : Vector ) : float
{
var sourceToTarget : Vector;
var sourceToTargetDist : float;
var sourceToTargetAngleDiff : float;
var selectionPriority : float;

sourceToTarget = target.GetWorldPosition() - sourcePosition;
sourceToTargetDist = VecLength2D( sourceToTarget );
// normalize2D sourcetoTarget
if ( sourceToTargetDist < 0.0001f )
{
sourceToTarget = Vector( 0.0f, 0.0f, 0.0f );
}
else
{
sourceToTarget *= ( 1.0f / sourceToTargetDist );
}
sourceToTargetAngleDiff = AbsF( Rad2Deg( AcosF( VecDot2D( sourceToTarget, headingVector ) ) ) );

selectionPriority = ( selectionWeights.angleWeight * ( ( 180 - sourceToTargetAngleDiff ) / 180 ) );
selectionPriority += selectionWeights.distanceWeight * ( ( softLockDist - sourceToTargetDist ) / softLockDist );

if ( sourceToTargetDist > 0.f && sourceToTargetDist <= 6.f )
{
selectionPriority += selectionWeights.distanceRingWeight * 1.0f;
}
else if ( sourceToTargetDist > 6.f && sourceToTargetDist <= softLockDist )
{
selectionPriority += selectionWeights.distanceRingWeight * 0.4f;
}

return selectionPriority;
}

protected function SetTarget( targetActor : CActor, optional forceSetTarget : bool )
{
var playerToTargetDistance : float;
var target : CActor;
var allow : bool;

target = GetTarget();

if ( !IsInNonGameplayCutscene() )
allow = true;

if ( allow )
{
if ( targetActor )
{
if ( ( targetActor.IsAlive() && !targetActor.IsKnockedUnconscious() ) || finishableEnemiesList.Contains( targetActor ) )
allow = true;
else
allow = false;
}
else
allow = true;
}

if ( forceSetTarget )
allow = true;

if ( allow && target != targetActor )
allow = true;
else
allow = false;

if ( allow )
{
SetPlayerTarget( targetActor );

//playerToTargetDistance = VecDistance( GetWorldPosition(), targetActor.GetNearestPointInBothPersonalSpaces( GetWorldPosition() ) );
//LogChannel( 'Targeting', "selection " + playerToTargetDistance );
}
}

/*
protected function SetTarget( targetActor : CActor, optional forceSetTarget : bool )
{
var playerToTargetDistance : float;
var target : CActor;
//var gec : CGameplayEffectsComponent;


if ( !IsInNonGameplayCutscene()
&& ( ( ( !targetActor || ( ( targetActor.IsAlive() || finishableEnemiesList.Contains( targetActor ) ) && !targetActor.IsKnockedUnconscious() ) ) && !IsActorLockedToTarget() ) || forceSetTarget ) )
{
target = GetTarget();

if ( target != targetActor )
{
if( target )
{
target.StopEffect( 'select_character' );
//gec = GetGameplayEffectsComponent( target );
//if(gec)
// gec.SetGameplayEffectFlag( EGEF_OutlineTarget, 0 );
}

SetPlayerTarget( targetActor );
target = targetActor;

if(target)
{
playerToTargetDistance = VecDistance( GetWorldPosition(), target.GetNearestPointInBothPersonalSpaces( GetWorldPosition() ) );
}

//LogChannel( 'Targeting', "selection " + playerToTargetDistance );
}
}
}
*/
public function SetSlideTarget( actor : CGameplayEntity )
{
//if ( slideTarget != actor && slideTarget )
// EnableCloseCombatCharacterRadius( false );

slideTarget = actor;

if ( slideTarget )
SetPlayerCombatTarget((CActor)slideTarget);
else
Log( "slideTarget = NULL" );

if ( slideTarget == nonActorTarget )
UpdateDisplayTarget( true, true );
else
UpdateDisplayTarget();

ConfirmDisplayTargetTimer(0.f);
}

event OnForceSelectLockTarget()
{
ForceSelectLockTarget();
}

private function ForceSelectLockTarget()
{
var newMoveTarget : CActor;
var target : CActor;

newMoveTarget = GetScreenSpaceLockTarget( GetDisplayTarget(), 180.f, 1.f, 90 );

if ( !newMoveTarget )
newMoveTarget = GetScreenSpaceLockTarget( GetDisplayTarget(), 180.f, 1.f, -90 );

if ( newMoveTarget )
{
thePlayer.ProcessLockTarget( newMoveTarget );

target = GetTarget();
if ( target )
{
thePlayer.SetSlideTarget( target );

if ( IsHardLockEnabled() )
thePlayer.HardLockToTarget( true );
}
}
else
{
thePlayer.HardLockToTarget( false );
}
}

public function SetFinisherVictim( actor : CActor )
{
finisherVictim = actor;
}

public function GetFinisherVictim() : CActor
{
return finisherVictim;
}

protected function SetNonActorTarget( actor : CGameplayEntity )
{
if ( nonActorTarget != actor )
nonActorTarget = actor;
}

timer function DisableTargetHighlightTimer( time : float , id : int)
{
var target : CActor;
target = GetTarget();

if( target )
{
target.StopEffect( 'select_character' );
}
}

public function WasVisibleInScaledFrame( entity : CEntity, frameSizeX : float, frameSizeY : float ) : bool
{
var position : Vector;
var positionFound : bool;
var inFront : bool;
var x, y : float;
var boneIndex : int;
var actor : CActor;
var gameplayEntity : CGameplayEntity;
var gameplayEntityMatrix : Matrix;
var drawableComp : CDrawableComponent;
var box : Box;
var ok : bool;

if ( !entity )
{
return false;
}
if ( frameSizeX <= 0.0f && frameSizeY <= 0.0f )
{
LogChannel( 'WasVisibleInScaledFrame', "ERROR: WasVisibleInScaledFrame: frameSizeX && frameSizeY are both negative!!!" );
return false;
}

if ( useNativeTargeting )
{
return targeting.WasVisibleInScaledFrame( entity, frameSizeX, frameSizeY );
}

position = entity.GetWorldPosition();

actor = (CActor)entity;
if ( actor )
{
boneIndex = entity.GetBoneIndex( 'pelvis' );
if ( boneIndex == -1 )
{
boneIndex = entity.GetBoneIndex( 'k_pelvis_g' ); // not hack at all. DONE !*100000000000000000000
}

if ( boneIndex != -1 )
{
position = MatrixGetTranslation( entity.GetBoneWorldMatrixByIndex( boneIndex ) );
}
else
{
position = entity.GetWorldPosition();
position.Z += ( (CMovingPhysicalAgentComponent)actor.GetMovingAgentComponent() ).GetCapsuleHeight() * 0.5;
}
positionFound = true;
}
else
{
gameplayEntity = (CGameplayEntity)entity;
if ( gameplayEntity && !( gameplayEntity.aimVector.X == 0 && gameplayEntity.aimVector.Y == 0 && gameplayEntity.aimVector.Z == 0 ) )
{
gameplayEntityMatrix = gameplayEntity.GetLocalToWorld();
position = VecTransform( gameplayEntityMatrix, gameplayEntity.aimVector );
positionFound = true;
}
}

// if still not found proper position for test
if ( !positionFound )
{
drawableComp = (CDrawableComponent)entity.GetComponentByClassName( 'CDrawableComponent' );
if ( drawableComp && drawableComp.GetObjectBoundingVolume( box ) )
{
position.Z += ( ( box.Max.Z - box.Min.Z ) * 0.66f );
}
}

inFront = theCamera.WorldVectorToViewRatio( position, x, y );
if ( !inFront )
{
return false;
}
x = AbsF( x );
y = AbsF( y );

ok = true;
ok = ok && ( frameSizeX <= 0.0f || x < frameSizeX );
ok = ok && ( frameSizeY <= 0.0f || y < frameSizeY );

return ok;
}

public function HardLockToTarget( flag : bool )
{
EnableHardLock( flag );
LockToTarget( flag );
}

public function LockToTarget( flag : bool )
{
if ( IsHardLockEnabled() && !flag )
return;

LockCameraToTarget( flag );
LockActorToTarget( flag );
}

public function LockCameraToTarget( flag : bool )
{
if ( flag && !IsCameraLockedToTarget() )
{
thePlayer.EnableManualCameraControl( false, 'LockCameraToTarget' );
//((CCustomCamera)theCamera.GetTopmostCameraObject()).EnableManualControl( false );
SetIsCameraLockedToTarget( flag );
}
else if ( !flag && IsCameraLockedToTarget() )
{
thePlayer.EnableManualCameraControl( true, 'LockCameraToTarget' );
//((CCustomCamera)theCamera.GetTopmostCameraObject()).EnableManualControl( true );
SetIsCameraLockedToTarget( flag );
}
}

public function LockActorToTarget( flag : bool, optional withoutIcon : bool )
{
var displayTargetActor : CActor;

if ( flag )
{
if ( !IsActorLockedToTarget() )
{
//SetSlideTarget( target );
SetIsActorLockedToTarget( flag );
SetMoveTargetChangeAllowed( true );
SetMoveTarget( GetTarget() );
SetMoveTargetChangeAllowed( false );
SetTarget( GetTarget() );
SetSlideTarget( GetTarget() );
AddTimer( 'CheckLockTargetIsAlive', 0.5, true );
}

if ( IsActorLockedToTarget() )
{
displayTargetActor = (CActor)( GetDisplayTarget() );

if ( displayTargetActor && IsThreat( displayTargetActor ) && !withoutIcon )
EnableHardLockIcon( flag );
}
}
else if ( !flag && IsActorLockedToTarget() )
{
SetIsActorLockedToTarget( flag );
SetMoveTargetChangeAllowed( true );
RemoveTimer( 'CheckLockTargetIsAlive' );
EnableHardLockIcon( flag );
}
}

private function EnableHardLockIcon( flag : bool )
{
var hud : CR4ScriptedHud;
var module : CR4HudModuleEnemyFocus;

if( GetTarget().HasTag( 'NoHardLockIcon' ) )
return;

hud = (CR4ScriptedHud)theGame.GetHud();
module = (CR4HudModuleEnemyFocus)hud.GetHudModule("EnemyFocusModule");
module.SetShowHardLock( flag );
}

private timer function CheckLockTargetIsAlive( time : float , id : int)
{
var vitality : float;
var essence : float;
var actor : CActor;
var target : CActor;

target = (CActor)GetDisplayTarget();

if( !target
|| !target.IsAlive()
|| ( !target.GetGameplayVisibility() )
|| !CanBeTargetedIfSwimming( target )
|| (!target.UsesVitality() && !target.UsesEssence()))
{
if ( !ProcessLockTarget() )
HardLockToTarget( false );
}
}

//////////////////////////////////////////////////////////////////////////////////////////
//
// @Damage
//
//////////////////////////////////////////////////////////////////////////////////////////
protected function PlayHitAnimation(damageAction : W3DamageAction, animType : EHitReactionType)
{
var hitRotation : float;

if( damageAction.HasAnyCriticalEffect() )
return;

if( !substateManager.ReactOnBeingHit() && !IsUsingVehicle() )
{
return;
}

if ( damageAction.GetHitReactionType() == EHRT_Reflect )
SetBehaviorVariable( 'isAttackReflected', 1.f );
else
SetBehaviorVariable( 'isAttackReflected', 0.f );
SetBehaviorVariable( 'HitReactionType',(int)animType);
SetBehaviorVariable( 'HitReactionWeapon', ProcessSwordOrFistHitReaction( this, (CActor)damageAction.attacker ) );

if (damageAction.attacker)
{
SetHitReactionDirection(damageAction.attacker);
SetDetailedHitReaction(damageAction.GetSwingType(), damageAction.GetSwingDirection());
}

RaiseForceEvent( 'Hit' );

if ( IsUsingBoat() )
{
SoundEvent("cmb_play_hit_light");
return;
}

if ( IsUsingVehicle() )
return;

if(damageAction.attacker)
{
hitRotation = VecHeading( damageAction.attacker.GetWorldPosition() - GetWorldPosition() );
if ( this.GetBehaviorVariable( 'HitReactionDirection' ) == (float)( (int)EHRD_Back ) )
hitRotation += 180.f;

//GetVisualDebug().AddArrow( 'temp', GetWorldPosition(), GetWorldPosition() + VecFromHeading( hitRotation )*2, 1.f, 0.2f, 0.2f, true, Color(0,255,255), true, 5.f );
SetCustomRotation( 'Hit', hitRotation, 1080.f, 0.1f, false );
}

CriticalEffectAnimationInterrupted("PlayHitAnimation");
}

public function ReduceDamage( out damageData : W3DamageAction)
{
super.ReduceDamage(damageData);

//halve damage if from your own bomb
if(damageData.attacker == this && (damageData.GetBuffSourceName() == "petard" || (W3Petard)damageData.causer) )
{
if ( theGame.CanLog() )
{
LogDMHits("CR4Player.ReduceDamage: hitting self with own bomb - damage reduced by 50%", damageData );
}
damageData.processedDmg.vitalityDamage = damageData.processedDmg.vitalityDamage / 2;
damageData.processedDmg.essenceDamage = damageData.processedDmg.essenceDamage / 2;
}
}

//crit hit chance 0-1
public function GetCriticalHitChance(isHeavyAttack : bool, target : CActor, victimMonsterCategory : EMonsterCategory) : float
{
var critChance : float;
var oilChanceAttribute : name;

critChance = 0;

//cheats
if(FactsQuerySum('debug_fact_critical_boy') > 0)
{
critChance += 1;
}

if( IsInState( 'HorseRiding' ) && ((CActor)GetUsedVehicle()).GetMovingAgentComponent().GetRelativeMoveSpeed() >= 4.0 )
{
critChance += 1;
}

//normal case
critChance += CalculateAttributeValue(GetAttributeValue(theGame.params.CRITICAL_HIT_CHANCE));

//active skills bonus
if(isHeavyAttack && CanUseSkill(S_Sword_s08))
critChance += CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s08, theGame.params.CRITICAL_HIT_CHANCE, false, true)) * GetSkillLevel(S_Sword_s08);
else if (!isHeavyAttack && CanUseSkill(S_Sword_s17))
critChance += CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s17, theGame.params.CRITICAL_HIT_CHANCE, false, true)) * GetSkillLevel(S_Sword_s17);

if(target && target.HasBuff(EET_Confusion))
{
critChance += ((W3ConfuseEffect)target.GetBuff(EET_Confusion)).GetCriticalHitChanceBonus();
}

//oils
oilChanceAttribute = MonsterCategoryToCriticalChanceBonus(victimMonsterCategory);
if(IsNameValid(oilChanceAttribute))
critChance += CalculateAttributeValue(GetAttributeValue(oilChanceAttribute));

return critChance;
}

//gets damage bonus for critical hit
public function GetCriticalHitDamageBonus(weaponId : SItemUniqueId, victimMonsterCategory : EMonsterCategory, isStrikeAtBack : bool) : SAbilityAttributeValue
{
var bonus, oilBonus : SAbilityAttributeValue;
var vsAttributeName : name;

bonus = super.GetCriticalHitDamageBonus(weaponId, victimMonsterCategory, isStrikeAtBack);

//oil bonus
if(inv.ItemHasOilApplied(weaponId))
{
vsAttributeName = MonsterCategoryToCriticalDamageBonus(victimMonsterCategory);
oilBonus = inv.GetItemAttributeValue(weaponId, vsAttributeName);
bonus += oilBonus;
}

return bonus;
}

/**
Called when we want to play hit animation
*/
public function ReactToBeingHit(damageAction : W3DamageAction, optional buffNotApplied : bool) : bool
{
var strength : float;
var animType : EHitReactionType;
var sup : bool;
var boat : CBoatComponent;
var combatActionType : int;
var attackAction : W3Action_Attack;
var npc : CNewNPC;
var shakeCam : bool;

attackAction = (W3Action_Attack)damageAction;
//not parried, not countered, not dot, not dodged
if(!damageAction.IsDoTDamage() && (!attackAction || (!attackAction.IsParried() && !attackAction.IsCountered() && !attackAction.WasDodged()) ) )
{
npc = (CNewNPC)attackAction.attacker;
if(npc && npc.IsHeavyAttack(attackAction.GetAttackName()))
theGame.VibrateControllerVeryHard();//player got heavy hit
else
theGame.VibrateControllerHard();//player got hit
}

if ( (CActor)GetUsedVehicle() && this.playerAiming.GetCurrentStateName() == 'Aiming' )
{
OnRangedForceHolster( true, true );
}

combatActionType = (int)GetBehaviorVariable( 'combatActionType' );

if ( thePlayer.IsCurrentlyDodging() && ( combatActionType == (int)CAT_Roll || combatActionType == (int)CAT_CiriDodge ) )
sup = false;
else if ( this.GetCurrentStateName() == 'DismountHorse' )
sup = false;
else
sup = super.ReactToBeingHit(damageAction, buffNotApplied);
sup = false;
//telemetry
if(damageAction.attacker)
theTelemetry.LogWithLabelAndValue( TE_FIGHT_HERO_GETS_HIT, damageAction.attacker.ToString(), (int)damageAction.processedDmg.vitalityDamage );

//camera shake
if(damageAction.DealsAnyDamage())
{
if( ((W3PlayerWitcher)this) && GetWitcherPlayer().IsAnyQuenActive() && damageAction.IsDoTDamage())
{
shakeCam = false;
}
else
{
shakeCam = true;
}

if(shakeCam)
{
animType = ModifyHitSeverityReaction(this, damageAction.GetHitReactionType());

if(animType == EHRT_Light || animType == EHRT_LightClose)
strength = 0.1;
else if(animType == EHRT_Heavy || animType == EHRT_Igni)
strength = 0.2;

GCameraShakeLight(strength, false, GetWorldPosition(), 10.0);
}

this.HitReactionEffect( 0.25 );

//reset uninterrupted hits
ResetUninterruptedHitsCount();
}

//pause health regen
if(!damageAction.IsDoTDamage() && IsThreatened() && ShouldPauseHealthRegenOnHit() && damageAction.DealsAnyDamage() && !damageAction.WasDodged() && attackAction.CanBeParried() && !attackAction.IsParried())
{
PauseHPRegenEffects('being_hit', theGame.params.ON_HIT_HP_REGEN_DELAY);
}

//if player is on a boat and not moving then force dismount
/*if(usedVehicle)
{
boat = (CBoatComponent) usedVehicle.GetComponentByClassName('CBoatComponent');
if(boat && boat.GetLinearVelocityXY() < boat.IDLE_SPEED_THRESHOLD)
{
boat.StopAndDismountBoat();
}
}*/

//finesse achievement fail
if(damageAction.processedDmg.vitalityDamage > 0 && !((W3Effect_Toxicity)damageAction.causer))
ReceivedCombatDamage();

//tutorial
if(FactsQuerySum("tut_fight_use_slomo") > 0)
{
theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_TutorialFight) );
FactsRemove("tut_fight_slomo_ON");
}

// State
if( !substateManager.ReactOnBeingHit( damageAction ) )
{
GoToCombatIfNeeded();
//PushState( 'CombatFists' );
}

return sup;
}

protected function ShouldPauseHealthRegenOnHit() : bool
{
return true;
}

public function PlayHitEffect(damageAction : W3DamageAction)
{
super.PlayHitEffect(damageAction);

//fullscreen hit fx
if(damageAction.DealsAnyDamage() && !damageAction.IsDoTDamage())
PlayEffect('hit_screen');
}

function HitReactionEffect( interval : float )
{
if ( hitReactionEffect )
{
PlayEffect( 'radial_blur' );
hitReactionEffect = false;
}
else
{
AddTimer( 'HitReactionEffectCooldown', interval, false );
}
}

timer function HitReactionEffectCooldown( td : float , id : int)
{
hitReactionEffect = true;
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// @Parry
//
//////////////////////////////////////////////////////////////////////////////////////////

function PerformParryCheck( parryInfo : SParryInfo) : bool
{
var mult : float;
var parryType : EParryType;
var parryDir : EPlayerParryDirection;
var parryHeading : float;
var fistFightParry : bool;
var action : W3DamageAction;
var xmlStaminaDamage : float;
var xmlStaminaDamageName : name = 'stamina_damage' ;

// if ( !parryInfo.canBeParried )
// return false;

if(CanParryAttack() && /*parryInfo.targetToAttackerAngleAbs < theGame.params.PARRY_HALF_ANGLE &&*/ FistFightCheck( parryInfo.target, parryInfo.attacker, fistFightParry ) )
{
parryHeading = GetParryHeading( parryInfo, parryDir ) ;
//GetVisualDebug().AddArrow( 'CombatActionHeading', GetWorldPosition(), GetWorldPosition() + VecFromHeading( GetParryHeading( parryInfo, parryDir ) )*2, 1.f, 0.2f, 0.2f, true, Color(0,255,255), true, 5.f );
SetBehaviorVariable( 'parryDirection', (float)( (int)( parryDir ) ) );
SetBehaviorVariable( 'parryDirectionOverlay', (float)( (int)( parryDir ) ) );
SetBehaviorVariable( 'parryType', ChooseParryTypeIndex( parryInfo ) );

if ( IsInCombatActionFriendly() )
RaiseEvent('CombatActionFriendlyEnd');

if ( HasStaminaToParry(parryInfo.attackActionName) )
{
this.SetBehaviorVariable( 'combatActionType', (int)CAT_Parry );

if ( parryInfo.targetToAttackerDist > 3.f && !bLAxisReleased && !thePlayer.IsCiri() )
{
if ( !RaiseForceEvent( 'PerformParryOverlay' ) )
return false;
else
ClearCustomOrientationInfoStack();
}
else
{
if ( RaiseForceEvent( 'PerformParry' ) )
{
OnCombatActionStart();
ClearCustomOrientationInfoStack();
SetSlideTarget( parryInfo.attacker );
SetCustomRotation( 'Parry', parryHeading, 1080.f, 0.1f, false );
}
else
return false;
}
}
else
{
AddEffectDefault(EET_Stagger, parryInfo.attacker, "Parry");
return true;
}

//parryTarget := this
if ( parryInfo.attacker.IsWeaponHeld( 'fist' ) && !parryInfo.target.IsWeaponHeld( 'fist' ) )
{
parryInfo.attacker.ReactToReflectedAttack(parryInfo.target);
}
else
{
if ( this.IsInFistFightMiniGame() && fistFightParry )
{
if ( IsNameValid(xmlStaminaDamageName) )
{
xmlStaminaDamage = CalculateAttributeValue(parryInfo.attacker.GetAttributeValue( xmlStaminaDamageName ));
DrainStamina(ESAT_FixedValue, xmlStaminaDamage);
}
}
else
{
DrainStamina(ESAT_Parry, 0, 0, '', 0, mult);
}
if(IsLightAttack(parryInfo.attackActionName))
parryInfo.target.PlayEffectOnHeldWeapon('light_block');
else
parryInfo.target.PlayEffectOnHeldWeapon('heavy_block');
}
return true;
}

return false;
}

protected function GetParryHeading( parryInfo : SParryInfo, out parryDir : EPlayerParryDirection ) : float
{
var targetToAttackerHeading : float;
var currToTargetAttackerAngleDiff : float;

targetToAttackerHeading = VecHeading( parryInfo.attacker.GetWorldPosition() - parryInfo.target.GetWorldPosition() );
currToTargetAttackerAngleDiff = AngleDistance( VecHeading( parryInfo.target.GetHeadingVector() ), targetToAttackerHeading );

if ( !parryInfo.target.IsWeaponHeld( 'fist' ) )
{
if( currToTargetAttackerAngleDiff > -45 && currToTargetAttackerAngleDiff < 45 )
{
parryDir = PPD_Forward;
return targetToAttackerHeading;
}
else if( currToTargetAttackerAngleDiff >= 45 && currToTargetAttackerAngleDiff < 135 )
{
parryDir = PPD_Right;
//return targetToAttackerHeading;
return targetToAttackerHeading + 90;
}
else if( currToTargetAttackerAngleDiff <= -45 && currToTargetAttackerAngleDiff > -135 )
{
parryDir = PPD_Left;
//return targetToAttackerHeading;
return targetToAttackerHeading - 90;
}
else
{
parryDir = PPD_Back;
//return targetToAttackerHeading;
return targetToAttackerHeading + 180;
}
}
else
{
if( currToTargetAttackerAngleDiff > -45 && currToTargetAttackerAngleDiff < 45 )
{
parryDir = PPD_Forward;
return targetToAttackerHeading;
}
else if( currToTargetAttackerAngleDiff >= 45 && currToTargetAttackerAngleDiff < 180 )
{
parryDir = PPD_Right;
return targetToAttackerHeading + 90;
}
else if( currToTargetAttackerAngleDiff <= -45 && currToTargetAttackerAngleDiff >= -180 )
{
parryDir = PPD_Left;
return targetToAttackerHeading - 90;
}
else
{
parryDir = PPD_Back;
return targetToAttackerHeading + 180;
}
}
}

function ProcessLockTarget( optional newLockTarget : CActor, optional checkLeftStickHeading : bool ) : bool
{
var attackerNearestPoint : Vector;
var playerNearestPoint : Vector;
var incomingAttacker : CActor;
var tempLockTarget : CActor;
var target : CActor;
var useIncomingAttacker : bool;

if ( newLockTarget )
tempLockTarget = newLockTarget;
else
{
incomingAttacker = GetClosestIncomingAttacker();
if ( incomingAttacker && incomingAttacker.IsAlive() && IsUsingVehicle() )
{
tempLockTarget = incomingAttacker;
useIncomingAttacker = false;
}

if ( !useIncomingAttacker )
{
target = GetTarget();
if ( target && target.IsAlive() && target.GetGameplayVisibility() && IsEnemyVisible( target ) && IsThreat( target ) && CanBeTargetedIfSwimming( target ) )
tempLockTarget = FindTarget();
else
{
tempLockTarget = GetScreenSpaceLockTarget( GetDisplayTarget(), 180.f, 1.f, 0.f );
}
}
}

if ( tempLockTarget )
{
if ( IsCombatMusicEnabled() || hostileEnemies.Size() > 0 )
{
if ( !IsThreat( tempLockTarget ) )
tempLockTarget = NULL;
}
}

SetTarget( tempLockTarget, true );
SetMoveTargetChangeAllowed( true );
SetMoveTarget( tempLockTarget );
SetMoveTargetChangeAllowed( false );
SetSlideTarget( tempLockTarget );

if ( tempLockTarget )
{
if ( this.IsActorLockedToTarget() )
EnableHardLockIcon( true );

return true;
}
else
return false;
}

//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////// @COMBAT ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

//checks if player is doing special attack light/heavy
public function IsDoingSpecialAttack(heavy : bool) : bool
{
var pat : EPlayerAttackType;

if(IsInCombatAction() && ( (int)GetBehaviorVariable('combatActionType')) == CAT_SpecialAttack)
{
pat = (int)GetBehaviorVariable('playerAttackType');

if(heavy && pat == PAT_Heavy)
{
return true;
}
else if(!heavy && pat == PAT_Light)
{
return true;
}
}

return false;
}

public function SetIsCurrentlyDodging(enable : bool, optional isRolling : bool)
{
super.SetIsCurrentlyDodging(enable, isRolling);

if ( isRolling )
{
SetCanPlayHitAnim( false );
this.AddBuffImmunity( EET_KnockdownTypeApplicator, 'Roll', false );
this.AddBuffImmunity( EET_Knockdown, 'Roll', false );
this.AddBuffImmunity( EET_HeavyKnockdown, 'Roll', false );
this.AddBuffImmunity( EET_Stagger, 'Roll', false );
}
else
{
SetCanPlayHitAnim( true );
this.RemoveBuffImmunity( EET_KnockdownTypeApplicator, 'Roll' );
this.RemoveBuffImmunity( EET_Knockdown, 'Roll' );
this.RemoveBuffImmunity( EET_HeavyKnockdown, 'Roll' );
this.RemoveBuffImmunity( EET_Stagger, 'Roll' );
}
}

public function EnableHardLock( flag : bool )
{
super.EnableHardLock(flag);

if(flag && ShouldProcessTutorial('TutorialTargettingWaiting'))
{
FactsAdd("tut_hardlocked");
}
}

protected function TestParryAndCounter(data : CPreAttackEventData, weaponId : SItemUniqueId, out parried : bool, out countered : bool) : array
{
var ret : array;

//cheat for QA tests - NPCs won't parry/counter
if(FactsQuerySum('player_is_the_boss') > 0)
{
//---------------- DEBUG
//draw debug AR
SetDebugAttackRange(data.rangeName);
RemoveTimer('PostAttackDebugRangeClear'); //disable AR clearing since we've just set a new one

return ret;
}

ret = super.TestParryAndCounter(data, weaponId, parried, countered);

//achievement
if(parried)
theGame.GetGamerProfile().ResetStat(ES_CounterattackChain);

return ret;
}

public function SetSpecialAttackTimeRatio(f : float)
{
LogSpecialHeavy(f);
specialAttackTimeRatio = f;
}

public function GetSpecialAttackTimeRatio() : float
{
return specialAttackTimeRatio;
}

//called when we processed special heavy attack action - either from hit or from CombatActionEnd()
public function OnSpecialAttackHeavyActionProcess()
{
//clear ration after attack performed
SetSpecialAttackTimeRatio(0.f);
}

protected function DoAttack(animData : CPreAttackEventData, weaponId : SItemUniqueId, parried : bool, countered : bool, parriedBy : array, attackAnimationName : name, hitTime : float)
{
var shakeStr : float;
var weapon : EPlayerWeapon;
var targetActor : CActor;

//cam shake for player's heavy attacks
/*
if ( animData.attackName == 'attack_heavy_special' )
{
if( specialAttackTimeRatio != 1 )
shakeStr = (specialAttackTimeRatio / 3.333) + 0.2;
else
shakeStr = 0.5;

GCameraShake( shakeStr, false, GetWorldPosition(), 10);
}
else if ( IsHeavyAttack(attackActionName) )
{
if(parriedBy.Size() > 0)
shakeStr = 0.2;
else
shakeStr = 0.1;

GCameraShake(shakeStr, false, GetWorldPosition(), 10);
}
*/
// modXTfinishers END

targetActor = (CActor)slideTarget;
if ( targetActor && hitTargets.Contains(targetActor) )
{
weapon = this.GetMostConvenientMeleeWeapon(targetActor,true);
if ( this.GetCurrentMeleeWeaponType() != PW_Fists && weapon != this.GetCurrentMeleeWeaponType() )
{
if ( weapon == PW_Steel )
{
thePlayer.OnEquipMeleeWeapon(PW_Steel,true);
}
else if ( weapon == PW_Silver )
{
thePlayer.OnEquipMeleeWeapon(PW_Silver,true);
}

}
}

super.DoAttack(animData, weaponId, parried, countered, parriedBy, attackAnimationName, hitTime);
}

//var delayCombatStanceTimeStamp : float;

private var confirmCombatStanceTimeStamp : float;
private var isConfirmingCombatStance : bool;
final function SetPlayerCombatStance(stance : EPlayerCombatStance, optional force : bool )
{
var stanceInt : int;

if ( !CanChangeCombatStance( stance, force ) )
return;

combatStance = stance;
stanceInt = (int)stance;

SetBehaviorVariable( 'playerCombatStance' , (float)stanceInt);
SetBehaviorVariable( 'playerCombatStanceForOverlay' , (float)stanceInt);
if ( force )
SetBehaviorVariable( 'forceCombatStance' , 1.f);
else
SetBehaviorVariable( 'forceCombatStance' , 0.f);
}

private function CanChangeCombatStance( stance : EPlayerCombatStance, optional force : bool ) : bool
{
var currTime : float;

if ( force )
return true;

if ( IsInFistFightMiniGame() )
return true;

if ( isInHolsterAnim )
return false;

if ( ( combatStance == PCS_Normal || combatStance == PCS_AlertFar )
&& stance == PCS_AlertNear )
{
currTime = theGame.GetEngineTimeAsSeconds();
if ( !isConfirmingCombatStance )
{
isConfirmingCombatStance = true;
confirmCombatStanceTimeStamp = currTime;

if ( this.playerMoveType == PMT_Idle )
this.SetBehaviorVariable('isInCombatForOverlay',0.f);
else
this.SetBehaviorVariable('isInCombatForOverlay',1.f);

return false;
}
else if ( currTime < confirmCombatStanceTimeStamp + 1.f )
{
if ( stance == PCS_AlertNear )
return false;
}
else
isConfirmingCombatStance = false;
}
else
isConfirmingCombatStance = false;

return true;
}

private var isInHolsterAnim : bool;
event OnHolsterWeaponStart()
{
isInHolsterAnim = true;
}

event OnHolsterWeaponEnd()
{
isInHolsterAnim = false;
}

final function GetPlayerCombatStance() : EPlayerCombatStance
{
return combatStance;
}

timer function DelayedDisableFindTarget( time : float , id : int)
{
if ( GetTarget().IsAlive() )
{
EnableFindTarget( false );
}
else
{
EnableFindTarget( true );
}
}

///////////////////////////////////////////////////////////////////////////
// @BUFFER @COMBATACTIONBUFFER
///////////////////////////////////////////////////////////////////////////

private var dodgeTimerRunning : bool;

function StartDodgeTimer()
{
dodgeTimerRunning = true;
thePlayer.AddTimer('DodgeTimer',0.2,false);
}

function StopDodgeTimer()
{
this.RemoveTimer('DodgeTimer');
dodgeTimerRunning = false;
}

function IsDodgeTimerRunning() : bool
{
return dodgeTimerRunning;
}

timer function DodgeTimer( dt : float, id : int )
{
dodgeTimerRunning = false;
}

public function EvadePressed( bufferAction : EBufferActionType )
{
}

public function PerformingCombatAction() : EBufferActionType
{
return BufferCombatAction;
}

public function PushCombatActionOnBuffer( action : EBufferActionType, stage : EButtonStage, optional allSteps : bool )
{
BufferButtonStage = stage;
BufferCombatAction = action;
BufferAllSteps = allSteps;
}

protected function ProcessCombatActionHeading( action : EBufferActionType ) : float
{
var processedActionHeading : float;

HandleMovement( 0.f );

if ( ShouldUsePCModeTargeting() )
return theGame.GetGameCamera().GetHeading();

if ( lAxisReleasedAfterCounter ) // && IsInCombatAction() )
ResetCachedRawPlayerHeading();

processedActionHeading = cachedRawPlayerHeading;

return processedActionHeading;
}
/*
private function ProcessCombatActionHeading( action : EBufferActionType ) : float
{
var processedActionHeading : float;
var unusedActor : CActor; //MS: placeholder variable to fix memory error

if ( IsUsingVehicle() )
{
processedActionHeading = theGame.GetGameCamera().GetHeading();
return processedActionHeading;
}

if ( !bLAxisReleased || lAxisPushedTimeStamp + 0.5f > theGame.GetEngineTimeAsSeconds() )
processedActionHeading = cachedRawPlayerHeading;
else
{
if ( GetDisplayTarget() )
{
if ( cachedCombatActionHeading == cachedRawPlayerHeading )
ResetCachedRawPlayerHeading();
else
{
cachedRawPlayerHeading = cachedCombatActionHeading;
canResetCachedCombatActionHeading = true;
}

processedActionHeading = cachedRawPlayerHeading;
}
else
{
if ( lAxisReleasedAfterCounterNoCA )
ResetRawPlayerHeading();

cachedRawPlayerHeading = rawPlayerHeading;

if ( lAxisReleasedAfterCounterNoCA )
processedActionHeading = GetHeading();
else
processedActionHeading = cachedRawPlayerHeading;
}
}

if ( this.IsCameraLockedToTarget() && this.IsActorLockedToTarget() && action != EBAT_Dodge && action != EBAT_Roll )
processedActionHeading = theGame.GetGameCamera().GetHeading();

if ( lAxisReleasedAfterCounterNoCA )
{
if ( action == EBAT_Dodge || action == EBAT_Roll )
{
if ( ( !IsEnemyInCone( this, GetHeadingVector(), softLockDist, 60.f, unusedActor ) || !IsEnemyInCone( this, GetHeadingVector() + 180, softLockDist, 60.f, unusedActor ) ) && moveTarget )
processedActionHeading = VecHeading( moveTarget.GetWorldPosition() - GetWorldPosition() ) + 180;
else
processedActionHeading = GetHeading() + 180;
}
}

//GetVisualDebug().AddArrow( 'cachedRawPlayerHeading', GetWorldPosition(), GetWorldPosition() + VecFromHeading( cachedRawPlayerHeading ), 1.f, 0.2f, 0.2f, true, Color(0,255,128), true, 5.f );
//GetVisualDebug().AddArrow( 'CombatActionHeading', GetWorldPosition(), GetWorldPosition() + VecFromHeading( GetCombatActionHeading() )*2, 1.f, 0.2f, 0.2f, true, Color(0,255,255), true, 5.f );

return processedActionHeading;
}*/

function ResetRawPlayerHeading()
{
if ( GetDisplayTarget() )
rawPlayerHeading = VecHeading( GetDisplayTarget().GetWorldPosition() - this.GetWorldPosition() );
else
rawPlayerHeading = GetHeading();

//LogChannel('ResetRawPlayerHeading',"ResetRawPlayerHeading" );
}

function ResetCachedRawPlayerHeading()
{
cachedRawPlayerHeading = rawPlayerHeading;
if ( GetDisplayTarget() && IsDisplayTargetTargetable() && AbsF( AngleDistance( VecHeading( GetDisplayTarget().GetWorldPosition() - this.GetWorldPosition() ), this.GetHeading() ) ) < 90.f )
cachedRawPlayerHeading = VecHeading( GetDisplayTarget().GetWorldPosition() - this.GetWorldPosition() );
else
cachedRawPlayerHeading = this.GetHeading();

if ( canResetCachedCombatActionHeading )
cachedCombatActionHeading = cachedRawPlayerHeading;
}

public function GetCombatActionTarget( action : EBufferActionType ) : CGameplayEntity
{
var selectedTargetableEntity : CGameplayEntity;

if ( !this.IsUsingVehicle() )
selectedTargetableEntity = FindNonActorTarget( true, action );

if ( selectedTargetableEntity )
{
return selectedTargetableEntity;
}
else
{
/*if ( !IsCombatMusicEnabled() && displayTarget )
{
if ( !( (CActor)displayTarget ) )
return NULL;
else
return displayTarget;
}*/

if ( !this.IsUsingVehicle() )
FindTarget( true, action, true );
else
((CR4PlayerStateUseGenericVehicle)this.GetState( 'UseGenericVehicle' )).FindTarget();

return GetTarget();
}
}

//MS: FindNonActorTarget may or may not have an interaction component, which is why it is separate from ProcessInteraction
private function FindNonActorTarget( actionCheck : bool, optional action : EBufferActionType ) : CGameplayEntity
{
var targetableEntities : array;
var selectedTargetableEntity : CGameplayEntity;
var selectionPriority : array< float >;
var selectionWeights : STargetSelectionWeights;
var findEntityDist : float;
var i, size : int;
var playerHeading : float;
var playerInventory : CInventoryComponent;
var castSignType : ESignType;
var targetingInfo : STargetingInfo;
var playerPosition : Vector;
var cameraPosition : Vector;
var playerHeadingVector : Vector;
var rawPlayerHeadingVector : Vector;

playerPosition = this.GetWorldPosition();
cameraPosition = theCamera.GetCameraPosition();
rawPlayerHeadingVector = VecFromHeading( rawPlayerHeading );

if ( bCanFindTarget && !IsHardLockEnabled() )
{
if ( actionCheck && IsInCombat() && action == EBAT_CastSign )
{
findEntityDist = 6.f;
selectionWeights.angleWeight = 0.375f;
selectionWeights.distanceWeight = 0.275f;
selectionWeights.distanceRingWeight = 0.35f;
}
else if ( !IsInCombat() && lastAxisInputIsMovement )
{
findEntityDist = softLockDist;
selectionWeights.angleWeight = 0.375f;
selectionWeights.distanceWeight = 0.275f;
selectionWeights.distanceRingWeight = 0.35f;
}
else
{
findEntityDist = softLockDist;
selectionWeights.angleWeight = 0.75f;
selectionWeights.distanceWeight = 0.125f;
selectionWeights.distanceRingWeight = 0.125f;
}

//MSTODO : Ask programmers for filter for interactive entities
if ( !IsInCombat() || !bLAxisReleased )
{
FindGameplayEntitiesInRange( targetableEntities, this, findEntityDist, 10, theGame.params.TAG_SOFT_LOCK );
}

if ( targetableEntities.Size() > 0 )
{
playerInventory = this.GetInventory();
castSignType = this.GetEquippedSign();

if ( !bLAxisReleased )
{
targetingInfo.source = this;
targetingInfo.canBeTargetedCheck = false;
targetingInfo.coneCheck = true;
targetingInfo.coneHalfAngleCos = 0.5f; // = CosF( Deg2Rad( 120.0f * 0.5f ) )
targetingInfo.coneDist = softLockDist;
targetingInfo.coneHeadingVector = rawPlayerHeadingVector;
targetingInfo.distCheck = true;
targetingInfo.invisibleCheck = false;
targetingInfo.navMeshCheck = false;
targetingInfo.frameScaleX = 1.0f;
targetingInfo.frameScaleY = 1.0f;
targetingInfo.knockDownCheck = false;
targetingInfo.knockDownCheckDist = 0.0f;
targetingInfo.rsHeadingCheck = false;
targetingInfo.rsHeadingLimitCos = 1.0f;
}

for( i = targetableEntities.Size()-1; i>=0; i-=1 )
{
if ( bLAxisReleased )
{
if ( !lastAxisInputIsMovement )
{
if ( !WasVisibleInScaledFrame( targetableEntities[i], 0.9f, 0.9f ) )
{
targetableEntities.Erase(i);
continue;
}
}
else if ( !WasVisibleInScaledFrame( targetableEntities[i], 1.f, 1.f ) )
{
targetableEntities.Erase(i);
continue;
}
}
else
{
targetingInfo.targetEntity = targetableEntities[i];
if ( actionCheck && moveTarget )
{
targetingInfo.inFrameCheck = false;
if ( !IsEntityTargetable( targetingInfo ) )
{
targetableEntities.Erase(i);
continue;
}
}
else
{
targetingInfo.inFrameCheck = true;
if ( !IsEntityTargetable( targetingInfo ) )
{
targetableEntities.Erase(i);
continue;
}
}
}

if ( actionCheck )
{
if ( action == EBAT_ItemUse )
{
if ( ( playerInventory.IsItemBomb( this.GetSelectedItemId() ) && !targetableEntities[i].HasTag( 'softLock_Bomb' ) )
|| ( playerInventory.IsItemCrossbow( this.GetSelectedItemId() ) && !targetableEntities[i].HasTag( 'softLock_Bolt' ) ) )
{
targetableEntities.Erase(i);
continue;
}
}
else if ( action == EBAT_CastSign )
{
if ( ( castSignType == ST_Aard && !targetableEntities[i].HasTag( 'softLock_Aard' ) )
|| ( castSignType == ST_Igni && !targetableEntities[i].HasTag( 'softLock_Igni' ) )
|| ( castSignType == ST_Axii && !targetableEntities[i].HasTag( 'softLock_Axii' ) )
|| castSignType == ST_Yrden
|| castSignType == ST_Quen )
{
targetableEntities.Erase(i);
continue;
}
}
else if ( action == EBAT_LightAttack || action == EBAT_HeavyAttack || action == EBAT_SpecialAttack_Heavy )
{
if ( ( IsWeaponHeld( 'fist' ) && !targetableEntities[i].HasTag( 'softLock_Fist' ) ) || ( !IsWeaponHeld( 'fist' ) && !targetableEntities[i].HasTag( 'softLock_Weapon' ) ) )
{
targetableEntities.Erase(i);
continue;
}
}
else
{
targetableEntities.Erase(i);
continue;
}
}
}
}

if ( targetableEntities.Size() > 0)
{
playerHeading = this.GetHeading();
playerHeadingVector = this.GetHeadingVector();
if ( IsInCombat() )
{
for( i = 0; i < targetableEntities.Size(); i += 1 )
{
if ( bLAxisReleased )
selectionPriority.PushBack( CalcSelectionPriority( targetableEntities[i], selectionWeights, cameraPosition, rawPlayerHeadingVector ) );
else
selectionPriority.PushBack( CalcSelectionPriority( targetableEntities[i], selectionWeights, playerPosition, rawPlayerHeadingVector ) );
}

if ( selectionPriority.Size() > 0 )
selectedTargetableEntity = targetableEntities[ ArrayFindMaxF( selectionPriority ) ];
}
else
{
if ( bLAxisReleased )
{
if ( !lastAxisInputIsMovement )
{
for( i = 0; i < targetableEntities.Size(); i += 1 )
selectionPriority.PushBack( CalcSelectionPriority( targetableEntities[i], selectionWeights, cameraPosition, rawPlayerHeadingVector ) );

if ( selectionPriority.Size() > 0 )
selectedTargetableEntity = targetableEntities[ ArrayFindMaxF( selectionPriority ) ];
}
else
{
if ( IsInCombatAction() )
selectedTargetableEntity = nonActorTarget;
else
{
for( i = 0; i < targetableEntities.Size(); i += 1 )
selectionPriority.PushBack( CalcSelectionPriority( targetableEntities[i], selectionWeights, playerPosition, playerHeadingVector ) );

if ( selectionPriority.Size() > 0 )
{
selectedTargetableEntity = targetableEntities[ ArrayFindMaxF( selectionPriority ) ];

targetingInfo.source = this;
targetingInfo.targetEntity = selectedTargetableEntity;
targetingInfo.canBeTargetedCheck = false;
targetingInfo.coneCheck = true;
targetingInfo.coneHalfAngleCos = 0.0f; // = CosF( Deg2Rad( 180.0f * 0.5f ) )
targetingInfo.coneDist = softLockDist;
targetingInfo.coneHeadingVector = this.GetHeadingVector();
targetingInfo.distCheck = true;
targetingInfo.invisibleCheck = false;
targetingInfo.navMeshCheck = false;
targetingInfo.inFrameCheck = false;
targetingInfo.frameScaleX = 1.0f;
targetingInfo.frameScaleY = 1.0f;
targetingInfo.knockDownCheck = false;
targetingInfo.knockDownCheckDist = 0.0f;
targetingInfo.rsHeadingCheck = false;
targetingInfo.rsHeadingLimitCos = 1.0f;

if ( !IsEntityTargetable( targetingInfo ) )
selectedTargetableEntity = NULL;
}
}
}
}
else
{
for( i = 0; i < targetableEntities.Size(); i += 1 )
selectionPriority.PushBack( CalcSelectionPriority( targetableEntities[i], selectionWeights, playerPosition, rawPlayerHeadingVector ) );

if ( selectionPriority.Size() > 0 )
selectedTargetableEntity = targetableEntities[ ArrayFindMaxF( selectionPriority ) ];
}
}
}
else
selectedTargetableEntity = NULL;
}

SetNonActorTarget( selectedTargetableEntity );
return selectedTargetableEntity;
}
/*
timer function IsItemUseInputHeld ( time : float , id : int)
{
if ( GetBIsInputAllowed()
&& GetBIsCombatActionAllowed()
&& IsActionAllowed( EIAB_Crossbow )
&& inv.IsIdValid( GetSelectedItemId() )
&& inv.IsItemCrossbow( GetSelectedItemId()En )
&& rangedWeapon.GetCurrentStateName() == 'State_WeaponWait' )
{
SetIsAimingCrossbow( true );
PushCombatActionOnBuffer( EBAT_ItemUse, BS_Pressed );
ProcessCombatActionBuffer();
}

if ( theInput.GetActionValue( 'ThrowItem' ) == 0.f )
{
if ( GetBIsCombatActionAllowed() )
{
PushCombatActionOnBuffer( EBAT_ItemUse, BS_Pressed );
ProcessCombatActionBuffer();
}

SetIsAimingCrossbow( false );
RemoveTimer( 'IsItemUseInputHeld' );
}
}*/

public function SetupCombatAction( action : EBufferActionType, stage : EButtonStage )
{
var weaponType : EPlayerWeapon;
var canAttackTarget : CGameplayEntity;
var target : CActor;

/*if( thePlayer.substateManager.GetStateCur() == 'Slide' )
{
return;
}*/
if ( !IsCombatMusicEnabled() )
{
SetCombatActionHeading( ProcessCombatActionHeading( action ) );
FindTarget();
UpdateDisplayTarget( true );
}

if ( displayTarget && IsDisplayTargetTargetable() )
canAttackTarget = displayTarget;
else if ( GetTarget() )
canAttackTarget = GetTarget();
else if( !target && IsCombatMusicEnabled() )
canAttackTarget = moveTarget;

target = (CActor)canAttackTarget;

if ( !AllowAttack( target, action ) )
return;

if( ( action != EBAT_ItemUse ) && ( action != EBAT_CastSign ) )
{
weaponType = weaponHolster.GetCurrentMeleeWeapon();
PrepareToAttack( target, action );

//Do not automatically attack when drawing sword
if ( weaponType != weaponHolster.GetCurrentMeleeWeapon() )
{
//Check if switching from PW_None to PW_Fists. If so, allow the attack
if ( !( weaponType == PW_None && weaponHolster.GetCurrentMeleeWeapon() == PW_Fists ) )
return;
}
}

//geralt's special attack heavy
if(action == EBAT_SpecialAttack_Heavy && !((W3ReplacerCiri)this) )
thePlayer.SetAttackActionName(SkillEnumToName(S_Sword_s02));

CriticalEffectAnimationInterrupted("SetupCombatAction " + action);
PushCombatActionOnBuffer( action, stage );

if( GetBIsCombatActionAllowed() )
{
ProcessCombatActionBuffer();
}
}

public function AllowAttack( target : CActor, action : EBufferActionType ) : bool
{
var newTarget : CActor;
var canAttackWhenNotInCombat : bool;
var messageDisplayed : bool;

var itemId : SItemUniqueId;
var isShootingCrossbow : bool;

var isInCorrectState : bool;

if ( target )
{
if ( target.IsTargetableByPlayer())
{
if ( !target.IsAttackableByPlayer() )
{
DisplayHudMessage(GetLocStringByKeyExt("panel_hud_message_cant_attack_this_target"));
return false;
}
}
}

if ( this.GetCurrentStateName() == 'Exploration' )
isInCorrectState = true;

if ( action == EBAT_ItemUse )
{
itemId = thePlayer.GetSelectedItemId();
if ( inv.IsIdValid(itemId) && inv.IsItemCrossbow(itemId) )
isShootingCrossbow = true;

if ( !isInCorrectState )
{
if ( this.GetCurrentStateName() == 'AimThrow' && !isShootingCrossbow )
{
isInCorrectState = true;
}
}
}

if ( isInCorrectState )
canAttackWhenNotInCombat = thePlayer.CanAttackWhenNotInCombat( action, false, newTarget, target );

if( !target )
{
if ( isInCorrectState )
{
SetCombatActionHeading( ProcessCombatActionHeading( action ) );
target = newTarget;
}
}

if ( isInCorrectState )
{
if ( !canAttackWhenNotInCombat )
{
if ( DisplayCannotAttackMessage( target ) )
messageDisplayed = true;
else if ( ( action == EBAT_LightAttack || action == EBAT_HeavyAttack )
&& !RaiseAttackFriendlyEvent( target ) )
messageDisplayed = true;
else
{
if ( !CanRaiseCombatActionFriendlyEvent( isShootingCrossbow ) )
messageDisplayed = true;
}
}

if ( messageDisplayed )
{
theInput.ForceDeactivateAction('ThrowItem');
theInput.ForceDeactivateAction('ThrowItemHold');
return false;
}
}

return true;
}


//returns true if processed
public function ProcessCombatActionBuffer() : bool
{
var actionResult : bool;
var action : EBufferActionType = this.BufferCombatAction;
var stage : EButtonStage = this.BufferButtonStage;
var s : SNotWorkingOutFunctionParametersHackStruct1;
var allSteps : bool = this.BufferAllSteps;

if ( IsInCombatActionFriendly() )
{
RaiseEvent('CombatActionFriendlyEnd');
}

//Disable any npcs that are set to unpushable when Player performs another combat action
if ( ( action != EBAT_SpecialAttack_Heavy && action != EBAT_ItemUse )
|| ( action == EBAT_SpecialAttack_Heavy && stage == BS_Pressed )
|| ( action == EBAT_ItemUse && stage != BS_Released ) )
{
GetMovingAgentComponent().GetMovementAdjustor().CancelAll();
SetUnpushableTarget( NULL );
}

//if ( !( action == EBAT_Dodge && stage == BS_Pressed && IsInCombatAction() && GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Dodge ) )
if ( !( action == EBAT_Dodge || action == EBAT_Roll ) )
SetIsCurrentlyDodging(false);

//-- init
SetCombatActionHeading( ProcessCombatActionHeading( action ) );

//theGame.GetSyncAnimManager().OnRemoveFinisherCameraAnimation();

if ( action == EBAT_ItemUse && GetInventory().IsItemCrossbow( selectedItemId ) )
{
//stage == BS_Pressed &&
if ( rangedWeapon
&& ( ( rangedWeapon.GetCurrentStateName() != 'State_WeaponShoot' && rangedWeapon.GetCurrentStateName() != 'State_WeaponAim' ) || GetIsShootingFriendly() ) )
{
SetSlideTarget( GetCombatActionTarget( action ) );
}
}
else if ( !( ( action == EBAT_SpecialAttack_Heavy && stage == BS_Released ) || GetCurrentStateName() == 'AimThrow' ) )
{
SetSlideTarget( GetCombatActionTarget( action ) );
}

if( !slideTarget )
LogChannel( 'Targeting', "NO SLIDE TARGET" );

//-- process
actionResult = true;

switch ( action )
{
case EBAT_EMPTY :
{
this.BufferAllSteps = false;
return true;
} break;

case EBAT_LightAttack :
{
if ( IsCiri() )
return false;

switch ( stage )
{
case BS_Pressed ://BS_Released :
{
// early out, stamina drain etc
//if( HasStaminaToUseAction(ESAT_LightAttack) )
//{

// replacing stamina lock with stamina drain - change in design
/*
s = LockStamina(ESAT_LightAttack);
if(s.retValue)
{
AddCombatActionStaminaLock(s.outValue);
}
*/
DrainStamina(ESAT_LightAttack);
//target.SignalGameplayEventParamInt('Time2Dodge', (int)EDT_Attack );

thePlayer.BreakPheromoneEffect();
actionResult = OnPerformAttack(theGame.params.ATTACK_NAME_LIGHT);
//}
} break;

default :
{
actionResult = false;
}break;
}
}break;

case EBAT_HeavyAttack :
{
if ( IsCiri() )
return false;

switch ( stage )
{
case BS_Released :
{
// early out, stamina drain etc
//if( HasStaminaToUseAction(ESAT_HeavyAttack) )
//{
// replacing stamina lock with stamina drain - change in design
/*
s = LockStamina(ESAT_HeavyAttack);
if(s.retValue)
{
AddCombatActionStaminaLock(s.outValue);
}
*/
DrainStamina(ESAT_HeavyAttack);

//target.SignalGameplayEventParamInt('Time2Dodge', (int)EDT_Attack );

thePlayer.BreakPheromoneEffect();
actionResult = this.OnPerformAttack(theGame.params.ATTACK_NAME_HEAVY);
//}
} break;

case BS_Pressed :
{
if ( this.GetCurrentStateName() == 'CombatFists' )
{
// early out, stamina drain etc
//if( HasStaminaToUseAction(ESAT_HeavyAttack) )
//{
// replacing stamina lock with stamina drain - change in design
/*
s = LockStamina(ESAT_HeavyAttack);
if(s.retValue)
{
AddCombatActionStaminaLock(s.outValue);
}
*/
DrainStamina(ESAT_HeavyAttack);

//target.SignalGameplayEventParamInt('Time2Dodge', (int)EDT_Attack );

thePlayer.BreakPheromoneEffect();
actionResult = this.OnPerformAttack(theGame.params.ATTACK_NAME_HEAVY);
//}
}
} break;

default :
{
actionResult = false;

} break;
}
} break;

case EBAT_ItemUse : //this gets called only for bombs. No usable items use this!
{
switch ( stage )
{
case BS_Pressed :
{
if ( !( (W3PlayerWitcher)this ) ||
( !IsInCombatActionFriendly() && !( !GetBIsCombatActionAllowed() && ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack || GetBehaviorVariable( 'combatActionType' ) == (int)CAT_CastSign ) ) ) )
//( !IsCastingSign() && !IsInCombatActionFriendly() && !( !GetBIsCombatActionAllowed() && GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack ) ) )
{
if ( inv.IsItemCrossbow( selectedItemId ) )
{
rangedWeapon = ( Crossbow )( inv.GetItemEntityUnsafe( selectedItemId ) );
rangedWeapon.OnRangedWeaponPress();
GetTarget().SignalGameplayEvent( 'Approach' );
}
else if(inv.IsItemBomb(selectedItemId) && this.inv.SingletonItemGetAmmo(selectedItemId) > 0 )
{
BombThrowStart();
GetTarget().SignalGameplayEvent( 'Approach' );
}
else
{
DrainStamina(ESAT_UsableItem);
UsableItemStart();
}
}

} if (!allSteps) break;

case BS_Released:
{
if ( !( (W3PlayerWitcher)this ) ||
( !IsInCombatActionFriendly() && ( GetBIsCombatActionAllowed() || !( !GetBIsCombatActionAllowed() && ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack || GetBehaviorVariable( 'combatActionType' ) == (int)CAT_CastSign ) ) ) ) )
//( !IsCastingSign() && !IsInCombatActionFriendly() && !( !GetBIsCombatActionAllowed() && GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack ) ) )
{
if ( inv.IsItemCrossbow( selectedItemId ) )
{
/*if ( rangedWeapon.GetCurrentStateName() == 'State_WeaponWait' )
{
rangedWeapon = ( Crossbow )( inv.GetItemEntityUnsafe( selectedItemId ) );
rangedWeapon.OnRangedWeaponPress();
}*/
rangedWeapon.OnRangedWeaponRelease();
}
else if(inv.IsItemBomb(selectedItemId))
{
BombThrowRelease();
}
else
{
UsableItemRelease();
}
}
} break;

default :
{
actionResult = false;
break;
}
}
} break;

case EBAT_Dodge :
{
switch ( stage )
{
case BS_Released :
{
theGame.GetBehTreeReactionManager().CreateReactionEvent( this, 'PlayerEvade', 1.0f, 10.0f, -1.0f, -1 );
thePlayer.BreakPheromoneEffect();
actionResult = this.OnPerformEvade( PET_Dodge );
} break;

/*case BS_Pressed :
{
actionResult = this.OnPerformEvade( PET_Roll );
} break;*/

default :
{
actionResult = false;
} break;
}
} break;

case EBAT_Roll :
{
if ( IsCiri() )
return false;

switch ( stage )
{
case BS_Released :
{
theGame.GetBehTreeReactionManager().CreateReactionEvent( this, 'PlayerEvade', 1.0f, 10.0f, -1.0f, -1 );
thePlayer.BreakPheromoneEffect();
actionResult = this.OnPerformEvade( PET_Roll );
} break;

case BS_Pressed :
{
if ( this.GetBehaviorVariable( 'combatActionType' ) == 2.f )
{
if ( GetCurrentStateName() == 'CombatSteel' || GetCurrentStateName() == 'CombatSilver' )
actionResult = this.OnPerformEvade( PET_Pirouette );
else
actionResult = this.OnPerformEvade( PET_Roll );
}
else
{
if ( GetCurrentStateName() == 'CombatSteel' || GetCurrentStateName() == 'CombatSilver' )
{
actionResult = this.OnPerformEvade( PET_Dodge );
actionResult = this.OnPerformEvade( PET_Pirouette );
}
else
{
actionResult = this.OnPerformEvade( PET_Dodge );
actionResult = this.OnPerformEvade( PET_Roll );
}
}


} break;

default :
{
actionResult = false;
} break;
}
} break;

case EBAT_Draw_Steel :
{
switch ( stage )
{
case BS_Pressed :
{
if( !IsActionAllowed(EIAB_DrawWeapon) )
{
thePlayer.DisplayActionDisallowedHudMessage(EIAB_DrawWeapon);
actionResult = false;
break;
}
if( GetWitcherPlayer().IsItemEquippedByCategoryName( 'steelsword' ) )
{
OnEquipMeleeWeapon( PW_Steel, false, true );
}

actionResult = false;

} break;

default :
{
actionResult = false;
} break;
}
} break;

case EBAT_Draw_Silver :
{
switch ( stage )
{
case BS_Pressed :
{
if( !IsActionAllowed(EIAB_DrawWeapon) )
{
thePlayer.DisplayActionDisallowedHudMessage(EIAB_DrawWeapon);
actionResult = false;
break;
}
if( GetWitcherPlayer().IsItemEquippedByCategoryName( 'silversword' ) )
{
OnEquipMeleeWeapon( PW_Silver, false, true );
}

actionResult = false;

} break;

default :
{
actionResult = false;
} break;
}
} break;

case EBAT_Sheathe_Sword :
{
switch ( stage )
{
case BS_Pressed :
{
if( GetCurrentMeleeWeaponType() == PW_Silver )
{
if( GetWitcherPlayer().IsItemEquippedByCategoryName( 'silversword' ) )
{
OnEquipMeleeWeapon( PW_Silver, false, true );
}
}
else if( GetCurrentMeleeWeaponType() == PW_Steel )
{
if( GetWitcherPlayer().IsItemEquippedByCategoryName( 'steelsword' ) )
{
OnEquipMeleeWeapon( PW_Steel, false, true );
}
}

actionResult = false;

} break;

default :
{
actionResult = false;
} break;
}
} break;

default:
return false; //not processed
}

//if here then buffer was processed
CleanCombatActionBuffer();

if (actionResult)
{
SetCombatAction( action ) ;

if(GetWitcherPlayer().IsInFrenzy())
GetWitcherPlayer().SkillFrenzyFinish(0);
}

return true;
}

public function CleanCombatActionBuffer()
{
BufferCombatAction = EBAT_EMPTY;
BufferAllSteps = false;
}

public function CancelHoldAttacks()
{
thePlayer.RemoveTimer( 'IsSpecialLightAttackInputHeld' );
thePlayer.RemoveTimer( 'IsSpecialHeavyAttackInputHeld' );
thePlayer.RemoveTimer( 'SpecialAttackLightSustainCost' );
thePlayer.RemoveTimer( 'SpecialAttackHeavySustainCost' );
thePlayer.RemoveTimer( 'UpdateSpecialAttackLightHeading' );
thePlayer.UnblockAction( EIAB_Crossbow, 'SpecialAttack' );

if ( thePlayer.GetBehaviorVariable( 'combatActionType' ) == (int)CAT_SpecialAttack )
{
if( thePlayer.GetBehaviorVariable( 'playerAttackType' ) == (int)PAT_Light
&& thePlayer.GetBehaviorVariable( 'isPerformingSpecialAttack' ) == 1.f )
{
thePlayer.SetAttackActionName(SkillEnumToName(S_Sword_s01));
thePlayer.PushCombatActionOnBuffer( EBAT_SpecialAttack_Light, BS_Released );
thePlayer.ProcessCombatActionBuffer();
//thePlayer.SetupCombatAction( EBAT_SpecialAttack_Light, BS_Released );
((W3PlayerWitcherStateCombatFists) GetState('Combat')).ResetTimeToEndCombat();

}
else if( thePlayer.GetBehaviorVariable( 'playerAttackType' ) == (int)PAT_Heavy
&& thePlayer.GetBehaviorVariable( 'isPerformingSpecialAttack' ) == 1.f )
{
thePlayer.SetAttackActionName(SkillEnumToName(S_Sword_s02));
thePlayer.PushCombatActionOnBuffer( EBAT_SpecialAttack_Heavy, BS_Released );
thePlayer.ProcessCombatActionBuffer();
//thePlayer.SetupCombatAction( EBAT_SpecialAttack_Heavy, BS_Released );
}
}
}

public function RaiseAttackFriendlyEvent( actor : CActor ) : bool
{
var playerToTargetHeading : float;

if ( actor && RaiseCombatActionFriendlyEvent() )
{
SetBehaviorVariable( 'tauntTypeForOverlay', 0.f );
SetBehaviorVariable( 'combatActionTypeForOverlay', (int)CAT_Attack );

if ( actor )
actor.SignalGameplayEvent('PersonalTauntAction');
theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'TauntAction', -1.0, 4.5f, -1, 9999, true ); //reactionSystemSearch

OnCombatActionStart();

playerToTargetHeading = VecHeading( actor.GetWorldPosition() - GetWorldPosition() );

SetCustomRotation( 'Attack', playerToTargetHeading, 0.0f, 0.3f, false );

return true;
}

return false;
}

public function SendAttackReactionEvent()
{
var reactionName : name;

/*switch ( action )
{
case EBAT_LightAttack :
reactionName = 'AttackAction';
break;
case EBAT_HeavyAttack :
reactionName = 'AttackAction';
break;
case EBAT_SpecialAttack_Light :
reactionName = 'AttackAction';
break;
case EBAT_SpecialAttack_Heavy :
reactionName = 'AttackAction';
break;
case EBAT_Ciri_SpecialAttack :
reactionName = 'AttackAction';
break;
default:
return;
}*/

reactionName = 'AttackAction';

if ( IsNameValid(reactionName) )
{
theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, reactionName, -1.0, 8.0f, -1, 5, true ); //reactionSystemSearch
}

// event for horse - trigger running away
theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'outOfMyWay', -1.0, 2.0f, -1, 5, true ); //reactionSystemSearch
}

var forceCanAttackWhenNotInCombat : int; // 0 = NoForce, 1 = ForceWhenNoDisplayTarget 2 = ForceEvenWithDisplayTarget
public function SetForceCanAttackWhenNotInCombat( forceMode : int )
{
forceCanAttackWhenNotInCombat = forceMode;
}

public function CanAttackWhenNotInCombat( actionType : EBufferActionType, altCast : bool, out newTarget : CActor, optional target : CGameplayEntity ) : bool
{
var localTargets : array;
var i, size : int;
var inputHeading : float;
var clearanceMin, clearanceMax : float;
var attackLength : float;
var attackAngle : float;
var npc : CNewNPC;
var canAttackTarget : CGameplayEntity;
var canAttackTargetActor : CActor;

if ( target )
canAttackTarget = target;
else if ( displayTarget && IsDisplayTargetTargetable() )
canAttackTarget = displayTarget;
else
canAttackTarget = slideTarget;

canAttackTargetActor = (CActor)canAttackTarget;

if ( forceCanAttackWhenNotInCombat == 2 )
return true;
else if ( forceCanAttackWhenNotInCombat == 1 && ( !canAttackTarget || !canAttackTargetActor.IsHuman() ) )
return true;

if ( actionType == EBAT_CastSign )
{
if ( thePlayer.GetEquippedSign() != ST_Quen && thePlayer.GetEquippedSign() != ST_Axii )
{
if ( CanUseSkill( S_Magic_s20 ) )
{
if ( thePlayer.GetEquippedSign() == ST_Aard )
attackLength = 6.f;
else if ( thePlayer.GetEquippedSign() == ST_Igni )
attackLength = 4.f;
else
attackLength = 6.f;
}
else
{
if ( thePlayer.GetEquippedSign() == ST_Aard )
attackLength = 9.f;
else if ( thePlayer.GetEquippedSign() == ST_Igni )
attackLength = 6.f;
else
attackLength = 6.f;
}

if ( altCast )
attackAngle = 180.f;
else
// sign cone angle / 2 with a bonus for safetey
attackAngle = 90.f;

if ( !lastAxisInputIsMovement )
inputHeading = VecHeading( theCamera.GetCameraDirection() );
else if ( lAxisReleasedAfterCounter )
inputHeading = GetHeading();
else
inputHeading = GetCombatActionHeading();

clearanceMin = 1.f;
clearanceMax = attackLength + 1.f;
}
else if ( thePlayer.GetEquippedSign() == ST_Axii )
{
npc = (CNewNPC)canAttackTarget;
if ( npc && npc.GetNPCType() == ENGT_Quest && !npc.HasTag(theGame.params.TAG_AXIIABLE_LOWER_CASE) && !npc.HasTag(theGame.params.TAG_AXIIABLE))
return false;
else if ( npc && npc.IsUsingHorse() )
return false;
else
return true;
}
else
return true;
}
else if ( actionType == EBAT_ItemUse )
{
attackLength = theGame.params.MAX_THROW_RANGE;
attackAngle = 90.f;

if ( thePlayer.lastAxisInputIsMovement )
inputHeading = GetCombatActionHeading();
else
inputHeading = VecHeading( theCamera.GetCameraDirection() );

clearanceMin = 0.8f;
clearanceMax = attackLength + 3.f;
}
else
{
if ( actionType == EBAT_SpecialAttack_Light || actionType == EBAT_SpecialAttack_Heavy )
{
attackLength = 1.9f;
attackAngle = 90.f;
}
else
{
if( thePlayer.GetCurrentMeleeWeaponType() == PW_Fists || thePlayer.GetCurrentMeleeWeaponType() == PW_None )
attackLength = 1.2f;
else
attackLength = 1.9f;

attackAngle = 90.f;
}

if ( lastAxisInputIsMovement )
inputHeading = GetCombatActionHeading();
else
inputHeading = VecHeading( theCamera.GetCameraDirection() );

clearanceMin = attackLength / 2.f;
clearanceMax = attackLength + 3.f;
}

//Use slideTarget first if it's NULL, then we try other npcs in the area
if ( canAttackTarget )
{
if ( ( canAttackTargetActor && canAttackTargetActor.IsHuman() ) || canAttackTargetActor.HasTag( 'softLock_Friendly' ) )
{
if ( ShouldPerformFriendlyAction( canAttackTargetActor, inputHeading, attackAngle, clearanceMin, clearanceMax ) )
{
SetSlideTarget( canAttackTargetActor );
newTarget = canAttackTargetActor;
return false;
}
}

//return true;
}

return true;

thePlayer.GetVisibleEnemies( localTargets );
size = localTargets.Size();

if ( size > 0 )
{
for ( i = size-1; i>=0; i-=1 )
{
/*
Andrzej: Geralt's friendly combat action - taunting actors with a sword or playing with Signs is set to work only for humans.
We don't want it to work against all non-humans, so I've added an exception that works similar to targeting non actor objects.
If you want Geralt to play friendly combat action when targeting monsters, add tag softLock_Friendly to monster's entity.
*/
if ( !localTargets[i].IsHuman() && !localTargets[i].HasTag( 'softLock_Friendly' ) )
localTargets.Erase(i);
}
}

size = localTargets.Size();
if ( size > 0 )
{
for ( i = 0; i < localTargets.Size(); i += 1 )
{
if ( ShouldPerformFriendlyAction( localTargets[i], inputHeading, attackAngle, clearanceMin, clearanceMax ) )
{
SetSlideTarget( localTargets[i] );
newTarget = localTargets[i];
return false;
}
}
}

newTarget = NULL;

return true;
}

private function ShouldPerformFriendlyAction( actor : CActor, inputHeading, attackAngle, clearanceMin, clearanceMax : float ) : bool
{
var npc : CNewNPC;
var argh : float;
var playerToTargetDist : float;

npc = (CNewNPC)actor;

if ( npc &&
( GetAttitudeBetween(thePlayer, npc) == AIA_Hostile || ( GetAttitudeBetween(thePlayer, npc) == AIA_Neutral && npc.GetNPCType() != ENGT_Guard ) ) )
{
}
else
{
playerToTargetDist = VecDistance( this.GetWorldPosition(), actor.PredictWorldPosition( 0.5f ) ); //actor.GetNearestPointInPersonalSpace( this.GetWorldPosition() ) );

argh = AbsF( AngleDistance( inputHeading, VecHeading( actor.GetWorldPosition() - thePlayer.GetWorldPosition() ) ) );

if ( AbsF( AngleDistance( inputHeading, VecHeading( actor.GetWorldPosition() - thePlayer.GetWorldPosition() ) ) ) < attackAngle )
{
if ( playerToTargetDist < clearanceMax )
{
return true;
}
}
else
{
if ( playerToTargetDist < clearanceMin )
{
return true;
}
}
}

return false;
}

///////////////////////////////////////////////////////////////////////////
// HUD //#B
///////////////////////////////////////////////////////////////////////////

public function GetHudMessagesSize() : int
{
return HudMessages.Size();
}

public function GetHudPendingMessage() : string
{
return HudMessages[0];
}

public function DisplayHudMessage( value : string ) : void
{
if (value == "")
{
return;
}

if( GetHudMessagesSize() > 0 )
{
if( HudMessages[HudMessages.Size()-1] == value )
{
return;
}
}
HudMessages.PushBack(value);
}

//hacks for review requests
private final function DisallowedActionDontShowHack(action : EInputActionBlock) : bool
{
var locks : array< SInputActionLock >;
var i : int;

//no info if we're trying to attack while staggered
if((action == EIAB_Fists || action == EIAB_SwordAttack || action == EIAB_Signs || action == EIAB_LightAttacks || action == EIAB_HeavyAttacks || action == EIAB_SpecialAttackLight || action == EIAB_SpecialAttackHeavy) && (HasBuff(EET_Stagger) || HasBuff(EET_LongStagger)) )
{
return true;
}

//always show meditation message
if(action == EIAB_OpenMeditation)
return false;

//if there's at least one lock from quest or from location fine
locks = GetActionLocks(action);
for(i=0; i {
if(locks[i].isFromQuest || locks[i].isFromPlace)
return false;
}

if ( this.IsCurrentlyUsingItemL() )
{
if ( action == EIAB_HeavyAttacks || action == EIAB_Parry )
return false;
}

//otherwise we don't display locks
return true;
}

public final function DisplayActionDisallowedHudMessage(action : EInputActionBlock, optional isCombatLock : bool, optional isPlaceLock : bool, optional isTimeLock : bool, optional isDangerous : bool)
{
var lockType : name;

if(action != EIAB_Undefined && DisallowedActionDontShowHack(action))
return;

//combat lock is strongest - overrides all
if(IsInCombat() && !IsActionCombat(action))
isCombatLock = true;

//if no specific lock set, check based on action
if(!isCombatLock && !isPlaceLock && ! isTimeLock && action != EIAB_Undefined)
{
lockType = inputHandler.GetActionBlockedHudLockType(action);

if(lockType == 'combat')
isCombatLock = true;
else if(lockType == 'place')
isPlaceLock = true;
else if(lockType == 'time')
isTimeLock = true;
}

if(isDangerous)
{
DisplayHudMessage(GetLocStringByKeyExt( "message_meditation_too_dangerous" ));
}
else if(isCombatLock)
{
DisplayHudMessage(GetLocStringByKeyExt( "panel_hud_message_actionnotallowed_combat" ));
}
else if(isPlaceLock)
{
DisplayHudMessage(GetLocStringByKeyExt( "menu_cannot_perform_action_here" ));
}
else if(isTimeLock)
{
DisplayHudMessage(GetLocStringByKeyExt( "menu_cannot_perform_action_now" ));
}
}

//removes first or all instances of given message
public function RemoveHudMessageByString(msg : string, optional allQueuedInstances : bool)
{
var i, j : int;

for(i=0; i {
if(HudMessages[i] == msg)
{
HudMessages.EraseFast(i);

if(!allQueuedInstances)
return;

break;
}
}

//if here then we want all remaining instances as well
for(j=HudMessages.Size()-1; j >= i; j-=1)
{
if(HudMessages[i] == msg)
{
HudMessages.EraseFast(i);
}
}
}

public function RemoveHudMessageByIndex(idx : int)
{
if(idx >= 0 && idx < HudMessages.Size())
HudMessages.Erase(idx);
}

function SetSettlementBlockCanter( valueAdd : int ) // #B
{
m_SettlementBlockCanter += valueAdd;
}

var countDownToStart : int;
default countDownToStart = 0;

function DisplayRaceStart( countDownSecondsNumber : int ) // #B
{
var i : int;
countDownToStart = countDownSecondsNumber;
for( i = countDownSecondsNumber; i > 0; i -= 1 )
{
DisplayHudMessage(IntToString(i));
}
DisplayHudMessage(GetLocStringByKeyExt("panel_hud_message_race_start"));
AddTimer('RaceCountdown',1,true);
}

timer function RaceCountdown(dt : float, id : int) // #B
{
var hud : CR4ScriptedHud;
var messageModule : CR4HudModuleMessage;

countDownToStart -= 1;
hud = (CR4ScriptedHud)theGame.GetHud();

if( hud )
{
messageModule = (CR4HudModuleMessage)hud.GetHudModule("MessageModule");
if( messageModule )
{
messageModule.OnMessageHidden(); // to force show next messeage
}
}

if( countDownToStart <= 0 )
{
RemoveTimer('RaceCountdown');
}
}

public function GetCountDownToStart() : int // #B
{
return countDownToStart;
}

public function HAXE3GetContainer() : W3Container //#B temp for E3
{
return HAXE3Container;
}

public function HAXE3SetContainer( container : W3Container) : void //#B temp for E3
{
HAXE3Container = container;
}

public function HAXE3GetAutoLoot() : bool //#B temp for E3
{
return HAXE3bAutoLoot;
}

public function HAXE3SetAutoLoot( value : bool ) : void //#B temp for E3
{
HAXE3bAutoLoot = value;
}

public function GetShowHud() : bool
{
return bShowHud;
}

public function SetShowHud( value : bool ) : void
{
bShowHud = value;
}

public function DisplayItemRewardNotification( itemName : name, optional quantity : int ) : void
{
var hud : CR4ScriptedHud;
hud = (CR4ScriptedHud)theGame.GetHud();
hud.OnItemRecivedDuringScene(itemName, quantity); // #B because our default currency are Crowns !!!
}

function IsNewQuest( questGuid : CGUID ) : bool // #B
{
var i : int;
for(i = 0; i < displayedQuestsGUID.Size(); i += 1 )
{
if( displayedQuestsGUID[i] == questGuid )
{
return false;
}
}
displayedQuestsGUID.PushBack(questGuid);
return true;
}

function GetRewardMultiplier( rewardName : name ) : float // #B
{
var i : int;
for(i = 0; i < rewardsMultiplier.Size(); i += 1 )
{
if( rewardsMultiplier[i].rewardName == rewardName )
{
return rewardsMultiplier[i].rewardMultiplier;
}
}
return 1.0;
}

function GetRewardMultiplierExists( rewardName : name ) : bool // #B
{
var i : int;
for(i = 0; i < rewardsMultiplier.Size(); i += 1 )
{
if( rewardsMultiplier[i].rewardName == rewardName )
{
return true;
}
}
return false;
}

function SetRewardMultiplier( rewardName : name, value : float ) : void // #B
{
var i : int;
var rewardMultiplier : SRewardMultiplier;

for(i = 0; i < rewardsMultiplier.Size(); i += 1 )
{
if( rewardsMultiplier[i].rewardName == rewardName )
{
rewardsMultiplier[i].rewardMultiplier = value;
return;
}
}

rewardMultiplier.rewardName = rewardName;
rewardMultiplier.rewardMultiplier = value;

rewardsMultiplier.PushBack(rewardMultiplier);
}

function RemoveRewardMultiplier( rewardName : name ) : void // #B
{
var i : int;
for(i = 0; i < rewardsMultiplier.Size(); i += 1 )
{
if( rewardsMultiplier[i].rewardName == rewardName )
{
rewardsMultiplier.Erase(i);
return;
}
}
}

////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @OILS ////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

public final function GetCurrentOilAmmo(id : SItemUniqueId) : int
{
return inv.GetItemModifierInt(id, 'oil_charges');
}

public final function GetMaxOilAmmo(id : SItemUniqueId) : int
{
return inv.GetItemModifierInt(id, 'oil_max_charges');
}

public final function ReduceOilAmmo(id : SItemUniqueId, optional ammo : int)
{
var currentAmmo : int;

if(ammo == 0)
ammo = 1;

currentAmmo = GetCurrentOilAmmo(id);
if(currentAmmo > 0)
{
currentAmmo = Max(currentAmmo - ammo, 0);
inv.SetItemModifierInt(id, 'oil_charges', currentAmmo);

if(currentAmmo == 0)
{
RemoveItemOil(id);

//count alchemy usage but only after nightmare
if(ShouldProcessTutorial('TutorialAlchemyRefill') && FactsQuerySum("q001_nightmare_ended") > 0 && GetWitcherPlayer())
FactsAdd('tut_alch_refill', 1);
}
}

theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnOilApplied );
}

//removes oil from given item
public function RemoveItemOil(id : SItemUniqueId)
{
var i : int;
var dm : CDefinitionsManagerAccessor;
var abilities : array;
var sword : CWitcherSword;

dm = theGame.GetDefinitionsManager();
inv.GetItemAbilities(id, abilities);

for(i=0; i if(dm.AbilityHasTag(abilities[i], theGame.params.OIL_ABILITY_TAG))
inv.RemoveItemCraftedAbility(id, abilities[i]);

inv.SetItemModifierInt(id, 'oil_charges', -1);
inv.SetItemModifierInt(id, 'oil_max_charges', -1);
sword = (CWitcherSword) inv.GetItemEntityUnsafe(id);
sword.RemoveOil( inv );

theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnOilApplied );
}
////////////////////////////////////////////////////////////////////////////////
//
// @Items
//
////////////////////////////////////////////////////////////////////////////////

public final function HasRequiredLevelToEquipItem(item : SItemUniqueId) : bool
{
//No witcher gear lvl ++
else if(inv.GetItemQuality(item) == 5){}
// No witcher gear lvl --
return true;
}

public function SkillReduceBombAmmoBonus()
{
var i, ammo, maxAmmo : int;
var items : array;

items = inv.GetSingletonItems();

for(i=0; i {
ammo = inv.GetItemModifierInt(items[i], 'ammo_current');

//if doesn't have infinite ammo
if(ammo > 0)
{
maxAmmo = inv.SingletonItemGetMaxAmmo(items[i]);

//if current ammo > max ammo, set current ammo to max ammo
if(ammo > maxAmmo)
{
inv.SetItemModifierInt(items[i], 'ammo_current', maxAmmo);
}
}
}
theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged );
}

public function ConsumeItem( itemId : SItemUniqueId ) : bool
{
var params : SCustomEffectParams;
var buffs : array;
var i : int;
var category : name;
var potionToxicity : float;

if(!inv.IsIdValid(itemId))
return false;

//apply buff
category = inv.GetItemCategory(itemId);
if(category == 'edibles' || inv.ItemHasTag(itemId, 'Drinks') || ( category == 'alchemy_ingredient' && inv.ItemHasTag(itemId, 'Alcohol')) )
{
//cannot eat in fistfights
if(IsFistFightMinigameEnabled())
{
DisplayActionDisallowedHudMessage(EIAB_Undefined, false, false, true);
return false;
}

//edible buff
inv.GetItemBuffs(itemId, buffs);

for(i=0; i {
params.effectType = buffs[i].effectType;
params.creator = this;
params.sourceName = "edible";
params.customAbilityName = buffs[i].effectAbilityName;
AddEffectCustom(params);
}

//custom hack
if ( inv.ItemHasTag(itemId, 'Alcohol') )
{
potionToxicity = CalculateAttributeValue(inv.GetItemAttributeValue(itemId, 'toxicity'));
abilityManager.GainStat(BCS_Toxicity, potionToxicity );
AddEffectDefault(EET_Drunkenness, NULL, inv.GetItemName(itemId));
}
PlayItemConsumeSound( itemId );
}

if(inv.IsItemFood(itemId))
FactsAdd("consumed_food_cnt");

//remove item
if(!inv.ItemHasTag(itemId, theGame.params.TAG_INFINITE_USE) && !inv.RemoveItem(itemId))
{
LogAssert(false,"Failed to remove consumable item from player inventory!" + inv.GetItemName( itemId ) );
return false;
}

return true;
}

public function MountVehicle( vehicleEntity : CEntity, mountType : EVehicleMountType, optional vehicleSlot : EVehicleSlot )
{
var vehicle : CVehicleComponent;
vehicle = (CVehicleComponent)(vehicleEntity.GetComponentByClassName('CVehicleComponent'));

if ( vehicle )
vehicle.Mount( this, mountType, vehicleSlot );
}

public function DismountVehicle( vehicleEntity : CEntity, dismountType : EDismountType )
{
var vehicle : CVehicleComponent;
vehicle = (CVehicleComponent)(vehicleEntity.GetComponentByClassName('CVehicleComponent'));

if ( vehicle )
vehicle.IssueCommandToDismount( dismountType );
}

////////////////
// @stamina @stats
////////////////

//Returns true if actor has enough stamina to perform given action type (refer to DrainStamina for more info).
//If there is not enough stamina and actor is a player character then a insufficient stamina indication is shown on HUD
public function HasStaminaToUseAction(action : EStaminaActionType, optional abilityName : name, optional dt :float, optional multiplier : float) : bool
{
var cost : float;
var ret : bool;

ret = super.HasStaminaToUseAction(action, abilityName, dt, multiplier);

if(!ret)
{
SetCombatActionHeading( GetHeading() );

if(multiplier == 0)
multiplier = 1;

cost = multiplier * GetStaminaActionCost(action, abilityName, dt);
SetShowToLowStaminaIndication(cost);
}

return ret;
}

//since we cannot add timer on abilityManager...
timer function AbilityManager_FloorStaminaSegment(dt : float, id : int)
{
((W3PlayerAbilityManager)abilityManager).FloorStaminaSegment();
}

public function DrainToxicity(amount : float )
{
if(abilityManager && abilityManager.IsInitialized() && IsAlive())
abilityManager.DrainToxicity(amount);
}

public function DrainFocus(amount : float )
{
if(abilityManager && abilityManager.IsInitialized() && IsAlive())
abilityManager.DrainFocus(amount);
}

public function GetOffenseStat():int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetOffenseStat();

return 0;
}

public function GetDefenseStat():int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetDefenseStat();

return 0;
}

public function GetSignsStat():float
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSignsStat();

return 0;
}

////////////////
// water
////////////////

private var inWaterTrigger : bool;

event OnOceanTriggerEnter()
{
inWaterTrigger = true;
}

event OnOceanTriggerLeave()
{
inWaterTrigger = false;
}

public function IsInWaterTrigger() : bool
{
return inWaterTrigger;
}

//////////////////////////////////////////////////////////////////////////////////////////
// @Skills @Perks
//////////////////////////////////////////////////////////////////////////////////////////

public function GetSkillColor(skill : ESkill) : ESkillColor
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillColor(skill);

return SC_None;
}

public function GetSkillSlotIndexFromSkill(skill : ESkill) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillSlotIndexFromSkill(skill);

return -1;
}

public final function GetSkillSlotIndex(slotID : int, checkIfUnlocked : bool) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillSlotIndex(slotID, checkIfUnlocked);

return -1;
}

public final function GetSkillSlotIDFromIndex(skillSlotIndex : int) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillSlotIDFromIndex(skillSlotIndex);

return -1;
}

public function GetSkillSlotID(skill : ESkill) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillSlotID(skill);

return -1;
}

public function GetSkillGroupBonus(groupID : int) : name
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetGroupBonus(groupID);

return '';
}

public function GetGroupBonusCount(commonColor : ESkillColor,groupID : int) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetGroupBonusCount(commonColor, groupID);

return 0;
}

public function GetMutagenSlotIDFromGroupID(groupID : int) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetMutagenSlotIDFromGroupID(groupID);

return -1;
}

public function GetSkillLevel(skill : ESkill) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillLevel(skill);

return -1;
}

public function GetBoughtSkillLevel(skill : ESkill) : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetBoughtSkillLevel(skill);

return -1;
}

public function AddSkill(skill : ESkill, optional isTemporary : bool)
{
if(abilityManager && abilityManager.IsInitialized())
((W3PlayerAbilityManager)abilityManager).AddSkill(skill, isTemporary);
}

public function AddMultipleSkills(skill : ESkill, optional number : int, optional isTemporary : bool)
{
var i : int;

if(number)
{
for( i=0; i {
AddSkill(skill,isTemporary);
}
}
else
{
AddSkill(skill,isTemporary);
}
}

public function GetSkillAbilityName(skill : ESkill) : name
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillAbilityName(skill);

return '';
}

public function HasStaminaToUseSkill(skill : ESkill, optional perSec : bool, optional signHack : bool) : bool
{
var ret : bool;
var cost : float;

cost = GetSkillStaminaUseCost(skill, perSec);

ret = ( CanUseSkill(skill) && (abilityManager.GetStat(BCS_Stamina, signHack) >= cost) );

//perk, using adrenaline instead of stamina when out of stamina
if(!ret && IsSkillSign(skill) && CanUseSkill(S_Perk_09) && GetStat(BCS_Focus) >= 1)
ret = true;

if(!ret)
{
SetCombatActionHeading( GetHeading() );
SetShowToLowStaminaIndication(cost);
}

return ret;
}

protected function GetSkillStaminaUseCost(skill : ESkill, optional perSec : bool) : float
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillStaminaUseCost(skill, perSec);

return 0;
}

//works for perks and bookperks as well
public function GetSkillAttributeValue(skill : ESkill, attributeName : name, addBaseCharAttribute : bool, addSkillModsAttribute : bool) : SAbilityAttributeValue
{
var null : SAbilityAttributeValue;

if(abilityManager && abilityManager.IsInitialized())
return abilityManager.GetSkillAttributeValue(SkillEnumToName(skill), attributeName, addBaseCharAttribute, addSkillModsAttribute);

return null;
}

public function GetSkillLocalisationKeyName(skill : ESkill) : string // #B
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillLocalisationKeyName(skill);

return "";
}

public function GetSkillLocalisationKeyDescription(skill : ESkill) : string // #B
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillLocalisationKeyDescription(skill);

return "";
}

public function GetSkillIconPath(skill : ESkill) : string // #B
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillIconPath(skill);

return "";
}

public function HasLearnedSkill(skill : ESkill) : bool
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).HasLearnedSkill(skill);

return false;
}

public function IsSkillEquipped(skill : ESkill) : bool
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).IsSkillEquipped(skill);

return false;
}

public function CanUseSkill(skill : ESkill) : bool
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).CanUseSkill(skill);

return false;
}

public function CanLearnSkill(skill : ESkill) : bool //#B
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).CanLearnSkill(skill);

return false;
}

public function HasSpentEnoughPoints(skill : ESkill) : bool //#J
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).HasSpentEnoughPoints(skill);

return false;
}

public function PathPointsForSkillsPath(skill : ESkill) : int //#J
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).PathPointsSpentInSkillPathOfSkill(skill);

return -1;
}

public function GetPlayerSkills() : array // #B
{
var null : array;

if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetPlayerSkills();

return null;
}

public function GetPlayerSkill(s : ESkill) : SSkill // #B
{
var null : SSkill;

if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetPlayerSkill(s);

return null;
}

public function GetSkillSubPathType(s : ESkill) : ESkillSubPath // #B
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillSubPathType(s);

return ESSP_NotSet;
}

public function GetSkillSlotsCount() : int
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillSlotsCount();

return 0;
}

public function GetSkillSlots() : array
{
var null : array;

if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillSlots();

return null;
}

public function GetPlayerSkillMutagens() : array
{
var null : array;

if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetPlayerSkillMutagens();

return null;
}

// mutagens
//public function OnSkillMutagenEquipped()

public function BlockSkill(skill : ESkill, block : bool, optional cooldown : float) : bool
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).BlockSkill(skill, block, cooldown);

return false;
}

public function IsSkillBlocked(skill : ESkill) : bool
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).IsSkillBlocked(skill);

return false;
}

//returns true if succeeded
public function EquipSkill(skill : ESkill, slotID : int) : bool
{
var ret : bool;
var groupID : int;
var pam : W3PlayerAbilityManager;

if(abilityManager && abilityManager.IsInitialized())
{
pam = (W3PlayerAbilityManager)abilityManager;
ret = pam.EquipSkill(skill, slotID);
if(ret)
{
groupID = pam.GetSkillGroupIdFromSkillSlotId(slotID);
LogSkillColors("Equipped <<" + GetSkillColor(skill) + ">> skill <<" + skill + ">> to group <<" + groupID + ">>");
LogSkillColors("Group bonus color is now <<" + pam.GetSkillGroupColor(groupID) + ">>");
LogSkillColors("");
}

return ret;
}

return false;
}

//returns true if succeeded
public function UnequipSkill(slotID : int) : bool
{
var ret : bool;
var groupID : int;
var skill : ESkill;
var pam : W3PlayerAbilityManager;

if(abilityManager && abilityManager.IsInitialized())
{
pam = (W3PlayerAbilityManager)abilityManager;
GetSkillOnSlot(slotID, skill);
ret = pam.UnequipSkill(slotID);
if(ret)
{
groupID = pam.GetSkillGroupIdFromSkillSlotId(slotID);
LogSkillColors("Unequipped <<" + GetSkillColor(skill) + ">> skill <<" + skill + ">> from group <<" + groupID + ">>");
LogSkillColors("Group bonus color is now <<" + pam.GetSkillGroupColor(groupID) + ">>");
LogSkillColors("");
}
return ret;
}

return false;
}

//returns true if succeeded
public function GetSkillOnSlot(slotID : int, out skill : ESkill) : bool
{
if(abilityManager && abilityManager.IsInitialized())
return ((W3PlayerAbilityManager)abilityManager).GetSkillOnSlot(slotID, skill);

skill = S_SUndefined;
return false;
}

//returns random free skill slot (if any, otherwise -1)
public function GetFreeSkillSlot() : int
{
var i, size : int;
var skill : ESkill;

size = ((W3PlayerAbilityManager)abilityManager).GetSkillSlotsCount();
for(i=1; i {
if(!GetSkillOnSlot(i, skill))
continue; //if slot locked

if(skill == S_SUndefined) //empty unlocked slot
return i;
}

return -1;
}

//////////////////
// @attacks
//////////////////

//performs an attack (mechanics wise) on given target and using given attack data
protected function Attack( hitTarget : CGameplayEntity, animData : CPreAttackEventData, weaponId : SItemUniqueId, parried : bool, countered : bool, parriedBy : array, attackAnimationName : name, hitTime : float, weaponEntity : CItemEntity)
{
var attackAction : W3Action_Attack;

if(!PrepareAttackAction(hitTarget, animData, weaponId, parried, countered, parriedBy, attackAnimationName, hitTime, weaponEntity, attackAction))
return; //failed to create a valid attack action

if ( attackAction.IsParried() && ( ((CNewNPC)attackAction.victim).IsShielded(attackAction.attacker) || ((CNewNPC)attackAction.victim).SignalGameplayEventReturnInt('IsDefending',0) == 1 ) )
{
thePlayer.SetCanPlayHitAnim(true);
thePlayer.ReactToReflectedAttack(attackAction.victim);
}

theTelemetry.LogWithLabel( TE_FIGHT_PLAYER_ATTACKS, attackAction.GetAttackName() );

//process action
theGame.damageMgr.ProcessAction(attackAction);

delete attackAction;
}

public function IsHeavyAttack(attackName : name) : bool
{
var skill : ESkill;
var sup : bool;

sup = super.IsHeavyAttack(attackName);
if(sup)
return true;

if ( attackName == 'attack_heavy_special' )
return true;

skill = SkillNameToEnum(attackName);

return skill == S_Sword_2 || skill == S_Sword_s02;
}

public function IsLightAttack(attackName : name) : bool
{
var skill : ESkill;
var sup : bool;

sup = super.IsLightAttack(attackName);
if(sup)
return true;

skill = SkillNameToEnum(attackName);

return skill == S_Sword_1 || skill == S_Sword_s01;
}

public final function ProcessWeaponCollision()
{
var l_stateName : name;

var l_weaponPosition : Vector;
var l_weaponTipPos : Vector;
var l_collidingPosition : Vector;
var l_offset : Vector;
var l_normal : Vector;

var l_slotMatrix : Matrix;

var l_distance : float;

var l_materialName : name;
var l_hitComponent : CComponent;
var l_destructibleCmp : CDestructionSystemComponent;
var barrel : COilBarrelEntity;

//return;

if( isCurrentlyDodging )
return;

l_stateName = GetCurrentStateName();

if( !attackEventInProgress && l_stateName == 'CombatFists' )
return;

CalcEntitySlotMatrix('r_weapon', l_slotMatrix);

l_weaponPosition = MatrixGetTranslation( l_slotMatrix );

// Finding weapon's tip
switch( l_stateName )
{
case 'CombatFists':
l_offset = MatrixGetAxisX( l_slotMatrix );
l_offset = VecNormalize( l_offset ) * 0.25f;
break;
// sword
default:
l_offset = MatrixGetAxisZ( l_slotMatrix );
l_offset = VecNormalize( l_offset ) * 1.f;
break;
}

l_weaponTipPos = l_weaponPosition + l_offset;



if( !attackEventInProgress )
{
// If the weapon is not moving fast enough, do not play collision fx
if( m_LastWeaponTipPos == Vector ( 0, 0, 0 ) )
l_distance = 0;
else
l_distance = VecDistance( l_weaponTipPos, m_LastWeaponTipPos ) ;

//GetVisualDebug().AddText( 'LastWeaponTipText', "Last - dist: " + l_distance, m_LastWeaponTipPos, true, , Color( 249, 98, 158 ) );
//GetVisualDebug().AddArrow( 'OldDirectArrow', l_weaponPosition, m_LastWeaponTipPos , 0.8f, 0.1f, 0.2f, true, Color( 249, 98, 158 ) );

m_LastWeaponTipPos = l_weaponTipPos;
if( l_distance < 0.35f )
return;

}

/*GetVisualDebug().AddSphere( 'WeaponPosition', 0.1f, l_weaponPosition, true, Color( 249, 98, 158 ) );
GetVisualDebug().AddText( 'WeaponTipText', "Weapon Tip", l_weaponTipPos, true, , Color( 249, 98, 158 ) );
GetVisualDebug().AddArrow( 'CollisionArrow', l_weaponPosition, l_weaponTipPos , 0.8f, 0.1f, 0.2f, true, Color( 249, 98, 158 ) );*/

m_LastWeaponTipPos = l_weaponTipPos;

if ( !theGame.GetWorld().StaticTraceWithAdditionalInfo( l_weaponPosition, l_weaponTipPos, l_collidingPosition, l_normal, l_materialName, l_hitComponent, m_WeaponFXCollisionGroupNames ) )
{
// Test left fist
if( l_stateName == 'CombatFists' )
{
CalcEntitySlotMatrix('l_weapon', l_slotMatrix);
l_weaponPosition = MatrixGetTranslation( l_slotMatrix );
l_offset = MatrixGetAxisX( l_slotMatrix );
l_offset = VecNormalize( l_offset ) * 0.25f;
l_weaponTipPos = l_weaponPosition + l_offset;
if( !theGame.GetWorld().StaticTrace( l_weaponPosition, l_weaponTipPos, l_collidingPosition, l_normal, m_WeaponFXCollisionGroupNames ) )
{
return;
}
}
else
{
return;
}
}

if( !m_CollisionEffect )
{
m_CollisionEffect = theGame.CreateEntity( m_CollisionFxTemplate, l_collidingPosition, EulerAngles(0,0,0) );
}

m_CollisionEffect.Teleport( l_collidingPosition );

// Play hit effect
switch( l_stateName )
{
case 'CombatFists':
m_CollisionEffect.PlayEffect('fist');
break;
default:
// Optimisation because IsSwordWooden() is heavy (around 0.13 ms)
if( m_RefreshWeaponFXType )
{
m_PlayWoodenFX = IsSwordWooden();
m_RefreshWeaponFXType = false;
}

if( m_PlayWoodenFX )
{
m_CollisionEffect.PlayEffect('wood');
}
else
{
switch( l_materialName )
{
case 'wood_hollow':
case 'wood_debris':
case 'wood_solid':
m_CollisionEffect.PlayEffect('wood');
break;
case 'dirt_hard':
case 'dirt_soil':
case 'hay':
m_CollisionEffect.PlayEffect('fist');
break;
case 'stone_debris':
case 'stone_solid':
case 'clay_tile':
case 'gravel_large':
case 'gravel_small':
case 'metal':
case 'custom_sword':
m_CollisionEffect.PlayEffect('sparks');
break;
default:
m_CollisionEffect.PlayEffect('wood');
break;
}

}
break;
}

//don't ask...
if(l_hitComponent)
{
barrel = (COilBarrelEntity)l_hitComponent.GetEntity();
if(barrel)
{
barrel.OnFireHit(NULL); //sets barrel on fire so that it explodes in a few sec
return;
}
}

// Destroy destructibles
l_destructibleCmp = (CDestructionSystemComponent) l_hitComponent;
if( l_destructibleCmp && l_stateName != 'CombatFists' )
{
l_destructibleCmp.ApplyFracture();
}


//GetVisualDebug().AddText( 'collisionText', "Collision Here", l_collidingPosition, true, , Color( 249, 98, 158 ) );
}

public function ReactToReflectedAttack( target : CGameplayEntity)
{

var hp, dmg : float;
var action : W3DamageAction;

super.ReactToReflectedAttack(target);

if ( !((CNewNPC)target).IsShielded(this) )
{
action = new W3DamageAction in this;
action.Initialize(target,this,NULL,'',EHRT_Reflect,CPS_AttackPower,true,false,false,false);
action.AddEffectInfo(EET_Stagger);
action.SetProcessBuffsIfNoDamage(true);

theGame.damageMgr.ProcessAction( action );
delete action;
}




theGame.damageMgr.ProcessAction( action );
delete action;


theGame.VibrateControllerLight();//player attack was reflected
}

//////////////////
// falling damage
//////////////////

//return false when not falling
function GetFallDist( out fallDist : float ) : bool
{
var fallDiff, jumpTotalDiff : float;

// Get the falling height
substateManager.m_SharedDataO.CalculateFallingHeights( fallDiff, jumpTotalDiff );

if ( fallDiff <= 0 )
return false;

fallDist = fallDiff;
return true;
}

function ApplyFallingDamage(heightDiff : float, optional reducing : bool) : float
{
var hpPerc : float;
var tut : STutorialMessage;

if ( IsSwimming() || FactsQuerySum("block_falling_damage") >= 1 )
return 0.0f;

hpPerc = super.ApplyFallingDamage( heightDiff, reducing );

if(hpPerc > 0)
{
theGame.VibrateControllerHard();//player falling damage

if(IsAlive())
{
if(ShouldProcessTutorial('TutorialFallingDamage'))
{
FactsAdd("tutorial_falling_damage");
}

if(FactsQuerySum("tutorial_falling_damage") > 1 && ShouldProcessTutorial('TutorialFallingRoll'))
{
//fill tutorial object data
tut.type = ETMT_Hint;
tut.tutorialScriptTag = 'TutorialFallingRoll';
tut.hintPositionType = ETHPT_DefaultGlobal;
tut.hintDurationType = ETHDT_Long;
tut.canBeShownInMenus = false;
tut.glossaryLink = false;
tut.markAsSeenOnShow = true;

//show tutorial
theGame.GetTutorialSystem().DisplayTutorial(tut);
}
}
}

return hpPerc;
}

//--------------------------------- STAMINA INDICATOR #B --------------------------------------

public function SetShowToLowStaminaIndication( value : float ) : void
{
fShowToLowStaminaIndication = value;
}

public function GetShowToLowStaminaIndication() : float
{
return fShowToLowStaminaIndication;
}

public final function IndicateTooLowAdrenaline()
{
SoundEvent("gui_no_adrenaline");
showTooLowAdrenaline = true;
}

/////////////////////////////////

protected function GotoCombatStateWithAction( initialAction : EInitialAction, optional initialBuff : CBaseGameplayEffect )
{
if ( this.GetCurrentActionType() == ActorAction_Exploration )
ActionCancelAll();

((W3PlayerWitcherStateCombatFists)this.GetState('CombatFists')).SetupState( initialAction, initialBuff );
this.GotoState( 'CombatFists' );

}
///////////////////////////////////////////////////////////////////////////////////////////
// COMBAT
public function IsThreat( actor : CActor, optional usePrecalcs : bool ) : bool
{
var npc : CNewNPC;
var dist : float;
var targetCapsuleHeight : float;
var isDistanceExpanded : bool;
var distanceToTarget : float;
var attitude : EAIAttitude;

if (!actor)
{
return false;
}

if ( finishableEnemiesList.Contains( actor ) )
{
return true;
}

if ( !actor.IsAlive() || actor.IsKnockedUnconscious() )
{
return false;
}

npc = (CNewNPC)actor;
if (npc && npc.IsHorse() )
{
return false;
}

if ( hostileEnemies.Contains( actor ) )
{
return true;
}

//MS: We add a tolerance to make geralt go to alertfar everytime he runs away from npc
if ( GetAttitudeBetween( this, actor ) == AIA_Hostile )
{
if ( usePrecalcs )
{
distanceToTarget = Distance2DBetweenCapsuleAndPoint( actor, this ) - targetingPrecalcs.playerRadius;
}
else
{
distanceToTarget = Distance2DBetweenCapsules( this, actor );
}

// shortDistance = findMoveTargetDist + 5.0f;
if ( distanceToTarget < findMoveTargetDist + 5.0f )
{
return true;
}

if ( actor.IsInCombat() || this.IsHardLockEnabled() )
{
targetCapsuleHeight = ( (CMovingPhysicalAgentComponent)actor.GetMovingAgentComponent() ).GetCapsuleHeight();
if ( targetCapsuleHeight >= 2.0f || npc.GetCurrentStance() == NS_Fly )
{
// expandedDistance = 40.f;
if ( distanceToTarget < 40.0f )
{
return true;
}
}
}
}

if ( actor.GetAttitudeGroup() == 'npc_charmed' )
{
if ( theGame.GetGlobalAttitude( GetBaseAttitudeGroup(), actor.GetBaseAttitudeGroup() ) == AIA_Hostile )
{
return true;
}
}

return false;
}

function SetBIsCombatActionAllowed ( flag : bool )
{
bIsCombatActionAllowed = flag;

if ( !flag )
{
SetBIsInCombatAction(true);
}
else
{
this.ProcessLAxisCaching();
//UnblockAction(EIAB_Interactions, 'InsideCombatAction' );
}

//LogChannel('combatActionAllowed', "Is SET TO: " + flag );
}

function GetBIsCombatActionAllowed() : bool
{
return bIsCombatActionAllowed;
}

function SetCombatAction( action : EBufferActionType )
{
currentCombatAction = action;
}

function GetCombatAction() : EBufferActionType
{
return currentCombatAction;
}

protected function WhenCombatActionIsFinished()
{
if(IsThrowingItem() || IsThrowingItemWithAim() )
{
if(inv.IsItemBomb(selectedItemId))
{
BombThrowAbort();
}
else
{
ThrowingAbort();
}
}

if ( this.GetCurrentStateName() != 'DismountHorse' )
OnRangedForceHolster( true );

//SetBehaviorVariable( 'combatActionType', (int)CAT_None2);
}

public function IsInCombatAction_Attack(): bool
{
if ( IsInCombatAction_NonSpecialAttack() || IsInCombatAction_SpecialAttack() )
return true;
else
return false;
}

public function IsInCombatAction_NonSpecialAttack(): bool
{
if ( IsInCombatAction() && ( GetCombatAction() == EBAT_LightAttack || GetCombatAction() == EBAT_HeavyAttack ) )
return true;
else
return false;
}

public function IsInSpecificCombatAction ( specificCombatAction : EBufferActionType ) : bool
{
if ( IsInCombatAction() && GetCombatAction() == specificCombatAction )
return true;
else
return false;
}

public function IsInRunAnimation() : bool
{
return isInRunAnimation;
}

//I need to call it after scene ends thats why it's public. PF
public function SetCombatIdleStance( stance : float )
{
SetBehaviorVariable( 'combatIdleStance', stance );
SetBehaviorVariable( 'CombatStanceForOverlay', stance );

if ( stance == 0.f )
LogChannel( 'ComboInput', "combatIdleStance = Left" );
else
LogChannel( 'ComboInput', "combatIdleStance = Right" );
}

public function GetCombatIdleStance() : float
{
// 0.f == Left
return GetBehaviorVariable( 'combatIdleStance' );
}

protected var isRotatingInPlace : bool;
event OnRotateInPlaceStart()
{
isRotatingInPlace = true;
}

event OnRotateInPlaceEnd()
{
isRotatingInPlace = false;
}

event OnFullyBlendedIdle()
{
if ( bLAxisReleased )
{
ResetRawPlayerHeading();
ResetCachedRawPlayerHeading();
defaultLocomotionController.ResetMoveDirection();
}
}

event OnRunLoopStart()
{
EnableRunCamera( true );
}

event OnRunLoopEnd()
{
EnableRunCamera( false );
}

event OnCombatActionStartBehgraph()
{
var buff : CBaseGameplayEffect;
var action : EBufferActionType;
var cost, delay : float;

// Block saves
//theGame.CreateNoSaveLock( noSaveLockCombatActionName, noSaveLockCombatAction, true );

OnCombatActionStart();

//Pause the stamina regen for as long as we're doing combat actions.
//Pause only once to avoid the pause counter from increasing with each lock
buff = GetBuff(EET_AutoStaminaRegen);

action = PerformingCombatAction();
switch ( action )
{
case EBAT_LightAttack :
{
abilityManager.GetStaminaActionCost(ESAT_LightAttack, cost, delay);
} break;
case EBAT_HeavyAttack :
{
abilityManager.GetStaminaActionCost(ESAT_HeavyAttack, cost, delay);
} break;
case EBAT_ItemUse :
{
abilityManager.GetStaminaActionCost(ESAT_UsableItem, cost, delay);
} break;
case EBAT_Parry :
{
abilityManager.GetStaminaActionCost(ESAT_Parry, cost, delay);
} break;
case EBAT_Dodge :
{
abilityManager.GetStaminaActionCost(ESAT_Dodge, cost, delay);
} break;
case EBAT_Roll :
abilityManager.GetStaminaActionCost(ESAT_Roll, cost, delay);
break;
case EBAT_SpecialAttack_Light :
{
abilityManager.GetStaminaActionCost(ESAT_Ability, cost, delay, 0,0, GetSkillAbilityName(S_Sword_s01));
} break;
case EBAT_SpecialAttack_Heavy :
{
abilityManager.GetStaminaActionCost(ESAT_Ability, cost, delay, 0,0, GetSkillAbilityName(S_Sword_s02));
} break;
case EBAT_Roll :
{
abilityManager.GetStaminaActionCost(ESAT_Evade, cost, delay);
} break;
/*
case EBAT_Ciri_SpecialAttack :
{
cost = GetStaminaActionCost();
} break;
*/
default :
;
}

if( (!buff || !buff.IsPaused('InsideCombatAction')) && delay > 0 )
PauseEffects(EET_AutoStaminaRegen, 'InsideCombatAction');
}

public function HolsterUsableItem() : bool
{
return holsterUsableItem;
}

private var isInGuardedState : bool;
public function IsInGuardedState() : bool
{
return isInGuardedState;
}

event OnGuardedStart()
{
isInParryOrCounter = true;
isInGuardedState = true;
}

event OnGuardedEnd()
{
isInParryOrCounter = false;
isInGuardedState = false;
}

private var restoreUsableItem : bool;
private var holsterUsableItem : bool;
event OnCombatActionStart()
{
//Block Actions
//BlockAction( EIAB_DrawWeapon, 'OnCombatActionStart' );
BlockAction( EIAB_UsableItem, 'OnCombatActionStart' );
BlockAction( EIAB_CallHorse, 'OnCombatActionStart' );

/*if ( !IsGuarded() )
SetParryTarget( NULL );*/

LogChannel('combatActionAllowed',"FALSE OnCombatActionStart");
SetBIsCombatActionAllowed( false );
SetBIsInputAllowed( false, 'OnCombatActionStart' );
//lastAxisInputIsMovement = true;

ClearFinishableEnemyList( 0.f, 0 );

bIsInHitAnim = false;

//Holster Crossbow if it's held
//if ( inv.IsItemCrossbow( inv.GetItemFromSlot( 'l_weapon' ) ) )//&& GetBehaviorVariable( 'combatActionType' ) != (int)CAT_Crossbow )
if ( rangedWeapon && rangedWeapon.GetCurrentStateName() != 'State_WeaponWait' )
{
CleanCombatActionBuffer();
SetIsAimingCrossbow( false );
OnRangedForceHolster( false, true );
}

//Holster UsableItem if it's held
holsterUsableItem = false;
if ( thePlayer.IsHoldingItemInLHand() ) // && !thePlayer.IsUsableItemLBlocked() )
{
if ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_CastSign )
holsterUsableItem = true;
else if ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack )
{
if ( this.GetCurrentStateName() == 'CombatFists' )
holsterUsableItem = true;
}
}

if ( holsterUsableItem )
{
thePlayer.SetPlayerActionToRestore ( PATR_None );
thePlayer.OnUseSelectedItem( true );

restoreUsableItem = true;
}

//Stop Geralt from automatically attacking while in AttackApproach when Player performs a non-attack combat action
if ( GetBehaviorVariable( 'combatActionType' ) != (int)CAT_Attack && GetBehaviorVariable( 'combatActionType' ) != (int)CAT_PreAttack )
{
RemoveTimer( 'ProcessAttackTimer' );
RemoveTimer( 'AttackTimerEnd' );
UnblockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' );
}
else
{
//MS: Do not remove this!! The attack to idle transition states will not work correctly if you change weapon mid-attack.
BlockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' );
}

//GetMovingAgentComponent().SnapToNavigableSpace(true);
}

var isInParryOrCounter : bool;
event OnParryOrCounterStart()
{
isInParryOrCounter = true;
OnCombatActionStartBehgraph();
}

event OnParryOrCounterEnd()
{
isInParryOrCounter = false;
OnCombatActionEnd();
SetBIsInCombatAction( false );
}

//called when a combat action is completed (e.g. single hit in a combo sequence)
event OnCombatActionEnd()
{
var item : SItemUniqueId;
var combatActionType : float;

super.OnCombatActionEnd();


//Unblock Actions
BlockAllActions( 'OnCombatActionStart', false );

UnblockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' );

//why? this way after EACH attack you reset it - what's the point then?
//ResetUninterruptedHitsCount();

oTCameraOffset = 0.f;
oTCameraPitchOffset = 0.f;

//LogChannel('combatActionAllowed',"TRUE OnCombatActionEnd");
SetBIsCombatActionAllowed( true );
//reapply critical buff if any
//Z ReapplyCriticalBuff();
SetBIsInputAllowed( true, 'OnCombatActionEnd' );
SetCanPlayHitAnim( true );
EnableFindTarget( true );

SetIsCurrentlyDodging( false );

SetFinisherVictim( NULL );

OnBlockAllCombatTickets( false );

LogStamina("CombatActionEnd");

//GetMovingAgentComponent().SnapToNavigableSpace(false);

SetAttackActionName('');
combatActionType = GetBehaviorVariable('combatActionType');

//clean-up after special attack heavy finishes
if(GetBehaviorVariable('combatActionType') == (int)CAT_SpecialAttack)
{
theGame.GetGameCamera().StopAnimation( 'camera_shake_loop_lvl1_1' );
OnSpecialAttackHeavyActionProcess();
}
// Do we need to interrupt?
substateManager.ReactToChanceToFallAndSlide();
}

event OnCombatActionFriendlyStart()
{
SetBIsInCombatActionFriendly(true);
OnCombatActionStart();
}

event OnCombatActionFriendlyEnd()
{
SetBIsInCombatActionFriendly(false);
OnCombatActionEnd();
SetBIsInCombatAction(false);
//RaiseForceEvent( 'ForceIdle' );
}

event OnHitStart()
{
var timeLeft : float;
var currentEffects : array;
var none : SAbilityAttributeValue;

CancelHoldAttacks();
WhenCombatActionIsFinished();
if ( isInFinisher )
{
if ( finisherTarget )
( (CNewNPC)finisherTarget ).SignalGameplayEvent( 'FinisherInterrupt' );
isInFinisher = false;
finisherTarget = NULL;
SetBIsCombatActionAllowed( true );
}

bIsInHitAnim = true;

OnCombatActionStart(); //"because it's needed"

//OnCombatActionStart pauses the regen and we don't want that
ResumeEffects(EET_AutoStaminaRegen, 'InsideCombatAction');

if( GetHealthPercents() < 0.3f )
{
PlayBattleCry('BattleCryBadSituation', 0.10f, true );
}
else
{
PlayBattleCry('BattleCryBadSituation', 0.05f, true );
}
}

event OnHitStartSwimming()
{
OnRangedForceHolster( true, true, false );
}

// modXTfinishers BEGIN
public var actionContext : XTFinishersActionContext;

public function LoadActionContext(context : XTFinishersActionContext) {
actionContext = context;
}
// modXTFinishers END

private var finisherSaveLock : int;
event OnFinisherStart()
{
var currentEffects : array;

theGame.CreateNoSaveLock("Finisher",finisherSaveLock,true,false);

isInFinisher = true;

finisherTarget = slideTarget;
OnCombatActionStart();

CancelHoldAttacks();

// modXTFinishers BEGIN
theGame.xtFinishersMgr.eventMgr.FireEvent(theGame.xtFinishersMgr.consts.FINISHER_EVENT_ID, CreateXTFinishersActionContextData(theGame.xtFinishersMgr.eventMgr, actionContext));
// modXTFinishers END

PlayFinisherCameraAnimation( theGame.GetSyncAnimManager().GetFinisherCameraAnimName() );
this.AddAnimEventCallback('SyncEvent','OnFinisherAnimEvent_SyncEvent');
SetImmortalityMode( AIM_Invulnerable, AIC_SyncedAnim );
}

public function IsPerformingFinisher() : bool
{
return isInFinisher;
}

private function PlayFinisherCameraAnimation( cameraAnimName : name )
{
var camera : CCustomCamera = theGame.GetGameCamera();
var animation : SCameraAnimationDefinition;

if (IsLastEnemyKilled() && theGame.GetWorld().NavigationCircleTest( this.GetWorldPosition(), 3.f ) )
if (actionContext.finisherCam.active) {
theGame.xtFinishersMgr.eventMgr.FireEvent(theGame.xtFinishersMgr.consts.FINISHER_CAM_PRE_EVENT_ID, CreateXTFinishersActionContextData(theGame.xtFinishersMgr.eventMgr, actionContext));
if (actionContext.finisherCam.active) {
camera.StopAnimation('camera_shake_hit_lvl3_1' );

animation.animation = cameraAnimName;
animation.priority = CAP_Highest;
animation.blendIn = 0.15f;
animation.blendOut = 1.0f;
animation.weight = 1.f;
animation.speed = 1.0f;
animation.reset = true;

camera.PlayAnimation( animation );
//thePlayer.AddTimer( 'RemoveFinisherCameraAnimationCheck', 0.01, true );

thePlayer.EnableManualCameraControl( false, 'Finisher' );

theGame.xtFinishersMgr.eventMgr.FireEvent(theGame.xtFinishersMgr.consts.FINISHER_CAM_EVENT_ID, CreateXTFinishersActionContextData(theGame.xtFinishersMgr.eventMgr, actionContext));
}
}
// modXTFinishers END
}

public function IsLastEnemyKilled() : bool
{
var tempMoveTargets : array;

FindMoveTarget();
tempMoveTargets = GetMoveTargets();
if ( tempMoveTargets.Size() <= 0 || !thePlayer.IsThreat( tempMoveTargets[0] ) )
return true;

return false;
}

event OnFinisherAnimEvent_SyncEvent( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo )
{
if ( finisherTarget )
( (CNewNPC)finisherTarget ).SignalGameplayEvent('FinisherKill');
finisherTarget = NULL;
}

event OnFinisherEnd()
{
isInFinisher = false;
finisherTarget = NULL;

theGame.ReleaseNoSaveLock(finisherSaveLock);

this.RemoveAnimEventCallback('SyncEvent');

//SetIsPerformingPhaseChangeAnimation( false ); // for eredin fight
// modXTFinishers BEGIN
if (actionContext) {
delete actionContext;
actionContext = NULL;
}
// modXTFinishers END

SetImmortalityMode( AIM_None, AIC_SyncedAnim );
theGame.RemoveTimeScale( 'AnimEventSlomoMo' );
AddTimer( 'FinisherEndEnableCamera', 0.5f );
//OnBlockAllCombatTickets( false );
OnCombatActionEnd();
OnCombatActionEndComplete();
}

private timer function FinisherEndEnableCamera( dt : float, id : int )
{
thePlayer.EnableManualCameraControl( true, 'Finisher' );
}

public function SpawnFinisherBlood()
{
var weaponEntity : CEntity;
var weaponSlotMatrix : Matrix;
var bloodFxPos : Vector;
var bloodFxRot : EulerAngles;
var tempEntity : CEntity;

weaponEntity = this.GetInventory().GetItemEntityUnsafe( GetInventory().GetItemFromSlot('r_weapon') );
weaponEntity.CalcEntitySlotMatrix( 'blood_fx_point', weaponSlotMatrix );
bloodFxPos = MatrixGetTranslation( weaponSlotMatrix );
bloodFxRot = this.GetWorldRotation();//MatrixGetRotation( weaponSlotMatrix );
tempEntity = theGame.CreateEntity( (CEntityTemplate)LoadResource('finisher_blood'), bloodFxPos, bloodFxRot);
tempEntity.PlayEffect('crawl_blood');
}

//called when all combat actions have ended (e.g. whole combo)
event OnCombatActionEndComplete()
{
var buff : CBaseGameplayEffect;

buff = ChooseCurrentCriticalBuffForAnim();
SetCombatAction( EBAT_EMPTY );

//Unblock Actions what you wann
UnblockAction( EIAB_DrawWeapon, 'OnCombatActionStart' );
UnblockAction( EIAB_OpenInventory, 'OnCombatActionStart' );
UnblockAction( EIAB_UsableItem, 'OnCombatActionStart' );

UnblockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' );

SetUnpushableTarget( NULL );
SetBIsInCombatAction(false);
SetIsCurrentlyDodging(false);
SetMoveTargetChangeAllowed( true );
SetCanPlayHitAnim( true );

SetFinisherVictim( NULL );

this.RemoveBuffImmunity(EET_Burning, 'AnimEvent_RemoveBurning');

if ( rangedWeapon && rangedWeapon.GetCurrentStateName() == 'State_WeaponWait' && !buff )
{
ClearCustomOrientationInfoStack();
SetSlideTarget( NULL );
}

UnblockAction( EIAB_Crossbow, 'OnForceHolster' );

specialAttackCamera = false;

bIsRollAllowed = false;

if ( bLAxisReleased )
{
ResetRawPlayerHeading();
ResetCachedRawPlayerHeading();
}

//reapply critical buff if any
ReapplyCriticalBuff();
SetBIsInputAllowed( true, 'OnCombatActionEndComplete' );

//stamina regen is paused as long as we are doing some combat actions
ResumeEffects(EET_AutoStaminaRegen, 'InsideCombatAction');

bIsInHitAnim = false;

SetBIsCombatActionAllowed( true );

m_LastWeaponTipPos = Vector(0, 0, 0, 0 );

//free tickets
this.AddTimer('FreeTickets',3.f,false);

// remove save lock
//theGame.ReleaseNoSaveLockByName( noSaveLockCombatActionName );
}

event OnMovementFullyBlended()
{
SetBehaviorVariable( 'isPerformingSpecialAttack', 0.f );

if ( restoreUsableItem )
{
restoreUsableItem = false;
SetPlayerActionToRestore ( PATR_Default );
OnUseSelectedItem();
}
}

event OnCombatMovementStart()
{
SetCombatIdleStance( 1.f );
OnCombatActionEndComplete();
}

timer function FreeTickets( dt : float, id : int )
{
FreeTicketAtCombatTarget();
}


/*
These declarations are needed here only to call event with the same name inside combat state (there's no other way to call it!).
*/
event OnGuardedReleased(){}
event OnPerformAttack( playerAttackType : name ){}
event OnPerformEvade( playerEvadeType : EPlayerEvadeType ){}
event OnInterruptAttack(){}
event OnPerformGuard(){}
event OnSpawnHorse(){}
event OnDismountActionScriptCallback(){}

event OnHorseSummonStart()
{
thePlayer.BlockAction(EIAB_CallHorse, 'HorseSummon');
thePlayer.BlockAction(EIAB_Signs, 'HorseSummon');
thePlayer.BlockAction(EIAB_Crossbow, 'HorseSummon');
thePlayer.BlockAction(EIAB_UsableItem, 'HorseSummon');
thePlayer.BlockAction(EIAB_ThrowBomb, 'HorseSummon');
thePlayer.BlockAction(EIAB_SwordAttack, 'HorseSummon');
thePlayer.BlockAction(EIAB_Jump, 'HorseSummon');
thePlayer.BlockAction(EIAB_Dodge, 'HorseSummon');
thePlayer.BlockAction(EIAB_LightAttacks, 'HorseSummon');
thePlayer.BlockAction(EIAB_HeavyAttacks, 'HorseSummon');
thePlayer.BlockAction(EIAB_SpecialAttackLight, 'HorseSummon');
thePlayer.BlockAction(EIAB_SpecialAttackHeavy, 'HorseSummon');

horseSummonTimeStamp = theGame.GetEngineTimeAsSeconds();
}

event OnHorseSummonStop()
{
thePlayer.BlockAllActions('HorseSummon',false);
}

/*
CombatAction events when on vehicles
*/
event OnCombatActionStartVehicle( action : EVehicleCombatAction )
{
this.SetBIsCombatActionAllowed( false );

if ( action != EHCA_ShootCrossbow )
{
SetIsAimingCrossbow( false );
OnRangedForceHolster();
}
}

event OnCombatActionEndVehicle()
{
this.SetBIsCombatActionAllowed( true );
}

////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @CRITICAL STATES /////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

protected function CriticalBuffInformBehavior(buff : CBaseGameplayEffect)
{
/*if ( this.GetCurrentStateName() == 'Exploration' || this.GetCurrentStateName() == 'AimThrow' )
GotoCombatStateWithAction( IA_CriticalState, buff );
else
{*/
if( !CanAnimationReactToCriticalState( buff ) )
{
return;
}

// if ( IsInCombatAction() )
// RaiseEvent('ForceBlendOut');

SetBehaviorVariable( 'CriticalStateType', (int)GetBuffCriticalType(buff) );
SetBehaviorVariable( 'bCriticalState', 1);

if(CriticalBuffUsesFullBodyAnim(buff))
RaiseEvent('CriticalState');

SetBehaviorVariable( 'IsInAir', (int)IsInAir());

LogCritical("Sending player critical state event for <<" + buff.GetEffectType() + ">>");

//}
}

private function CanAnimationReactToCriticalState( buff : CBaseGameplayEffect ) : bool
{
var buffCritical : W3CriticalEffect;
var buffCriticalDOT : W3CriticalDOTEffect;
var isHeavyCritical : bool;

isHeavyCritical = false;

// Find out if it is a heavy critical state
buffCritical = ( W3CriticalEffect ) buff;
if( buffCritical )
{
isHeavyCritical = buffCritical.explorationStateHandling == ECH_HandleNow;
}
else
{
buffCriticalDOT = ( W3CriticalDOTEffect ) buff;
if( buffCriticalDOT )
{
isHeavyCritical = buffCriticalDOT.explorationStateHandling == ECH_HandleNow;
}
}

// If it is not, we may skip it
if( !isHeavyCritical )
{
if( !CanReactToCriticalState() )
{
return false;
}
}

return true;
}

public function CanReactToCriticalState() : bool
{
return substateManager.CanReactToHardCriticalState();
}

event OnCriticalStateAnimStart()
{
var heading : float;
var newCritical : ECriticalStateType;
var newReqCS : CBaseGameplayEffect;

OnCombatActionEndComplete();

//abort throwing if super was processed properly
newReqCS = newRequestedCS;
if(super.OnCriticalStateAnimStart())
{
//WhenCombatActionIsFinished();
RemoveTimer( 'IsItemUseInputHeld' );
keepRequestingCriticalAnimStart = false;
CancelHoldAttacks();

//knockdown direction
// No knockdown when using a vehicule: the vehicule will handle the knock down logic
//PFTODO
//we need this for NPCs also (knockdown dir)
if(!IsUsingVehicle())
{
newCritical = GetBuffCriticalType(newReqCS);
if(newCritical == ECST_HeavyKnockdown
|| newCritical == ECST_Knockdown
|| newCritical == ECST_Stagger
|| newCritical == ECST_Ragdoll
|| newCritical == ECST_LongStagger )
{
if(newReqCS.GetCreator())
heading = VecHeading(newReqCS.GetCreator().GetWorldPosition() - GetWorldPosition());
else
heading = GetHeading();

//this.GetMovingAgentComponent().GetMovementAdjustor().CancelAll();
SetCustomRotation( 'Knockdown', heading, 2160.f, 0.1f, true );

if ( newCritical != ECST_Stagger && newCritical != ECST_LongStagger )
substateManager.ReactOnCriticalState( true );
}
}

return true;
}

//SetBehaviorVariable( 'bCriticalStopped', 1);
return false;
}

/*
Called when new critical effect has started
This will interrupt current critical state

returns true if the effect got fired properly
*/
public function StartCSAnim(buff : CBaseGameplayEffect) : bool
{
SetBehaviorVariable( 'bCriticalStopped', 0 );

if(super.StartCSAnim(buff))
{
if(!CriticalBuffUsesFullBodyAnim(buff))
{
OnCriticalStateAnimStart();
}

ResumeEffects(EET_AutoStaminaRegen, 'InsideCombatAction');

keepRequestingCriticalAnimStart = true;
AddTimer('RequestCriticalAnimStart', 0, true);
//RequestCriticalAnimStart(0);

return true;
}

return false;
}

public function CriticalEffectAnimationInterrupted(reason : string) : bool
{
var ret : bool; //for debug

LogCriticalPlayer("R4Player.CriticalEffectAnimationInterrupted() - because: " + reason);

ret = super.CriticalEffectAnimationInterrupted(reason);

if(ret)
{
keepRequestingCriticalAnimStart = false;
}

substateManager.ReactOnCriticalState( false );

return ret;
}

public function CriticalStateAnimStopped(forceRemoveBuff : bool)
{
LogCriticalPlayer("R4Player.CriticalStateAnimStopped() - forced: " + forceRemoveBuff);

super.CriticalStateAnimStopped(forceRemoveBuff);

substateManager.ReactOnCriticalState( false );
}

// keeps requesting (sending event) to enter critical states anim state in behavior
timer function RequestCriticalAnimStart(dt : float, id : int)
{
if(keepRequestingCriticalAnimStart)
{
if(newRequestedCS && newRequestedCS.GetDurationLeft() > 0)
{
CriticalBuffInformBehavior(newRequestedCS);
}
else
{
keepRequestingCriticalAnimStart = false;
RemoveTimer('RequestCriticalAnimStart');
}
}
else
{
RemoveTimer('RequestCriticalAnimStart');
}
}

event OnRagdollUpdate(progress : float)
{
//super.OnRagdollUpdate(progress);

SetIsInAir(progress == 0);
}

// getting from ragdoll after certain time has passed
event OnRagdollOnGround()
{
// try to getup immediately as currently when laying on ground we might be constantly switched between on ground and in air
TryToEndRagdollOnGround( 0.0f );
}

event OnRagdollInAir()
{
RemoveTimer('TryToEndRagdollOnGround');
}

event OnNoLongerInRagdoll()
{
RemoveTimer('TryToEndRagdollOnGround');
}

timer function TryToEndRagdollOnGround( td : float, optional id : int)
{
var critical : CBaseGameplayEffect;
var type : EEffectType;

critical = GetCurrentlyAnimatedCS();
if(critical)
{
type = critical.GetEffectType();
if(type == EET_Knockdown || type == EET_HeavyKnockdown || type == EET_Ragdoll)
{
// 2.5 seconds is not that long but this is not ragdoll simulator :)
if (critical.GetTimeActive() >= 2.5f)
{
SetIsInAir(false);
RequestCriticalAnimStop();
RemoveTimer('TryToEndRagdollOnGround');
}
else
{
AddTimer('TryToEndRagdollOnGround', 0.2f, true);
}
return;
}
}

// not in critical or type differs
RemoveTimer('TryToEndRagdollOnGround');
}

public function RequestCriticalAnimStop(optional dontSetCriticalToStopped : bool)
{
var buff : CBaseGameplayEffect;

buff = GetCurrentlyAnimatedCS();
if(buff && !CriticalBuffUsesFullBodyAnim(buff))
{
CriticalStateAnimStopped(false);
}

if(!buff || !CriticalBuffUsesFullBodyAnim(buff))
{
SetBehaviorVariable( 'bCriticalState', 0);
}

super.RequestCriticalAnimStop(dontSetCriticalToStopped);
}
////////////////////////////////////////////////////////////////////////////////////////////
// @Buffs @Effects
////////////////////////////////////////////////////////////////////////////////////////////

public function SimulateBuffTimePassing(simulatedTime : float)
{
effectManager.SimulateBuffTimePassing(simulatedTime);
}

public function AddEffectDefault(effectType : EEffectType, creat : CGameplayEntity, srcName : string, optional isSignEffect : bool) : EEffectInteract
{
var params : SCustomEffectParams;

/*
Welcome to the Ancient Pit. If you're here reading this then you're doomed...

You're probably asking why someone is overriding default effect durations with some custom arbitrary numbers...

The thuth is: noone remembers...

But we need this and you cannot remove it or shit will start falling apart.
*/
if(effectType == EET_Stagger || effectType == EET_LongStagger || effectType == EET_Knockdown || effectType == EET_HeavyKnockdown)
{
params.effectType = effectType;
params.creator = creat;
params.sourceName = srcName;
params.isSignEffect = isSignEffect;

if ( effectType == EET_Stagger )
params.duration = 1.83;
else if ( effectType == EET_LongStagger )
params.duration = 4;
else if ( effectType == EET_Knockdown )
params.duration = 2.5;
else if ( effectType == EET_HeavyKnockdown )
params.duration = 4;

return super.AddEffectCustom(params);
}
else
{
return super.AddEffectDefault(effectType, creat, srcName, isSignEffect);
}
}


////////////////////////////////////////////////////////////////////////////////////////////

//a cheat to ressurect player
public function CheatResurrect()
{
if(IsAlive())
return;

SetAlive(true);

SetKinematic(true);

delete abilityManager;
delete effectManager;

SetAbilityManager(); //defined in inheriting classes but must be called before setting any other managers - sets skills and stats
abilityManager.Init(this, GetCharacterStats(), false, theGame.GetDifficultyMode());

SetEffectManager();

abilityManager.PostInit(); //called after other managers are ready

EnableFindTarget( true );
SetBehaviorVariable( 'Ragdoll_Weight', 0.f );
RaiseForceEvent( 'RecoverFromRagdoll' );
SetCanPlayHitAnim( true );
SetBehaviorVariable( 'CriticalStateType', (int)ECST_None );
//if( GetCurrentStateName() != 'CombatSteel')
// PushState( 'CombatSteel' );
//else
GoToStateIfNew('Exploration');

( (CDismembermentComponent)this.GetComponent( 'Dismemberment' ) ).ClearVisibleWound();

SetIsInAir(false); //might block getup from ragdol in knockdown

theInput.SetContext('Exploration');

ResetDeathType();

ForceUnlockAllInputActions(false);

theGame.CloseMenu('DeathScreenMenu');

//restore sounds
theSound.LeaveGameState(ESGS_Death);

theGame.ReleaseNoSaveLock(deathNoSaveLock);
}

////////////////////////////////////////////////////////////////////////////////////////////

public function SetIsInsideInteraction(b : bool) {isInsideInteraction = b;}
public function IsInsideInteraction() : bool {return isInsideInteraction;}

public function SetIsInsideHorseInteraction( b : bool, horse : CEntity )
{
isInsideHorseInteraction = b;
horseInteractionSource = horse;
}
public function IsInsideHorseInteraction() : bool {return isInsideHorseInteraction;}


event OnInteractionActivationTest( interactionComponentName : string, activator : CEntity )
{
if ( interactionComponentName == "ClimbLadder" )
{
if( PlayerHasLadderExplorationReady() )
{
return true;
}
}

return false;
}

private function PlayerHasLadderExplorationReady() : bool
{
if( !substateManager.CanInteract() )
{
return false;
}

if( !substateManager.m_SharedDataO.HasValidLadderExploration() )
{
return false;
}

return true;
}

////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// @COMBAT /////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

public function SetGuarded(flag : bool)
{
super.SetGuarded(flag);

if(flag && FactsQuerySum("tut_fight_use_slomo") > 0)
{
theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_TutorialFight) );
FactsRemove("tut_fight_slomo_ON");
}
}


public function IsGuarded() : bool
{
return super.IsGuarded() && ( !rangedWeapon || rangedWeapon.GetCurrentStateName() == 'State_WeaponWait' );
}
////////////////////////////////////////////////////////////////////////////////////////////
///////////////////// @THROWABLE @BOMBS @PETARDS @Usable ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

public function GetSelectedItemId() : SItemUniqueId {return selectedItemId;}
public function ClearSelectedItemId() {selectedItemId = GetInvalidUniqueId();}

public function IsHoldingItemInLHand() : bool
{
return currentlyEquipedItemL != GetInvalidUniqueId();
}

public function GetCurrentlyUsedItemL () : W3UsableItem
{
return currentlyUsedItemL;
}

public function SetPlayerActionToRestore ( actionToRestoreType : EPlayerActionToRestore )
{
playerActionToRestore = actionToRestoreType;
}

public function IsCurrentlyUsingItemL () : bool
{
return currentlyUsingItem;
}

function BlockSlotsOnLItemUse ()
{
var slotsToBlock : array;

slotsToBlock.PushBack( 'Slot1' );
slotsToBlock.PushBack( 'Slot2' );
slotsToBlock.PushBack( 'Slot3' );
slotsToBlock.PushBack( 'Slot4' );
slotsToBlock.PushBack( 'Slot5' );
slotsToBlock.PushBack( 'Yrden' );
slotsToBlock.PushBack( 'Quen' );
slotsToBlock.PushBack( 'Igni' );
slotsToBlock.PushBack( 'Axii' );
slotsToBlock.PushBack( 'Aard' );


EnableRadialSlotsWithSource ( false, slotsToBlock, 'usableItemL' );
}

function UnblockSlotsOnLItemUse ()
{
var slotsToBlock : array;

slotsToBlock.PushBack( 'Slot1' );
slotsToBlock.PushBack( 'Slot2' );
slotsToBlock.PushBack( 'Slot3' );
slotsToBlock.PushBack( 'Slot4' );
slotsToBlock.PushBack( 'Slot5' );
slotsToBlock.PushBack( 'Yrden' );
slotsToBlock.PushBack( 'Quen' );
slotsToBlock.PushBack( 'Igni' );
slotsToBlock.PushBack( 'Axii' );
slotsToBlock.PushBack( 'Aard' );


EnableRadialSlotsWithSource ( true, slotsToBlock, 'usableItemL' );
}

function IsUsableItemLBlocked () : bool
{
return isUsableItemBlocked;
}
function HideUsableItem( optional force : bool )
{
if( currentlyEquipedItemL != GetInvalidUniqueId() )
{
if ( force )
{
if (!RaiseEvent( 'ItemEndL' ) )
{
OnUsingItemsReset();
}
return;

}
RaiseEvent( 'ItemUseL' );
}
}
function ProcessUsableItemsTransition ( actionToRestore : EPlayerActionToRestore )
{
var category : name;
var signSkill : ESkill;

category = inv.GetItemCategory ( selectedItemId );
signSkill = SignEnumToSkillEnum( GetEquippedSign());

switch ( actionToRestore )
{
case PATR_None:
if ( currentlyUsedItemL )
{
inv.UnmountItem( currentlyEquipedItemL, true );
}
currentlyEquipedItemL = GetInvalidUniqueId();
return;

case PATR_Default:
if ( IsSlotQuickslot( inv.GetSlotForItemId ( selectedItemId )) && category == 'usable' && currentlyEquipedItemL != selectedItemId )
{
if ( currentlyUsedItemL )
{
inv.UnmountItem( currentlyEquipedItemL, true );
}
currentlyEquipedItemL = GetInvalidUniqueId();
OnUseSelectedItem();
return;
}
break;
case PATR_Crossbow:
if ( inv.IsItemCrossbow ( selectedItemId ) )
{
if ( currentlyUsedItemL )
{
inv.UnmountItem( currentlyEquipedItemL, true );
}
currentlyEquipedItemL = GetInvalidUniqueId();
SetIsAimingCrossbow( true );

if ( theInput.IsActionPressed( 'ThrowItem' ) )
SetupCombatAction( EBAT_ItemUse, BS_Pressed );
else
{
SetupCombatAction( EBAT_ItemUse, BS_Pressed );
SetupCombatAction( EBAT_ItemUse, BS_Released );
}
return;
}
break;
case PATR_CastSign:
if( signSkill != S_SUndefined && playerActionToRestore == PATR_CastSign )
{
if ( currentlyUsedItemL )
{
inv.UnmountItem( currentlyEquipedItemL, true );
}
currentlyEquipedItemL = GetInvalidUniqueId();

if( HasStaminaToUseSkill( signSkill, false ) )
{
if( GetInvalidUniqueId() != inv.GetItemFromSlot( 'l_weapon' ) )
PushCombatActionOnBuffer( EBAT_CastSign, BS_Pressed );
else
SetupCombatAction( EBAT_CastSign, BS_Pressed );
}
else
{
thePlayer.SoundEvent("gui_no_stamina");
}
return;
}
break;
case PATR_ThrowBomb:
if ( inv.IsItemBomb ( selectedItemId ) )
{
if ( currentlyUsedItemL )
{
inv.UnmountItem( currentlyEquipedItemL, true );
}
currentlyEquipedItemL = GetInvalidUniqueId();
PrepareToAttack();
SetupCombatAction( EBAT_ItemUse, BS_Pressed );
return;
}
break;
case PATR_CallHorse:
theGame.OnSpawnPlayerHorse();
break;
default:
if ( currentlyUsedItemL )
{
inv.UnmountItem( currentlyEquipedItemL, true );
}
currentlyEquipedItemL = GetInvalidUniqueId();
return;
}
if ( currentlyUsedItemL )
{
inv.UnmountItem( currentlyEquipedItemL, true );
}
currentlyEquipedItemL = GetInvalidUniqueId();
}

function GetUsableItemLtransitionAllowed () : bool
{
return isUsableItemLtransitionAllowed;
}

function SetUsableItemLtransitionAllowed ( isAllowed : bool)
{
isUsableItemLtransitionAllowed = isAllowed;
}

event OnItemUseLUnBlocked ()
{
if ( isUsableItemBlocked )
{
isUsableItemBlocked = false;
UnblockSlotsOnLItemUse ();
}
}

event OnItemUseLBlocked ()
{
if ( !isUsableItemBlocked )
{
isUsableItemBlocked = true;
BlockSlotsOnLItemUse ();
}
}

event OnUsingItemsReset()
{
if ( currentlyUsingItem )
{
OnItemUseLUnBlocked ();
OnUsingItemsComplete();
}
}
event OnUsingItemsComplete ()
{
if ( isUsableItemBlocked )
{
OnItemUseLUnBlocked ();
}
currentlyUsingItem = false;
if ( GetUsableItemLtransitionAllowed () )
{
ProcessUsableItemsTransition( playerActionToRestore );
}
else
{
if ( currentlyUsedItemL )
{
inv.UnmountItem( currentlyEquipedItemL, true );
}
currentlyEquipedItemL = GetInvalidUniqueId();
}

SetPlayerActionToRestore ( PATR_Default );
}

event OnUseSelectedItem( optional force : bool )
{
var category : name;
var itemEntity : W3UsableItem;

if ( isUsableItemBlocked && !force )
{
return false;
}
if ( IsCastingSign() )
return false;

if ( currentlyEquipedItemL != GetInvalidUniqueId() )
{
SetBehaviorVariable( 'SelectedItemL', (int)GetUsableItemTypeById( currentlyEquipedItemL ) );
if ( force )
{
if ( RaiseEvent( 'ItemEndL' ) )
{
SetUsableItemLtransitionAllowed ( true );
return true;
}
}
else
{
if ( RaiseEvent( 'ItemUseL' ) )
{
SetUsableItemLtransitionAllowed ( true );
return true;
}
}
}
else
{
category = inv.GetItemCategory( selectedItemId );
if( category != 'usable' )
{
return false;
}
SetBehaviorVariable( 'SelectedItemL', (int)GetUsableItemTypeById( selectedItemId ) );
if( RaiseEvent( 'ItemUseL' ) )
{
currentlyEquipedItemL = selectedItemId;
SetUsableItemLtransitionAllowed ( false );
currentlyUsingItem = true;

return true;
}
inv.UnmountItem( selectedItemId, true );
}
}

protected saved var currentlyUsingItem : bool;

public function ProcessUseSelectedItem( itemEntity : W3UsableItem, optional shouldCallOnUsed : bool )
{
currentlyUsedItemL = itemEntity;
DrainStamina(ESAT_UsableItem);

if ( shouldCallOnUsed )
{
currentlyUsedItemL.OnUsed( thePlayer );
}
}

function GetUsableItemTypeById ( itemId : SItemUniqueId ) : EUsableItemType
{
var itemName : name;

itemName = inv.GetItemName ( itemId );

return theGame.GetDefinitionsManager().GetUsableItemType ( itemName );

}

// Starts the 'WaitForItemSpawnAndProccesTask' task
public function StartWaitForItemSpawnAndProccesTask()
{
AddTimer( 'WaitForItemSpawnAndProccesTask', 0.001f, true,,,,true );
}

// Kills the 'WaitForItemSpawnAndProccesTask' task
public function KillWaitForItemSpawnAndProccesTask()
{
RemoveTimer ( 'WaitForItemSpawnAndProccesTask' );
}

// Informs the 'WaitForItemSpawnAndProccesTask' task, that selected item should be used ASAP.
// Flag will be reset by the task itself
public function AllowUseSelectedItem()
{
m_useSelectedItemIfSpawned = true;
}

// Task waits for inventory to created selected item. Item will be used ASAP as the task is allowed to do so.
// Right after that - it kills itself.
timer function WaitForItemSpawnAndProccesTask( timeDelta : float , id : int )
{
var itemEntity : W3UsableItem;
var canTaskBeKilled : bool;
canTaskBeKilled = false;

if ( IsCastingSign() )
{
return;
}

// selectad item is wrong!
if ( selectedItemId == GetInvalidUniqueId() )
{
canTaskBeKilled = true;
}

itemEntity = (W3UsableItem)inv.GetItemEntityUnsafe( selectedItemId );
if ( itemEntity && m_useSelectedItemIfSpawned )
{
// we have selected item and we are allowed to use it, so to it and kill itself.
canTaskBeKilled = true;
m_useSelectedItemIfSpawned = false; // reset flag
ProcessUseSelectedItem( itemEntity, true );
}

if ( canTaskBeKilled )
{
KillWaitForItemSpawnAndProccesTask();
}
}

event OnBombProjectileReleased()
{
ResetRawPlayerHeading();
UnblockAction(EIAB_ThrowBomb, 'BombThrow');
UnblockAction(EIAB_Crossbow, 'BombThrow');

if(GetCurrentStateName() == 'AimThrow')
PopState();

FactsAdd("ach_bomb", 1, 4 );
theGame.GetGamerProfile().CheckLearningTheRopes();
}

public function SetIsThrowingItemWithAim(b : bool)
{
isThrowingItemWithAim = b;
}

public function SetIsThrowingItem( flag : bool ) {isThrowingItem = flag;}
public function IsThrowingItem() : bool {return isThrowingItem;}
public function IsThrowingItemWithAim() : bool {return isThrowingItemWithAim;}
public function SetThrowHold(b : bool) {isThrowHoldPressed = b;}
public function IsThrowHold() : bool {return isThrowHoldPressed;}
public function SetIsAimingCrossbow( flag : bool ) {isAimingCrossbow = flag;}
public function GetIsAimingCrossbow() : bool {return isAimingCrossbow;}

event OnThrowAnimLeave()
{
var throwStage : EThrowStage;
var thrownEntity : CThrowable;

thrownEntity = (CThrowable)EntityHandleGet( thrownEntityHandle );

if(thrownEntity && !thrownEntity.WasThrown())
{
throwStage = (int)GetBehaviorVariable( 'throwStage', (int)TS_Stop);
if(inv.IsItemBomb(selectedItemId))
{
BombThrowCleanUp();
}
else
{
ThrowingAbort();
}
}

thrownEntity = NULL;
SetIsThrowingItem( false );
SetIsThrowingItemWithAim( false );

this.EnableRadialSlotsWithSource( true, this.radialSlots, 'throwBomb' );
UnblockAction(EIAB_ThrowBomb, 'BombThrow');
UnblockAction(EIAB_Crossbow, 'BombThrow');
}

//Called when bomb throwing has started - it is ensured that we CAN throw it. At this point we don't know yet if it's a quick throw or aimed throw
protected function BombThrowStart()
{
var slideTargetActor : CActor;

BlockAction( EIAB_ThrowBomb, 'BombThrow' );
BlockAction(EIAB_Crossbow, 'BombThrow');

SetBehaviorVariable( 'throwStage', (int)TS_Start );
SetBehaviorVariable( 'combatActionType', (int)CAT_ItemThrow );

if ( slideTarget )
{
AddCustomOrientationTarget( OT_Actor, 'BombThrow' );

slideTargetActor = (CActor)( slideTarget );

//AK BOMB: moved rotation from anim event to scripts to prevent rotation to friendly and neutral npcs.
// removed the check after commenting out ProcessCanAttackWhenNotInCombatBomb
//if( !slideTargetActor || ( slideTargetActor && GetAttitudeBetween(this, slideTarget) == AIA_Hostile ) )
// SetCustomRotation( 'Throw', VecHeading( slideTarget.GetWorldPosition() - GetWorldPosition() ), 0.0f, 0.3f, false );
}
else
{
if ( lastAxisInputIsMovement )
AddCustomOrientationTarget( OT_Actor, 'BombThrow' );
else
AddCustomOrientationTarget( OT_Camera, 'BombThrow' );
}

UpdateLookAtTarget();
SetCustomRotation( 'Throw', VecHeading( this.GetLookAtPosition() - GetWorldPosition() ), 0.0f, 0.3f, false );

SetBehaviorVariable( 'itemType', (int)IT_Petard );

ProcessCanAttackWhenNotInCombatBomb();

if ( RaiseForceEvent('CombatAction') )
OnCombatActionStart();

//FIXME might be aborted afterwards and no bomb would be thrown actually
theTelemetry.LogWithLabel(TE_FIGHT_HERO_THROWS_BOMB, inv.GetItemName( selectedItemId ));
}

//from animation
event OnThrowAnimStart()
{
var itemId : SItemUniqueId;
var thrownEntity : CThrowable;
//Disable slots on radial menu
this.radialSlots.Clear();
GetWitcherPlayer().GetItemEquippedOnSlot(EES_Petard1, itemId );

if( GetSelectedItemId() == itemId )
{
this.radialSlots.PushBack( 'Slot2' );
}
else
{
this.radialSlots.PushBack( 'Slot1' );
}
this.radialSlots.PushBack( 'Slot3' );
this.radialSlots.PushBack( 'Slot4' );
this.radialSlots.PushBack( 'Slot5' );
this.EnableRadialSlotsWithSource( false, this.radialSlots, 'throwBomb' );

thrownEntity = (CThrowable)inv.GetDeploymentItemEntity( selectedItemId,,,true );
thrownEntity.Initialize( this, selectedItemId );
EntityHandleSet( thrownEntityHandle, thrownEntity );
SetIsThrowingItem( true );
}

public function BombThrowAbort()
{
BombThrowCleanUp();
UnblockAction( EIAB_ThrowBomb, 'BombThrow' );
UnblockAction(EIAB_Crossbow, 'BombThrow');
}

private function BombThrowCleanUp()
{
var throwStage : EThrowStage;
var thrownEntity : CThrowable;
var vehicle : CVehicleComponent;

thrownEntity = (CThrowable)EntityHandleGet( thrownEntityHandle );

this.EnableRadialSlotsWithSource( true, this.radialSlots, 'throwBomb' );
throwStage = (int)GetBehaviorVariable( 'throwStage', (int)TS_Stop);

SetBehaviorVariable( 'throwStage', (int)TS_Stop );

if( GetCurrentStateName() == 'AimThrow')
{
PopState();
thrownEntity.StopAiming( true );
}
else if ( this.IsUsingHorse() )
{
vehicle = (CVehicleComponent)(GetUsedVehicle().GetComponentByClassName('CVehicleComponent'));
vehicle.GetUserCombatManager().OnForceItemActionAbort();
}

//if bomb was not detached yet (is not flying)
if(thrownEntity && !thrownEntity.WasThrown())
{
thrownEntity.BreakAttachment();
thrownEntity.Destroy();
}

thrownEntity = NULL;
SetIsThrowingItem( false );
SetIsThrowingItemWithAim( false );
RemoveCustomOrientationTarget( 'BombThrow' );
}

public function ProcessCanAttackWhenNotInCombatBomb()
{
/* //AK BOMB: keeping it just in case we need to bring it back
var impactRange : float;
var entities : array;
var ent : CEntity;
var actor : CActor;
var petard : W3Petard;
var vehicle : CEntity;
var slotMatrix : Matrix;
var isShootingFriendly : bool;


if ( thrownEntity )
{
petard = (W3Petard)( thrownEntity );

if ( !IsThreatened() )
{
if ( this.playerAiming.GetCurrentStateName() == 'Aiming' )
ent = playerAiming.GetSweptFriendly();
else
actor = (CActor)GetDisplayTarget();

if( ent || ( actor && actor.IsHuman() && !IsThreat( actor ) ) )
SetIsShootingFriendly( true );
else
SetIsShootingFriendly( false );
}
else
SetIsShootingFriendly( false );
}
else
SetIsShootingFriendly( false );
*/

SetIsShootingFriendly( false );
SetBehaviorVariable( 'isShootingFriendly', (float)( GetIsShootingFriendly() ) );
}

public function SetIsShootingFriendly( flag : bool )
{
isShootingFriendly = flag;
}

public function GetIsShootingFriendly() : bool
{
return isShootingFriendly;
}

//only for usable items
protected function UsableItemStart()
{
var thrownEntity : CThrowable;

//this seems like bullshit but it's because usable items use the same code as throwing bombs and shooting crossbow
thrownEntity = (CThrowable)inv.GetDeploymentItemEntity( selectedItemId,,,true );
thrownEntity.Initialize( this, selectedItemId );
EntityHandleSet( thrownEntityHandle, thrownEntity );
SetBehaviorVariable( 'throwStage', (int)TS_Start );
SetIsThrowingItem( true );
SetBehaviorVariable( 'combatActionType', (int)CAT_ItemThrow );

if ( slideTarget )
{
AddCustomOrientationTarget( OT_Actor, 'UsableItems' );
}
else
{
if ( lastAxisInputIsMovement )
AddCustomOrientationTarget( OT_Actor, 'UsableItems' );
else
AddCustomOrientationTarget( OT_Camera, 'UsableItems' );
}

SetBehaviorVariable( 'itemType', (int)(-1) );

if ( RaiseForceEvent('CombatAction') )
OnCombatActionStart();
}

protected function BombThrowRelease()
{
OnDelayOrientationChangeOff();

if ( GetIsShootingFriendly() )
BombThrowAbort();
else
{
SetBehaviorVariable( 'throwStage', (int)TS_End );

if ( playerAiming.GetCurrentStateName() == 'Aiming' )
SetCustomRotation( 'Throw', VecHeading( this.GetLookAtPosition() - GetWorldPosition() ), 0.0f, 0.2f, false );
}
}

protected function UsableItemRelease()
{
OnDelayOrientationChangeOff();
SetBehaviorVariable( 'throwStage', (int)TS_End );
RemoveCustomOrientationTarget( 'UsableItems' );
}

// Called when usable item use or crossbow shot was aborted (bombs use different function)
public function ThrowingAbort()
{
var thrownEntity : CThrowable;

thrownEntity = (CThrowable)EntityHandleGet( thrownEntityHandle );

SetBehaviorVariable( 'throwStage', (int)TS_Stop );
RaiseEvent( 'actionStop' );

if( GetCurrentStateName() == 'AimThrow')
{
PopState();
thrownEntity.StopAiming( true );
}

//if bomb was not detached yet (is not flying)
if(thrownEntity && !thrownEntity.WasThrown())
{
thrownEntity.BreakAttachment();
thrownEntity.Destroy();
}
this.EnableRadialSlotsWithSource( true, this.radialSlots, 'throwBomb' );
}

public function CanSetupCombatAction_Throw() : bool
{
//if has item selected
if(!inv.IsIdValid( selectedItemId ))
return false;

//if not a throwable item
if(!inv.IsItemSingletonItem(selectedItemId))
return false;

//if input is not blocked
if(!GetBIsInputAllowed())
return false;

//if has ammo
if(inv.GetItemQuantity(GetSelectedItemId()) <= 0 && !inv.ItemHasTag(selectedItemId, theGame.params.TAG_INFINITE_AMMO))
return false;

//if action is not blocked or (HACK) we're in swimming
if(!inputHandler.IsActionAllowed(EIAB_ThrowBomb) && GetCurrentStateName() != 'Swimming')
return false;

return true;
}

public function GetThrownEntity() : CThrowable
{
return (CThrowable)EntityHandleGet( thrownEntityHandle );
}

// Crossbow events and functions
event OnWeaponWait() { rangedWeapon.OnWeaponWait(); }
event OnWeaponDrawStart() { rangedWeapon.OnWeaponDrawStart(); }
event OnWeaponReloadStart() { rangedWeapon.OnWeaponReloadStart(); }
event OnWeaponReloadEnd() { rangedWeapon.OnWeaponReloadEnd(); }
event OnWeaponAimStart() { rangedWeapon.OnWeaponAimStart(); }
event OnWeaponShootStart() { rangedWeapon.OnWeaponShootStart(); }
event OnWeaponShootEnd() { rangedWeapon.OnWeaponShootEnd(); }
event OnWeaponAimEnd() { rangedWeapon.OnWeaponAimEnd(); }
event OnWeaponHolsterStart() { rangedWeapon.OnWeaponHolsterStart(); }
event OnWeaponHolsterEnd() { rangedWeapon.OnWeaponHolsterEnd(); }
event OnWeaponToNormalTransStart() { rangedWeapon.OnWeaponToNormalTransStart(); }
event OnWeaponToNormalTransEnd() { rangedWeapon.OnWeaponToNormalTransEnd(); }

event OnEnableAimingMode( enable : bool )
{
if( !crossbowDontPopStateHack )
{
if ( enable )
PushState( 'AimThrow' );
else if ( GetCurrentStateName() == 'AimThrow' )
PopState();
}
}

event OnRangedForceHolster( optional forceUpperBodyAnim, instant, dropItem : bool )
{
if(rangedWeapon)
rangedWeapon.OnForceHolster( forceUpperBodyAnim, instant, dropItem );
}


public function IsCrossbowHeld() : bool
{
if (rangedWeapon)
return rangedWeapon.GetCurrentStateName() != 'State_WeaponWait';
return false;
}

// Tickets
event OnBlockAllCombatTickets( release : bool )
{
if (!release )
((CR4PlayerStateCombat)GetState('Combat')).OnBlockAllCombatTickets(false);
}
event OnForceTicketUpdate() {}

////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @ATTACKS /////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

/*script*/ event OnPocessActionPost(action : W3DamageAction)
{
var npc : CNewNPC;
var attackAction : W3Action_Attack;
var lifeLeech : float;

super.OnPocessActionPost(action);

attackAction = (W3Action_Attack)action;

if(attackAction)
{
npc = (CNewNPC)action.victim;

if(npc && npc.IsHuman() )
{
PlayBattleCry('BattleCryHumansHit', 0.05f );
}
else
{
PlayBattleCry('BattleCryMonstersHit', 0.05f );
}

if(attackAction.IsActionMelee())
{
//uninterrupted hits counting
IncreaseUninterruptedHitsCount();

//camera shake
// modXTFinishers BEGIN
/*
if( IsLightAttack( attackAction.GetAttackName() ) )
{
GCameraShake(0.1, false, GetWorldPosition(), 10);
}
*/
// modXTFinishers END

//Caretaker Shovel life steal
if(npc && inv.GetItemName(attackAction.GetWeaponId()) == 'PC Caretaker Shovel')
{
//inv.PlayItemEffect( items[i], 'stab_attack' );
lifeLeech = CalculateAttributeValue(inv.GetItemAttributeValue(attackAction.GetWeaponId() ,'lifesteal'));
if (npc.UsesVitality())
lifeLeech *= action.processedDmg.vitalityDamage;
else if (UsesEssence())
lifeLeech *= action.processedDmg.essenceDamage;
else
lifeLeech = 0;

if ( lifeLeech > 0 )
{
inv.PlayItemEffect( attackAction.GetWeaponId(), 'stab_attack' );
PlayEffect('drain_energy_caretaker_shovel');
GainStat(BCS_Vitality, lifeLeech);
}
}
}
}
}

public function SetHitReactTransScale(f : float) {hitReactTransScale = f;}
public function GetHitReactTransScale() : float
{
if ( ( (CNewNPC)slideTarget ).GetIsTranslationScaled() )
return hitReactTransScale;
else
return 1.f;
}

////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @HORSE /////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

public function GetHorseWithInventory() : CNewNPC
{
return (CNewNPC)EntityHandleGet( horseWithInventory );
}
public function GetHorseCurrentlyMounted() : CNewNPC
{
return currentlyMountedHorse;
}
// Do not use outside of vehicle component
public function _SetHorseCurrentlyMounted( horse : CNewNPC )
{
currentlyMountedHorse = horse;
}

public function WasHorseRecentlySummoned() : bool
{
if ( horseSummonTimeStamp + 5.f > theGame.GetEngineTimeAsSeconds() )
return true;

return false;
}

private const var MOUNT_DISTANCE_CBT : float;
default MOUNT_DISTANCE_CBT = 3.0;

private const var MOUNT_ANGLE_CBT : float;
default MOUNT_ANGLE_CBT = 35.0;

private const var MOUNT_ANGLE_EXP : float;
default MOUNT_ANGLE_EXP = 45.0;

public function IsMountingHorseAllowed( optional alwaysAllowedInExploration : bool ) : bool
{
var angle : float;
var distance : float;

if( IsInsideHorseInteraction() )
{
angle = AngleDistance( thePlayer.rawPlayerHeading, VecHeading( thePlayer.horseInteractionSource.GetWorldPosition() - thePlayer.GetWorldPosition() ) );

if( thePlayer.IsInCombat() )
{
if( AbsF( angle ) < MOUNT_ANGLE_CBT )
{
distance = VecDistance( thePlayer.GetWorldPosition(), thePlayer.horseInteractionSource.GetWorldPosition() );

if( distance < MOUNT_DISTANCE_CBT )
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}

}
else
{
if( alwaysAllowedInExploration )
{
return true;
}
else
{
if( AbsF( angle ) < MOUNT_ANGLE_EXP )
{
return true;
}
else
{
return false;
}
}
}
}
else
{
return false;
}
}

public function FollowActor( actor : CActor )
{
var l_aiTreeDecorator : CAIPlayerActionDecorator;
var l_aiTree_onFoot : CAIFollowSideBySideAction;
var l_aiTree_onHorse : CAIRiderFollowSideBySideAction;
var l_success : bool = false;

actor.AddTag( 'playerFollowing' );

if( thePlayer.IsUsingHorse() )
{
l_aiTree_onHorse = new CAIRiderFollowSideBySideAction in this;
l_aiTree_onHorse.OnCreated();

l_aiTree_onHorse.params.targetTag = 'playerFollowing';
}
else
{
l_aiTree_onFoot = new CAIFollowSideBySideAction in this;
l_aiTree_onFoot.OnCreated();

l_aiTree_onFoot.params.targetTag = 'playerFollowing';
}

l_aiTreeDecorator = new CAIPlayerActionDecorator in this;
l_aiTreeDecorator.OnCreated();
l_aiTreeDecorator.interruptOnInput = false;

if( thePlayer.IsUsingHorse() )
l_aiTreeDecorator.scriptedAction = l_aiTree_onHorse;
else
l_aiTreeDecorator.scriptedAction = l_aiTree_onFoot;

if( l_aiTreeDecorator )
l_success = ForceAIBehavior( l_aiTreeDecorator, BTAP_Emergency );
else if( thePlayer.IsUsingHorse() )
l_success = ForceAIBehavior( l_aiTree_onHorse, BTAP_Emergency );
else
l_success = ForceAIBehavior( l_aiTree_onFoot, BTAP_Emergency );

if ( l_success )
{
GetMovingAgentComponent().SetGameplayRelativeMoveSpeed( 0.0f );
}
}

public function SetCanFollowNpc( val : bool, actor : CActor ) { canFollowNpc = val; actorToFollow = actor; }
public function CanFollowNpc() : bool { return canFollowNpc; }
public function GetActorToFollow() : CActor { return actorToFollow; }

/*public function SetIsFollowing( val : bool )
{
isFollowing = val;

if( val )
followingStartTime = theGame.GetEngineTimeAsSeconds();
else
followingStartTime = 0.0;
}
public function GetFollowingStartTime() : float { return followingStartTime; }
public function IsFollowing() : bool { return isFollowing; }

timer function ResetIsFollowing( td : float, id : int )
{
isFollowing = false;
}*/

////////////////////////////////////////////////////////////////////////////////////////////
///////////////////// @SWIMMING ////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

public function SetIsSwimming ( toggle : bool )
{
if( isSwimming != toggle )
{
thePlayer.substateManager.SetBehaviorParamBool( 'isSwimmingForOverlay', toggle );
isSwimming = toggle;
}
}
//public function IsSwimming () : bool { return isSwimming; }

////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @DURABILITY //////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

//returns true if repaired





public function RepairItemUsingConsumable(item, consumable : SItemUniqueId) : bool
{
inv.SetItemDurabilityScript(item, inv.GetItemMaxDurability(item));
var curr, max, repairValue, itemValue, repairBonus, newDurability : float;


//basic check
if(!inv.IsIdValid(item) || !inv.IsIdValid(consumable) || !inv.HasItemDurability(item))
return false;

curr = inv.GetItemDurability(item);
max = inv.GetItemMaxDurability(item);

//check durability level
if(curr > max)
return false;

//check consumable type
if( (inv.IsItemAnyArmor(item) && inv.ItemHasTag(consumable, theGame.params.TAG_REPAIR_CONSUMABLE_ARMOR)) ||
(inv.IsItemSilverSwordUsableByPlayer(item) && inv.ItemHasTag(consumable, theGame.params.TAG_REPAIR_CONSUMABLE_SILVER)) ||
(inv.IsItemSteelSwordUsableByPlayer(item) && inv.ItemHasTag(consumable, theGame.params.TAG_REPAIR_CONSUMABLE_STEEL)) )
{
//item stats
itemValue = CalculateAttributeValue(inv.GetItemAttributeValue(consumable, 'durabilityRepairValue'));
if(itemValue <= 0)
{
LogAssert(false, "CR4Player.RepairItemUsingConsumable: consumable <<" + inv.GetItemName(consumable) + ">> has <=0 durabilityRepairValue!!!");
return false;
}
repairBonus = CalculateAttributeValue(inv.GetItemAttributeValue(consumable, 'durabilityBonusValue'));

//calculate
repairValue = max * itemValue /100;

/* disabled repairing over 100%
if(HasBookPerk(S_Book_28))
max = max * (1 + (repairBonus + perkValue) /100);
*/

newDurability = MinF(max, curr + repairValue);

inv.SetItemDurabilityScript(item, newDurability);

//consume
return true;
}
{
inv.RemoveItem(consumable);

return true;
}
return false;
}

////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @PushingObject /////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
/*
event OnRigidBodyCollision( component : CComponent, actorIndex : int, shapeIndex : int )
{
pushableComponent = component;
if ( pushableComponent )
this.RaiseEvent('PushObject');

//component.ApplyForceAtPointToPhysicalObject
}

event OnRigidBodyExit( component : CComponent )
{
this.RaiseEvent('PushObjectEnd');
pushableComponent = NULL;
}

event OnPushObjectStart()
{
moveAdj = GetMovingAgentComponent().GetMovementAdjustor();
moveAdj.CancelAll();
pushRotTicket = moveAdj.CreateNewRequest( 'RotateToObject' );
moveAdj.MaxRotationAdjustmentSpeed(pushRotTicket,30);
moveAdj.Continuous(pushRotTicket);
moveAdj.DontEnd(pushRotTicket);
this.AddTimer('PushObjectUpdate',0.01,true, , , true);

}

event OnPushObjectStop()
{
this.RemoveTimer('PushObjectUpdate');
moveAdj.CancelByName('RotateToObject');
moveAdj = NULL;
}

timer function PushObjectUpdate( dt : float , id : int)
{
var impulse : Vector;
moveAdj.RotateTo( pushRotTicket, rawPlayerHeading );
impulse = this.GetHeadingVector()*10.0;
//impulse.Z += 0.5;
//pushableComponent.ApplyLocalImpulseToPhysicalObject(impulse);
}
*/

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @DAY @NIGHT CYCLE CHECK /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

private function CheckDayNightCycle()
{
var time : GameTime;
var isNight : bool;

//if changed
isNight = theGame.envMgr.IsNight();
if(prevDayNightIsNight != isNight)
{
if(isNight)
OnNightStarted();
else
OnDayStarted();

prevDayNightIsNight = isNight;
}

//schedule next call
if(isNight)
time = theGame.envMgr.GetGameTimeTillNextDay();
else
time = theGame.envMgr.GetGameTimeTillNextNight();

AddGameTimeTimer('DayNightCycle', time);
}

timer function DayNightCycle(dt : GameTime, id : int)
{
CheckDayNightCycle();
}

/*script*/ event OnNightStarted()
{
var pam : W3PlayerAbilityManager;

if(CanUseSkill(S_Perk_01))
{
pam = (W3PlayerAbilityManager)abilityManager;
pam.SetPerk01Abilities(false, true);
}
}

/*script*/ event OnDayStarted()
{
var pam : W3PlayerAbilityManager;

if(CanUseSkill(S_Perk_01))
{
pam = (W3PlayerAbilityManager)abilityManager;
pam.SetPerk01Abilities(true, false);
}
}

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @INPUT //////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

public function ForceUnlockAllInputActions(alsoQuestLocks : bool)
{
if ( inputHandler )
inputHandler.ForceUnlockAllInputActions(alsoQuestLocks);
}

public function SetPrevRawLeftJoyRot()
{
prevRawLeftJoyRot = rawLeftJoyRot;
}

public function GetPrevRawLeftJoyRot() : float
{
return prevRawLeftJoyRot;
}

public function GetExplorationInputContext() : name
{
return explorationInputContext;
}

public function GetCombatInputContext() : name
{
return combatInputContext;
}

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @EXPLORATION ////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

public function SetIsOnBoat(b : bool)
{
isOnBoat = b;
}

public function IsOnBoat() : bool
{
return isOnBoat;
}

public function IsInShallowWater() : bool
{
return isInShallowWater;
}

event OnEnterShallowWater()
{
if ( isInShallowWater )
return false;

isInShallowWater = true;
BlockAction( EIAB_Dodge,'ShallowWater', false, false, true );
BlockAction( EIAB_Sprint,'ShallowWater', false, false, true );
BlockAction( EIAB_Crossbow,'ShallowWater', false, false, true );
BlockAction( EIAB_Jump,'ShallowWater', false, false, true );
SetBehaviorVariable( 'shallowWater',1.0);
}
event OnExitShallowWater()
{
if ( !isInShallowWater )
return false;

isInShallowWater = false;
BlockAllActions('ShallowWater',false);
SetBehaviorVariable( 'shallowWater',0.0);
}

public function TestIsInSettlement() : bool
{
return IsInSettlement();
}

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// GLOSSARY ////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

//Processes glossary image filename and exchanges it with override if provided
public function ProcessGlossaryImageOverride( defaultImage : string, uniqueTag : name ) : string
{
var size : int;
var i : int;

size = glossaryImageOverride.Size();

if( size == 0 )
return defaultImage;

for( i = 0; i < size; i += 1 )
{
if( glossaryImageOverride[i].uniqueTag == uniqueTag )
return glossaryImageOverride[i].imageFileName;

}

return defaultImage;
}

//Adds glossary image override filename to array
public function EnableGlossaryImageOverride( uniqueTag : name, imageFileName : string, enable : bool )
{
var imageData : SGlossaryImageOverride;
var size : int;
var i : int;

for( i = 0; i < glossaryImageOverride.Size(); i += 1 )
{
if( glossaryImageOverride[i].uniqueTag == uniqueTag )
{
glossaryImageOverride.Remove(glossaryImageOverride[i]);
}
}

if( enable )
{
if( IsNameValid(uniqueTag) && imageFileName != "" )
{
glossaryImageOverride.PushBack( SGlossaryImageOverride( uniqueTag, imageFileName ) );
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// MONSTER HUNT INVESTIGATION AREAS /////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

public function SetCurrentMonsterHuntInvestigationArea ( area : W3MonsterHuntInvestigationArea )
{
currentMonsterHuntInvestigationArea = area;
}


///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// BARBER SYSTEM CUSTOM HEAD /////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

public function RememberCustomHead( headName : name )
{
rememberedCustomHead = headName;
}

public function GetRememberedCustomHead() : name
{
return rememberedCustomHead;
}

public function ClearRememberedCustomHead()
{
rememberedCustomHead = '';
}

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @TUTORIAL ////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

public function CreateTutorialInput()
{
var prevInputHandler : CPlayerInput;

prevInputHandler = inputHandler;
inputHandler = new W3PlayerTutorialInput in this;
inputHandler.Initialize(false, prevInputHandler);

if(prevInputHandler)
delete prevInputHandler;
}

public function CreateInput()
{
var oldInputHandler : CPlayerInput;

oldInputHandler = inputHandler;
inputHandler = new CPlayerInput in this;
inputHandler.Initialize(false, oldInputHandler);
}

timer function TutorialSilverCombat(dt : float, id : int)
{
var i : int;
var actors : array;

if(IsInCombat())
{
actors = GetNPCsAndPlayersInRange(20, 1000000, ,FLAG_ExcludePlayer + FLAG_OnlyAliveActors);
for(i=0; i {
if(actors[i] && IsRequiredAttitudeBetween(this, actors[i], true) && actors[i].UsesEssence())
{
FactsAdd("TutorialShowSilver");

RemoveTimer('TutorialSilverCombat');
break;
}
}
}
}

private saved var m_bossTag : name;

public function GetBossTag() : name
{
return m_bossTag;
}

public function SetBossTag( bossTag : name )
{
m_bossTag = bossTag;
}

private saved var m_usingCoatOfArms : bool; default m_usingCoatOfArms = false;

public function IsUsingCoatOfArms() : bool
{
return m_usingCoatOfArms;
}

public function SetUsingCoatOfArms( using : bool)
{
m_usingCoatOfArms = using;
}

private saved var m_initialTimeOut : float;
private saved var m_currentTimeOut : float;

public function GetInitialTimeOut() : float
{
return m_initialTimeOut;
}

public function SetInitialTimeOut( timeOut : float )
{
m_initialTimeOut = timeOut;
}

public function GetCurrentTimeOut() : float
{
return m_currentTimeOut;
}

public function SetCurrentTimeOut( timeOut : float )
{
m_currentTimeOut = timeOut;
}


///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @FINISHERS ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

timer function DelayedFinisherInputTimer(dt : float, id : int)
{
//theGame.SetTimeScale( 0.1, theGame.GetTimescaleSource(ETS_FinisherInput), theGame.GetTimescalePriority(ETS_FinisherInput) );
//GetFinisherVictim().EnableFinishComponent( true );
}

timer function RemoveFinisherCameraAnimationCheck(dt : float, id : int)
{
if ( !isInFinisher && !bLAxisReleased )
{
theGame.GetSyncAnimManager().OnRemoveFinisherCameraAnimation();
RemoveTimer( 'RemoveFinisherCameraAnimationCheck' );
}
}

///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// @DEBUG @TIMERS ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

timer function GameplayFactRemove(dt : float, timerId : int)
{
theGame.GameplayFactRemoveFromTimer(timerId);
}

//gives NORMAL starting inventory
timer function GiveStartingItems(dt : float, timerId : int)
{
var template : CEntityTemplate;
var invEntity : CInventoryComponent;
var entity : CEntity;
var items : array;
var id : SItemUniqueId;
var i : int;

//wait for inventory to init
if(inv)
{
inv.GetAllItems(items);
if(items.Size() <= 0)
{
return;
}
}
else
{
return;
}

//add items
template = (CEntityTemplate)LoadResource("geralt_inventory_release");
entity = theGame.CreateEntity(template, Vector(0,0,0));
invEntity = (CInventoryComponent)entity.GetComponentByClassName('CInventoryComponent');

invEntity.GetAllItems(items);
for(i=0; i {
id = invEntity.GiveItemTo(inv, items[i], 0, false, true);
if ( inv.ItemHasTag(id,'Scabbard') )
{
inv.MountItem(id);
}
else if(!inv.IsItemFists(id) && inv.GetItemName(id) != 'Cat 1') //hack for cat potion - don't equip!
{
EquipItem(id);
}
else if(inv.IsItemSingletonItem(id))
{
inv.SingletonItemSetAmmo(id, inv.SingletonItemGetMaxAmmo(id));
}
}

entity.Destroy();

//remove timer
RemoveTimer('GiveStartingItems');
}

//Adds items used for testing. Won't be called in final release. Items are added from geralt_inventory entity.
//Works as a timer since we need to wait for inventory to init and there is no such event.
timer function Debug_GiveTestingItems(dt : float, optional id : int)
{
var template : CEntityTemplate;
var invTesting : CInventoryComponent;
var entity : CEntity;
var items : array;
var i : int;
var slot : EEquipmentSlots;

//wait for inventory to init
if(inv)
{
inv.GetAllItems(items);
if(items.Size() <= 0)
{
return;
}
}
else
{
return;
}

template = (CEntityTemplate)LoadResource("geralt_inventory_internal");
entity = theGame.CreateEntity(template, Vector(0,0,0));
invTesting = (CInventoryComponent)entity.GetComponentByClassName('CInventoryComponent');
invTesting.GiveAllItemsTo(inv, true);
entity.Destroy();

//once called remove the timer
RemoveTimer('Debug_GiveTestingItems');

//equip crossbow, bombs and bolts, select bolts
inv.GetAllItems(items);

for(i=0; i {
if( inv.IsItemCrossbow(items[i]) || inv.IsItemBomb(items[i]) )
{
slot = inv.GetSlotForItemId(items[i]);
EquipItem(items[i], slot);

if( (W3PlayerWitcher)this && inv.IsItemCrossbow(items[i]) )
GetWitcherPlayer().SelectQuickslotItem(slot);
}
else if(inv.IsItemBolt(items[i]))
{
slot = inv.GetSlotForItemId(items[i]);
EquipItem(items[i], slot);
}

if(inv.IsItemSingletonItem(items[i]))
{
inv.SingletonItemSetAmmo(items[i], inv.SingletonItemGetMaxAmmo(items[i]));
}
}
}

//called in tutorial in not final version to remove testing items
timer function Debug_RemoveTestingItems(dt : float, id : int)
{
var template : CEntityTemplate;
var entity : CEntity;
var invTesting : CInventoryComponent;
var ids : array;
var i : int;

template = (CEntityTemplate)LoadResource("geralt_inventory_internal");
entity = theGame.CreateEntity(template, Vector(0,0,0));
invTesting = (CInventoryComponent)entity.GetComponentByClassName('CInventoryComponent');
invTesting.GetAllItems(ids);

for(i=0; i inv.RemoveItemByName(invTesting.GetItemName(ids[i]), invTesting.GetItemQuantity(ids[i]));

entity.Destroy();
RemoveTimer('Debug_RemoveTestingItems');
}

timer function Debug_DelayedConsoleCommand(dt : float, id : int)
{
//inv.AddAnItem('Recipe for Mutagen 23');
inv.AddAnItem('Boots 2 schematic');
}

function DBG_SkillSlots()
{
((W3PlayerAbilityManager)abilityManager).DBG_SkillSlots();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// @BACKLIGHT COLOR ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

public final function SetPadBacklightColor(r, g, b : int)
{
var padBacklightColor : Vector;

padBacklightColor.X = r / 255;
padBacklightColor.Y = g / 255;
padBacklightColor.Z = b / 255;

SetBacklightColor(padBacklightColor);
}

public final function SetPadBacklightColorFromSign(signType : ESignType)
{
LogPS4Light("SetPadBacklightColorFromSign... " + signType);

switch(signType)
{
case ST_Yrden: SetPadBacklightColor( 200 , 81 , 255 ); break; // Violet
case ST_Quen: SetPadBacklightColor( 255 , 205 , 68 ); break; // Yellow
case ST_Igni: SetPadBacklightColor( 255 , 79 , 10 ); break; // Orange
case ST_Axii: SetPadBacklightColor( 255 , 255 , 255 ); break; // White
case ST_Aard: SetPadBacklightColor( 158 , 214 , 255 ); break; // Blue
}
}

timer function ResetPadBacklightColorTimer(dt : float, id : int)
{
ResetPadBacklightColor();
}

public final function ResetPadBacklightColor(optional skipHeldWeapon : bool)
{
var weapons : array;
var sword : CWitcherSword;
var healthPercentage : float;
var tmpBacklight : Vector;

if(!skipHeldWeapon)
{
weapons = inv.GetHeldWeapons();

//if holding a sword the default backlight color matches the one set in sword entity
if(weapons.Size() > 0)
{
sword = (CWitcherSword)inv.GetItemEntityUnsafe(weapons[0]);
if(sword)
{
tmpBacklight.X = sword.padBacklightColor.X / 255.0f;
tmpBacklight.Y = sword.padBacklightColor.Y / 255.0f;
tmpBacklight.Z = sword.padBacklightColor.Z / 255.0f;
tmpBacklight.W = 1.0f;
SetBacklightColor( tmpBacklight );
LogPS4Light("Setting light from sword template: " + NoTrailZeros(sword.padBacklightColor.X) + ", " + NoTrailZeros(sword.padBacklightColor.Y) + ", " + NoTrailZeros(sword.padBacklightColor.Z) );
return;
}
}
}

healthPercentage = GetStatPercents( BCS_Vitality );
SetBacklightFromHealth( healthPercentage );
LogPS4Light("Setting light from health, " + NoTrailZeros(RoundMath(healthPercentage*100)) + "%");
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

event OnOpenningDoor()
{
if( !thePlayer.IsUsingHorse() )
RaiseEvent('OpenDoor');
}

public var loopingCameraShakeAnimName : name;
timer function RemoveQuestCameraShakeTimer( dt : float , id : int)
{
RemoveQuestCameraShake( loopingCameraShakeAnimName );
}

public function RemoveQuestCameraShake( animName : name )
{
var camera : CCustomCamera = theGame.GetGameCamera();
var animation : SCameraAnimationDefinition;

camera.StopAnimation( animName );
}

public function GetCameraPadding() : float
{
if( theGame.IsFocusModeActive() )
{
return 0.25; // Tweaked for [108933] Geralt is being clipped when using focus mode while running towards camera.
}
else
{
return 0.02f; // Tweaked for [114907] Player dissolving while aiming crossbow.
}
}

public function IsPerformingPhaseChangeAnimation() : bool { return isPerformingPhaseChangeAnimation; }
public function SetIsPerformingPhaseChangeAnimation( val : bool ) { isPerformingPhaseChangeAnimation = val; }

private function DealCounterDamageToOlgierd()
{
var damage : W3DamageAction;

damage = new W3DamageAction in this;

damage.Initialize( thePlayer.GetTarget(), thePlayer.GetTarget(), NULL, this, EHRT_None, CPS_Undefined, false, false, false, true );
damage.AddDamage( theGame.params.DAMAGE_NAME_DIRECT, thePlayer.GetTarget().GetStatMax( BCS_Vitality ) * 3 / 100 );
theGame.damageMgr.ProcessAction( damage );

delete damage;
}

timer function PlayDelayedCounterDamageEffect( dt : float, id : int )
{
thePlayer.GetTarget().PlayEffect( 'olgierd_energy_blast' );
}

// TEST
public function SetTestAdjustRequestedMovementDirection( val : bool )
{
testAdjustRequestedMovementDirection = val;
}

event OnVisualDebug( frame : CScriptedRenderFrame, flag : EShowFlags )
{
var boneFollow : int;
var bonePosition : Vector;
var yrdenEntity : W3YrdenEntity;

substateManager.OnVisualDebug( frame, flag );

boneFollow = thePlayer.GetBoneIndex( 'Reference' );
bonePosition = MatrixGetTranslation( thePlayer.GetBoneWorldMatrixByIndex( boneFollow ) );
frame.DrawText( "R", bonePosition, Color( 50, 200, 70 ) );
//frame.DrawText( "R", bonePositionCam, Color( 200, 50, 70 ) );

boneFollow = thePlayer.GetBoneIndex( 'Trajectory' );
bonePosition = MatrixGetTranslation( thePlayer.GetBoneWorldMatrixByIndex( boneFollow ) );
frame.DrawSphere( bonePosition, 0.1f, Color( 200, 50, 70 ) );
frame.DrawText( "T", bonePosition, Color( 200, 50, 70 ) );

//frame.DrawSphere( lastSafePosition, 1.0f, Color( 50, 200, 70 ) );
//frame.DrawText( "SavePos", lastSafePosition, Color( 50, 200, 70 ) );

yrdenEntity = (W3YrdenEntity)GetWitcherPlayer().GetSignEntity(ST_Yrden);
yrdenEntity.OnVisualDebug(frame, flag, false);

return true;
}

timer function PotDrinkTimer(dt : float, id : int)
{
inputHandler.PotDrinkTimer(false);
}

public function SetIsHorseRacing( val : bool )
{
isHorseRacing = val;
}

public function GetIsHorseRacing() : bool
{
return isHorseRacing;
}

public function SetHorseCombatSlowMo( val : bool )
{
horseCombatSlowMo = val;
}

public function GetHorseCombatSlowMo() : bool
{
return horseCombatSlowMo;
}

public function SetItemsPerLevelGiven( id : int )
{
itemsPerLevelGiven[id] = true;
}

private function AddItemPerLevelList()
{
var i : int;

itemsPerLevel.Clear();
itemsPerLevel.PushBack('O');
itemsPerLevel.PushBack('No Mans Land sword 2');
itemsPerLevel.PushBack('No Mans Land sword 3');
itemsPerLevel.PushBack('Silver sword 2');
itemsPerLevel.PushBack('Boots 01');
itemsPerLevel.PushBack('Novigraadan sword 2');
itemsPerLevel.PushBack('Light armor 01');
itemsPerLevel.PushBack('Heavy boots 01');
itemsPerLevel.PushBack('Nilfgaardian sword 3');
itemsPerLevel.PushBack('Silver sword 3');
itemsPerLevel.PushBack('Heavy gloves 01');
itemsPerLevel.PushBack('Skellige sword 2');
itemsPerLevel.PushBack('Heavy pants 01');
itemsPerLevel.PushBack('Silver sword 4');
itemsPerLevel.PushBack('No Mans Land sword 4');
itemsPerLevel.PushBack('Heavy armor 01');
itemsPerLevel.PushBack('Heavy boots 02');
itemsPerLevel.PushBack('Skellige sword 3');
itemsPerLevel.PushBack('Silver sword 5');
itemsPerLevel.PushBack('Heavy pants 02');
itemsPerLevel.PushBack('Heavy gloves 02');
itemsPerLevel.PushBack('Heavy gloves 02');
itemsPerLevel.PushBack('Heavy armor 02');
itemsPerLevel.PushBack('Scoiatael sword 1');

if ( itemsPerLevelGiven.Size() < 49 )
{
itemsPerLevelGiven.Clear();
for (i = 0; i < itemsPerLevel.Size(); i += 1) { itemsPerLevelGiven.PushBack( false ); }
}
}

// TEMP
public function DealDamageToBoat( dmg : float, index : int, optional globalHitPos : Vector )
{
var boat : CBoatDestructionComponent;

if(usedVehicle)
{
boat = (CBoatDestructionComponent) usedVehicle.GetComponentByClassName( 'CBoatDestructionComponent' );
if( boat )
{
boat.DealDamage( dmg, index, globalHitPos );
}
}
}

////////////////////////////////////////////////////////////////////////////////
//
// PLAYABLE AREA
//
public function OnStartTeleportingPlayerToPlayableArea()
{
var FADEOUT_INTERVAL : float = 0.5;

// if we jumped on horse right before being teleported, we need to disable falling damage because height difference may kill us
if ( thePlayer.IsUsingHorse() )
{
if ( thePlayer.GetUsedHorseComponent().OnCheckHorseJump() )
{
thePlayer.GetUsedHorseComponent().SetCanTakeDamageFromFalling( false );
}
}

if ( thePlayer.IsActionAllowed( EIAB_FastTravel ) )
{
OnOpenMapToLetPlayerGoBackToPlayableArea();
}
else
{
theGame.FadeOutAsync( FADEOUT_INTERVAL );
thePlayer.AddTimer( 'BorderTeleportFadeOutTimer', FADEOUT_INTERVAL, false );
}
}

timer function BorderTeleportFadeOutTimer( dt : float, id : int )
{
OnTeleportPlayerToPlayableArea( false );
}

public function OnOpenMapToLetPlayerGoBackToPlayableArea()
{
var initData : W3MapInitData;

initData = new W3MapInitData in this;
initData.SetTriggeredExitEntity( true );
initData.ignoreSaveSystem = true;
initData.setDefaultState('FastTravel');
theGame.RequestMenuWithBackground( 'MapMenu', 'CommonMenu', initData );
}

public function OnTeleportPlayerToPlayableArea( afterClosingMap : bool )
{
var BLACKSCREEN_INTERVAL : float = 0.5;
var manager : CCommonMapManager = theGame.GetCommonMapManager();

theGame.FadeOutAsync( 0 );
thePlayer.TeleportWithRotation( manager.GetBorderTeleportPosition(), manager.GetBorderTeleportRotation() );
thePlayer.AddTimer( 'BorderTeleportFadeInTimer', BLACKSCREEN_INTERVAL, false );
}

timer function BorderTeleportFadeInTimer( dt : float, id : int )
{
var FADEIN_INTERVAL : float = 0.5;

theGame.FadeInAsync( FADEIN_INTERVAL );
}

public final function SetLastInstantKillTime(g : GameTime)
{
lastInstantKillTime = g;
}
//
//
//
////////////////////////////////////////////////////////////////////////////////

timer function TestTimer(dt : float, id : int )
{
LogChannel('asdf', "asdf");
theGame.FadeOutAsync( 5 );
}

public final function Debug_ReleaseCriticalStateSaveLocks()
{
effectManager.Debug_ReleaseCriticalStateSaveLocks();
}

timer function Debug_SpamSpeed(dt : float, id : int)
{
if(currentlyMountedHorse)
{
LogSpeed("curr player's horse speed: " + NoTrailZeros(currentlyMountedHorse.GetMovingAgentComponent().GetSpeed())) ;
}
else
{
LogSpeed("curr player speed: " + NoTrailZeros(GetMovingAgentComponent().GetSpeed())) ;
}
}

timer function RemoveInstantKillSloMo(dt : float, id : int)
{
theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_InstantKill) );
}

// modXTFinishers BEGIN
timer function XTFinishersSlowdownTimerCallback(dt : float, id : int) {
((XTFinishersAbstractSlowdownManager)theGame.xtFinishersMgr.slowdownMgr).EndSlowdownSegment(true);
}
// modXTFinishers END

timer function RemoveForceFinisher(dt : float, id : int)
{
forceFinisher = false;
}

public final function Debug_ClearAllActionLocks(optional action : EInputActionBlock, optional all : bool)
{
inputHandler.Debug_ClearAllActionLocks(action, all);
}

function OnFocusedCameraBlendBegin() {}
function OnFocusedCameraBlendUpdate( progress : float ) {}
function OnFocusedCameraBlendEnd() {}

public function GetEtherealCount() : int { return etherealCount; }
public function IncrementEtherealCount()
{
etherealCount += 1;
if( etherealCount == 6 )
ResetEtherealCount();
}
public function ResetEtherealCount() { etherealCount = 0; }

// PHANTOM WEAPON
//------------------------------------------------------------------------------------------------------------------
public function InitPhantomWeaponMgr()
{
if( !phantomWeaponMgr )
{
phantomWeaponMgr = new CPhantomWeaponManager in this;
phantomWeaponMgr.Init( this.GetInventory() );
}
}

public function DestroyPhantomWeaponMgr()
{
if( phantomWeaponMgr )
{
delete phantomWeaponMgr;
}
}

public function GetPhantomWeaponMgr() : CPhantomWeaponManager
{
if( phantomWeaponMgr )
{
return phantomWeaponMgr;
}
else
{
return NULL;
}
}

public timer function DischargeWeaponAfter( td : float, id : int )
{
GetPhantomWeaponMgr().DischargeWeapon();
}
//------------------------------------------------------------------------------------------------------------------


exec function ttt()
{
thePlayer.AddTimer( 'TestTimer', 5, false );
}
[/spoiler]();>();>();>();>;>;>();>();>();>();>();>();>();>();>();>();>();>();>();>();>

Link to comment
Share on other sites

versão 1.21

Ola me ajudem, esta dando esse erro


Erro [content0] game \ gameplay \ focus \ focus.ws (202): A função 'LogWithName' não tem 1 param (s)

Erro [content0] game \ gameplay \ focus \ focus.ws (262): Função 'LogWithName' não leva 1 param (s)

Erro [content0] game \ gui \ menus \ gwintgamemenu.ws (105): A função 'LogWithName' não tem 1 param (s)

(44): Função 'LogWithName' não leva 1 param (s)

(56): Função 'LogWithName' não leva 1 parâmetro (s)

Erro [content0] game \ player \ states \ playerdialogstate.ws (46): A função 'LogWithName' não tem 1 param (s)

Erro [content0] game \ player \ states \ aimthrow.ws (39): A função 'LogWithName' não tem 1 param (s)

Erro [content0] game \ player \ states \ combat.ws (123): Função 'LogWithName' não tem 1 param (s)

Erro [content0] game \ player \ states \ exploration.ws (55): A função 'LogWithName' não tem 1 param (s)

Erro [content0] game \ player \ states \ swimming.ws (247): Função 'LogWithName' não leva 1 param (s)


Aviso [content0] engine \ telemetrykeyword.ws (5): A função nativa 'Log' não foi exportada da classe 'CR4TelemetryScriptProxy' no código C ++.

Warning [content0] engine \ environment.ws (25): A função nativa global 'EnableDebugOverlayFilter' não foi exportada do código C ++.

Warning [content0] engine \ environment.ws (27): A função nativa global 'EnableDebugPostProcess' não foi exportada do código C ++.

Aviso [content0] engine \ showflags.ws (9): A função nativa global 'DebugSetEShowFlag' não foi exportada do código C ++.

Edited by sharksbull
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...