From 7776c405a572592ef5f933991231b56e3877a8dd Mon Sep 17 00:00:00 2001 From: Abheek Dhawan Date: Mon, 7 Feb 2022 17:26:49 -0600 Subject: [PATCH] Reformat repo and add features - Use a new custom book instead of Gwent book - Toggle spoilers in mod menu --- .woodpecker/release.yml | 4 +- .../user_config_matrix/pc/modStatTrak.xml | Bin 0 -> 868 bytes .../game/components/inventoryComponent.ws | Bin 335086 -> 0 bytes dlc/dlcStatTrak/content/ar.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/blob0.bundle | Bin 0 -> 8801 bytes dlc/dlcStatTrak/content/br.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/cn.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/cz.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/de.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/en.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/es.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/esmx.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/fr.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/hu.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/it.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/jp.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/kr.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/metadata.store | Bin 0 -> 493 bytes dlc/dlcStatTrak/content/pl.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/ru.w3strings | Bin 0 -> 179 bytes dlc/dlcStatTrak/content/zh.w3strings | Bin 0 -> 179 bytes .../game/components/inventoryComponent.ws | 5873 +++++++ .../content/scripts/game/player/r4player.ws | 14676 ++++++++++++++++ .../achievementStatTrak/achievement_stats.ws | 10 + src/StatTrak.w3modproj | 8 + .../Bundle/dlc/StatTrak/dlcStatTrak.reddlc | Bin 0 -> 760 bytes .../gameplay/items/def_stattrak_items.xml | Bin 0 -> 1274 bytes .../game/components/inventoryComponent.ws | 5873 +++++++ .../files/Mod/scripts/game/player/r4player.ws | 14676 ++++++++++++++++ .../achievementStatTrak/achievement_stats.ws | 212 + strings/csv/en.w3strings.csv | 8 + 31 files changed, 41337 insertions(+), 3 deletions(-) create mode 100644 bin/config/r4game/user_config_matrix/pc/modStatTrak.xml delete mode 100644 content/scripts/game/components/inventoryComponent.ws create mode 100644 dlc/dlcStatTrak/content/ar.w3strings create mode 100644 dlc/dlcStatTrak/content/blob0.bundle create mode 100644 dlc/dlcStatTrak/content/br.w3strings create mode 100644 dlc/dlcStatTrak/content/cn.w3strings create mode 100644 dlc/dlcStatTrak/content/cz.w3strings create mode 100644 dlc/dlcStatTrak/content/de.w3strings create mode 100644 dlc/dlcStatTrak/content/en.w3strings create mode 100644 dlc/dlcStatTrak/content/es.w3strings create mode 100644 dlc/dlcStatTrak/content/esmx.w3strings create mode 100644 dlc/dlcStatTrak/content/fr.w3strings create mode 100644 dlc/dlcStatTrak/content/hu.w3strings create mode 100644 dlc/dlcStatTrak/content/it.w3strings create mode 100644 dlc/dlcStatTrak/content/jp.w3strings create mode 100644 dlc/dlcStatTrak/content/kr.w3strings create mode 100644 dlc/dlcStatTrak/content/metadata.store create mode 100644 dlc/dlcStatTrak/content/pl.w3strings create mode 100644 dlc/dlcStatTrak/content/ru.w3strings create mode 100644 dlc/dlcStatTrak/content/zh.w3strings create mode 100644 mods/modStatTrak/content/scripts/game/components/inventoryComponent.ws create mode 100644 mods/modStatTrak/content/scripts/game/player/r4player.ws rename {content => mods/modStatTrak/content}/scripts/local/achievementStatTrak/achievement_stats.ws (94%) create mode 100644 src/StatTrak.w3modproj create mode 100644 src/StatTrak/files/DLC/Bundle/dlc/StatTrak/dlcStatTrak.reddlc create mode 100644 src/StatTrak/files/DLC/Bundle/dlc/StatTrak/gameplay/items/def_stattrak_items.xml create mode 100644 src/StatTrak/files/Mod/scripts/game/components/inventoryComponent.ws create mode 100644 src/StatTrak/files/Mod/scripts/game/player/r4player.ws create mode 100644 src/StatTrak/files/Mod/scripts/local/achievementStatTrak/achievement_stats.ws create mode 100644 strings/csv/en.w3strings.csv diff --git a/.woodpecker/release.yml b/.woodpecker/release.yml index 93d7cc9..57cca77 100644 --- a/.woodpecker/release.yml +++ b/.woodpecker/release.yml @@ -2,11 +2,9 @@ pipeline: prep-release: image: alpine:latest commands: - - mkdir -p modAchievementStatTrak - - mv content/ modAchievementStatTrak/ - apk update - apk add zip - - zip -r modAchievementStatTrak.zip modAchievementStatTrak/ + - zip -r StatTrak.zip {dlc,mods,bin}/ when: event: tag diff --git a/bin/config/r4game/user_config_matrix/pc/modStatTrak.xml b/bin/config/r4game/user_config_matrix/pc/modStatTrak.xml new file mode 100644 index 0000000000000000000000000000000000000000..2646504956246c38cc981c5c4083cfeef038e51a GIT binary patch literal 868 zcma))PfvqD5XIlw#P2}7YxUv@ZH#|2%r(?3t$rTcouDf+D$;~*a^}u^chqk7K zXLt1vFW=kmp`ILSs%LN${$i(ofA-%h%WGL*QJukjs|gGXFb&OoG~fKwt)O51ew+w5 zR*e&p9&vS~v2N)+_~*E<_q(az)o}yPoU=9jE7*_G5_2;NtDlm-2%f{PC*4|nzTY>$ t_hw$Fu&tX}GsKGJ=l7LwQ(zu%QB%8H>GCGTwLUXpdF}lAsULLA{Wr_sf~Nog literal 0 HcmV?d00001 diff --git a/content/scripts/game/components/inventoryComponent.ws b/content/scripts/game/components/inventoryComponent.ws deleted file mode 100644 index d803fcc7dc07bd8fd8c1928dfb54466c64747173..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 335086 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

>XX54TX{ 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 diff --git a/dlc/dlcStatTrak/content/ar.w3strings b/dlc/dlcStatTrak/content/ar.w3strings new file mode 100644 index 0000000000000000000000000000000000000000..369a9117253b4c407f0ded1bc9ff5d8ec3122691 GIT binary patch literal 179 zcmWFv2@YSxz`!uwnMI&Uf?Wv6&L7M_*#mDr$vNq{ zzjJ@*oZtEVKBq6gUv76-ur=7#Scf`nv`G;#K>!?gT2zhn1q|5;rscstdii_oNwX-u z-r2Opo~y*Dj5_i+4}5TGZaIsl@8TDe6D+05nLfo}3B51M20}WqHHd9!L**GwsGHmT zzs%f{0C}CCd-I4o+59`}{CML8H~~(86W|0m0ZxDu-~>1UPJk2mZwN%%dg_l}poBkl z%{2aP!+H5rjrWsF7d z#p?%I1_2|jXt5%s+L<0nE2%chxABWJksQ(tmewJs({g4{eNA0W%1H0&c=WHdnvObL z0Uz3Wc1>Wrz5~vv3rpr>3Du{ltXnqX7*=#8tg;TR8cPz>hOjT0RFP&UhZHJk?8}6) zKOhgY>ws72Ubyh)Vm=erg3Vuk;h?C#dn|u>2g$G29`IL^jDNrQMkC4TAFteOCfTY_ ztsEhFCC8N=B3bn0>f29|JiTrD_$o&li6}GIsTc{Le^^pU?W}gwR3| z-Ps7ACXH7t#ANo|XjKlf-7f+uI4&09nI}R%FYz^@KzvU^7R<2I;+Ywt>>ekCSF&M2 z6DhXACEBvYl9oIgJ}*`XR?GSowdB$Um#~6`yNeQ^3a|ZJkeI^9Td5R5w0PqLH~~(8 z6W|0m0ZxDu-~>1UPGD;gSgyYPM-%p96bYzsV;Br+=unV^hDT5iFFf>dKsn7Z(nLrf zrCANJQmj~e5u}8BCoOu2mh43{Wt=&bgr;e6^a!Lv_@gu&Xu^XEj4&K}Da3NTbRX^6 zNhT{q6fc|I=pZ}$ahNpiBz^SWS%`@abfFW0Aeo+l^dYc-28P5uwp$7z=Hq<}`5}|% z3>GRoR0?NX$-y|e$4&_L!~x+~7-TX)Pno)oav$uG0-R%rQ5EJ6RCIJ)M{fO*A)|L?3L#2vv|y3DS(Ir1p#ng|PKY7BXXbR_fmPFZ>BenKv5% literal 0 HcmV?d00001 diff --git a/dlc/dlcStatTrak/content/br.w3strings b/dlc/dlcStatTrak/content/br.w3strings new file mode 100644 index 0000000000000000000000000000000000000000..369a9117253b4c407f0ded1bc9ff5d8ec3122691 GIT binary patch literal 179 zcmWFv2@YSxz`!uwnMI&Uf?Wv6jOVqo~i!oZNh#E_JepJbqyRGOEPlgf~ilN=LVl2{T_l$ad@U>%^QlJI`P4gId7=0AXuWHUIzs literal 0 HcmV?d00001 diff --git a/dlc/dlcStatTrak/content/pl.w3strings b/dlc/dlcStatTrak/content/pl.w3strings new file mode 100644 index 0000000000000000000000000000000000000000..369a9117253b4c407f0ded1bc9ff5d8ec3122691 GIT binary patch literal 179 zcmWFv2@YSxz`!uwnMI&Uf?Wv6; +}; + +import class CInventoryComponent extends CComponent +{ + editable var priceMult : float; + editable var priceRepairMult : float; + editable var priceRepair : float; + editable var fundsType : EInventoryFundsType; + + private var recentlyAddedItems : array; + private var fundsMax : int; + private var daysToIncreaseFunds : int; + + default priceMult = 1.0; + default priceRepairMult = 1.0; + default priceRepair = 10.0; + default fundsType = EInventoryFunds_Avg; + default daysToIncreaseFunds = 5; + + + + + public function GetFundsType() : EInventoryFundsType + { + return fundsType; + } + + public function GetDaysToIncreaseFunds() : int + { + return daysToIncreaseFunds; + } + + public function GetFundsMax() : float + { + if ( EInventoryFunds_Broke == fundsType ) + { + return 0; + } + else if ( EInventoryFunds_Avg == fundsType ) + { + return 5000; + } + else if ( EInventoryFunds_Poor == fundsType ) + { + return 2500; + } + else if ( EInventoryFunds_Rich == fundsType ) + { + return 7500; + } + else if ( EInventoryFunds_RichQuickStart == fundsType ) + { + return 15000; + } + return -1; + } + + public function SetupFunds() + { + if ( EInventoryFunds_Broke == fundsType ) + { + AddMoney( 0 ); + } + else if ( EInventoryFunds_Poor == fundsType ) + { + AddMoney( (int)( 200 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_Avg == fundsType ) + { + AddMoney( (int)( 500 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_Rich == fundsType ) + { + AddMoney( (int)( 1000 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_RichQuickStart == fundsType ) + { + AddMoney( (int)( 5000 * GetFundsModifier() ) ); + } + } + + public function IncreaseFunds() + { + if ( GetMoney() < GetFundsMax() ) + { + if ( EInventoryFunds_Avg == fundsType ) + { + AddMoney( (int)( 150 * GetFundsModifier()) ); + } + else if ( EInventoryFunds_Poor == fundsType ) + { + AddMoney( (int)( 100 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_Rich == fundsType ) + { + AddMoney( (int)( 1000 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_RichQuickStart == fundsType ) + { + AddMoney( 1000 + (int)( 2500 * GetFundsModifier() ) ); + } + } + } + + public function GetMoney() : int + { + return GetItemQuantityByName( 'Crowns' ); + } + + public function SetMoney( amount : int ) + { + var currentMoney : int; + + if ( amount >= 0 ) + { + currentMoney = GetMoney(); + RemoveMoney( currentMoney ); + + AddAnItem( 'Crowns', amount ); + } + } + + public function AddMoney( amount : int ) + { + if ( amount > 0 ) + { + AddAnItem( 'Crowns', amount ); + + if ( thePlayer == GetEntity() ) + { + theTelemetry.LogWithValue( TE_HERO_CASH_CHANGED, amount ); + } + } + } + + public function RemoveMoney( amount : int ) + { + if ( amount > 0 ) + { + RemoveItemByName( 'Crowns', amount ); + + if ( thePlayer == GetEntity() ) + { + theTelemetry.LogWithValue( TE_HERO_CASH_CHANGED, -amount ); + } + } + } + + + + + + import final function GetItemAbilityAttributeValue( itemId : SItemUniqueId, attributeName : name, abilityName : name) : SAbilityAttributeValue; + + import final function GetItemFromSlot( slotName : name ) : SItemUniqueId; + + + import final function IsIdValid( itemId : SItemUniqueId ) : bool; + + + import final function GetItemCount( optional useAssociatedInventory : bool ) : int; + + + import final function GetItemsNames() : array< name >; + + + import final function GetAllItems( out items : array< SItemUniqueId > ); + + + import public function GetItemId( itemName : name ) : SItemUniqueId; + + + import public function GetItemsIds( itemName : name ) : array< SItemUniqueId >; + + + import final function GetItemsByTag( tag : name ) : array< SItemUniqueId >; + + + import final function GetItemsByCategory( category : name ) : array< SItemUniqueId >; + + + import final function GetSchematicIngredients(itemName : SItemUniqueId, out quantity : array, out names : array); + + + import final function GetSchematicRequiredCraftsmanType(craftName : SItemUniqueId) : name; + + + import final function GetSchematicRequiredCraftsmanLevel(craftName : SItemUniqueId) : name; + + + import final function GetNumOfStackedItems( itemUniqueId: SItemUniqueId ) : int; + + import final function InitInvFromTemplate( resource : CEntityTemplate ); + + + + + import final function SplitItem( itemID : SItemUniqueId, quantity : int ) : SItemUniqueId; + + + + import final function SetItemStackable( itemID : SItemUniqueId, flag : bool ); + + + import final function GetCategoryDefaultItem( category : name ) : name; + + + + + + + import final function GetItemLocalizedNameByName( itemName : CName ) : string; + + + import final function GetItemLocalizedDescriptionByName( itemName : CName ) : string; + + + import final function GetItemLocalizedNameByUniqueID( itemUniqueId : SItemUniqueId ) : string; + + + import final function GetItemLocalizedDescriptionByUniqueID( itemUniqueId : SItemUniqueId ) : string; + + + import final function GetItemIconPathByUniqueID( itemUniqueId : SItemUniqueId ) : string; + + + import final function GetItemIconPathByName( itemName : CName ) : string; + + import final function AddSlot( itemUniqueId : SItemUniqueId ) : bool; + + import final function GetSlotItemsLimit( itemUniqueId : SItemUniqueId ) : int; + + import private final function BalanceItemsWithPlayerLevel( playerLevel : int ); + + public function ForceSpawnItemOnStart( itemId : SItemUniqueId ) : bool + { + return ItemHasTag(itemId, 'MutagenIngredient'); + } + + + public final function GetItemArmorTotal(item : SItemUniqueId) : SAbilityAttributeValue + { + var armor, armorBonus : SAbilityAttributeValue; + var durMult : float; + + armor = GetItemAttributeValue(item, theGame.params.ARMOR_VALUE_NAME); + armorBonus = GetRepairObjectBonusValueForArmor(item); + durMult = theGame.params.GetDurabilityMultiplier( GetItemDurabilityRatio(item), false); + + return armor * durMult + armorBonus; + } + + public final function GetItemLevel(item : SItemUniqueId) : int + { + var itemCategory : name; + var itemAttributes : array; + var itemName : name; + var isWitcherGear : bool; + var isRelicGear : bool; + var level, baseLevel : int; + + itemCategory = GetItemCategory(item); + itemName = GetItemName(item); + + isWitcherGear = false; + isRelicGear = false; + if ( RoundMath(CalculateAttributeValue( GetItemAttributeValue(item, 'quality' ) )) == 5 ) isWitcherGear = true; + if ( RoundMath(CalculateAttributeValue( GetItemAttributeValue(item, 'quality' ) )) == 4 ) isRelicGear = true; + + switch(itemCategory) + { + case 'armor' : + case 'boots' : + case 'gloves' : + case 'pants' : + itemAttributes.PushBack( GetItemAttributeValue(item, 'armor') ); + break; + + case 'silversword' : + itemAttributes.PushBack( GetItemAttributeValue(item, 'SilverDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'BludgeoningDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'RendingDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'ElementalDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'FireDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'PiercingDamage') ); + break; + + case 'steelsword' : + itemAttributes.PushBack( GetItemAttributeValue(item, 'SlashingDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'BludgeoningDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'RendingDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'ElementalDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'FireDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'SilverDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'PiercingDamage') ); + break; + + case 'crossbow' : + itemAttributes.PushBack( GetItemAttributeValue(item, 'attack_power') ); + break; + + default : + break; + } + + level = theGame.params.GetItemLevel(itemCategory, itemAttributes, itemName, baseLevel); + + if ( FactsQuerySum("NewGamePlus") > 0 ) + { + if ( baseLevel > GetWitcherPlayer().GetMaxLevel() ) + { + level = baseLevel; + } + } + + if ( isWitcherGear ) level = level - 2; + if ( isRelicGear ) level = level - 1; + if ( level < 1 ) level = 1; + if ( ItemHasTag(item, 'OlgierdSabre') ) level = level - 3; + if ( (isRelicGear || isWitcherGear) && ItemHasTag(item, 'EP1') ) level = level - 1; + + if ( FactsQuerySum("NewGamePlus") > 0 ) + { + if ( level > GetWitcherPlayer().GetMaxLevel() ) + { + level = GetWitcherPlayer().GetMaxLevel(); + } + } + + return level; + } + + public function GetItemLevelColorById( itemId : SItemUniqueId ) : string + { + var color : string; + + if (GetItemLevel(itemId) <= thePlayer.GetLevel()) + { + color = ""; + } + else + { + color = ""; + } + + return color; + } + + public function GetItemLevelColor( lvl_item : int ) : string + { + var color : string; + + if ( lvl_item > thePlayer.GetLevel() ) + { + color = ""; + } else + { + color = ""; + } + + return color; + } + + public final function AutoBalanaceItemsWithPlayerLevel() + { + var playerLevel : int; + + playerLevel = thePlayer.GetLevel(); + + if( playerLevel < 0 ) + { + playerLevel = 0; + } + + BalanceItemsWithPlayerLevel( playerLevel ); + } + + public function GetItemsByName(itemName : name) : array + { + var ret : array; + var i : int; + + if(!IsNameValid(itemName)) + return ret; + + GetAllItems(ret); + + for(i=ret.Size()-1; i>=0; i-=1) + { + if(GetItemName(ret[i]) != itemName) + { + ret.EraseFast( i ); + } + } + + return ret; + } + + public final function GetSingletonItems() : array + { + return GetItemsByTag(theGame.params.TAG_ITEM_SINGLETON); + } + + + import final function GetItemQuantityByName( itemName : name, optional useAssociatedInventory : bool , optional ignoreTags : array< name > ) : int; + + + import final function GetItemQuantityByCategory( itemCategory : name, optional useAssociatedInventory : bool , optional ignoreTags : array< name > ) : int; + + + import final function GetItemQuantityByTag( itemTag : name, optional useAssociatedInventory : bool , optional ignoreTags : array< name > ) : int; + + + import final function GetAllItemsQuantity( optional useAssociatedInventory : bool , optional ignoreTags : array< name > ) : int; + + + public function IsEmpty(optional bSkipNoDropNoShow : bool) : bool + { + var i : int; + var itemIds : array; + + if(bSkipNoDropNoShow) + { + GetAllItems( itemIds ); + for( i = itemIds.Size() - 1; i >= 0; i -= 1 ) + { + if( !ItemHasTag( itemIds[ i ],theGame.params.TAG_DONT_SHOW ) && !ItemHasTag( itemIds[ i ], 'NoDrop' ) ) + { + return false; + } + else if ( ItemHasTag( itemIds[ i ], 'Lootable') ) + { + return false; + } + } + + return true; + } + + return GetItemCount() <= 0; + } + + + public function GetAllHeldAndMountedItemsCategories( out heldItems : array, optional out mountedItems : array ) + { + var allItems : array; + var i : int; + + GetAllItems(allItems); + for(i=allItems.Size()-1; i >= 0; i-=1) + { + if ( IsItemHeld(allItems[i]) ) + heldItems.PushBack(GetItemCategory(allItems[i])); + else if ( IsItemMounted(allItems[i]) ) + mountedItems.PushBack(GetItemCategory(allItems[i])); + } + } + + public function GetAllHeldItemsNames( out heldItems : array ) + { + var allItems : array; + var i : int; + + GetAllItems(allItems); + for(i=allItems.Size()-1; i >= 0; i-=1) + { + if ( IsItemHeld(allItems[i]) ) + heldItems.PushBack(GetItemName(allItems[i])); + } + } + + public function HasMountedItemByTag(tag : name) : bool + { + var i : int; + var allItems : array; + + if(!IsNameValid(tag)) + return false; + + allItems = GetItemsByTag(tag); + for(i=0; i; + + if(!IsNameValid(tag)) + return false; + + allItems = GetItemsByTag(tag); + for(i=0; i ) : bool; + + + import final function GetCraftedItemName( itemId : SItemUniqueId ) : name; + + + import final function TotalItemStats( invItem : SInventoryItem ) : float; + + import final function GetItemPrice( itemId : SItemUniqueId ) : int; + + + import final function GetItemPriceModified( itemId : SItemUniqueId, optional playerSellingItem : Bool ) : int; + + + import final function GetInventoryItemPriceModified( invItem : SInventoryItem, optional playerSellingItem : Bool ) : int; + + + import final function GetItemPriceRepair( invItem : SInventoryItem, out costRepairPoint : int, out costRepairTotal : int ); + + + import final function GetItemPriceRemoveUpgrade( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceDisassemble( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceAddSlot( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceCrafting( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceEnchantItem( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceRemoveEnchantment( invItem : SInventoryItem ) : int; + + import final function GetFundsModifier() : float; + + + import final function GetItemQuantity( itemId : SItemUniqueId ) : int; + + + import final function ItemHasTag( itemId : SItemUniqueId, tag : name ) : bool; + + + import final function AddItemTag( itemId : SItemUniqueId, tag : name ) : bool; + + + import final function RemoveItemTag( itemId : SItemUniqueId, tag : name ) : bool; + + + public final function ManageItemsTag( items : array, tag : name, add : bool ) + { + var i : int; + + if( add ) + { + for( i = 0 ; i < items.Size() ; i += 1 ) + { + AddItemTag( items[ i ], tag ); + } + } + else + { + for( i = 0 ; i < items.Size() ; i += 1 ) + { + RemoveItemTag( items[ i ], tag ); + } + } + } + + + import final function GetItemByItemEntity( itemEntity : CItemEntity ) : SItemUniqueId; + + + public function ItemHasAbility(item : SItemUniqueId, abilityName : name) : bool + { + var abilities : array; + + GetItemAbilities(item, abilities); + return abilities.Contains(abilityName); + } + + import final function GetItemAttributeValue( itemId : SItemUniqueId, attributeName : name, optional abilityTags : array< name >, optional withoutTags : bool ) : SAbilityAttributeValue; + + + import final function GetItemBaseAttributes( itemId : SItemUniqueId, out attributes : array ); + + + import final function GetItemAttributes( itemId : SItemUniqueId, out attributes : array ); + + + import final function GetItemAbilities( itemId : SItemUniqueId, out abilities : array ); + + + import final function GetItemContainedAbilities( itemId : SItemUniqueId, out abilities : array ); + + + public function GetItemAbilitiesWithAttribute(id : SItemUniqueId, attributeName : name, attributeVal : float) : array + { + var i : int; + var abs, ret : array; + var dm : CDefinitionsManagerAccessor; + var val : float; + var min, max : SAbilityAttributeValue; + + GetItemAbilities(id, abs); + dm = theGame.GetDefinitionsManager(); + + for(i=0; i ) + { + var i : int; + var dm : CDefinitionsManagerAccessor; + var allAbilities : array; + + dm = theGame.GetDefinitionsManager(); + GetItemAbilities(itemId, allAbilities); + + for(i=0; i; + + public final function GiveMoneyTo(otherInventory : CInventoryComponent, optional quantity : int, optional informGUI : bool ) + { + var moneyId : array; + + moneyId = GetItemsByName('Crowns'); + GiveItemTo(otherInventory, moneyId[0], quantity, false, true, informGUI); + } + + public final function GiveItemTo( otherInventory : CInventoryComponent, itemId : SItemUniqueId, optional quantity : int, optional refreshNewFlag : bool, optional forceTransferNoDrops : bool, optional informGUI : bool ) : SItemUniqueId + { + var arr : array; + var itemName : name; + var i : int; + var uiData : SInventoryItemUIData; + var isQuestItem : bool; + + + if(quantity == 0) + quantity = 1; + + quantity = Clamp(quantity, 0, GetItemQuantity(itemId)); + if(quantity == 0) + return GetInvalidUniqueId(); + + itemName = GetItemName(itemId); + + if(!forceTransferNoDrops && ( ItemHasTag(itemId, 'NoDrop') && !ItemHasTag(itemId, 'Lootable') )) + { + LogItems("Cannot transfer item <<" + itemName + ">> as it has the NoDrop tag set!!!"); + return GetInvalidUniqueId(); + } + + + if(IsItemSingletonItem(itemId)) + { + + if(otherInventory == thePlayer.inv && otherInventory.GetItemQuantityByName(itemName) > 0) + { + LogAssert(false, "CInventoryComponent.GiveItemTo: cannot add singleton item as player already has this item!"); + return GetInvalidUniqueId(); + } + + else + { + arr = GiveItem(otherInventory, itemId, quantity); + } + } + else + { + + arr = GiveItem(otherInventory, itemId, quantity); + } + + + if(otherInventory == thePlayer.inv) + { + isQuestItem = this.IsItemQuest( itemId ); + theTelemetry.LogWithLabelAndValue(TE_INV_ITEM_PICKED, itemName, quantity); + + if ( !theGame.AreSavesLocked() && ( isQuestItem || this.GetItemQuality( itemId ) >= 4 ) ) + { + theGame.RequestAutoSave( "item gained", false ); + } + } + + if (refreshNewFlag) + { + for (i = 0; i < arr.Size(); i += 1) + { + uiData = otherInventory.GetInventoryItemUIData( arr[i] ); + uiData.isNew = true; + otherInventory.SetInventoryItemUIData( arr[i], uiData ); + } + } + + return arr[0]; + } + + public final function GiveAllItemsTo(otherInventory : CInventoryComponent, optional forceTransferNoDrops : bool, optional informGUI : bool) + { + var items : array; + + GetAllItems(items); + GiveItemsTo(otherInventory, items, forceTransferNoDrops, informGUI); + } + + public final function GiveItemsTo(otherInventory : CInventoryComponent, items : array, optional forceTransferNoDrops : bool, optional informGUI : bool) : array + { + var i : int; + var ret : array; + + for( i = 0; i < items.Size(); i += 1 ) + { + ret.PushBack(GiveItemTo(otherInventory, items[i], GetItemQuantity(items[i]), true, forceTransferNoDrops, informGUI)); + } + + return ret; + } + + + import final function HasItem( item : name ) : bool; + + + + final function HasItemById(id : SItemUniqueId) : bool + { + var arr : array; + + GetAllItems(arr); + return arr.Contains(id); + } + + public function HasItemByTag(tag : name) : bool + { + var quantity : int; + + quantity = GetItemQuantityByTag( tag ); + return quantity > 0; + } + + public function HasItemByCategory(category : name) : bool + { + var quantity : int; + + quantity = GetItemQuantityByCategory( category ); + return quantity > 0; + } + + + public function HasInfiniteBolts() : bool + { + var ids : array; + var i : int; + + ids = GetItemsByTag(theGame.params.TAG_INFINITE_AMMO); + for(i=0; i; + var i : int; + + ids = GetItemsByTag(theGame.params.TAG_GROUND_AMMO); + for(i=0; i; + var i : int; + + ids = GetItemsByTag(theGame.params.TAG_UNDERWATER_AMMO); + for(i=0; i; + import private final function AddSingleItem( item : name, optional informGui : bool , optional markAsNew : bool , optional lootable : bool ) : SItemUniqueId; + + + public final function AddAnItem(item : name, optional quantity : int, optional dontInformGui : bool, optional dontMarkAsNew : bool, optional showAsRewardInUIHax : bool) : array + { + var arr : array; + var i : int; + var isReadableItem : bool; + + + if( theGame.GetDefinitionsManager().IsItemSingletonItem(item) && GetEntity() == thePlayer) + { + if(GetItemQuantityByName(item) > 0) + { + arr = GetItemsIds(item); + } + else + { + arr.PushBack(AddSingleItem(item, !dontInformGui, !dontMarkAsNew)); + } + + quantity = 1; + } + else + { + if(quantity < 2 ) + { + arr.PushBack(AddSingleItem(item, !dontInformGui, !dontMarkAsNew)); + } + else + { + arr = AddMultiItem(item, quantity, !dontInformGui, !dontMarkAsNew); + } + } + + + if(this == thePlayer.GetInventory()) + { + if(ItemHasTag(arr[0],'ReadableItem')) + UpdateInitialReadState(arr[0]); + + + if(showAsRewardInUIHax || ItemHasTag(arr[0],'GwintCard')) + thePlayer.DisplayItemRewardNotification(GetItemName(arr[0]), quantity ); + } + + return arr; + } + + + import final function RemoveItem( itemId : SItemUniqueId, optional quantity : int ) : bool; + + + private final function InternalRemoveItems(ids : array, quantity : int) + { + var i, currQuantityToTake : int; + + + for(i=0; i0, "CInventoryComponent.InternalRemoveItems(" + GetItemName(ids[i]) + "): somehow took too many items! Should be " + (-quantity) + " less... Investigate!"); + } + } + + + + public function RemoveItemByName(itemName : name, optional quantity : int) : bool + { + var totalItemCount : int; + var ids : array; + + + totalItemCount = GetItemQuantityByName(itemName); + if(totalItemCount < quantity || quantity == 0) + { + return false; + } + + if(quantity == 0) + { + quantity = 1; + } + else if(quantity < 0) + { + quantity = totalItemCount; + } + + ids = GetItemsIds(itemName); + + if(GetEntity() == thePlayer && thePlayer.GetSelectedItemId() == ids[0] ) + { + thePlayer.ClearSelectedItemId(); + } + + InternalRemoveItems(ids, quantity); + + return true; + } + + + + public function RemoveItemByCategory(itemCategory : name, optional quantity : int) : bool + { + var totalItemCount : int; + var ids : array; + var selectedItemId : SItemUniqueId; + var i : int; + + + totalItemCount = GetItemQuantityByCategory(itemCategory); + if(totalItemCount < quantity) + { + return false; + } + + if(quantity == 0) + { + quantity = 1; + } + else if(quantity < 0) + { + quantity = totalItemCount; + } + + ids = GetItemsByCategory(itemCategory); + + if(GetEntity() == thePlayer) + { + selectedItemId = thePlayer.GetSelectedItemId(); + for(i=0; i; + var i : int; + var selectedItemId : SItemUniqueId; + + + totalItemCount = GetItemQuantityByTag(itemTag); + if(totalItemCount < quantity) + { + return false; + } + + if(quantity == 0) + { + quantity = 1; + } + else if(quantity < 0) + { + quantity = totalItemCount; + } + + ids = GetItemsByTag(itemTag); + + if(GetEntity() == thePlayer) + { + selectedItemId = thePlayer.GetSelectedItemId(); + for(i=0; i ) : CEntity; + + + import final function ThrowAwayLootableItems( optional skipNoDropNoShow : bool ) : CEntity; + + + import final function GetItemRecyclingParts( itemId : SItemUniqueId ) : array; + + import final function GetItemWeight( id : SItemUniqueId ) : float; + + + public final function HasQuestItem() : bool + { + var allItems : array< SItemUniqueId >; + var i : int; + + allItems = GetItemsByTag('Quest'); + for ( i=0; i theGame.params.ITEM_DAMAGED_DURABILITY ) + { + FactsAdd( "tut_item_damaged", 1 ); + } + } + } + + SetItemDurability( itemId, durability ); + } + + + public function ReduceItemDurability(itemId : SItemUniqueId, optional forced : bool) : bool + { + var dur, value, durabilityDiff, itemToughness, indestructible : float; + var chance : int; + if(!IsIdValid(itemId) || !HasItemDurability(itemId) || ItemHasAbility(itemId, 'MA_Indestructible')) + { + return false; + } + + + if(IsItemWeapon(itemId)) + { + chance = theGame.params.DURABILITY_WEAPON_LOSE_CHANCE; + value = theGame.params.GetWeaponDurabilityLoseValue(); + } + else if(IsItemAnyArmor(itemId)) + { + chance = theGame.params.DURABILITY_ARMOR_LOSE_CHANCE; + value = theGame.params.DURABILITY_ARMOR_LOSE_VALUE; + } + + dur = GetItemDurability(itemId); + + if ( dur == 0 ) + { + return false; + } + + + if ( forced || RandRange( 100 ) < chance ) + { + itemToughness = CalculateAttributeValue( GetItemAttributeValue( itemId, 'toughness' ) ); + indestructible = CalculateAttributeValue( GetItemAttributeValue( itemId, 'indestructible' ) ); + + value = value * ( 1 - indestructible ); + + if ( itemToughness > 0.0f && itemToughness <= 1.0f ) + { + durabilityDiff = ( dur - value ) * itemToughness; + + SetItemDurabilityScript( itemId, MaxF(durabilityDiff, 0 ) ); + } + else + { + SetItemDurabilityScript( itemId, MaxF( dur - value, 0 ) ); + } + } + + return true; + } + + public function GetItemDurabilityRatio(itemId : SItemUniqueId) : float + { + if ( !IsIdValid( itemId ) || !HasItemDurability( itemId ) ) + return -1; + + return GetItemDurability(itemId) / GetItemMaxDurability(itemId); + } + + + + + + + public function GetItemResistStatWithDurabilityModifiers(itemId : SItemUniqueId, stat : ECharacterDefenseStats, out points : SAbilityAttributeValue, out percents : SAbilityAttributeValue) + { + var mult : float; + var null : SAbilityAttributeValue; + + points = null; + percents = null; + if(!IsItemAnyArmor(itemId)) + return; + + mult = theGame.params.GetDurabilityMultiplier(GetItemDurabilityRatio(itemId), false); + + points = GetItemAttributeValue(itemId, ResistStatEnumToName(stat, true)); + percents = GetItemAttributeValue(itemId, ResistStatEnumToName(stat, false)); + + points = points * mult; + percents = percents * mult; + } + + + public function GetItemResistanceTypes(id : SItemUniqueId) : array + { + var ret : array; + var i : int; + var stat : ECharacterDefenseStats; + var atts : array; + var tmpBool : bool; + + if(!IsIdValid(id)) + return ret; + + GetItemAttributes(id, atts); + for(i=0; i; + var card : array; + var iHave, shopHave, cardLimit, delta : int; + var curItem : SItemUniqueId; + var i : int; + + allItems = GetItemsByCategory('gwint'); + for(i=allItems.Size()-1; i >= 0; i-=1) + { + curItem = allItems[i]; + + attr = GetItemAttributeValue( curItem, 'max_count'); + card = thePlayer.GetInventory().GetItemsByName( GetItemName( curItem ) ); + iHave = thePlayer.GetInventory().GetItemQuantity( card[0] ); + cardLimit = RoundF(attr.valueBase); + shopHave = GetItemQuantity( curItem ); + + if (iHave > 0 && shopHave > 0) + { + delta = shopHave - (cardLimit - iHave); + + if ( delta > 0 ) + { + RemoveItem( curItem, delta ); + } + } + } + } + + function ClearTHmaps() + { + var attr : SAbilityAttributeValue; + var allItems : array; + var map : array; + var i : int; + var thCompleted : bool; + var iHave, shopHave : int; + + allItems = GetItemsByTag('ThMap'); + for(i=allItems.Size()-1; i >= 0; i-=1) + { + attr = GetItemAttributeValue( allItems[i], 'max_count'); + map = thePlayer.GetInventory().GetItemsByName( GetItemName( allItems[i] ) ); + thCompleted = FactsDoesExist(GetItemName(allItems[i])); + iHave = thePlayer.GetInventory().GetItemQuantity( map[0] ); + shopHave = RoundF(attr.valueBase); + + if ( iHave >= shopHave || thCompleted ) + { + RemoveItem( allItems[i], GetItemQuantity( allItems[i] ) ); + } + } + } + + + public final function ClearKnownRecipes() + { + var witcher : W3PlayerWitcher; + var recipes, craftRecipes : array; + var i : int; + var itemName : name; + var allItems : array; + + witcher = GetWitcherPlayer(); + if(!witcher) + return; + + + recipes = witcher.GetAlchemyRecipes(); + craftRecipes = witcher.GetCraftingSchematicsNames(); + ArrayOfNamesAppend(recipes, craftRecipes); + + + GetAllItems(allItems); + + + for(i=allItems.Size()-1; i>=0; i-=1) + { + itemName = GetItemName(allItems[i]); + if(recipes.Contains(itemName)) + RemoveItem(allItems[i], GetItemQuantity(allItems[i])); + } + } + + + + + + function LoadBooksDefinitions() : void + { + var readableArray : array; + var i : int; + + readableArray = GetItemsByTag('ReadableItem'); + + for( i = 0; i < readableArray.Size(); i += 1 ) + { + if( IsBookRead(readableArray[i])) + { + continue; + } + UpdateInitialReadState(readableArray[i]); + } + } + + function UpdateInitialReadState( item : SItemUniqueId ) + { + var abilitiesArray : array; + var i : int; + GetItemAbilities(item,abilitiesArray); + + for( i = 0; i < abilitiesArray.Size(); i += 1 ) + { + if( abilitiesArray[i] == 'WasRead' ) + { + ReadBook(item); + break; + } + } + } + + function IsBookRead( item : SItemUniqueId ) : bool + { + var bookName : name; + var bResult : bool; + + bookName = GetItemName( item ); + + bResult = IsBookReadByName( bookName ); + return bResult; + } + + function IsBookReadByName( bookName : name ) : bool + { + var bookFactName : string; + + bookFactName = GetBookReadFactName( bookName ); + if( FactsDoesExist(bookFactName) ) + { + return FactsQuerySum( bookFactName ); + } + + return false; + } + + function ReadBook( item : SItemUniqueId, optional noNotification : bool ) + { + + var bookName : name; + var abilitiesArray : array; + var i : int; + var commonMapManager : CCommonMapManager = theGame.GetCommonMapManager(); + + bookName = GetItemName( item ); + + if ( !IsBookRead ( item ) && ItemHasTag ( item, 'FastTravel' )) + { + GetItemAbilities(item, abilitiesArray); + + for ( i = 0; i < abilitiesArray.Size(); i+=1 ) + { + commonMapManager.SetEntityMapPinDiscoveredScript(true, abilitiesArray[i], true ); + } + } + ReadBookByNameId( bookName, item, false, noNotification ); + + + + + if(ItemHasTag(item, 'PerkBook')) + { + + } + } + + public function GetBookText(item : SItemUniqueId) : string + { + // modStatTrak BEGIN + if ( GetItemName( item ) != 'Gwent Almanac' && GetItemName( item ) != 'Achievement Stats' ) + { + return ReplaceTagsToIcons(GetLocStringByKeyExt(GetItemLocalizedNameByUniqueID(item)+"_text")); + } + else if ( GetItemName( item ) == 'Gwent Almanac' ) + { + return GetGwentAlmanacContents(); + } + else + { + return getFormattedAchievementStats(getAchievementStats()); + } + // modStatTrak END + } + + public function GetBookTextByName( bookName : name ) : string + { + // modStatTrak BEGIN + if( bookName != 'Gwent Almanac' && bookName != 'Achievement Stats' ) + { + return ReplaceTagsToIcons( GetLocStringByKeyExt( GetItemLocalizedNameByName( bookName ) + "_text" ) ); + } + else if ( bookName == 'Gwent Almanac' ) + { + return GetGwentAlmanacContents(); + } + else + { + return getFormattedAchievementStats(getAchievementStats()); + } + // modStatTrak END + } + + function ReadSchematicsAndRecipes( item : SItemUniqueId ) + { + var itemCategory : name; + var itemName : name; + var player : W3PlayerWitcher; + + ReadBook( item ); + + player = GetWitcherPlayer(); + if ( !player ) + { + return; + } + + itemName = GetItemName( item ); + itemCategory = GetItemCategory( item ); + if ( itemCategory == 'alchemy_recipe' ) + { + if ( player.CanLearnAlchemyRecipe( itemName ) ) + { + player.AddAlchemyRecipe( itemName ); + player.GetInventory().AddItemTag(item, 'NoShow'); + + } + } + else if ( itemCategory == 'crafting_schematic' ) + { + player.AddCraftingSchematic( itemName ); + player.GetInventory().AddItemTag(item, 'NoShow'); + + } + } + + function ReadBookByName( bookName : name , unread : bool, optional noNotification : bool ) + { + var defMgr : CDefinitionsManagerAccessor; + var bookFactName : string; + + if( IsBookReadByName( bookName ) != unread ) + { + return; + } + + bookFactName = "BookReadState_"+bookName; + bookFactName = StrReplace(bookFactName," ","_"); + + if( unread ) + { + FactsSubstract( bookFactName, 1 ); + } + else + { + FactsAdd( bookFactName, 1 ); + + + defMgr = theGame.GetDefinitionsManager(); + if(!IsAlchemyRecipe(bookName) && !IsCraftingSchematic(bookName) && !defMgr.ItemHasTag( bookName, 'Painting' ) ) + { + theGame.GetGamerProfile().IncStat(ES_ReadBooks); + + if( !noNotification ) + { + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "notification_book_moved" ), 0, false ); + } + } + + + if ( AddBestiaryFromBook(bookName) ) + return; + + + + } + } + + function ReadBookByNameId( bookName : name, itemId:SItemUniqueId, unread : bool, optional noNotification : bool ) + { + var bookFactName : string; + + if( IsBookReadByName( bookName ) != unread ) + { + return; + } + + bookFactName = "BookReadState_"+bookName; + bookFactName = StrReplace(bookFactName," ","_"); + + if( unread ) + { + FactsSubstract( bookFactName, 1 ); + } + else + { + FactsAdd( bookFactName, 1 ); + + + if( !IsAlchemyRecipe( bookName ) && !IsCraftingSchematic( bookName ) ) + { + theGame.GetGamerProfile().IncStat(ES_ReadBooks); + + if( !noNotification ) + { + + GetWitcherPlayer().AddReadBook( bookName ); + } + } + + + if ( AddBestiaryFromBook(bookName) ) + return; + else + ReadSchematicsAndRecipes( itemId ); + } + } + + + private function AddBestiaryFromBook( bookName : name ) : bool + { + var i, j, r, len : int; + var manager : CWitcherJournalManager; + var resource : array; + var entryBase : CJournalBase; + var childGroups : array; + var childEntries : array; + var descriptionGroup : CJournalCreatureDescriptionGroup; + var descriptionEntry : CJournalCreatureDescriptionEntry; + + manager = theGame.GetJournalManager(); + + switch ( bookName ) + { + case 'Beasts vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWolf" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryDog" ) ); + break; + case 'Beasts vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBear" ) ); + break; + case 'Cursed Monsters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWerewolf" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryLycanthrope" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 24'); + break; + case 'Cursed Monsters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWerebear" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryMiscreant" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 11'); + break; + case 'Draconides vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCockatrice" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBasilisk" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 3'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 23'); + break; + case 'Draconides vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWyvern" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryForktail" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 10'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 17'); + break; + case 'Hybrid Monsters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryHarpy" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryErynia" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiarySiren" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiarySuccubus" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 14'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 21'); + break; + case 'Hybrid Monsters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGriffin" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 4'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 27'); + break; + case 'Insectoids vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryEndriagaWorker" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryEndriagaTruten" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryEndriaga" ) ); + break; + case 'Insectoids vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCrabSpider" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryArmoredArachas" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryPoisonousArachas" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 2'); + break; + case 'Magical Monsters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGolem" ) ); + break; + case 'Magical Monsters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryElemental" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryIceGolem" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryFireElemental" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWhMinion" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 20'); + break; + case 'Necrophage vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGhoul" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryAlghoul" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGreaterRotFiend" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryDrowner" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 15'); + break; + case 'Necrophage vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGraveHag" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWaterHag" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryFogling" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 5'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 9'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 18'); + break; + case 'Relict Monsters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBies" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCzart" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 8'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 16'); + break; + case 'Relict Monsters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryLeshy" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiarySilvan" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 22'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 26'); + break; + case 'Specters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryMoonwright" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryNoonwright" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryPesta" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 6'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 13'); + break; + case 'Specters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWraith" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryHim" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 19'); + break; + case 'Ogres vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryNekker" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryIceTroll" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCaveTroll" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 12'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 25'); + break; + case 'Ogres vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCyclop" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryIceGiant" ) ); + break; + case 'Vampires vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryEkkima" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryHigherVampire" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 7'); + break; + case 'Vampires vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryKatakan" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 1'); + break; + + case 'bestiary_sharley_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiarySharley" ) ); + break; + case 'bestiary_barghest_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBarghest" ) ); + break; + case 'bestiary_garkain_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGarkain" ) ); + break; + case 'bestiary_alp_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryAlp" ) ); + break; + case 'bestiary_bruxa_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBruxa" ) ); + break; + case 'bestiary_spriggan_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiarySpriggan" ) ); + break; + case 'bestiary_fleder_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryFleder" ) ); + break; + case 'bestiary_wight_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWicht" ) ); + break; + case 'bestiary_dracolizard_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryDracolizard" ) ); + break; + case 'bestiary_panther_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryPanther" ) ); + break; + case 'bestiary_kikimore_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryKikimoraWarrior" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryKikimoraWorker" ) ); + break; + case 'bestiary_scolopendromorph_book': + case 'mq7023_fluff_book_scolopendromorphs': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryScolopendromorph" ) ); + break; + case 'bestiary_archespore_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryArchespore" ) ); + break; + case 'bestiary_protofleder_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryProtofleder" ) ); + break; + default: + return false; + } + + + + + len = resource.Size(); + if( len > 0) + { + + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "panel_hud_journal_entry_bestiary_new" ), 0, true ); + theSound.SoundEvent("gui_ingame_new_journal"); + } + + for (r=0; r < len; r += 1 ) + { + if ( !resource[ r ] ) + { + + continue; + } + entryBase = resource[r].GetEntry(); + if ( entryBase ) + { + manager.ActivateEntry( entryBase, JS_Active ); + manager.SetEntryHasAdvancedInfo( entryBase, true ); + + + manager.GetAllChildren( entryBase, childGroups ); + for ( i = 0; i < childGroups.Size(); i += 1 ) + { + descriptionGroup = ( CJournalCreatureDescriptionGroup )childGroups[ i ]; + if ( descriptionGroup ) + { + manager.GetAllChildren( descriptionGroup, childEntries ); + for ( j = 0; j < childEntries.Size(); j += 1 ) + { + descriptionEntry = ( CJournalCreatureDescriptionEntry )childEntries[ j ]; + if ( descriptionEntry ) + { + manager.ActivateEntry( descriptionEntry, JS_Active ); + } + } + break; + } + } + } + } + + if ( resource.Size() > 0 ) + return true; + else + return false; + } + + + + + + + + + function GetWeaponDTNames( id : SItemUniqueId, out dmgNames : array< name > ) : int + { + var attrs : array< name >; + var i, size : int; + + dmgNames.Clear(); + + if( IsIdValid(id) ) + { + GetItemAttributes( id, attrs ); + size = attrs.Size(); + + for( i = 0; i < size; i += 1 ) + if( IsDamageTypeNameValid(attrs[i]) ) + dmgNames.PushBack( attrs[i] ); + + if(dmgNames.Size() == 0) + LogAssert(false, "CInventoryComponent.GetWeaponDTNames: weapon <<" + GetItemName(id) + ">> has no damage types defined!"); + } + return dmgNames.Size(); + } + + public function GetWeapons() : array + { + var ids, ids2 : array; + + ids = GetItemsByCategory('monster_weapon'); + ids2 = GetItemsByTag('Weapon'); + ArrayOfIdsAppend(ids, ids2); + + return ids; + } + + public function GetHeldWeapons() : array + { + var i : int; + var w : array; + + w = GetWeapons(); + + for(i=w.Size()-1; i>=0; i-=1) + { + if(!IsItemHeld(w[i])) + { + w.EraseFast( i ); + } + } + + return w; + } + + public function GetCurrentlyHeldSword() : SItemUniqueId + { + var i : int; + var w : array; + + w = GetHeldWeapons(); + + for( i = 0 ; i < w.Size() ; i+=1 ) + { + if( IsItemSteelSwordUsableByPlayer( w[i] ) || IsItemSilverSwordUsableByPlayer( w[i] ) ) + { + return w[i]; + } + } + + return GetInvalidUniqueId(); + } + + public function GetCurrentlyHeldSwordEntity( out ent : CItemEntity ) : bool + { + var id : SItemUniqueId; + + id = GetCurrentlyHeldSword(); + + if( IsIdValid( id ) ) + { + ent = GetItemEntityUnsafe( id ); + + if( ent ) + { + return true; + } + else + { + return false; + } + } + return false; + } + + public function GetHeldWeaponsWithCategory( category : name, out items : array ) + { + var i : int; + + items = GetItemsByCategory( category ); + + for ( i = items.Size()-1; i >= 0; i -= 1) + { + if ( !IsItemHeld( items[i] ) ) + { + items.EraseFast( i ); + } + } + } + + public function GetPotionItemBuffData(id : SItemUniqueId, out type : EEffectType, out customAbilityName : name) : bool + { + var size, i : int; + var arr : array; + + if(IsIdValid(id)) + { + GetItemContainedAbilities( id, arr ); + size = arr.Size(); + + for( i = 0; i < size; i += 1 ) + { + if( IsEffectNameValid(arr[i]) ) + { + EffectNameToType(arr[i], type, customAbilityName); + return true; + } + } + } + + return false; + } + + + public function RecycleItem( id : SItemUniqueId, level : ECraftsmanLevel ) : array + { + var itemsAdded : array; + var currentAdded : array; + + var parts : array; + var i : int; + + parts = GetItemRecyclingParts( id ); + + for ( i = 0; i < parts.Size(); i += 1 ) + { + if ( ECL_Grand_Master == level || ECL_Arch_Master == level ) + { + currentAdded = AddAnItem( parts[i].itemName, parts[i].quantity ); + } + else if ( ECL_Master == level && parts[i].quantity > 1 ) + { + currentAdded = AddAnItem( parts[i].itemName, RandRange( parts[i].quantity, 1 ) ); + } + else + { + currentAdded = AddAnItem( parts[i].itemName, 1 ); + } + itemsAdded.PushBack(currentAdded[0]); + } + + RemoveItem(id); + + return itemsAdded; + } + + + + + + + public function GetItemBuffs( id : SItemUniqueId, out buffs : array) : int + { + var attrs, abs, absFast : array< name >; + var i, k : int; + var type : EEffectType; + var abilityName : name; + var buff : SEffectInfo; + var dm : CDefinitionsManagerAccessor; + + buffs.Clear(); + + if( !IsIdValid(id) ) + return 0; + + + GetItemContainedAbilities(id, absFast); + if(absFast.Size() == 0) + return 0; + + GetItemAbilities(id, abs); + dm = theGame.GetDefinitionsManager(); + for(k=0; k; + var i : int; + var owner : CActor; + var bag : W3ActorRemains; + var template : CEntityTemplate; + var bagtags : array ; + var bagPosition : Vector; + var tracedPosition, tracedNormal : Vector; + + if(ItemHasTag(item, 'NoDrop')) + return; + + owner = (CActor)GetEntity(); + FindGameplayEntitiesInRange(entities, owner, 0.5, 100); + + for(i=0; i; + + + if(buffArmor) + { + items = GetItemsByTag(theGame.params.TAG_ARMOR); + } + if(buffSwords) + { + items2 = GetItemsByTag(theGame.params.TAG_PLAYER_STEELSWORD); + ArrayOfIdsAppend(items, items2); + items2.Clear(); + items2 = GetItemsByTag(theGame.params.TAG_PLAYER_SILVERSWORD); + ArrayOfIdsAppend(items, items2); + } + + upgradedSomething = false; + + for(i=0; i currAmmo) + { + SetItemModifierInt(items[i], 'repairObjectBonusAmmo', ammo); + upgradedSomething = true; + + + if(currAmmo == 0) + { + if(isArmor) + AddItemCraftedAbility(items[i], theGame.params.REPAIR_OBJECT_BONUS_ARMOR_ABILITY, false); + else + AddItemCraftedAbility(items[i], theGame.params.REPAIR_OBJECT_BONUS_WEAPON_ABILITY, false); + } + } + } + + return upgradedSomething; + } + + public final function ReduceItemRepairObjectBonusCharge(item : SItemUniqueId) + { + var currAmmo : int; + + currAmmo = GetItemModifierInt(item, 'repairObjectBonusAmmo', 0); + + if(currAmmo > 0) + { + SetItemModifierInt(item, 'repairObjectBonusAmmo', currAmmo - 1); + + if(currAmmo == 1) + { + if(IsItemAnyArmor(item)) + RemoveItemCraftedAbility(item, theGame.params.REPAIR_OBJECT_BONUS_ARMOR_ABILITY); + else + RemoveItemCraftedAbility(item, theGame.params.REPAIR_OBJECT_BONUS_WEAPON_ABILITY); + } + } + } + + + public final function GetRepairObjectBonusValueForArmor(armor : SItemUniqueId) : SAbilityAttributeValue + { + var retVal, bonusValue, baseArmor : SAbilityAttributeValue; + + if(GetItemModifierInt(armor, 'repairObjectBonusAmmo', 0) > 0) + { + bonusValue = GetItemAttributeValue(armor, theGame.params.REPAIR_OBJECT_BONUS); + baseArmor = GetItemAttributeValue(armor, theGame.params.ARMOR_VALUE_NAME); + + baseArmor.valueMultiplicative += 1; + retVal.valueAdditive = bonusValue.valueAdditive + CalculateAttributeValue(baseArmor) * bonusValue.valueMultiplicative; + } + + return retVal; + } + + + + + + + public function CanItemHaveOil(id : SItemUniqueId) : bool + { + return IsItemSteelSwordUsableByPlayer(id) || IsItemSilverSwordUsableByPlayer(id); + } + + public final function RemoveAllOilsFromItem( id : SItemUniqueId ) + { + var i : int; + var oils : array< W3Effect_Oil >; + var actor : CActor; + + actor = ( CActor ) GetEntity(); + oils = GetOilsAppliedOnItem( id ); + for( i = oils.Size() - 1; i >= 0; i -= 1 ) + { + actor.RemoveEffect( oils[ i ] ); + } + } + + public final function GetActiveOilsAppliedOnItemCount( id : SItemUniqueId ) : int + { + var oils : array< W3Effect_Oil >; + var i, count : int; + + count = 0; + oils = GetOilsAppliedOnItem( id ); + for( i=0; i 0 ) + { + count += 1; + } + } + return count; + } + + public final function RemoveOldestOilFromItem( id : SItemUniqueId ) + { + var buffToRemove : W3Effect_Oil; + var actor : CActor; + + actor = ( CActor ) GetEntity(); + if(! actor ) + return; + + buffToRemove = GetOldestOilAppliedOnItem(id, false); + + if(buffToRemove) + { + actor.RemoveEffect( buffToRemove ); + } + } + + public final function GetOilsAppliedOnItem( id : SItemUniqueId ) : array< W3Effect_Oil > + { + var i : int; + var oils : array< CBaseGameplayEffect >; + var buff : W3Effect_Oil; + var ret : array < W3Effect_Oil >; + var actor : CActor; + + actor = ( CActor ) GetEntity(); + if(! actor ) + return ret; + + oils = actor.GetBuffs( EET_Oil ); + for( i = oils.Size() - 1; i >= 0; i -= 1 ) + { + buff = ( W3Effect_Oil ) oils[ i ]; + if(buff && buff.GetSwordItemId() == id ) + { + ret.PushBack( buff ); + } + } + + return ret; + } + + public final function GetNewestOilAppliedOnItem( id : SItemUniqueId, onlyShowable : bool ) : W3Effect_Oil + { + return GetOilAppliedOnItemInternal( id, onlyShowable, true ); + } + + public final function GetOldestOilAppliedOnItem( id : SItemUniqueId, onlyShowable : bool ) : W3Effect_Oil + { + return GetOilAppliedOnItemInternal( id, onlyShowable, false ); + } + + private final function GetOilAppliedOnItemInternal( id : SItemUniqueId, onlyShowable : bool, newest : bool ) : W3Effect_Oil + { + var oils : array< W3Effect_Oil >; + var i, lastIndex : int; + + oils = GetOilsAppliedOnItem( id ); + lastIndex = -1; + + for( i=0; i oils[lastIndex].GetQueueTimer() ) + { + lastIndex = i; + } + } + + if( lastIndex == -1 ) + { + return NULL; + } + + return oils[lastIndex]; + } + + public final function ItemHasAnyActiveOilApplied( id : SItemUniqueId ) : bool + { + return GetActiveOilsAppliedOnItemCount( id ); + } + + public final function ItemHasActiveOilApplied( id : SItemUniqueId, monsterCategory : EMonsterCategory ) : bool + { + var i : int; + var oils : array< W3Effect_Oil >; + + oils = GetOilsAppliedOnItem( id ); + for( i=0; i 0 ) + { + return true; + } + } + + return false; + } + + + + + + public final function GetParamsForRunewordTooltip(runewordName : name, out i : array, out f : array, out s : array) + { + var min, max : SAbilityAttributeValue; + var val : float; + var attackRangeBase, attackRangeExt : CAIAttackRange; + + i.Clear(); + f.Clear(); + s.Clear(); + + switch(runewordName) + { + case 'Glyphword 5': + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 5 _Stats', 'glyphword5_chance', min, max); + i.PushBack( RoundMath( CalculateAttributeValue(min) * 100) ); + break; + case 'Glyphword 6' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 6 _Stats', 'glyphword6_stamina_drain_perc', min, max); + i.PushBack( RoundMath( CalculateAttributeValue(min) * 100) ); + break; + case 'Glyphword 12' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 12 _Stats', 'glyphword12_range', min, max); + val = CalculateAttributeValue(min); + s.PushBack( NoTrailZeros(val) ); + + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 12 _Stats', 'glyphword12_chance', min, max); + i.PushBack( RoundMath( min.valueAdditive * 100) ); + break; + case 'Glyphword 17' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 17 _Stats', 'quen_apply_chance', min, max); + val = CalculateAttributeValue(min); + i.PushBack( RoundMath(val * 100) ); + break; + case 'Glyphword 14' : + case 'Glyphword 18' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 18 _Stats', 'increas_duration', min, max); + val = CalculateAttributeValue(min); + s.PushBack( NoTrailZeros(val) ); + break; + + case 'Runeword 2' : + attackRangeBase = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'specialattacklight'); + attackRangeExt = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'runeword2_light'); + s.PushBack( NoTrailZeros(attackRangeExt.rangeMax - attackRangeBase.rangeMax) ); + + attackRangeBase = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'slash_long'); + attackRangeExt = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'runeword2_heavy'); + s.PushBack( NoTrailZeros(attackRangeExt.rangeMax - attackRangeBase.rangeMax) ); + + break; + case 'Runeword 4' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Runeword 4 _Stats', 'max_bonus', min, max); + i.PushBack( RoundMath(max.valueMultiplicative * 100) ); + break; + case 'Runeword 6' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 6 _Stats', 'runeword6_duration_bonus', min, max ); + i.PushBack( RoundMath(min.valueMultiplicative * 100) ); + break; + case 'Runeword 7' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 7 _Stats', 'stamina', min, max ); + i.PushBack( RoundMath(min.valueMultiplicative * 100) ); + break; + case 'Runeword 10' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 10 _Stats', 'stamina', min, max ); + i.PushBack( RoundMath(min.valueMultiplicative * 100) ); + break; + case 'Runeword 11' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 11 _Stats', 'duration', min, max ); + s.PushBack( NoTrailZeros(min.valueAdditive) ); + break; + case 'Runeword 12' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 12 _Stats', 'focus', min, max ); + f.PushBack(min.valueAdditive); + f.PushBack(max.valueAdditive); + break; + default: + break; + } + } + + public final function GetPotionAttributesForTooltip(potionId : SItemUniqueId, out tips : array):void + { + var i, j, settingsSize : int; + var buffType : EEffectType; + var abilityName : name; + var abs, attrs : array; + var val : SAbilityAttributeValue; + var newAttr : SAttributeTooltip; + var attributeString : string; + + + if(!( IsItemPotion(potionId) || IsItemFood(potionId) ) ) + return; + + + GetItemContainedAbilities(potionId, abs); + for(i=0; i, out localizedFluff : string) + { + if( !IsIdValid(itemId) ) + { + return; + } + localizedName = GetItemLocalizedNameByUniqueID(itemId); + localizedDescription = GetItemLocalizedDescriptionByUniqueID(itemId); + localizedFluff = "IMPLEMENT ME - fluff text"; + price = GetItemPriceModified( itemId, false ); + localizedCategory = GetItemCategoryLocalisedString(GetItemCategory(itemId)); + GetItemStats(itemId, itemStats); + } + + + public function GetItemBaseStats(itemId : SItemUniqueId, out itemStats : array) + { + var attributes : array; + + var dm : CDefinitionsManagerAccessor; + var oilAbilities, oilAttributes : array; + var weights : array; + var i, j : int; + var tmpI, tmpJ : int; + + var idx : int; + var oilStatsCount : int; + var oilName : name; + var oilStats : array; + var oilStatFirst : SAttributeTooltip; + var oils : array< W3Effect_Oil >; + + GetItemBaseAttributes(itemId, attributes); + + + oils = GetOilsAppliedOnItem( itemId ); + dm = theGame.GetDefinitionsManager(); + for( i=0; i) + { + var attributes : array; + + GetItemAttributes(itemId, attributes); + GetItemTooltipAttributes(itemId, attributes, itemStats); + } + + private function GetItemTooltipAttributes(itemId : SItemUniqueId, attributes : array, out itemStats : array):void + { + var itemCategory:name; + var i, j, settingsSize : int; + var attributeString : string; + var attributeColor : string; + var attributeName : name; + var isPercentageValue : string; + var primaryStatLabel : string; + var statLabel : string; + + var stat : SAttributeTooltip; + var attributeVal : SAbilityAttributeValue; + + settingsSize = theGame.tooltipSettings.GetNumRows(); + itemStats.Clear(); + itemCategory = GetItemCategory(itemId); + for(i=0; i) + { + var itemCategory : name; + var i, j, settingsSize : int; + var attributeString : string; + var attributeColor : string; + var attributeName : name; + var isPercentageValue : string; + var attributes, itemAbilities, tmpArray : array; + var weights : array; + var stat : SAttributeTooltip; + var attributeVal, min, max : SAbilityAttributeValue; + var dm : CDefinitionsManagerAccessor; + var primaryStatLabel : string; + var statLabel : string; + + settingsSize = theGame.tooltipSettings.GetNumRows(); + dm = theGame.GetDefinitionsManager(); + dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, weights, i, j); + attributes = dm.GetAbilitiesAttributes(itemAbilities); + + itemStats.Clear(); + itemCategory = dm.GetItemCategory(itemName); + for(i=0; i ) : bool + { + var i : int; + var currItemName : name; + + currItemName = GetItemName( itemID ); + + for ( i = 0; i < excludedItems.Size(); i+=1 ) + { + if ( currItemName == excludedItems[i].itemName ) + { + return true; + } + } + return false; + } + + + public function GetItemPrimaryStat(itemId : SItemUniqueId, out attributeLabel : string, out attributeVal : float ) : void + { + var attributeName : name; + var attributeValue:SAbilityAttributeValue; + + GetItemPrimaryStatImplById(itemId, attributeLabel, attributeVal, attributeName); + + attributeValue = GetItemAttributeValue(itemId, attributeName); + + if(attributeValue.valueBase != 0) + { + attributeVal = attributeValue.valueBase; + } + if(attributeValue.valueMultiplicative != 0) + { + attributeVal = attributeValue.valueMultiplicative; + } + if(attributeValue.valueAdditive != 0) + { + attributeVal = attributeValue.valueAdditive; + } + } + + public function GetItemStatByName(itemName : name, statName : name, out resultValue : float) : void + { + var dm : CDefinitionsManagerAccessor; + var attributes, itemAbilities : array; + var min, max, attributeValue : SAbilityAttributeValue; + var tmpInt : int; + var tmpArray : array; + + dm = theGame.GetDefinitionsManager(); + dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, tmpArray, tmpInt, tmpInt); + attributes = dm.GetAbilitiesAttributes(itemAbilities); + + dm.GetAbilitiesAttributeValue(itemAbilities, statName, min, max); + attributeValue = GetAttributeRandomizedValue(min, max); + + if(attributeValue.valueBase != 0) + { + resultValue = attributeValue.valueBase; + } + if(attributeValue.valueMultiplicative != 0) + { + resultValue = attributeValue.valueMultiplicative; + } + if(attributeValue.valueAdditive != 0) + { + resultValue = attributeValue.valueAdditive; + } + } + + public function GetItemPrimaryStatFromName(itemName : name, out attributeLabel : string, out attributeVal : float, out primAttrName : name) : void + { + var dm : CDefinitionsManagerAccessor; + var attributeName : name; + var attributes, itemAbilities : array; + var attributeValue, min, max : SAbilityAttributeValue; + + var tmpInt : int; + var tmpArray : array; + + dm = theGame.GetDefinitionsManager(); + + GetItemPrimaryStatImpl(dm.GetItemCategory(itemName), attributeLabel, attributeVal, attributeName); + dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, tmpArray, tmpInt, tmpInt); + attributes = dm.GetAbilitiesAttributes(itemAbilities); + for (tmpInt = 0; tmpInt < attributes.Size(); tmpInt += 1) + if (attributes[tmpInt] == attributeName) + { + dm.GetAbilitiesAttributeValue(itemAbilities, attributeName, min, max); + attributeValue = GetAttributeRandomizedValue(min, max); + primAttrName = attributeName; + break; + } + + if(attributeValue.valueBase != 0) + { + attributeVal = attributeValue.valueBase; + } + if(attributeValue.valueMultiplicative != 0) + { + attributeVal = attributeValue.valueMultiplicative; + } + if(attributeValue.valueAdditive != 0) + { + attributeVal = attributeValue.valueAdditive; + } + + } + + public function IsPrimaryStatById(itemId : SItemUniqueId, attributeName : name, out attributeLabel : string) : bool + { + var attrValue : float; + var attrName : name; + + GetItemPrimaryStatImplById(itemId, attributeLabel, attrValue, attrName); + return attrName == attributeName; + } + + private function GetItemPrimaryStatImplById(itemId : SItemUniqueId, out attributeLabel : string, out attributeVal : float, out attributeName : name ) : void + { + var itemOnSlot : SItemUniqueId; + var categoryName : name; + var abList : array; + + attributeName = ''; + attributeLabel = ""; + categoryName = GetItemCategory(itemId); + + + if (categoryName == 'bolt' || categoryName == 'petard') + { + GetItemAttributes(itemId, abList); + if (abList.Contains('FireDamage')) + { + attributeName = 'FireDamage'; + } + else if (abList.Contains('PiercingDamage')) + { + attributeName = 'PiercingDamage'; + } + else if (abList.Contains('PiercingDamage')) + { + attributeName = 'PiercingDamage'; + } + else if (abList.Contains('PoisonDamage')) + { + attributeName = 'PoisonDamage'; + } + else if (abList.Contains('BludgeoningDamage')) + { + attributeName = 'BludgeoningDamage'; + } + else + { + attributeName = 'PhysicalDamage'; + } + attributeLabel = GetAttributeNameLocStr(attributeName, false); + } + else if (categoryName == 'secondary') + { + GetItemAttributes(itemId, abList); + if (abList.Contains('BludgeoningDamage')) + { + attributeName = 'BludgeoningDamage'; + } + else + { + attributeName = 'PhysicalDamage'; + } + attributeLabel = GetAttributeNameLocStr(attributeName, false); + } + else if (categoryName == 'steelsword') + { + GetItemAttributes(itemId, abList); + if (abList.Contains('SlashingDamage')) + { + attributeName = 'SlashingDamage'; + attributeLabel = GetLocStringByKeyExt("panel_inventory_tooltip_damage"); + } + else if (abList.Contains('BludgeoningDamage')) + { + attributeName = 'BludgeoningDamage'; + } + else if (abList.Contains('PiercingDamage')) + { + attributeName = 'PiercingDamage'; + } + else + { + attributeName = 'PhysicalDamage'; + } + if (attributeLabel == "") + { + attributeLabel = GetAttributeNameLocStr(attributeName, false); + } + } + else + { + GetItemPrimaryStatImpl(categoryName, attributeLabel, attributeVal, attributeName); + } + } + + public function IsPrimaryStat(categoryName : name, attributeName : name, out attributeLabel : string) : bool + { + var attrValue : float; + var attrName : name; + + GetItemPrimaryStatImpl(categoryName, attributeLabel, attrValue, attrName); + return attrName == attributeName; + } + + private function GetItemPrimaryStatImpl(categoryName : name, out attributeLabel : string, out attributeVal : float, out attributeName : name ) : void + { + attributeName = ''; + attributeLabel = ""; + switch (categoryName) + { + case 'steelsword': + attributeName = 'SlashingDamage'; + attributeLabel = GetLocStringByKeyExt("panel_inventory_tooltip_damage"); + break; + case 'silversword': + attributeName = 'SilverDamage'; + attributeLabel = GetLocStringByKeyExt("panel_inventory_tooltip_damage"); + break; + case 'armor': + case 'gloves': + case 'gloves': + case 'boots': + case 'pants': + attributeName = 'armor'; + break; + case 'potion': + case 'oil': + + break; + case 'bolt': + case 'petard': + attributeName = 'PhysicalDamage'; + break; + case 'crossbow': + default: + attributeLabel = ""; + attributeVal = 0; + return; + break; + } + + if (attributeLabel == "") + { + attributeLabel = GetAttributeNameLocStr(attributeName, false); + } + } + + public function CanBeCompared(itemId : SItemUniqueId) : bool + { + var wplayer : W3PlayerWitcher; + var itemSlot : EEquipmentSlots; + var equipedItem : SItemUniqueId; + var horseManager : W3HorseManager; + + var isArmorOrWeapon : bool; + + if (IsItemHorseItem(itemId)) + { + horseManager = GetWitcherPlayer().GetHorseManager(); + + if (!horseManager) + { + return false; + } + + if (horseManager.IsItemEquipped(itemId)) + { + return false; + } + + itemSlot = GetHorseSlotForItem(itemId); + equipedItem = horseManager.GetItemInSlot(itemSlot); + if (!horseManager.GetInventoryComponent().IsIdValid(equipedItem)) + { + return false; + } + } + else + { + isArmorOrWeapon = IsItemAnyArmor(itemId) || IsItemWeapon(itemId); + if (!isArmorOrWeapon) + { + return false; + } + + wplayer = GetWitcherPlayer(); + if (wplayer.IsItemEquipped(itemId)) + { + return false; + } + + itemSlot = GetSlotForItemId(itemId); + wplayer.GetItemEquippedOnSlot(itemSlot, equipedItem); + if (!wplayer.inv.IsIdValid(equipedItem)) + { + return false; + } + } + + return true; + } + + public function GetHorseSlotForItem(id : SItemUniqueId) : EEquipmentSlots + { + var tags : array; + + GetItemTags(id, tags); + + if(tags.Contains('Saddle')) return EES_HorseSaddle; + else if(tags.Contains('HorseBag')) return EES_HorseBag; + else if(tags.Contains('Trophy')) return EES_HorseTrophy; + else if(tags.Contains('Blinders')) return EES_HorseBlinders; + else return EES_InvalidSlot; + } + + + + + + public final function SingletonItemRefillAmmo( id : SItemUniqueId, optional alchemyTableUsed : bool ) + { + var l_bed : W3WitcherBed; + var refilledByBed : bool; + + refilledByBed = false; + + + if( FactsQuerySum( "PlayerInsideOuterWitcherHouse" ) >= 1 && FactsQuerySum( "AlchemyTableExists" ) >= 1 && !IsItemMutagenPotion( id ) ) + { + l_bed = (W3WitcherBed)theGame.GetEntityByTag( 'witcherBed' ); + + if( l_bed.GetWasUsed() || alchemyTableUsed ) + { + SetItemModifierInt( id, 'ammo_current', SingletonItemGetMaxAmmo(id) + theGame.params.QUANTITY_INCREASED_BY_ALCHEMY_TABLE ) ; + refilledByBed = true; + if( !l_bed.GetWereItemsRefilled() ) + { + l_bed.SetWereItemsRefilled( true ); + } + } + } + + + if( !refilledByBed && SingletonItemGetAmmo( id ) < SingletonItemGetMaxAmmo( id ) ) + { + SetItemModifierInt(id, 'ammo_current', SingletonItemGetMaxAmmo(id)); + } + + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged ); + } + + public function SingletonItemSetAmmo(id : SItemUniqueId, quantity : int) + { + var amount : int; + + if(ItemHasTag(id, theGame.params.TAG_INFINITE_AMMO)) + { + amount = -1; + } + else + { + amount = Clamp(quantity, 0, SingletonItemGetMaxAmmo(id)); + } + + SetItemModifierInt(id, 'ammo_current', amount); + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged ); + } + + public function SingletonItemAddAmmo(id : SItemUniqueId, quantity : int) + { + var ammo : int; + + if(quantity <= 0) + return; + + ammo = GetItemModifierInt(id, 'ammo_current'); + + if(ammo == -1) + return; + + ammo = Clamp(ammo + quantity, 0, SingletonItemGetMaxAmmo(id)); + SetItemModifierInt(id, 'ammo_current', ammo); + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged ); + } + + public function SingletonItemsRefillAmmo( optional alchemyTableUsed : bool ) : bool + { + var i : int; + var singletonItems : array; + var alco : SItemUniqueId; + var arrStr : array; + var witcher : W3PlayerWitcher; + var itemLabel : string; + + witcher = GetWitcherPlayer(); + if(GetEntity() == witcher && HasNotFilledSingletonItem( alchemyTableUsed ) ) + { + alco = witcher.GetAlcoholForAlchemicalItemsRefill(); + + if(!IsIdValid(alco)) + { + + theGame.GetGuiManager().ShowNotification(GetLocStringByKeyExt("message_common_alchemy_items_cannot_refill")); + theSound.SoundEvent("gui_global_denied"); + + return false; + } + else + { + + arrStr.PushBack(GetItemName(alco)); + itemLabel = GetLocStringByKeyExt(GetItemLocalizedNameByUniqueID(alco)); + theGame.GetGuiManager().ShowNotification( itemLabel + " - " + GetLocStringByKeyExtWithParams("message_common_alchemy_items_refilled", , , arrStr)); + theSound.SoundEvent("gui_alchemy_brew"); + + if(!ItemHasTag(alco, theGame.params.TAG_INFINITE_USE)) + RemoveItem(alco); + } + } + + singletonItems = GetSingletonItems(); + for(i=0; i; + var alco : SItemUniqueId; + var arrStr : array; + var witcher : W3PlayerWitcher; + var itemLabel : string; + + witcher = GetWitcherPlayer(); + if(!dontUpdateUI && GetEntity() == witcher && HasNotFilledSingletonItem()) + { + + arrStr.PushBack(GetItemName(alco)); + itemLabel = GetLocStringByKeyExt(GetItemLocalizedNameByUniqueID(alco)); + theGame.GetGuiManager().ShowNotification( itemLabel + " - " + GetLocStringByKeyExtWithParams("message_common_alchemy_items_refilled", , , arrStr)); + theSound.SoundEvent("gui_alchemy_brew"); + } + + singletonItems = GetSingletonItems(); + for(i=0; i; + var hasLab : bool; + var l_bed : W3WitcherBed; + + + hasLab = false; + if( FactsQuerySum( "PlayerInsideOuterWitcherHouse" ) >= 1 && FactsQuerySum( "AlchemyTableExists" ) >= 1 ) + { + l_bed = (W3WitcherBed)theGame.GetEntityByTag( 'witcherBed' ); + if( l_bed.GetWasUsed() || alchemyTableUsed ) + { + hasLab = true; + } + } + + singletonItems = GetSingletonItems(); + for(i=0; i 0) + { + FactsAdd('tut_alch_refill', 1); + } + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged ); + } + + public function SingletonItemGetAmmo(itemID : SItemUniqueId) : int + { + if(!IsItemSingletonItem(itemID)) + return 0; + + return GetItemModifierInt(itemID, 'ammo_current'); + } + + public function SingletonItemGetMaxAmmo(itemID : SItemUniqueId) : int + { + var ammo, i : int; + var perk20Bonus, min, max : SAbilityAttributeValue; + var atts : array; + var canUseSkill : bool; + + ammo = RoundMath(CalculateAttributeValue(GetItemAttributeValue(itemID, 'ammo'))); + + if( !ItemHasTag( itemID, 'NoAdditionalAmmo' ) ) + { + if(GetEntity() == GetWitcherPlayer() && ammo > 0) + { + if(IsItemBomb(itemID) && thePlayer.CanUseSkill(S_Alchemy_s08) ) + { + ammo += thePlayer.GetSkillLevel(S_Alchemy_s08); + } + + if(thePlayer.HasBuff(EET_Mutagen03) && (IsItemBomb(itemID) || (!IsItemMutagenPotion(itemID) && IsItemPotion(itemID))) ) + { + ammo += 1; + } + + if( GetWitcherPlayer().IsSetBonusActive( EISB_RedWolf_2 ) && !IsItemMutagenPotion(itemID) ) + { + theGame.GetDefinitionsManager().GetAbilityAttributeValue( GetSetBonusAbility( EISB_RedWolf_2 ), 'amount', min, max); + ammo += (int)min.valueAdditive; + } + + + if( IsItemBomb( itemID ) && thePlayer.CanUseSkill( S_Perk_20 ) && GetItemName( itemID ) != 'Snow Ball' ) + { + GetItemAttributes( itemID, atts ); + canUseSkill = thePlayer.CanUseSkill( S_Alchemy_s10 ); + perk20Bonus = GetWitcherPlayer().GetSkillAttributeValue( S_Perk_20, 'stack_multiplier', false, false ); + + for( i=0 ; i; + var l_i : int; + var l_haveBombOrPot : bool; + + l_items = GetSingletonItems(); + + for( l_i = 0 ; l_i < l_items.Size() ; l_i += 1 ) + { + if( IsItemPotion( l_items[ l_i ] ) || IsItemBomb( l_items[ l_i ] ) ) + { + l_haveBombOrPot = true; + if( SingletonItemGetMaxAmmo( l_items[ l_i ] ) >= SingletonItemGetAmmo( l_items[ l_i ] ) ) + { + if( SingletonItemsRefillAmmo( true ) ) + { + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_applied" ),, true ); + } + + return; + } + } + } + + if( !l_haveBombOrPot ) + { + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_no_items" ),, true ); + return; + } + + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_already_on" ),, true ); + } + + + + + + public final function IsItemSteelSwordUsableByPlayer(item : SItemUniqueId) : bool + { + return ItemHasTag(item, theGame.params.TAG_PLAYER_STEELSWORD) && !ItemHasTag(item, 'SecondaryWeapon'); + } + + public final function IsItemSilverSwordUsableByPlayer(item : SItemUniqueId) : bool + { + return ItemHasTag(item, theGame.params.TAG_PLAYER_SILVERSWORD) && !ItemHasTag(item, 'SecondaryWeapon'); + } + + public final function IsItemFists(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'fist';} + public final function IsItemWeapon(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Weapon') || ItemHasTag(item, 'WeaponTab');} + public final function IsItemCrossbow(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'crossbow';} + public final function IsItemChestArmor(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'armor';} + public final function IsItemBody(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Body');} + public final function IsRecipeOrSchematic( item : SItemUniqueId ) : bool {return GetItemCategory(item) == 'alchemy_recipe' || GetItemCategory(item) == 'crafting_schematic'; } + public final function IsItemBoots(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'boots';} + public final function IsItemGloves(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'gloves';} + public final function IsItemPants(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'trousers' || GetItemCategory(item) == 'pants';} + public final function IsItemTrophy(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'trophy';} + public final function IsItemMask(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'mask';} + public final function IsItemBomb(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'petard';} + public final function IsItemBolt(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'bolt';} + public final function IsItemUpgrade(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'upgrade';} + public final function IsItemTool(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'tool';} + public final function IsItemPotion(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Potion');} + public final function IsItemOil(item : SItemUniqueId) : bool {return ItemHasTag(item, 'SilverOil') || ItemHasTag(item, 'SteelOil');} + public final function IsItemAnyArmor(item : SItemUniqueId) : bool {return ItemHasTag(item, theGame.params.TAG_ARMOR);} + public final function IsItemUpgradeable(item : SItemUniqueId) : bool {return ItemHasTag(item, theGame.params.TAG_ITEM_UPGRADEABLE);} + public final function IsItemIngredient(item : SItemUniqueId) : bool {return ItemHasTag(item, 'AlchemyIngredient') || ItemHasTag(item, 'CraftingIngredient');} + public final function IsItemDismantleKit(item : SItemUniqueId) : bool {return ItemHasTag(item, 'DismantleKit');} + public final function IsItemHorseBag(item : SItemUniqueId) : bool {return ItemHasTag(item, 'HorseBag');} + public final function IsItemReadable(item : SItemUniqueId) : bool {return ItemHasTag(item, 'ReadableItem');} + public final function IsItemAlchemyItem(item : SItemUniqueId) : bool {return IsItemOil(item) || IsItemPotion(item) || IsItemBomb(item); } + public final function IsItemSingletonItem(item : SItemUniqueId) : bool {return ItemHasTag(item, theGame.params.TAG_ITEM_SINGLETON);} + public final function IsItemQuest(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Quest');} + public final function IsItemFood(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Edibles') || ItemHasTag(item, 'Drinks');} + public final function IsItemSecondaryWeapon(item : SItemUniqueId) : bool {return ItemHasTag(item, 'SecondaryWeapon');} + public final function IsItemHorseItem(item: SItemUniqueId) : bool {return ItemHasTag(item, 'Saddle') || ItemHasTag(item, 'HorseBag') || ItemHasTag(item, 'Trophy') || ItemHasTag(item, 'Blinders'); } + public final function IsItemSaddle(item: SItemUniqueId) : bool {return ItemHasTag(item, 'Saddle');} + public final function IsItemBlinders(item: SItemUniqueId) : bool {return ItemHasTag(item, 'Blinders');} + public final function IsItemDye( item : SItemUniqueId ) : bool { return ItemHasTag( item, 'mod_dye' ); } + public final function IsItemUsable( item : SItemUniqueId ) : bool { return GetItemCategory( item ) == 'usable'; } + public final function IsItemJunk( item : SItemUniqueId ) : bool { return ItemHasTag( item,'junk' ) || GetItemCategory( item ) == 'junk' ; } + public final function IsItemAlchemyIngredient(item : SItemUniqueId) : bool { return ItemHasTag( item, 'AlchemyIngredient' ); } + public final function IsItemCraftingIngredient(item : SItemUniqueId) : bool { return ItemHasTag( item, 'CraftingIngredient' ); } + public final function IsItemArmorReapairKit(item : SItemUniqueId) : bool { return ItemHasTag( item, 'ArmorReapairKit' ); } + public final function IsItemWeaponReapairKit(item : SItemUniqueId) : bool { return ItemHasTag( item, 'WeaponReapairKit' ); } + public final function IsQuickSlotItem( item : SItemUniqueId ) : bool { return ItemHasTag( item, 'QuickSlot' ); } + + public final function IsItemNew( item : SItemUniqueId ) : bool + { + var uiData : SInventoryItemUIData; + + uiData = GetInventoryItemUIData( item ); + return uiData.isNew; + } + + public final function IsItemMutagenPotion(item : SItemUniqueId) : bool + { + return IsItemPotion(item) && ItemHasTag(item, 'Mutagen'); + } + + public final function CanItemBeColored( item : SItemUniqueId) : bool + { + if ( RoundMath( CalculateAttributeValue( GetItemAttributeValue( item, 'quality' ) ) ) == 5 ) + { + return true; + } + return false; + } + + public final function IsItemSetItem(item : SItemUniqueId) : bool + { + return + ItemHasTag(item, theGame.params.ITEM_SET_TAG_BEAR) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_GRYPHON) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_LYNX) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_WOLF) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_RED_WOLF) || + ItemHasTag( item, theGame.params.ITEM_SET_TAG_VAMPIRE ) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_VIPER); + } + + public function GetArmorType(item : SItemUniqueId) : EArmorType + { + var isItemEquipped : bool; + + isItemEquipped = GetWitcherPlayer().IsItemEquipped(item); + + + if( thePlayer.HasAbility('Glyphword 2 _Stats', true) && isItemEquipped ) + {return EAT_Light;} + if( thePlayer.HasAbility('Glyphword 3 _Stats', true) && isItemEquipped ) + {return EAT_Medium;} + if( thePlayer.HasAbility('Glyphword 4 _Stats', true) && isItemEquipped ) + {return EAT_Heavy;} + + if(ItemHasTag(item, 'LightArmor')) + return EAT_Light; + else if(ItemHasTag(item, 'MediumArmor')) + return EAT_Medium; + else if(ItemHasTag(item, 'HeavyArmor')) + return EAT_Heavy; + + return EAT_Undefined; + } + + public final function GetAlchemyCraftableItems() : array + { + var items : array; + var i : int; + + GetAllItems(items); + + for(i=items.Size()-1; i>=0; i-=1) + { + if(!IsItemPotion(items[i]) && !IsItemBomb(items[i]) && !IsItemOil(items[i])) + items.EraseFast(i); + } + + return items; + } + + public function IsItemEncumbranceItem(item : SItemUniqueId) : bool + { + if(ItemHasTag(item, theGame.params.TAG_ENCUMBRANCE_ITEM_FORCE_YES)) + return true; + + if(ItemHasTag(item, theGame.params.TAG_ENCUMBRANCE_ITEM_FORCE_NO)) + return false; + + + if ( + IsRecipeOrSchematic( item ) + || IsItemBody( item ) + + + + + + + + + + + + + ) + return false; + + return true; + } + + public function GetItemEncumbrance(item : SItemUniqueId) : float + { + var itemCategory : name; + if ( IsItemEncumbranceItem( item ) ) + { + itemCategory = GetItemCategory( item ); + if ( itemCategory == 'quest' || itemCategory == 'key' ) + { + return 0.01 * GetItemQuantity( item ); + } + else if ( itemCategory == 'usable' || itemCategory == 'upgrade' || itemCategory == 'junk' ) + { + return 0.01 + GetItemWeight( item ) * GetItemQuantity( item ) * 0.2; + } + else if ( IsItemAlchemyItem( item ) || IsItemIngredient( item ) || IsItemFood( item ) || IsItemReadable( item ) ) + { + return 0.0; + } + else + { + return 0.01 + GetItemWeight( item ) * GetItemQuantity( item ) * 0.5; + } + } + return 0; + } + + public function GetFilterTypeByItem( item : SItemUniqueId ) : EInventoryFilterType + { + var filterType : EInventoryFilterType; + + if( ItemHasTag( item, 'Quest' ) ) + { + return IFT_QuestItems; + } + else if( IsItemIngredient( item ) ) + { + return IFT_Ingredients; + } + else if( IsItemAlchemyItem(item) ) + { + return IFT_AlchemyItems; + } + else if( IsItemAnyArmor(item) ) + { + return IFT_Armors; + } + else if( IsItemWeapon( item ) ) + { + return IFT_Weapons; + } + else + { + return IFT_Default; + } + } + + + public function IsItemQuickslotItem(item : SItemUniqueId) : bool + { + return IsSlotQuickslot( GetSlotForItemId(item) ); + } + + public function GetCrossbowAmmo(id : SItemUniqueId) : int + { + if(!IsItemCrossbow(id)) + return -1; + + return (int)CalculateAttributeValue(GetItemAttributeValue(id, 'ammo')); + } + + + + public function GetSlotForItemId(item : SItemUniqueId) : EEquipmentSlots + { + var tags : array; + var player : W3PlayerWitcher; + var slot : EEquipmentSlots; + + player = ((W3PlayerWitcher)GetEntity()); + + GetItemTags(item, tags); + slot = GetSlotForItem( GetItemCategory(item), tags, player ); + + if(!player) + return slot; + + if(IsMultipleSlot(slot)) + { + if(slot == EES_Petard1 && player.IsAnyItemEquippedOnSlot(slot)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_Petard2)) + slot = EES_Petard2; + } + else if(slot == EES_Quickslot1 && player.IsAnyItemEquippedOnSlot(slot)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_Quickslot2)) + slot = EES_Quickslot2; + } + else if(slot == EES_Potion1 && player.IsAnyItemEquippedOnSlot(EES_Potion1)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_Potion2)) + { + slot = EES_Potion2; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_Potion3)) + { + slot = EES_Potion3; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_Potion4)) + { + slot = EES_Potion4; + } + } + } + } + else if(slot == EES_PotionMutagen1 && player.IsAnyItemEquippedOnSlot(slot)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_PotionMutagen2)) + { + slot = EES_PotionMutagen2; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_PotionMutagen3)) + { + slot = EES_PotionMutagen3; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_PotionMutagen4)) + { + slot = EES_PotionMutagen4; + } + } + } + } + else if(slot == EES_SkillMutagen1 && player.IsAnyItemEquippedOnSlot(slot)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_SkillMutagen2)) + { + slot = EES_SkillMutagen2; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_SkillMutagen3)) + { + slot = EES_SkillMutagen3; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_SkillMutagen4)) + { + slot = EES_SkillMutagen4; + } + } + } + } + } + + return slot; + } + + + + public function GetAllWeapons() : array + { + return GetItemsByTag('Weapon'); + } + + + public function GetSpecifiedPlayerItemsQuest(steelSword, silverSword, armor, boots, gloves, pants, trophy, mask, bombs, crossbow, secondaryWeapon, equippedOnly : bool) : array + { + var items, allItems : array; + var i : int; + + GetAllItems(allItems); + + for(i=0; i; + var witcher : W3PlayerWitcher; + var refill : W3RefillableContainer; + + witcher = GetWitcherPlayer(); + + if(GetEntity() == witcher) + { + + + + + + if(IsItemCrossbow(itemId) && HasInfiniteBolts()) + { + crossbows = GetItemsByCategory('crossbow'); + crossbows.Remove(itemId); + + if(crossbows.Size() == 0) + { + RemoveItemByName('Bodkin Bolt', GetItemQuantityByName('Bodkin Bolt')); + RemoveItemByName('Harpoon Bolt', GetItemQuantityByName('Harpoon Bolt')); + } + } + else if(IsItemBolt(itemId) && witcher.IsItemEquipped(itemId) && witcher.inv.GetItemQuantity(itemId) == quantity) + { + + witcher.UnequipItem(itemId); + } + + + if(IsItemCrossbow(itemId) && witcher.IsItemEquipped(itemId) && witcher.rangedWeapon) + { + witcher.rangedWeapon.ClearDeployedEntity(true); + witcher.rangedWeapon = NULL; + } + if( GetItemCategory(itemId) == 'usable' ) + { + if(witcher.IsHoldingItemInLHand() && itemId == witcher.currentlyEquipedItemL ) + { + witcher.HideUsableItem(true); + } + } + if( IsItemSteelSwordUsableByPlayer( itemId ) || IsItemSilverSwordUsableByPlayer( itemId ) ) + { + RemoveAllOilsFromItem( itemId ); + } + + + if(witcher.IsItemEquipped(itemId) && quantity >= witcher.inv.GetItemQuantity(itemId)) + witcher.UnequipItem(itemId); + } + + + if(GetEntity() == thePlayer && IsItemWeapon(itemId) && (IsItemHeld(itemId) || IsItemMounted(itemId) )) + { + thePlayer.OnHolsteredItem(GetItemCategory(itemId),'r_weapon'); + } + + + ent = (CGameplayEntity)GetEntity(); + if(ent) + ent.OnItemTaken( itemId, quantity ); + + + if(IsLootRenewable()) + { + refill = (W3RefillableContainer)GetEntity(); + if(refill) + refill.AddTimer('Refill', 20, true); + } + } + + + function GenerateItemLevel( item : SItemUniqueId, rewardItem : bool ) + { + var stat : SAbilityAttributeValue; + var playerLevel : int; + var lvl, i : int; + var quality : int; + var ilMin, ilMax : int; + + playerLevel = GetWitcherPlayer().GetLevel(); + + lvl = playerLevel - 1; + + + if ( ( W3MerchantNPC )GetEntity() ) + { + lvl = RoundF( playerLevel + RandRangeF( 2, 0 ) ); + AddItemTag( item, 'AutogenUseLevelRange' ); + } + else if ( rewardItem ) + { + lvl = RoundF( playerLevel + RandRangeF( 1, 0 ) ); + } + else if ( ItemHasTag( item, 'AutogenUseLevelRange') ) + { + quality = RoundMath( CalculateAttributeValue( GetItemAttributeValue( item, 'quality' ) ) ); + ilMin = RoundMath(CalculateAttributeValue( GetItemAttributeValue( item, 'item_level_min' ) )); + ilMax = RoundMath(CalculateAttributeValue( GetItemAttributeValue( item, 'item_level_max' ) )); + + lvl += 1; + if ( !ItemHasTag( item, 'AutogenForceLevel') ) + lvl += RoundMath(RandRangeF( 1, -1 )); + + if ( FactsQuerySum("NewGamePlus") > 0 ) + { + if ( lvl < ilMin + theGame.params.GetNewGamePlusLevel() ) lvl = ilMin + theGame.params.GetNewGamePlusLevel(); + if ( lvl > ilMax + theGame.params.GetNewGamePlusLevel() ) lvl = ilMax + theGame.params.GetNewGamePlusLevel(); + } + else + { + if ( lvl < ilMin ) lvl = ilMin; + if ( lvl > ilMax ) lvl = ilMax; + } + + if ( quality == 5 ) lvl += 2; + if ( quality == 4 ) lvl += 1; + if ( (quality == 5 || quality == 4) && ItemHasTag(item, 'EP1') ) lvl += 1; + } + else if ( !ItemHasTag( item, 'AutogenForceLevel') ) + { + quality = RoundMath( CalculateAttributeValue( GetItemAttributeValue( item, 'quality' ) ) ); + + if ( quality == 5 ) + { + lvl = RoundF( playerLevel + RandRangeF( 2, 0 ) ); + } + else if ( quality == 4 ) + { + lvl = RoundF( playerLevel + RandRangeF( 1, -2 ) ); + } + else if ( quality == 3 ) + { + lvl = RoundF( playerLevel + RandRangeF( -1, -3 ) ); + + if ( RandF() > 0.9 ) + { + lvl = playerLevel; + } + } + else if ( quality == 2 ) + { + lvl = RoundF( playerLevel + RandRangeF( -2, -5 ) ); + + if ( RandF() > 0.95 ) + { + lvl = playerLevel; + } + } + else + { + lvl = RoundF( playerLevel + RandRangeF( -2, -8 ) ); + + if ( RandF() == 0 ) + { + lvl = playerLevel; + } + } + } + + if (FactsQuerySum("StandAloneEP1") > 0) + lvl = GetWitcherPlayer().GetLevel() - 1; + + + if ( FactsQuerySum("NewGamePlus") > 0 && !ItemHasTag( item, 'AutogenUseLevelRange') ) + { + if ( quality == 5 ) lvl += 2; + if ( quality == 4 ) lvl += 1; + } + + if ( lvl < 1 ) lvl = 1; + if ( lvl > GetWitcherPlayer().GetMaxLevel() ) lvl = GetWitcherPlayer().GetMaxLevel(); + + if ( ItemHasTag( item, 'PlayerSteelWeapon' ) && !( ItemHasAbility( item, 'autogen_steel_base' ) || ItemHasAbility( item, 'autogen_fixed_steel_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_steel_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_steel_base' ); + else + AddItemCraftedAbility(item, 'autogen_steel_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_steel_dmg', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag(item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_steel_dmg', true ); + else + AddItemCraftedAbility(item, 'autogen_steel_dmg', true ); + } + } + else if ( ItemHasTag( item, 'PlayerSilverWeapon' ) && !( ItemHasAbility( item, 'autogen_silver_base' ) || ItemHasAbility( item, 'autogen_fixed_silver_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_silver_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_silver_base' ); + else + AddItemCraftedAbility(item, 'autogen_silver_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_silver_dmg', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag(item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_silver_dmg', true ); + else + AddItemCraftedAbility(item, 'autogen_silver_dmg', true ); + } + } + else if ( GetItemCategory( item ) == 'armor' && !( ItemHasAbility( item, 'autogen_armor_base' ) || ItemHasAbility( item, 'autogen_fixed_armor_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_armor_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_armor_base' ); + else + AddItemCraftedAbility(item, 'autogen_armor_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_armor_armor', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag( item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_armor_armor', true ); + else + AddItemCraftedAbility(item, 'autogen_armor_armor', true ); + } + } + else if ( ( GetItemCategory( item ) == 'boots' || GetItemCategory( item ) == 'pants' ) && !( ItemHasAbility( item, 'autogen_pants_base' ) || ItemHasAbility( item, 'autogen_fixed_pants_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_pants_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_pants_base' ); + else + AddItemCraftedAbility(item, 'autogen_pants_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_pants_armor', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag( item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_pants_armor', true ); + else + AddItemCraftedAbility(item, 'autogen_pants_armor', true ); + } + } + else if ( GetItemCategory( item ) == 'gloves' && !( ItemHasAbility( item, 'autogen_gloves_base' ) || ItemHasAbility( item, 'autogen_fixed_gloves_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_gloves_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_gloves_base' ); + else + AddItemCraftedAbility(item, 'autogen_gloves_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_gloves_armor', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag(item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_gloves_armor', true ); + else + AddItemCraftedAbility(item, 'autogen_gloves_armor', true ); + } + } + } + + + event OnItemAdded(data : SItemChangedData) + { + var i, j : int; + var ent : CGameplayEntity; + var allCardsNames, foundCardsNames : array; + var allStringNamesOfCards : array; + var foundCardsStringNames : array; + var gwintCards : array; + var itemName : name; + var witcher : W3PlayerWitcher; + var itemCategory : name; + var dm : CDefinitionsManagerAccessor; + var locKey : string; + var leaderCardsHack : array; + + var hud : CR4ScriptedHud; + var journalUpdateModule : CR4HudModuleJournalUpdate; + var itemId : SItemUniqueId; + + var isItemShematic : bool; + + var ngp : bool; + + ent = (CGameplayEntity)GetEntity(); + + itemId = data.ids[0]; + + + if( data.informGui ) + { + recentlyAddedItems.PushBack( itemId ); + if( ItemHasTag( itemId, 'FocusObject' ) ) + { + GetWitcherPlayer().GetMedallion().Activate( true, 3.0); + } + } + + + if ( ItemHasTag(itemId, 'Autogen') ) + { + GenerateItemLevel( itemId, false ); + } + + witcher = GetWitcherPlayer(); + + + if(ent == witcher || ((W3MerchantNPC)ent) ) + { + ngp = FactsQuerySum("NewGamePlus") > 0; + for(i=0; i= allStringNamesOfCards.Size()) + { + foundCardsNames.Clear(); + for(j=0; j= allStringNamesOfCards.Size()) + { + theGame.GetGamerProfile().AddAchievement(EA_GwintCollector); + FactsAdd("gwint_all_cards_collected", 1, -1); + } + } + + if(!FactsDoesExist("fix_for_gwent_achievement_bug_121588")) + FactsAdd("fix_for_gwent_achievement_bug_121588", 1, -1); + } + + itemCategory = GetItemCategory( itemId ); + isItemShematic = itemCategory == 'alchemy_recipe' || itemCategory == 'crafting_schematic'; + + if( isItemShematic ) + { + ReadSchematicsAndRecipes( itemId ); + } + + + if( ItemHasTag( data.ids[i], 'GwintCard')) + { + witcher.AddGwentCard(GetItemName(data.ids[i]), data.quantity); + } + + + + if( !isItemShematic && ( this.ItemHasTag( itemId, 'ReadableItem' ) || this.ItemHasTag( itemId, 'Painting' ) ) && !this.ItemHasTag( itemId, 'NoNotification' ) ) + { + hud = (CR4ScriptedHud)theGame.GetHud(); + if( hud ) + { + journalUpdateModule = (CR4HudModuleJournalUpdate)hud.GetHudModule( "JournalUpdateModule" ); + if( journalUpdateModule ) + { + journalUpdateModule.AddQuestBookInfo( itemId ); + } + } + } + } + } + + + if( IsItemSingletonItem( itemId ) ) + { + for(i=0; i 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkArmorAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkArmorAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'gloves' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_gloves'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkGlovesAbility(), true); + break; + case 3 : + ability = 'quality_magical_gloves'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalGlovesAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkGlovesAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalGlovesAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkGlovesAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'pants' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_pants'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkPantsAbility(), true); + break; + case 3 : + ability = 'quality_magical_pants'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalPantsAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkPantsAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalPantsAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkPantsAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'boots' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_boots'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkBootsAbility(), true); + break; + case 3 : + ability = 'quality_magical_boots'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalBootsAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkBootsAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalBootsAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkBootsAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'steelsword' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_steelsword'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + break; + case 3 : + ability = 'quality_magical_steelsword'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'silversword' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_silversword'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + break; + case 3 : + ability = 'quality_magical_silversword'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + break; + + default : break; + } + } + + if(IsNameValid(ability)) + { + AddItemCraftedAbility(item, ability, false); + SetItemModifierInt(item, 'ItemQualityModified', 1); + } + } + + public function IncreaseNGPItemlevel(item : SItemUniqueId) + { + var i, diff : int; + + diff = theGame.params.NewGamePlusLevelDifference(); + + if (diff > 0) + { + if ( ItemHasTag( item, 'PlayerSteelWeapon' ) ) + { + for( i=0; i; + var tempItemQualityAtribute : SAbilityAttributeValue; + + + excludedTags.PushBack(theGame.params.OIL_ABILITY_TAG); + itemQualityAtribute = GetItemAttributeValue( itemId, 'quality', excludedTags, true ); + + itemQuality = itemQualityAtribute.valueAdditive; + if( itemQuality == 0 ) + { + itemQuality = 1; + } + return RoundMath(itemQuality); + } + + public function GetItemQualityFromName( itemName : name, out min : int, out max : int) + { + var dm : CDefinitionsManagerAccessor; + var attributeName : name; + var attributes, itemAbilities : array; + var attributeMin, attributeMax : SAbilityAttributeValue; + + var tmpInt : int; + var tmpArray : array; + + dm = theGame.GetDefinitionsManager(); + + dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, tmpArray, tmpInt, tmpInt); + attributes = dm.GetAbilitiesAttributes(itemAbilities); + for (tmpInt = 0; tmpInt < attributes.Size(); tmpInt += 1) + { + if (attributes[tmpInt] == 'quality') + { + dm.GetAbilitiesAttributeValue(itemAbilities, 'quality', attributeMin, attributeMax); + min = RoundMath(CalculateAttributeValue(attributeMin)); + max = RoundMath(CalculateAttributeValue(attributeMax)); + break; + } + } + } + + public function GetRecentlyAddedItems() : array + { + return recentlyAddedItems; + } + + public function GetRecentlyAddedItemsListSize() : int + { + return recentlyAddedItems.Size(); + } + + public function RemoveItemFromRecentlyAddedList( itemId : SItemUniqueId ) : bool + { + var i : int; + + for( i = 0; i < recentlyAddedItems.Size(); i += 1 ) + { + if( recentlyAddedItems[i] == itemId ) + { + recentlyAddedItems.EraseFast( i ); + return true; + } + } + + return false; + } + + + + + import final function NotifyScriptedListeners( notify : bool ); + + var listeners : array< IInventoryScriptedListener >; + + function AddListener( listener : IInventoryScriptedListener ) + { + if ( listeners.FindFirst( listener ) == -1 ) + { + listeners.PushBack( listener ); + if ( listeners.Size() == 1 ) + { + NotifyScriptedListeners( true ); + } + } + } + + function RemoveListener( listener : IInventoryScriptedListener ) + { + if ( listeners.Remove( listener ) ) + { + if ( listeners.Size() == 0 ) + { + NotifyScriptedListeners( false ); + } + } + } + + event OnInventoryScriptedEvent( eventType : EInventoryEventType, itemId : SItemUniqueId, quantity : int, fromAssociatedInventory : bool ) + { + var i, size : int; + + size = listeners.Size(); + for (i=size-1; i>=0; i-=1 ) + { + listeners[i].OnInventoryScriptedEvent( eventType, itemId, quantity, fromAssociatedInventory ); + } + + + if(GetEntity() == GetWitcherPlayer() && (eventType == IET_ItemRemoved || eventType == IET_ItemQuantityChanged) ) + GetWitcherPlayer().UpdateEncumbrance(); + } + + + + + public final function GetMutationResearchPoints( color : ESkillColor, item : SItemUniqueId ) : int + { + var val : SAbilityAttributeValue; + var colorAttribute : name; + + + if( color == SC_None || color == SC_Yellow || !IsIdValid( item ) ) + { + return 0; + } + + + switch( color ) + { + case SC_Red: + colorAttribute = 'mutation_research_points_red'; + break; + case SC_Blue: + colorAttribute = 'mutation_research_points_blue'; + break; + case SC_Green: + colorAttribute = 'mutation_research_points_green'; + break; + } + + + val = GetItemAttributeValue( item, colorAttribute ); + + return ( int )val.valueAdditive; + } + + public function GetSkillMutagenColor(item : SItemUniqueId) : ESkillColor + { + var abs : array; + + + if(!ItemHasTag(item, 'MutagenIngredient')) + return SC_None; + + GetItemAbilities(item, abs); + + if(abs.Contains('mutagen_color_green')) return SC_Green; + if(abs.Contains('mutagen_color_blue')) return SC_Blue; + if(abs.Contains('mutagen_color_red')) return SC_Red; + if(abs.Contains('lesser_mutagen_color_green')) return SC_Green; + if(abs.Contains('lesser_mutagen_color_blue')) return SC_Blue; + if(abs.Contains('lesser_mutagen_color_red')) return SC_Red; + if(abs.Contains('greater_mutagen_color_green')) return SC_Green; + if(abs.Contains('greater_mutagen_color_blue')) return SC_Blue; + if(abs.Contains('greater_mutagen_color_red')) return SC_Red; + + return SC_None; + } + + + + + + + + + + import final function GetItemEnhancementSlotsCount( itemId : SItemUniqueId ) : int; + import final function GetItemEnhancementItems( itemId : SItemUniqueId, out names : array< name > ); + import final function GetItemEnhancementCount( itemId : SItemUniqueId ) : int; + import final function GetItemColor( itemId : SItemUniqueId ) : name; + import final function IsItemColored( itemId : SItemUniqueId ) : bool; + import final function SetPreviewColor( itemId : SItemUniqueId, colorId : int ); + import final function ClearPreviewColor( itemId : SItemUniqueId ) : bool; + import final function ColorItem( itemId : SItemUniqueId, dyeId : SItemUniqueId ); + import final function ClearItemColor( itemId : SItemUniqueId ) : bool; + import final function EnchantItem( enhancedItemId : SItemUniqueId, enchantmentName : name, enchantmentStat : name ) : bool; + import final function GetEnchantment( enhancedItemId : SItemUniqueId ) : name; + import final function IsItemEnchanted( enhancedItemId : SItemUniqueId ) : bool; + import final function UnenchantItem( enhancedItemId : SItemUniqueId ) : bool; + import private function EnhanceItem( enhancedItemId : SItemUniqueId, extensionItemId : SItemUniqueId ) : bool; + import private function RemoveItemEnhancementByIndex( enhancedItemId : SItemUniqueId, slotIndex : int ) : bool; + import private function RemoveItemEnhancementByName( enhancedItemId : SItemUniqueId, extensionItemName : name ) : bool; + import final function PreviewItemAttributeAfterUpgrade( baseItemId : SItemUniqueId, upgradeItemId : SItemUniqueId, attributeName : name, optional baseInventory : CInventoryComponent, optional upgradeInventory : CInventoryComponent ) : SAbilityAttributeValue; + import final function HasEnhancementItemTag( enhancedItemId : SItemUniqueId, slotIndex : int, tag : name ) : bool; + + + function NotifyEnhancedItem( enhancedItemId : SItemUniqueId ) + { + var weapons : array; + var sword : CWitcherSword; + var i : int; + + sword = (CWitcherSword) GetItemEntityUnsafe( enhancedItemId ); + sword.UpdateEnhancements( this ); + } + + function EnhanceItemScript( enhancedItemId : SItemUniqueId, extensionItemId : SItemUniqueId ) : bool + { + var i : int; + var enhancements : array; + var runeword : Runeword; + + if ( EnhanceItem( enhancedItemId, extensionItemId ) ) + { + NotifyEnhancedItem( enhancedItemId ); + + GetItemEnhancementItems( enhancedItemId, enhancements ); + if ( theGame.runewordMgr.GetRuneword( enhancements, runeword ) ) + { + for ( i = 0; i < runeword.abilities.Size(); i+=1 ) + { + AddItemBaseAbility( enhancedItemId, runeword.abilities[i] ); + } + } + return true; + } + return false; + } + + function RemoveItemEnhancementByIndexScript( enhancedItemId : SItemUniqueId, slotIndex : int ) : bool + { + var i : int; + var enhancements : array; + var runeword : Runeword; + var hasRuneword : bool; + var names : array< name >; + + GetItemEnhancementItems( enhancedItemId, enhancements ); + hasRuneword = theGame.runewordMgr.GetRuneword( enhancements, runeword ); + + GetItemEnhancementItems( enhancedItemId, names ); + + if ( RemoveItemEnhancementByIndex( enhancedItemId, slotIndex ) ) + { + NotifyEnhancedItem( enhancedItemId ); + + + + if ( hasRuneword ) + { + + for ( i = 0; i < runeword.abilities.Size(); i+=1 ) + { + RemoveItemBaseAbility( enhancedItemId, runeword.abilities[i] ); + } + } + return true; + } + return false; + } + + + function RemoveItemEnhancementByNameScript( enhancedItemId : SItemUniqueId, extensionItemName : name ) : bool + { + var i : int; + var enhancements : array; + var runeword : Runeword; + var hasRuneword : bool; + + GetItemEnhancementItems( enhancedItemId, enhancements ); + hasRuneword = theGame.runewordMgr.GetRuneword( enhancements, runeword ); + + + if ( RemoveItemEnhancementByName( enhancedItemId, extensionItemName ) ) + { + NotifyEnhancedItem( enhancedItemId ); + + + AddAnItem( extensionItemName, 1, true, true ); + if ( hasRuneword ) + { + + for ( i = 0; i < runeword.abilities.Size(); i+=1 ) + { + RemoveItemBaseAbility( enhancedItemId, runeword.abilities[i] ); + } + } + return true; + } + return false; + } + + function RemoveAllItemEnhancements( enhancedItemId : SItemUniqueId ) + { + var count, i : int; + + count = GetItemEnhancementCount( enhancedItemId ); + for ( i = count - 1; i >= 0; i-=1 ) + { + RemoveItemEnhancementByIndexScript( enhancedItemId, i ); + } + } + + function GetHeldAndMountedItems( out items : array< SItemUniqueId > ) + { + var allItems : array< SItemUniqueId >; + var i : int; + var itemName : name; + + GetAllItems( allItems ); + + items.Clear(); + for( i = 0; i < allItems.Size(); i += 1 ) + { + if ( IsItemHeld( allItems[ i ] ) || IsItemMounted( allItems[ i ] ) ) + { + items.PushBack( allItems[ i ] ); + } + } + } + + + public function GetHasValidDecorationItems( items : array, decoration : W3HouseDecorationBase ) : bool + { + var i, size : int; + + size = items.Size(); + + + if(size == 0 ) + { + LogChannel( 'houseDecorations', "No items with valid tag were found!" ); + return false; + } + + + for( i=0; i < size; i+= 1 ) + { + + if( GetWitcherPlayer().IsItemEquipped( items[i] ) ) + { + LogChannel( 'houseDecorations', "Found item is equipped, erasing..." ); + continue; + } + + + if( IsItemQuest( items[i] ) && decoration.GetAcceptQuestItems() == false ) + { + LogChannel( 'houseDecorations', "Found item is quest item, and quest items are not accepted, erasing..." ); + continue; + } + + + if( decoration.GetItemHasForbiddenTag( items[i] ) ) + { + LogChannel( 'houseDecorations', "Found item has a forbidden tag, erasing..." ); + continue; + } + + LogChannel( 'houseDecorations', "Item checks out: "+ GetItemName( items[i] ) ); + return true; + } + LogChannel( 'houseDecorations', "No valid items were found!" ); + + return false; + } + + + function GetMissingCards() : array< name > + { + var defMgr : CDefinitionsManagerAccessor = theGame.GetDefinitionsManager(); + var allCardNames : array< name > = defMgr.GetItemsWithTag(theGame.params.GWINT_CARD_ACHIEVEMENT_TAG); + var playersCards : array< SItemUniqueId > = GetItemsByTag(theGame.params.GWINT_CARD_ACHIEVEMENT_TAG); + var playersCardLocs : array< string >; + var missingCardLocs : array< string >; + var missingCards : array< name >; + var i, j : int; + var found : bool; + + + for ( i = 0; i < allCardNames.Size(); i+=1 ) + { + found = false; + + for ( j = 0; j < playersCards.Size(); j+=1 ) + { + if ( allCardNames[i] == GetItemName( playersCards[j] ) ) + { + found = true; + playersCardLocs.PushBack( defMgr.GetItemLocalisationKeyName ( allCardNames[i] ) ); + break; + } + } + + if ( !found ) + { + missingCardLocs.PushBack( defMgr.GetItemLocalisationKeyName( allCardNames[i] ) ); + missingCards.PushBack( allCardNames[i] ); + } + } + + if( missingCardLocs.Size() < 2 ) + { + return missingCards; + } + + + for ( i = missingCardLocs.Size()-1 ; i >= 0 ; i-=1 ) + { + for ( j = 0 ; j < playersCardLocs.Size() ; j+=1 ) + { + if ( missingCardLocs[i] == playersCardLocs[j] + && missingCardLocs[i] != "gwint_name_emhyr" && missingCardLocs[i] != "gwint_name_foltest" + && missingCardLocs[i] != "gwint_name_francesca" && missingCardLocs[i] != "gwint_name_eredin" ) + { + missingCardLocs.EraseFast( i ); + missingCards.EraseFast( i ); + break; + } + } + } + + return missingCards; + } + + public function FindCardSources( missingCards : array< name > ) : array< SCardSourceData > + { + var sourceCSV : C2dArray; + var sourceTable : array< SCardSourceData >; + var sourceRemaining : array< SCardSourceData >; + var sourceCount, i, j : int; + + if ( theGame.IsFinalBuild() ) + { + sourceCSV = LoadCSV("gameplay\globals\card_sources.csv"); + } + else + { + sourceCSV = LoadCSV("qa\card_sources.csv"); + } + + sourceCount = sourceCSV.GetNumRows(); + sourceTable.Resize(sourceCount); + + for ( i = 0 ; i < sourceCount ; i+=1 ) + { + sourceTable[i].cardName = sourceCSV.GetValueAsName("CardName",i); + sourceTable[i].source = sourceCSV.GetValue("Source",i); + sourceTable[i].originArea = sourceCSV.GetValue("OriginArea",i); + sourceTable[i].originQuest = sourceCSV.GetValue("OriginQuest",i); + sourceTable[i].details = sourceCSV.GetValue("Details",i); + sourceTable[i].coords = sourceCSV.GetValue("Coords",i); + } + + for ( i = 0 ; i < missingCards.Size() ; i+=1 ) + { + for ( j = 0 ; j < sourceCount ; j+=1 ) + { + if ( sourceTable[j].cardName == missingCards[i] ) + { + sourceRemaining.PushBack( sourceTable[j] ); + } + } + } + + return sourceRemaining; + } + + public function GetGwentAlmanacContents() : string + { + var sourcesRemaining : array< SCardSourceData >; + var missingCards : array< string >; + var almanacContents : string; + var i : int; + var NML, Novigrad, Skellige, Prologue, Vizima, KaerMorhen, Random : int; + + sourcesRemaining = FindCardSources( GetMissingCards() ); + + for ( i = 0 ; i < sourcesRemaining.Size() ; i+=1 ) + { + switch ( sourcesRemaining[i].originArea ) + { + case "NML": + NML += 1; + break; + case "Novigrad": + Novigrad += 1; + break; + case "Skellige": + Skellige += 1; + break; + case "Prologue": + Prologue += 1; + break; + case "Vizima": + Vizima += 1; + break; + case "KaerMorhen": + KaerMorhen += 1; + break; + case "Random": + Random += 1; + break; + default: + break; + } + } + + if ( NML + Novigrad + Skellige + Prologue + Vizima + KaerMorhen + Random == 0 ) + { + almanacContents = GetLocStringByKeyExt( "gwent_almanac_text" ) + "
"; + almanacContents += GetLocStringByKeyExt( "gwent_almanac_completed_text" ); + } + else + { + almanacContents = GetLocStringByKeyExt( "gwent_almanac_text" ) + "
"; + if ( NML > 0 ) + { + almanacContents += GetLocStringByKeyExt( "location_name_velen" ) + ": " + NML + "
"; + } + if ( Novigrad > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_novigrad" ) + ": " + Novigrad + "
"; + } + if ( Skellige > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_skellige" ) + ": " + Skellige + "
"; + } + if ( Prologue > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_prolog_village" ) + ": " + Prologue + "
"; + } + if ( Vizima > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_wyzima_castle" ) + ": " + Vizima + "
"; + } + if ( KaerMorhen > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_kaer_morhen" ) + ": " + KaerMorhen + "
"; + } + almanacContents += GetLocStringByKeyExt( "gwent_source_random" ) + ": " + Random; + } + + return almanacContents; + } + + public function GetUnusedMutagensCount(itemName:name):int + { + var items : array; + var equippedOnSlot : EEquipmentSlots; + var availableCount : int; + var res, i : int = 0; + + items = thePlayer.inv.GetItemsByName(itemName); + + for(i=0; i; + var equippedOnSlot : EEquipmentSlots; + var availableCount : int; + var res, i : int = 0; + + items = thePlayer.inv.GetItemsByName(itemName); + + for(i=0; i; + var curItem : SItemUniqueId; + var equippedOnSlot : EEquipmentSlots; + + var i : int; + var itemRemoved : int; + var availableToRemoved : int; + var removedRes : bool; + + itemRemoved = 0; + items = thePlayer.inv.GetItemsByName( itemName ); + + for( i=0; i < items.Size(); i+=1 ) + { + curItem = items[ i ]; + equippedOnSlot = GetWitcherPlayer().GetItemSlot( curItem ); + + if( equippedOnSlot == EES_InvalidSlot ) + { + availableToRemoved = Min( thePlayer.inv.GetItemQuantity( curItem ), ( count - itemRemoved ) ); + removedRes = thePlayer.inv.RemoveItem(items[i], availableToRemoved); + + if (removedRes) + { + itemRemoved = itemRemoved + availableToRemoved; + + if (itemRemoved >= count) + { + return; + } + } + + } + } + } + +} + +exec function findMissingCards( optional card : name ) +{ + var inv : CInventoryComponent = thePlayer.GetInventory(); + var sourcesRemaining : array< SCardSourceData >; + var missingCards : array< name >; + var i : int; + var sourceLogString : string; + + if ( card != '' ) + { + missingCards.PushBack( card ); + } + else + { + missingCards = inv.GetMissingCards(); + } + + sourcesRemaining = inv.FindCardSources( missingCards ); + + for ( i = 0 ; i < sourcesRemaining.Size() ; i+=1 ) + { + sourceLogString = sourcesRemaining[i].cardName + " is a " + sourcesRemaining[i].source ; + if ( sourcesRemaining[i].originArea == "Random" ) + { + sourceLogString += " card from a random merchant."; + } + else + { + sourceLogString += " item in " + sourcesRemaining[i].originArea + " from "; + + if ( sourcesRemaining[i].originQuest != "" ) + { + sourceLogString += sourcesRemaining[i].originQuest + " , "; + } + + sourceLogString += sourcesRemaining[i].details; + } + Log( sourceLogString ); + + if ( sourcesRemaining[i].coords != "" ) + { + Log( sourcesRemaining[i].coords ); + } + } +} + +exec function slotTest() +{ + var inv : CInventoryComponent = thePlayer.inv; + var weaponItemId : SItemUniqueId; + var upgradeItemId : SItemUniqueId; + var i : int; + + LogChannel('SlotTest', "----------------------------------------------------------------"); + + + inv.AddAnItem( 'Perun rune', 1); + inv.AddAnItem( 'Svarog rune', 1); + + + for ( i = 0; i < 2; i += 1 ) + { + + if ( !GetItem( inv, 'steelsword', weaponItemId ) || + !GetItem( inv, 'upgrade', upgradeItemId ) ) + { + return; + } + + + PrintItem( inv, weaponItemId ); + + + if ( inv.EnhanceItemScript( weaponItemId, upgradeItemId ) ) + { + LogChannel('SlotTest', "Enhanced item"); + } + else + { + LogChannel('SlotTest', "Failed to enhance item!"); + } + } + + + if ( !GetItem( inv, 'steelsword', weaponItemId ) ) + { + return; + } + + + PrintItem( inv, weaponItemId ); + + + if ( inv.RemoveItemEnhancementByNameScript( weaponItemId, 'Svarog rune' ) ) + { + LogChannel('SlotTest', "Removed enhancement"); + } + else + { + LogChannel('SlotTest', "Failed to remove enhancement!"); + } + + + if ( !GetItem( inv, 'steelsword', weaponItemId ) ) + { + return; + } + + + PrintItem( inv, weaponItemId ); + + + if ( inv.RemoveItemEnhancementByIndexScript( weaponItemId, 0 ) ) + { + LogChannel('SlotTest', "Removed enhancement"); + } + else + { + LogChannel('SlotTest', "Failed to remove enhancement!"); + } + + + if ( !GetItem( inv, 'steelsword', weaponItemId ) ) + { + return; + } + + + PrintItem( inv, weaponItemId ); +} + +function GetItem( inv : CInventoryComponent, category : name, out itemId : SItemUniqueId ) : bool +{ + var itemIds : array< SItemUniqueId >; + + itemIds = inv.GetItemsByCategory( category ); + if ( itemIds.Size() > 0 ) + { + itemId = itemIds[ 0 ]; + return true; + } + LogChannel( 'SlotTest', "Failed to get item with GetItemsByCategory( '" + category + "' )" ); + return false; +} + +function PrintItem( inv : CInventoryComponent, weaponItemId : SItemUniqueId ) +{ + var names : array< name >; + var tags : array< name >; + var i : int; + var line : string; + var attribute : SAbilityAttributeValue; + + LogChannel('SlotTest', "Slots: " + inv.GetItemEnhancementCount( weaponItemId ) + "/" + inv.GetItemEnhancementSlotsCount( weaponItemId ) ); + inv.GetItemEnhancementItems( weaponItemId, names ); + if ( names.Size() > 0 ) + { + for ( i = 0; i < names.Size(); i += 1 ) + { + if ( i == 0 ) + { + line += "["; + } + line += names[ i ]; + if ( i < names.Size() - 1 ) + { + line += ", "; + } + if ( i == names.Size() - 1 ) + { + line += "]"; + } + } + } + else + { + line += "[]"; + } + LogChannel('SlotTest', "Upgrade item names " + line ); + + tags.PushBack('Upgrade'); + + attribute = inv.GetItemAttributeValue( weaponItemId, 'PhysicalDamage' ); + LogChannel('SlotTest', "Attribute '" + 'PhysicalDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + attribute = inv.GetItemAttributeValue( weaponItemId, 'SilverDamage' ); + LogChannel('SlotTest', "Attribute '" + 'SilverDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + + attribute = inv.GetItemAttributeValue( weaponItemId, 'PhysicalDamage', tags, true ); + LogChannel('SlotTest', "Attribute '" + 'PhysicalDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + attribute = inv.GetItemAttributeValue( weaponItemId, 'SilverDamage', tags, true ); + LogChannel('SlotTest', "Attribute '" + 'SilverDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + + attribute = inv.GetItemAttributeValue( weaponItemId, 'PhysicalDamage', tags ); + LogChannel('SlotTest', "Attribute '" + 'PhysicalDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + attribute = inv.GetItemAttributeValue( weaponItemId, 'SilverDamage', tags ); + LogChannel('SlotTest', "Attribute '" + 'SilverDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + +} + +function PlayItemEquipSound( itemCategory : name ) : void +{ + switch( itemCategory ) + { + case 'steelsword' : + theSound.SoundEvent("gui_inventory_steelsword_attach"); + return; + case 'silversword' : + theSound.SoundEvent("gui_inventory_silversword_attach"); + return; + case 'secondary' : + theSound.SoundEvent("gui_inventory_weapon_attach"); + return; + case 'armor' : + theSound.SoundEvent("gui_inventory_armor_attach"); + return; + case 'pants' : + theSound.SoundEvent("gui_inventory_pants_attach"); + return; + case 'boots' : + theSound.SoundEvent("gui_inventory_boots_attach"); + return; + case 'gloves' : + theSound.SoundEvent("gui_inventory_gauntlet_attach"); + return; + case 'potion' : + theSound.SoundEvent("gui_inventory_potion_attach"); + return; + case 'petard' : + theSound.SoundEvent("gui_inventory_bombs_attach"); + return; + case 'ranged' : + theSound.SoundEvent("gui_inventory_ranged_attach"); + return; + case 'herb' : + theSound.SoundEvent("gui_pick_up_herbs"); + return; + case 'trophy' : + case 'horse_bag' : + theSound.SoundEvent("gui_inventory_horse_bage_attach"); + return; + case 'horse_blinder' : + theSound.SoundEvent("gui_inventory_horse_blinder_attach"); + return; + case 'horse_saddle' : + theSound.SoundEvent("gui_inventory_horse_saddle_attach"); + return; + default : + theSound.SoundEvent("gui_inventory_other_attach"); + return; + } +} + +function PlayItemUnequipSound( itemCategory : name ) : void +{ + switch( itemCategory ) + { + case 'steelsword' : + theSound.SoundEvent("gui_inventory_steelsword_back"); + return; + case 'silversword' : + theSound.SoundEvent("gui_inventory_silversword_back"); + return; + case 'secondary' : + theSound.SoundEvent("gui_inventory_weapon_back"); + return; + case 'armor' : + theSound.SoundEvent("gui_inventory_armor_back"); + return; + case 'pants' : + theSound.SoundEvent("gui_inventory_pants_back"); + return; + case 'boots' : + theSound.SoundEvent("gui_inventory_boots_back"); + return; + case 'gloves' : + theSound.SoundEvent("gui_inventory_gauntlet_back"); + return; + case 'petard' : + theSound.SoundEvent("gui_inventory_bombs_back"); + return; + case 'potion' : + theSound.SoundEvent("gui_inventory_potion_back"); + return; + case 'ranged' : + theSound.SoundEvent("gui_inventory_ranged_back"); + return; + case 'trophy' : + case 'horse_bag' : + theSound.SoundEvent("gui_inventory_horse_bage_back"); + return; + case 'horse_blinder' : + theSound.SoundEvent("gui_inventory_horse_blinder_back"); + return; + case 'horse_saddle' : + theSound.SoundEvent("gui_inventory_horse_saddle_back"); + return; + default : + theSound.SoundEvent("gui_inventory_other_back"); + return; + } +} + +function PlayItemConsumeSound( item : SItemUniqueId ) : void +{ + if( thePlayer.GetInventory().ItemHasTag( item, 'Drinks' ) || thePlayer.GetInventory().ItemHasTag( item, 'Alcohol' ) ) + { + theSound.SoundEvent('gui_inventory_drink'); + } + else + { + theSound.SoundEvent('gui_inventory_eat'); + } +} \ No newline at end of file diff --git a/mods/modStatTrak/content/scripts/game/player/r4player.ws b/mods/modStatTrak/content/scripts/game/player/r4player.ws new file mode 100644 index 0000000..1d634d6 --- /dev/null +++ b/mods/modStatTrak/content/scripts/game/player/r4player.ws @@ -0,0 +1,14676 @@ +/***********************************************************************/ +/** © 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 abstract import class CR4Player extends CPlayer +{ + + protected var pcGamePlayInitialized : bool; + + + private var pcMode : bool; + default pcMode = true; + + + protected saved var weaponHolster : WeaponHolster; + public var rangedWeapon : Crossbow; + public var crossbowDontPopStateHack : bool; default crossbowDontPopStateHack = false; + + private var hitReactTransScale : float; + + private var bIsCombatActionAllowed : bool; + private var currentCombatAction : EBufferActionType; + + private var uninterruptedHitsCount : int; + private var uninterruptedHitsCameraStarted : bool; + private var uninterruptedHitsCurrentCameraEffect : name; + + private var counterTimestamps : array; + + private var hitReactionEffect : bool; + + private var lookAtPosition : Vector; + private var orientationTarget : EOrientationTarget; + private var customOrientationTarget : EOrientationTarget; + protected var customOrientationStack : array; + + public var delayOrientationChange : bool; + protected var delayCameraOrientationChange : bool; + private var actionType : int; + private var customOrientationStackIndex : int; + + private var emptyMoveTargetTimer : float; + + private var onlyOneEnemyLeft : bool; + + public var isInFinisher : bool; + private var finisherTarget : CGameplayEntity; + + private var combatStance : EPlayerCombatStance; + + public var approachAttack : int; + 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; + + public var specialHeavyChargeDuration : float; + public var specialHeavyStartEngineTime : EngineTime; + public var playedSpecialAttackMissingResourceSound : bool; + public function SetPlayedSpecialAttackMissingResourceSound(b : bool) {playedSpecialAttackMissingResourceSound = b;} + + public var counterCollisionGroupNames : array; + + public saved var lastInstantKillTime : GameTime; + + + private var noSaveLockCombatActionName : string; default noSaveLockCombatActionName = 'combat_action'; + private var noSaveLockCombatAction : int; + private var deathNoSaveLock : int; + private var noSaveLock : int; + + + protected saved var newGamePlusInitialized : bool; + default newGamePlusInitialized = false; + + + 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; + + + private var keepRequestingCriticalAnimStart : bool; + + default keepRequestingCriticalAnimStart = false; + + + private var currentCustomAction : EPlayerExplorationAction; + public var substateManager : CExplorationStateManager; + protected var isOnBoat : bool; + 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; + + + + 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; + + + private var gwintAiDifficulty : EGwintDifficultyMode; default gwintAiDifficulty = EGDM_Easy; + private var gwintAiAggression : EGwintAggressionMode; default gwintAiAggression = EGAM_Defensive; + private var gwintMinigameState : EMinigameState; default gwintMinigameState = EMS_None; + + + import private var horseWithInventory : EntityHandle; + private var currentlyMountedHorse : CNewNPC; + private var horseSummonTimeStamp : float; + private saved var isHorseRacing : bool; + private var horseCombatSlowMo : bool; + default isHorseRacing = false; + default horseCombatSlowMo = true; + + + private var HudMessages : array ; + protected var fShowToLowStaminaIndication : float; + public var showTooLowAdrenaline : bool; + private var HAXE3Container : W3Container; + private var HAXE3bAutoLoot: bool; + private var bShowHud : bool; + private var dodgeFeedbackTarget : CActor; + + default HAXE3bAutoLoot = false; + default fShowToLowStaminaIndication = 0.0f; + default bShowHud = true; + + saved var displayedQuestsGUID : array< CGUID >; + saved var rewardsMultiplier : array< SRewardMultiplier >; + saved var glossaryImageOverride : array< SGlossaryImageOverride >; + + + private var prevRawLeftJoyRot : float; + protected var explorationInputContext : name; + protected var combatInputContext : name; + protected var combatFistsInputContext : name; + + + private var isInsideInteraction : bool; + private var isInsideHorseInteraction : bool; + public var horseInteractionSource : CEntity; + public var nearbyLockedContainersNoKey : array; + + + private var bMoveTargetChangeAllowed : bool; default bMoveTargetChangeAllowed = true; + private var moveAdj : CMovementAdjustor; + private var defaultLocomotionController : CR4LocomotionPlayerControllerScript; + + + 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; + + + var navQuery : CNavigationReachabilityQueryInterface; + + + public saved var rememberedCustomHead : name; + + + public saved var disableWeatherDisplay : bool; + + + public saved var proudWalk : bool; + private var etherealCount : int; + default etherealCount = 0; + + + public saved var injuredWalk : bool; + public saved var tiedWalk : bool; + private var insideDiveAttackArea : bool; + default insideDiveAttackArea = false; + private var diveAreaNumber : int; + default diveAreaNumber = -1; + + + private var flyingBossCamera : bool; + default flyingBossCamera = false; + + public function SetFlyingBossCamera( val : bool ) { flyingBossCamera = val; } + public function GetFlyingBossCamera() : bool { return flyingBossCamera; } + + + public saved var upscaledTooltipState : bool; + default upscaledTooltipState = false; + + + private var phantomWeaponMgr : CPhantomWeaponManager; + + + + 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; + } + + + editable var delayBetweenIllusionOneliners : float; + + hint delayBetweenIllusionOneliners = "delay in secs between oneliners about illusionary objects"; + + default delayBetweenIllusionOneliners = 5; + + + 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; + + + private var previousWeather : name; + private var previousRainStrength : float; + + + protected var receivedDamageInCombat : bool; + protected var prevDayNightIsNight : bool; + public var failedFundamentalsFirstAchievementCondition : bool; + + private var spawnedTime : float; + + public var currentMonsterHuntInvestigationArea : W3MonsterHuntInvestigationArea; + + private var isPerformingPhaseChangeAnimation : bool; + default isPerformingPhaseChangeAnimation = false; + + default receivedDamageInCombat = false; + + + public var playerMode : W3PlayerMode; + + + protected saved var selectedItemId : SItemUniqueId; + protected saved var blockedRadialSlots : array < SRadialSlotDef >; + + + public var enemyCollectionDist : float; + public var findMoveTargetDistMin : float; + public var findMoveTargetDistMax : float; + private var findMoveTargetScaledFrame : float; + public var interactDist : float; + protected var bCanFindTarget : bool; + private var bIsConfirmingEmptyTarget : bool; + private var displayTarget : CGameplayEntity; + private var isShootingFriendly : bool; + + default findMoveTargetDistMax = 18.f; + default findMoveTargetScaledFrame = 0.5f; + default interactDist = 3.5f; + + + private var currentSelectedTarget : CActor; + private var selectedTargetToConfirm : CActor; + private var bConfirmTargetTimerIsEnabled : bool; + + + public saved var thrownEntityHandle : EntityHandle; + private var isThrowingItemWithAim : bool; + private saved var isThrowingItem : bool; + private var isThrowHoldPressed : bool; + + + private var isAimingCrossbow : bool; + + default isThrowingItemWithAim = false; + + + public var playerAiming : PlayerAiming; + + + public var forceDismember : bool; + public var forceDismemberName : name; + public var forceDismemberChance : int; + public var forceDismemberExplosion : bool; + + + private var finisherVictim : CActor; + public var forceFinisher : bool; + public var forceFinisherAnimName : name; + public var forceFinisherChance : int; + public var forcedStance : bool; + + + 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; + + + 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; + } + + + + + + public var horseOnNavMesh : bool; + default horseOnNavMesh = true; + + public function SetHorseNav( val : bool ) { horseOnNavMesh = val; } + + + public var testAdjustRequestedMovementDirection : bool; + default testAdjustRequestedMovementDirection = false; + + + default autoState = 'Exploration'; + + + + + + + import final function GetEnemiesInRange( out enemies : array< CActor > ); + import final function GetVisibleEnemies( out enemies : array< CActor > ); + import final function IsEnemyVisible( enemy : CActor ) : bool; + + + import final function SetupEnemiesCollection( range, heightTolerance : float, + maxEnemies : int, + optional tag : name, + optional flags : int ); + + 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; + } + + + + + 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'); + AddAnimEventCallback('MoveNoise', 'OnAnimEvent_MoveNoise'); + + AddItemPerLevelList(); + + enemyCollectionDist = findMoveTargetDistMax; + + + theGame.RemoveTimeScale('horse_melee'); + + + if(!spawnData.restored && !((W3ReplacerCiri)this) ) + { + AddTimer('GiveStartingItems', 0.00001, true, , , true); + + if(!theGame.IsFinalBuild()) + { + + AddAbility('GeraltSkills_Testing'); + AddTimer('Debug_GiveTestingItems',0.0001,true); + } + + + FactsAdd("tut_stash_fresh_playthrough"); + } + + InitTargeting(); + + + if( spawnData.restored ) + { + + + + theGame.GameplayFactsRemove( "in_combat" ); + } + + + + if ( !weaponHolster ) + { + weaponHolster = new WeaponHolster in this; + } + + weaponHolster.Initialize( this, spawnData.restored ); + + if ( !interiorTracker ) + { + interiorTracker = new CPlayerInteriorTracker in this; + } + interiorTracker.Init( spawnData.restored ); + + + super.OnSpawned( spawnData ); + + + medallion = new W3MedallionFX in this; + + playerMode = new W3PlayerMode in this; + playerMode.Initialize( this ); + + + playerAiming = new PlayerAiming in this; + playerAiming.Initialize( this ); + + + navQuery = new CNavigationReachabilityQueryInterface in this; + + + EnableFindTarget( true ); + AddTimer( 'CombatCheck', 0.2f, true ); + + + substateManager = ( CExplorationStateManager ) GetComponentByClassName( 'CExplorationStateManager' ); + + findMoveTargetDist = findMoveTargetDistMax; + + SetupEnemiesCollection( enemyCollectionDist, findMoveTargetDist, 10, 'None', FLAG_Attitude_Neutral + FLAG_Attitude_Hostile + FLAG_Attitude_Friendly + FLAG_OnlyAliveActors ); + + + inputHandler.RemoveLocksOnSpawn(); + + + ((CActor) this ).SetInteractionPriority( IP_Prio_0 ); + + prevDayNightIsNight = theGame.envMgr.IsNight(); + CheckDayNightCycle(); + + + EnableVisualDebug( SHOW_AI, true ); + + + 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'); + } + + + 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(); + + + SetImmortalityMode( AIM_None, AIC_SyncedAnim ); + + + theGame.GetDefinitionsManager().GetContainedAbilities('DwimeritiumBomb_3', atts); + for(i=0; i 0) + BlockAllActions('mq3036', false); + + spawnedTime = theGame.GetEngineTimeAsSeconds(); + + if ( theGame.GetInGameConfigWrapper().GetVarValue('Gameplay', 'EnableUberMovement' ) == "1" ) + theGame.EnableUberMovement( true ); + else + theGame.EnableUberMovement( false ); + + + if ( !FactsDoesExist("gwent_difficulty") ) + FactsAdd("gwent_difficulty", 2); + + + if(!newGamePlusInitialized && FactsQuerySum("NewGamePlus") > 0) + { + NewGamePlusInitialize(); + } + + + if( lastInstantKillTime > theGame.GetGameTime() ) + { + SetLastInstantKillTime( GameTimeCreate(0) ); + } + + // modStatTrak BEGIN + if (!this.GetInventory().HasItem('Achievement Stats')) + { + this.GetInventory().AddAnItem('Achievement Stats', 1, 0, 0); + } + //modStatTrak END + } + + public function NewGamePlusInitialize() + { + + SetLastInstantKillTime( GameTimeCreate(0) ); + } + + 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(); + + + theGame.ReleaseNoSaveLock( noSaveLock ); + } + + + + + + public function GetBlockedSlots () : array < SRadialSlotDef > + { + return blockedRadialSlots; + } + + public function ClearBlockedSlots() + { + var i : int; + + + + 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; + } + } + } + + + + } + + 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; + } + + + + + + + public function RepairItem ( rapairKitId : SItemUniqueId, usedOnItem : SItemUniqueId ); + public function HasRepairAbleGearEquiped () : bool; + public function HasRepairAbleWaponEquiped () : bool; + public function IsItemRepairAble ( item : SItemUniqueId ) : bool; + + + + + + + public final function ReduceAllOilsAmmo( id : SItemUniqueId ) + { + var i : int; + var oils : array< W3Effect_Oil >; + + oils = inv.GetOilsAppliedOnItem( id ); + + for( i=0; i; + var buff, recentOil : W3Effect_Oil; + var i : int; + + item = GetEquippedSword( steel ); + oils = GetBuffs( EET_Oil ); + + if( oils.Size() > 1 ) + { + + + recentOil = inv.GetNewestOilAppliedOnItem( item, false ); + } + + for( i=0; i; + var buff : W3Effect_Oil; + var i : int; + + item = GetEquippedSword( isSteel ); + oils = GetBuffs( EET_Oil ); + + for( i=0; i; + var ammo, ammoBonus : float; + var dm : CDefinitionsManagerAccessor; + var buffParams : SCustomEffectParams; + var oilParams : W3OilBuffParams; + var oilName : name; + var min, max : SAbilityAttributeValue; + var i : int; + var oils : array< W3Effect_Oil >; + var existingOil : W3Effect_Oil; + + if( !CanApplyOilOnItem( oilId, usedOnItem ) ) + { + return false; + } + + dm = theGame.GetDefinitionsManager(); + inv.GetItemAbilitiesWithTag( oilId, theGame.params.OIL_ABILITY_TAG, oilAbilities ); + oilName = inv.GetItemName( oilId ); + oils = inv.GetOilsAppliedOnItem( usedOnItem ); + + + for( i=0; i= CalculateAttributeValue( max ) ) + { + inv.RemoveOldestOilFromItem( usedOnItem ); + } + } + } + + + ammo = CalculateAttributeValue(inv.GetItemAttributeValue(oilId, 'ammo')); + if(CanUseSkill(S_Alchemy_s06)) + { + ammoBonus = CalculateAttributeValue(GetSkillAttributeValue(S_Alchemy_s06, 'ammo_bonus', false, false)); + ammo *= 1 + ammoBonus * GetSkillLevel(S_Alchemy_s06); + } + + + if( existingOil ) + { + existingOil.Reapply( RoundMath( ammo ) ); + } + else + { + buffParams.effectType = EET_Oil; + buffParams.creator = this; + oilParams = new W3OilBuffParams in this; + oilParams.iconPath = dm.GetItemIconPath( oilName ); + oilParams.localizedName = dm.GetItemLocalisationKeyName( oilName ); + oilParams.localizedDescription = dm.GetItemLocalisationKeyName( oilName ); + oilParams.sword = usedOnItem; + oilParams.maxCount = RoundMath( ammo ); + oilParams.currCount = RoundMath( ammo ); + oilParams.oilAbilityName = oilAbilities[ 0 ]; + oilParams.oilItemName = oilName; + buffParams.buffSpecificParams = oilParams; + + AddEffectCustom( buffParams ); + + delete oilParams; + } + + LogOils("Added oil <<" + oilName + ">> to <<" + inv.GetItemName( usedOnItem ) + ">>"); + + + SetFailedFundamentalsFirstAchievementCondition( true ); + + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnOilApplied ); + + if( !inv.IsItemHeld( usedOnItem ) ) + { + PauseOilBuffs( inv.IsItemSteelSwordUsableByPlayer( usedOnItem ) ); + } + + return true; + } + + + public final function IsEquippedSwordUpgradedWithOil(steel : bool, optional oilName : name) : bool + { + var sword : SItemUniqueId; + var i : int; + var oils : array< W3Effect_Oil >; + + sword = GetEquippedSword( steel ); + if( !inv.IsIdValid( sword ) ) + { + return false; + } + + if( oilName == '' ) + { + return inv.ItemHasAnyActiveOilApplied( sword ); + } + + oils = inv.GetOilsAppliedOnItem( sword ); + for( i=0; i 0.1f; + } + + function HandleMovement( deltaTime : float ) + { + + + + + 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; + } + + + if ( !ignoreRepeatCheck ) + { + if( battlecry_lastTry == _BattleCry ) + return; + } + + battlecry_lastTry = _BattleCry; + + l_randValue = RandF(); + + + if( l_randValue < _Chance && ( _IgnoreDelay || BattleCryIsReady() ) ) + { + thePlayer.PlayVoiceset( 90, _BattleCry ); + + 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(); + } + } + + + + playerTickTimerPhase = ( playerTickTimerPhase + 1 ) % 3; + + focusModeController = theGame.GetFocusModeController(); + focusModeController.UpdateFocusInteractions( deltaTime ); + + + cnt = (int)( effectManager.GetCriticalBuffsCount() > 0 ); + SetBehaviorVariable('hasCriticalBuff', cnt); + } + + event OnDeath( damageAction : W3DamageAction ) + { + super.OnDeath( damageAction ); + + RemoveTimer('RequestCriticalAnimStart'); + + EnableFindTarget( false ); + BlockAllActions('Death', true); + + EnableHardLock( false ); + + theGame.CreateNoSaveLock( 'player_death', deathNoSaveLock, false, false ); + theGame.SetDeathSaveLockId( deathNoSaveLock ); + + ClearHostileEnemiesList(); + RemoveReactions(); + SetPlayerCombatTarget(NULL); + OnEnableAimingMode( false ); + + theGame.EnableFreeCamera( false ); + } + + + 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(); + } + + + + + + + public function AddCounterTimeStamp(time : EngineTime) {counterTimestamps.PushBack(time);} + + + public function CheckCounterSpamming(attacker : CActor) : bool + { + var counterWindowStartTime : EngineTime; + var i, spamCounter : int; + var reflexAction : bool; + var testEngineTime : EngineTime; + + if(!attacker) + return false; + + counterWindowStartTime = ((CNewNPC)attacker).GetCounterWindowStartTime(); + spamCounter = 0; + reflexAction = false; + + + if ( counterWindowStartTime == testEngineTime ) + { + return false; + } + + for(i = counterTimestamps.Size() - 1; i>=0; i-=1) + { + + if(counterTimestamps[i] >= (counterWindowStartTime - EngineTimeFromFloat(0.4)) ) + { + spamCounter += 1; + } + + else + { + counterTimestamps.Remove(counterTimestamps[i]); + continue; + } + + + if(!reflexAction && (counterTimestamps[i] >= counterWindowStartTime)) + reflexAction = true; + } + + + 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, mutation8TriggerHP : float; + var effectType : EEffectType; + var repelType : EPlayerRepelType = PRT_Random; + var params : SCustomEffectParams; + var thisPos, attackerPos : Vector; + var fistFightCheck, isMutation8 : 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; + var min, max : SAbilityAttributeValue; + var npc : CNewNPC; + + 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 ) + { + + validCounter = CheckCounterSpamming(parryInfo.attacker); + + if(validCounter) + { + if ( IsInCombatActionFriendly() ) + RaiseEvent('CombatActionFriendlyEnd'); + + SetBehaviorVariable( 'parryType', ChooseParryTypeIndex( parryInfo ) ); + SetBehaviorVariable( 'counter', (float)validCounter); + + + + SetBehaviorVariable( 'parryType', ChooseParryTypeIndex( parryInfo ) ); + SetBehaviorVariable( 'counter', (float)validCounter); + this.SetBehaviorVariable( 'combatActionType', (int)CAT_Parry ); + + + if ( !fistFightCounter ) + { + attackerInventory = parryInfo.attacker.GetInventory(); + weaponId = attackerInventory.GetItemFromSlot('r_weapon'); + attackerInventory.GetItemTags( weaponId , weaponTags ); + + if( GetWitcherPlayer().IsMutationActive( EPMT_Mutation8 ) ) + { + isMutation8 = true; + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation8', 'hp_perc_trigger', min, max ); + mutation8TriggerHP = min.valueMultiplicative; + } + + + + npc = (CNewNPC)parryInfo.attacker; + + + if ( parryInfo.attacker.HasAbility('mon_gravehag') ) + { + repelType = PRT_Slash; + parryInfo.attacker.AddEffectDefault(EET_CounterStrikeHit, this, 'ReflexParryPerformed'); + + } + else if ( npc && !npc.IsHuman() && !npc.HasTag( 'dettlaff_vampire' ) ) + { + repelType = PRT_SideStepSlash; + } + else if ( weaponTags.Contains('spear2h') ) + { + repelType = PRT_SideStepSlash; + parryInfo.attacker.AddEffectDefault(EET_CounterStrikeHit, this, "ReflexParryPerformed"); + parryInfo.attacker.SignalGameplayEvent( 'SpearDestruction'); + } + else if( isMutation8 && npc && !npc.IsImmuneToMutation8Finisher() ) + { + repelType = PRT_RepelToFinisher; + npc.AddEffectDefault( EET_CounterStrikeHit, this, "ReflexParryPerformed" ); + + + SetTarget( npc, true ); + + PerformFinisher( 0.f, 0 ); + } + else + { + + 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; + + ragdollTarget = parryInfo.attacker; + AddTimer( 'ApplyCounterRagdollTimer', 0.3 ); + } + else + { + useKnockdown = false; + if ( CanUseSkill(S_Sword_s11) ) + { + if( GetSkillLevel(S_Sword_s11) > 1 && RandRangeF(3,0) < GetWitcherPlayer().GetStat(BCS_Focus) ) + { + duration = CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s11, 'duration', false, true)); + useKnockdown = true; + } + } + else if ( parryInfo.attacker.IsHuman() ) + { + + 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'); + + + 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"); + } + + + 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(); + + + 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'); + } + } + + + + + 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; + + + 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; + } + } + + + 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 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; + + + 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); + + + 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); + IncHitCounter(); + + 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 ); + } + } + + + public function ReceivedCombatDamage() + { + receivedDamageInCombat = true; + } + + + + + + + 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); + + + AddTimer('UninterruptedHitsResetOnIdle', 4.f, false); + } + + timer function StartUninterruptedBlurr(dt : float, id : int) + { + var changed : bool; + var movingAgent : CMovingPhysicalAgentComponent; + var target : CActor; + + + if(uninterruptedHitsCount < 4) + { + LogUnitAtt("Stopping camera effect"); + thePlayer.StopEffect(uninterruptedHitsCurrentCameraEffect); + uninterruptedHitsCurrentCameraEffect = ''; + uninterruptedHitsCameraStarted = false; + RemoveTimer('StartUninterruptedBlurr'); + } + else + { + target = GetTarget(); + + if( target ) + { + movingAgent = ( (CMovingPhysicalAgentComponent) (target.GetMovingAgentComponent()) ); + } + + if(!uninterruptedHitsCameraStarted) + { + LogUnitAtt("Starting camera effect"); + AddTimer('StartUninterruptedBlurr', 0.001, true); + 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(changed) + { + + thePlayer.StopEffect(uninterruptedHitsCurrentCameraEffect); + + + 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; + + + thePlayer.PlayEffect(uninterruptedHitsCurrentCameraEffect); + } + } + } + } + + + + + + 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; + } + + + 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 ); + } + } + } + + + public function UnregisterForPlayerAction( listener : CGameplayEntity, isLockedByPlace : bool ) + { + playerActionEventListeners.Remove( listener ); + playerActionEventBlockingListeners.Remove( listener ); + if ( playerActionEventBlockingListeners.Size() == 0 ) + { + PlayerActionBlockGameplayActions( 'PlayerAction', false, isLockedByPlace ); + } + } + + event OnPlayerActionStart() + { + + 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; + + + 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 ( 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(); + } + } + + + + + + public function CanPerformPlayerAction(optional alsoOutsideExplorationState : bool) : bool + { + + if(!alsoOutsideExplorationState && GetCurrentStateName() != 'Exploration') + return false; + + if( isInAir || (substateManager && !substateManager.CanInteract()) || IsInCombatAction() || GetCriticalBuffsCount() > 0) + return false; + + return true; + } + + + 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(); + + + 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]); + } + } + } + + + 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; + + + CheckOfirItems(GetInventory(), hasArmor, hasBoots, hasGloves, hasPants, hasSword, hasSaddle, hasBag, hasBlinders); + + + 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; + + inv.GetAllItems(items); + dm = theGame.GetDefinitionsManager(); + + for(i=0; i; + var min, max : SAbilityAttributeValue; + + if(!inv.IsItemAlchemyItem(itemID)) + return; + + + currLevel = (int)CalculateAttributeValue(inv.GetItemAttributeValue(itemID, 'level')); + + + if(currLevel == 3 || currLevel == 2 || currLevel < 2 || currLevel > 3) + return; + + + currAbilities = inv.GetItemAbilitiesWithAttribute(itemID, 'level', currLevel); + + + inv.GetItemContainedAbilities(itemID, abs); + dm = theGame.GetDefinitionsManager(); + for(j=0; j> on item <<" + inv.GetItemName(itemID) + ">> !!!"); + } + else + { + for(j=0; j 0 ) + angles = VecToRotation( VecFromHeading( customOrientationInfoStack[ customOrientationInfoStack.Size() - 1 ].customHeading ) ); + else + angles = VecToRotation( GetHeadingVector() ); + + + dir = RotForward( angles ); + lookAtTarget = dir * 30.f + this.GetWorldPosition(); + 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; + } + lookAtTarget += theCamera.GetCameraDirection() * 100.f; + lookAtActive = 1.0f; + } + else if ( localOrientationTarget == OT_CameraOffset ) + { + + + dir = theCamera.GetCameraDirection(); + angles = VecToRotation( dir ); + angles.Pitch = -angles.Pitch + oTCameraPitchOffset; + angles.Yaw -= oTCameraOffset; + dir = RotForward( angles ); + + lookAtTarget = dir * 30.f + this.GetWorldPosition(); + 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 ) + + 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 + { + + + if ( slideTarget ) + { + lookAtTarget = ProcessLookAtTargetPosition( slideTarget, useTorsoBone ); + } + else + { + target = GetTarget(); + if ( target ) + { + lookAtTarget = ProcessLookAtTargetPosition( target, useTorsoBone ); + } + } + + lookAtActive = 1.0f; + } + + if ( !slideTarget && !IsUsingVehicle() ) + { + + playerRot = GetWorldRotation(); + lookAtTarget = GetWorldPosition() + VecFromHeading( playerRot.Yaw ) * 100.0f; + lookAtActive = 0.0f; + } + + if ( useTorsoBone ) + lookAtTarget.Z += 0.2f; + } + + + + + 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 ); + 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; + } + + + + + + event OnBlockingSceneEnded( optional output : CStorySceneOutput) + { + + SetImmortalityMode( AIM_None, AIC_SyncedAnim ); + super.OnBlockingSceneEnded(output); + } + + + + + + 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' && (category == 'steelsword' || category == 'silversword') ) + { + if( category == 'silversword' ) + { + ManageAerondightBuff( false ); + } + + GetBuff( EET_LynxSetBonus ).Pause( 'drawing weapon' ); + + PauseOilBuffs( category == 'steelsword' ); + } + + 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 ); + + + + m_RefreshWeaponFXType = true; + } + + event OnHolsterLeftHandItem() + { + weaponHolster.OnHolsterLeftHandItem(); + } + + timer function DelayedTryToReequipWeapon( dt: float, id : int ) + { + var weaponType : EPlayerWeapon; + + if( IsInCombat() && GetTarget() ) + { + weaponType = GetMostConvenientMeleeWeapon( GetTarget() ); + + if ( weaponType == PW_Steel || weaponType == PW_Silver ) + weaponHolster.OnEquipMeleeWeapon( weaponType, false ); + } + } + + 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(); + + + { + weaponType = GetCurrentMeleeWeaponType(); + + if ( weaponType == PW_None ) + { + + weaponType = GetMostConvenientMeleeWeapon( target ); + } + + + 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; + } + + + if( !ShouldGoToCombat( enemy ) ) + { + return false; + } + + weaponType = this.GetCurrentMeleeWeaponType(); + + if ( weaponType == PW_None || ( reevaluateCurrentWeapon && weaponType == PW_Fists ) || ( !IsInCombat() && weaponHolster.IsOnTheMiddleOfHolstering() ) ) + { + + weaponType = weaponHolster.GetMostConvenientMeleeWeapon( enemy ); + reevaluateCurrentWeapon = false; + } + + + 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() ) ) + { + + weaponType = weaponHolster.GetMostConvenientMeleeWeapon( enemy ); + } + + + GoToCombat( weaponType ); + + + return true; + } + + public function GoToExplorationIfNeeded() : bool + { + + + if( ! IsInCombatState() ) + { + return false; + } + + if( !ShouldGoToExploration() ) + { + return false; + } + + + weaponHolster.EndedCombat(); + + + GotoState( 'Exploration' ); + return true; + } + + event OnStateCanGoToCombat() + { + return false; + } + + event OnStateCanUpdateExplorationSubstates() + { + return false; + } + + private function ShouldGoToCombat( optional enemy : CActor ) : bool + { + var currentStateName : name; + + + if( !OnStateCanGoToCombat() ) + { + return false; + } + + currentStateName = GetCurrentStateName(); + + if( currentStateName == 'AimThrow' ) + { + return false; + } + + if( currentStateName == 'Swimming' ) + { + return false; + } + + if( currentStateName == 'TraverseExploration' ) + { + return false; + } + + + + + + + if ( !enemy ) + { + return playerMode.combatMode; + } + + + + + + return true; + } + + private function ShouldGoToExploration() : bool + { + if ( IsInCombat() ) + { + 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 ) + { + + 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 ); + } + } + + + public function GotoState( newState : name, optional keepStack : bool, optional forceEvents : bool ) + { + + + super.GotoState( newState, keepStack, forceEvents ); + + } + + 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(); + } + } + } + + + + + protected var disableActionBlend : bool; + + + + + 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 ) + { + + ( (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 maxSlideDistance : 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.MaxLocationAdjustmentSpeed( slideTicket, 1000000 ); + movementAdjustor.ScaleAnimation( slideTicket ); + minSlideDistance = ((CMovingPhysicalAgentComponent)this.GetMovingAgentComponent()).GetCapsuleRadius()+((CMovingPhysicalAgentComponent)slideNPC.GetMovingAgentComponent()).GetCapsuleRadius(); + if( IsInCombatFist() ) + { + maxSlideDistance = 1000.0f; + } + else + { + maxSlideDistance = minSlideDistance; + } + movementAdjustor.SlideTowards( slideTicket, slideTarget, minSlideDistance, maxSlideDistance ); + } + else if( !slideNPC.GetGameplayVisibility() ) + { + movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor(); + movementAdjustor.CancelByName( 'SlideToTarget' ); + slideNPC = NULL; + } + else + { + movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor(); + movementAdjustor.SlideTowards( slideTicket, slideTarget, minSlideDistance, maxSlideDistance ); + } + } + + event OnAnimEvent_ActionBlend( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + } + + + event OnAnimEvent_SubstateManager( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + + 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.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 ) + { + + } + + + event OnAnimEvent_pad_vibration( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + var witcher : W3PlayerWitcher; + + theGame.VibrateControllerHard(); + + + 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; + } + } + } + + + event OnAnimEvent_pad_vibration_light( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + + } + + event OnAnimEvent_KillWithRagdoll( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + + + } + + 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 OnAnimEvent_MoveNoise( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'MoveNoise', -1, 30.0f, -1.f, -1, true ); + } + + + 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' ) + { + + rotationRate = GetRotationRateFromAnimEvent( variant.enumValue ); + + movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor(); + if ( animEventType == AET_DurationStart || animEventType == AET_DurationStartInTheMiddle ) + { + + + if (! movementAdjustor.IsRequestActive( movementAdjustor.GetRequest( 'RotateToTarget' ) ) ) + { + + ticket = movementAdjustor.CreateNewRequest( 'RotateToTarget' ); + + + if ((int)rotationRate == 0) + movementAdjustor.AdjustmentDuration( ticket, animEventDuration ); + else + { + movementAdjustor.Continuous( ticket ); + movementAdjustor.BindToEvent( ticket, 'RotateToTarget' ); + } + + movementAdjustor.DontUseSourceAnimation( ticket ); + movementAdjustor.ReplaceRotation( ticket ); + } + else + { + + ticket = movementAdjustor.GetRequest( 'RotateToTarget' ); + } + MovAdjRotateToTarget( ticket ); + + if ((int)rotationRate > 0) + { + movementAdjustor.MaxRotationAdjustmentSpeed( ticket, (float)((int)rotationRate) ); + } + } + else if ( animEventType == AET_DurationEnd ) + { + + + } + else + { + + ticket = movementAdjustor.GetRequest( 'RotateToTarget' ); + MovAdjRotateToTarget( ticket ); + } + } + super.OnEnumAnimEvent(animEventName, variant, animEventType, animEventDuration, animInfo); + } + + event OnTeleported() + { + if( substateManager ) + { + substateManager.OnTeleported(); + } + } + + + + + + + event OnStartFistfightMinigame() + { + super.OnStartFistfightMinigame(); + + + 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 ); + } + } + + + + + 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, forceFaction : eGwintFaction ) + { + var gwintManager:CR4GwintManager; + gwintManager = theGame.GetGwintManager(); + + gwintMinigameState = EMS_None; + + gwintManager.SetEnemyDeckByName(deckName); + gwintManager.SetForcedFaction(forceFaction); + + if (gwintManager.GetHasDoneTutorial() || !theGame.GetTutorialSystem().AreMessagesEnabled()) + { + gwintManager.gameRequested = true; + theGame.RequestMenu( 'DeckBuilder' ); + } + else + { + theGame.GetGuiManager().ShowUserDialog( UMID_SkipGwintTutorial, "gwint_tutorial_play_query_title", "gwint_tutorial_play_query", UDB_YesNo ); + } + } + + public function StartGwint_TutorialOrSkip( skipTutorial : bool ) + { + var gwintManager : CR4GwintManager; + + if( skipTutorial ) + { + gwintManager = theGame.GetGwintManager(); + gwintManager.gameRequested = true; + gwintManager.SetHasDoneTutorial(true); + gwintManager.SetHasDoneDeckTutorial(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; + } + + + + + 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; + } + + + if( substateManager.UpdateCameraIfNeeded( moveData, dt ) ) + { + return true; + } + + + if ( theGame.IsFocusModeActive() ) + { + theGame.GetGameCamera().ChangePivotRotationController( 'Exploration' ); + theGame.GetGameCamera().ChangePivotDistanceController( 'Default' ); + theGame.GetGameCamera().ChangePivotPositionController( 'Default' ); + + + moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController(); + moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController(); + moveData.pivotPositionController = theGame.GetGameCamera().GetActivePivotPositionController(); + + + + 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; + } + + + + + 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 ); + + } + + + if( customCameraStack.Size() > 0 ) + { + + + } + + 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 ( 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' ); + + + moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController(); + moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController(); + moveData.pivotPositionController = theGame.GetGameCamera().GetActivePivotPositionController(); + + + 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 ); + + + + 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 ( playerMoveType >= PMT_Run ) + { + + camDist = -0.5f; + camOffset = 0.25; + + if ( !wasRunning ) + { + smoothTime = 1.f; + wasRunning = true; + } + DampFloatSpring( smoothTime, vel, 0.1, 0.5, timeDelta ); + } + else + { + + camDist = 0.f; + camOffset = 0.4f; + smoothTime = 0.2f; + wasRunning = false; + } + + + + DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( 0.3f, camDist, 0.3f ), smoothTime, 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' ); + + moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController(); + moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController(); + + + 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; + + } + else if ( oTCameraOffset == rightOffset ) + { + screenSpaceOffset = -0.65f; + oTCameraPitchOffset = 13.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; + } + } + 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; + } + else + { + angles = VecToRotation( GetHeadingVector() ); + heading = angles.Yaw + oTCameraOffset; + pitch = -angles.Pitch - oTCameraPitchOffset; + } + + if ( !wasBRAxisPushed && ( !bRAxisReleased ) ) + 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 ); + 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(); + + + cameraOffsetLeft = 30.f; + cameraOffsetRight = -30.f; + + + + + + + + theGame.GetGameCamera().ChangePivotRotationController( 'SignChannel' ); + theGame.GetGameCamera().ChangePivotDistanceController( 'SignChannel' ); + + 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 ) + { + + if( thePlayer.GetAutoCameraCenter() ) + { + theGame.GetGameCamera().ForceManualControlVerTimeout(); + } + + playerToCamAngle = AbsF( AngleDistance( GetHeading(), moveData.pivotRotationValue.Yaw ) ); + + + useExplorationSprintCam = false; + + if ( useExplorationSprintCam ) + { + if ( playerToCamAngle <= 45 ) + { + theGame.GetGameCamera().ChangePivotRotationController( 'Sprint' ); + + 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 + { + + 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_CastSign + && ( GetEquippedSign() == ST_Aard || GetEquippedSign() == ST_Yrden ) + && GetBehaviorVariable( 'alternateSignCast' ) == 1 ) + { + + theGame.GetGameCamera().ForceManualControlVerTimeout(); + pitch = -20.f; + + + } + + + + + + + + if ( IsCurrentSignChanneled() && GetCurrentlyCastSign() == ST_Quen ) + { + pitch = moveData.pivotRotationValue.Pitch; + } + + moveData.pivotRotationController.SetDesiredHeading( heading, ); + moveData.pivotRotationController.SetDesiredPitch( pitch ); + } + } + + + + event OnGameCameraExplorationRotCtrlChange() + { + if( substateManager ) + { + return substateManager.OnGameCameraExplorationRotCtrlChange( ); + } + + return false; + } + + + + + + + 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 ); + } + } + + + 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; + } + + + 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() ) + newCustomOrientationTarget = OT_Camera; + else if ( lastAxisInputIsMovement ) + { + if ( this.IsSwimming() ) + { + + + newCustomOrientationTarget = OT_Camera; + + + } + 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() ) ) + { + + heading = VecHeading( GetDisplayTarget().GetWorldPosition() - GetWorldPosition() ); + + + } + 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 ); + } + } + + + event OnDelayOrientationChangeOff() + { + delayOrientationChange = false; + delayCameraOrientationChange = false; + RemoveTimer( 'DelayOrientationChangeTimer' ); + + + + } + + 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 ) ) + { + 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(); + } + } + } + + + + + + + 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; + + + + + 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; + private var hostileMonsters : array; + 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( 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; + public function GetMoveTargets() : array { return moveTargets; } + public function GetNumberOfMoveTargets() : int { return moveTargets.Size(); } + public function GetHostileEnemies() : array { return hostileEnemies; } + public function GetHostileEnemiesCount() : int { return hostileEnemies.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 ( GetCurrentStateName() != 'PlayerDialogScene' && IsAlive() ) + { + GetVisibleEnemies( actors ); + + + if ( hostileEnemies.Size() > 0 ) + { + for( i=0; i < hostileEnemies.Size() ; i+=1 ) + { + if ( !actors.Contains( hostileEnemies[i] ) ) + actors.PushBack( hostileEnemies[i] ); + } + } + + + if ( finishableEnemiesList.Size() > 0 ) + { + for( i=0; i < finishableEnemiesList.Size() ; i+=1 ) + { + if ( !actors.Contains( finishableEnemiesList[i] ) ) + actors.PushBack( finishableEnemiesList[i] ); + } + } + + + if ( moveTarget && !actors.Contains( moveTarget ) ) + actors.PushBack( moveTarget ); + + FilterActors( actors, onlyThreatTargets, false ); + + + 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; + } + } + } + } + + + 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; + + else + setIsThreatened = false; + + + if ( setIsThreatened ) + { + enemyCollectionDist = 50.f; + SetIsThreatened( true ); + } + else + { + if ( IsThreatened() ) + AddTimer( 'finishableEnemiesList', 1.f ); + + enemyCollectionDist = findMoveTargetDistMax; + SetIsThreatened( false ); + } + + moveTargets = actors; + potentialMoveTargets = moveTargets; + + + 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 ); + 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 && ( 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 ); + + + if ( IsThreatened() && !IsInFistFightMiniGame() ) + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'CombatNearbyAction', 5.0, 18.0f, -1.f, -1, true ); + else + theGame.GetBehTreeReactionManager().RemoveReactionEvent( this, 'CombatNearbyAction'); + + + 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 ( 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' ) + { + 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 ( 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 navDistLimit : float = findMoveTargetDist; + 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; + } + + + public function LockToMoveTarget( lockTime : float ) + { + + } + + private timer function DisableLockToMoveTargetTimer( time : float , id : int) + { + if ( !this.IsActorLockedToTarget() ) + { + SetMoveTargetChangeAllowed( true ); + } + } + + public function SetMoveTargetChangeAllowed( flag : bool ) + { + + } + + 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; + } + + nonActorTargetMult = 1.25; + + + 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' ) + 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 ); + } + } + + + 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; + var sourceToTargetDists : array; + var i : int; + var targetingInfo : STargetingInfo; + + + + 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; + + + + + 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; + } + } + + + + 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 ); + + + targetingDist = softLockDistVehicle; + + if ( targets.Size() > 0 ) + { + targetingInfo.source = this; + targetingInfo.canBeTargetedCheck = true; + targetingInfo.coneCheck = false; + targetingInfo.coneHalfAngleCos = 0.86602540378f; + 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; + + 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 ); + + + } + } + + 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 ) + 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; + + + if ( info.canBeTargetedCheck && !targetActor.CanBeTargeted() ) + { + return false; + } + + + if ( info.invisibleCheck && !targetActor.GetGameplayVisibility() ) + { + return false; + } + + sourcePosition = sourceActor.GetWorldPosition(); + targetPosition = targetEntity.GetWorldPosition(); + + if ( targetActor ) + { + { + targetNPC = (CNewNPC)targetActor; + if ( targetNPC ) + { + if ( targetNPC.IsHorse() && !targetNPC.GetHorseComponent().IsDismounted() ) + { + return false; + } + } + } + } + + if ( info.distCheck || info.knockDownCheck ) + { + if ( usePrecalcs ) + { + if ( targetActor ) + { + + 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 ); + } + } + } + + + if ( info.distCheck ) + { + if ( sourceToTargetDist >= info.coneDist ) + { + return false; + } + } + + + if ( info.coneCheck || info.rsHeadingCheck ) + { + direction = VecNormalize2D( targetPosition - sourcePosition ); + } + + + if ( info.coneCheck ) + { + if ( VecDot2D( direction, info.coneHeadingVector ) < info.coneHalfAngleCos ) + { + return false; + } + } + + + 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; + } + } + } + + + if ( info.inFrameCheck && !WasVisibleInScaledFrame( targetEntity, info.frameScaleX, info.frameScaleY ) ) + { + return false; + } + + + 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; + } + } + + + if ( info.knockDownCheck ) + { + + if ( targetActor && !targetActor.IsAlive() ) + { + + finishEnabled = targetActor.GetComponent( 'Finish' ).IsEnabled(); + if ( finishEnabled ) + { + + if ( finishableEnemiesList.Contains( targetActor ) ) + { + + 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 ); + } + } + + + 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; + + + 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 ); + + + 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; + } + else + { + if ( IsSwimming() ) + { + if ( usePrecalcs ) + { + coneHeading = targetingPrecalcs.cameraHeading; + } + else + { + coneHeading = theGame.GetGameCamera().GetHeading(); + } + coneHalfAngleDot = 0.17364817766f; + } + else if ( bLAxisReleased ) + { + if( IsInCombatAction() ) + { + coneHeading = GetCombatActionHeading(); + } + else + { + if ( ShouldUsePCModeTargeting() ) + coneHeading = theGame.GetGameCamera().GetHeading(); + else + coneHeading = cachedRawPlayerHeading; + } + + if ( IsInCombat() ) + { + if ( ShouldUsePCModeTargeting() ) + coneHalfAngleDot = -1; + else + coneHalfAngleDot = 0.17364817766f; + } + else + { + coneHalfAngleDot = -1.0f; + } + } + else + { + if( IsInCombatAction() ) + { + coneHeading = GetCombatActionHeading(); + } + else + { + if ( ShouldUsePCModeTargeting() ) + coneHeading = theGame.GetGameCamera().GetHeading(); + else + coneHeading = cachedRawPlayerHeading; + } + + if ( ShouldUsePCModeTargeting() ) + coneHalfAngleDot = -1; + else + coneHalfAngleDot = 0.17364817766f; + } + + 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; + } + + + + + 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; + 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; + + + + 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; + + 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; + } + } + } + + + 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() ) + { + + 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; + } + + + 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 ) + { + + 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(); + + + if ( nonCombatCheck ) + { + info.coneHeadingVector = targetingPrecalcs.playerHeadingVector; + if ( lastAxisInputIsMovement ) + { + info.coneHeadingVector = selectionHeadingVector; + info.invisibleCheck = false; + info.coneCheck = true; + info.coneHalfAngleCos = 0.76604444311f; + } + else + { + info.invisibleCheck = false; + info.frameScaleX = 0.9f; + info.frameScaleY = 0.9f; + } + } + else + { + info.coneHeadingVector = Vector( 0.0f, 0.0f, 0.0f ); + + + if ( IsInCombat() ) + { + info.inFrameCheck = false; + } + else + { + if ( !bLAxisReleased ) + { + info.coneCheck = true; + + if ( this.IsSwimming() ) + info.coneHalfAngleCos = -1; + else + info.coneHalfAngleCos = 0.86602540378f; + + info.coneHeadingVector = targetingIn.rawPlayerHeadingVector; + } + } + } + + cameraPosition = theCamera.GetCameraPosition(); + cameraDirection = targetingPrecalcs.cameraDirection; + playerToCamPlaneDist = VecDot2D( cameraDirection, this.GetWorldPosition() - cameraPosition ); + + + 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 ) + { + + 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(); + + + 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' ) ) )) + { + 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 ( 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 ]; + } + } + + + 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() ) + { + 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 ) + { + selectionWeights.angleWeight = 0.55f; + selectionWeights.distanceWeight = 0.45f; + selectionWeights.distanceRingWeight = 0.f; + } + else + { + selectionWeights.angleWeight = 0.75f; + selectionWeights.distanceWeight = 0.25f; + selectionWeights.distanceRingWeight = 0.f; + } + } + 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 ); + + 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 ); + + + + } + } + + + public function SetSlideTarget( actor : CGameplayEntity ) + { + + + + 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' ); + } + + 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 ( !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 ) + { + if( flag && GetTarget().HasTag( 'NoHardLock' ) ) + return; + + 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' ); + + SetIsCameraLockedToTarget( flag ); + } + else if ( !flag && IsCameraLockedToTarget() ) + { + thePlayer.EnableManualCameraControl( true, 'LockCameraToTarget' ); + + SetIsCameraLockedToTarget( flag ); + } + } + + public function LockActorToTarget( flag : bool, optional withoutIcon : bool ) + { + var displayTargetActor : CActor; + + if ( flag ) + { + if ( !IsActorLockedToTarget() ) + { + + 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 ); + } + } + + + + + + + protected function PlayHitAnimation(damageAction : W3DamageAction, animType : EHitReactionType) + { + var hitRotation : float; + var onHitCounter : SAbilityAttributeValue; + var counter : int; + + 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) + { + super.PlayHitAnimation( damageAction, animType ); + if ( damageAction.attacker.HasAbility( 'IncreaseHitReactionSeverityWithHitCounter' ) ) + { + counter = GetHitCounter(); + switch ( counter ) + { + case 2 : + SetBehaviorVariable( 'HitReactionType', 2 ); + break; + + case 3 : + AddEffectDefault( EET_Stagger, damageAction.attacker, damageAction.attacker.GetName() ); + break; + + case 4 : + AddEffectDefault( EET_Knockdown, damageAction.attacker, damageAction.attacker.GetName() ); + break; + + default : + break; + } + } + SetHitReactionDirection(damageAction.attacker); + SetDetailedHitReaction(damageAction.GetSwingType(), damageAction.GetSwingDirection()); + } + + RaiseForceEvent( 'Hit' ); + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'ActorInHitReaction', -1, 30.0f, -1.f, -1, true ); + + 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; + + + SetCustomRotation( 'Hit', hitRotation, 1080.f, 0.1f, false ); + } + + CriticalEffectAnimationInterrupted("PlayHitAnimation"); + } + + public function ReduceDamage( out damageData : W3DamageAction) + { + super.ReduceDamage(damageData); + + + 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; + } + } + + + public function GetCriticalHitChance( isLightAttack : bool, isHeavyAttack : bool, target : CActor, victimMonsterCategory : EMonsterCategory, isBolt : bool ) : float + { + var critChance : float; + var oilChanceAttribute : name; + var weapons : array< SItemUniqueId >; + var i : int; + var holdsCrossbow : bool; + var critVal : SAbilityAttributeValue; + + critChance = 0; + + + if( FactsQuerySum( 'debug_fact_critical_boy' ) > 0 ) + { + critChance += 1; + } + + if( IsInState( 'HorseRiding' ) && ( ( CActor )GetUsedVehicle() ).GetMovingAgentComponent().GetRelativeMoveSpeed() >= 4.0 ) + { + critChance += 1; + } + + + critChance += CalculateAttributeValue( GetAttributeValue( theGame.params.CRITICAL_HIT_CHANCE ) ); + + + weapons = inv.GetHeldWeapons(); + for( i=0; i 0 && !((W3Effect_Toxicity)damageAction.causer)) + ReceivedCombatDamage(); + + + if(FactsQuerySum("tut_fight_use_slomo") > 0) + { + theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_TutorialFight) ); + FactsRemove("tut_fight_slomo_ON"); + } + + + if( !substateManager.ReactOnBeingHit( damageAction ) ) + { + GoToCombatIfNeeded(); + + } + + return sup; + } + + protected function ShouldPauseHealthRegenOnHit() : bool + { + return true; + } + + public function PlayHitEffect(damageAction : W3DamageAction) + { + super.PlayHitEffect(damageAction); + + + 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; + } + + + + + + + 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' ; + var counter : int; + var onHitCounter : SAbilityAttributeValue; + + + + + if(CanParryAttack() && FistFightCheck( parryInfo.target, parryInfo.attacker, fistFightParry ) ) + { + parryHeading = GetParryHeading( parryInfo, parryDir ) ; + + 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(); + IncDefendCounter(); + } + } + else + { + counter = GetDefendCounter(); + onHitCounter = parryInfo.attacker.GetAttributeValue( 'break_through_parry_on_hit_counter' ); + if ( onHitCounter.valueBase > 0 && counter == onHitCounter.valueBase ) + { + AddEffectDefault( EET_Stagger, parryInfo.attacker, "Break through parry" ); + } + else if ( RaiseForceEvent( 'PerformParry' ) ) + { + OnCombatActionStart(); + ClearCustomOrientationInfoStack(); + SetSlideTarget( parryInfo.attacker ); + SetCustomRotation( 'Parry', parryHeading, 1080.f, 0.1f, false ); + IncDefendCounter(); + } + else + return false; + } + } + else + { + AddEffectDefault(EET_Stagger, parryInfo.attacker, "Parry"); + return true; + } + + 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 + 90; + } + else if( currToTargetAttackerAngleDiff <= -45 && currToTargetAttackerAngleDiff > -135 ) + { + parryDir = PPD_Left; + + return targetToAttackerHeading - 90; + } + else + { + parryDir = PPD_Back; + + 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.HasTag( 'NoHardLock' ) ) + return false; + + if ( newLockTarget ) + tempLockTarget = newLockTarget; + else + { + incomingAttacker = GetClosestIncomingAttacker(); + if ( incomingAttacker && incomingAttacker.IsAlive() && IsUsingVehicle() ) + { + tempLockTarget = incomingAttacker; + useIncomingAttacker = false; + } + + if ( !useIncomingAttacker ) + { + target = GetTarget(); + if( target.HasTag('ForceHardLock')) + { + return true; + } + else 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.HasTag( 'NoHardLock' ) ) + return false; + + 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; + } + + + + + + event OnTaskSyncAnim( npc : CNewNPC, animNameLeft : name ) {} + + + 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; + + + if(FactsQuerySum('player_is_the_boss') > 0) + { + + + SetDebugAttackRange(data.rangeName); + RemoveTimer('PostAttackDebugRangeClear'); + + return ret; + } + + ret = super.TestParryAndCounter(data, weaponId, parried, countered); + + + if(parried) + theGame.GetGamerProfile().ResetStat(ES_CounterattackChain); + + return ret; + } + + public function SetSpecialAttackTimeRatio(f : float) + { + LogSpecialHeavy(f); + specialAttackTimeRatio = f; + } + + public function GetSpecialAttackTimeRatio() : float + { + return specialAttackTimeRatio; + } + + + public function OnSpecialAttackHeavyActionProcess() + { + + 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; + + + 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); + } + + 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); + } + + + + 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); + + if ( stance == PCS_AlertNear ) + this.SetBehaviorVariable('isInCombatForOverlay',1.f); + else + this.SetBehaviorVariable('isInCombatForOverlay',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; + + 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 ); + } + } + + + + + + 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 ) + ResetCachedRawPlayerHeading(); + + processedActionHeading = cachedRawPlayerHeading; + + return processedActionHeading; + } + + + function ResetRawPlayerHeading() + { + if ( GetDisplayTarget() ) + rawPlayerHeading = VecHeading( GetDisplayTarget().GetWorldPosition() - this.GetWorldPosition() ); + else + rawPlayerHeading = GetHeading(); + + + } + + 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 ( !this.IsUsingVehicle() ) + FindTarget( true, action, true ); + else + ((CR4PlayerStateUseGenericVehicle)this.GetState( 'UseGenericVehicle' )).FindTarget(); + + return GetTarget(); + } + } + + + 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; + } + + + 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; + 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; + 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; + } + + + public function SetupCombatAction( action : EBufferActionType, stage : EButtonStage ) + { + var weaponType : EPlayerWeapon; + var canAttackTarget : CGameplayEntity; + var target : CActor; + + + 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 ); + + + if ( weaponType != weaponHolster.GetCurrentMeleeWeapon() ) + { + + if ( !( weaponType == PW_None && weaponHolster.GetCurrentMeleeWeapon() == PW_Fists ) ) + return; + } + } + + + 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'); + this.SignalGameplayEvent( 'FriendlyAttackAction' ); + return false; + } + } + + return true; + } + + + + 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'); + } + + + 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 || action == EBAT_Roll ) ) + { + SetIsCurrentlyDodging(false); + } + + SetCombatActionHeading( ProcessCombatActionHeading( action ) ); + + + + if ( action == EBAT_ItemUse && GetInventory().IsItemCrossbow( selectedItemId ) ) + { + + 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" ); + + + 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 : + { + + + + + + + DrainStamina(ESAT_LightAttack); + + + 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 : + { + + + + + + DrainStamina(ESAT_HeavyAttack); + + + + thePlayer.BreakPheromoneEffect(); + actionResult = this.OnPerformAttack(theGame.params.ATTACK_NAME_HEAVY); + + } break; + + case BS_Pressed : + { + if ( this.GetCurrentStateName() == 'CombatFists' ) + { + + + + + + DrainStamina(ESAT_HeavyAttack); + + + + thePlayer.BreakPheromoneEffect(); + actionResult = this.OnPerformAttack(theGame.params.ATTACK_NAME_HEAVY); + + } + } break; + + default : + { + actionResult = false; + + } break; + } + } break; + + case EBAT_ItemUse : + { + switch ( stage ) + { + case BS_Pressed : + { + if ( !( (W3PlayerWitcher)this ) || + ( !IsInCombatActionFriendly() && !( !GetBIsCombatActionAllowed() && ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack || GetBehaviorVariable( 'combatActionType' ) == (int)CAT_CastSign ) ) ) ) + + { + if ( inv.IsItemCrossbow( selectedItemId ) ) + { + rangedWeapon = ( Crossbow )( inv.GetItemEntityUnsafe( selectedItemId ) ); + rangedWeapon.OnRangedWeaponPress(); + GetTarget().SignalGameplayEvent( 'Approach' ); + GetTarget().SignalGameplayEvent( 'ShootingCrossbow' ); + } + else if(inv.IsItemBomb(selectedItemId) && this.inv.SingletonItemGetAmmo(selectedItemId) > 0 ) + { + if( ((W3PlayerWitcher)this).GetBombDelay( ((W3PlayerWitcher)this).GetItemSlot( selectedItemId ) ) <= 0.0f ) + { + 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 ) ) ) ) ) + + { + if ( inv.IsItemCrossbow( selectedItemId ) ) + { + + 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; + + + + 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; + } + + + CleanCombatActionBuffer(); + + if (actionResult) + { + SetCombatAction( action ) ; + + if(GetWitcherPlayer().IsInFrenzy()) + GetWitcherPlayer().SkillFrenzyFinish(0); + } + + return true; + } + + public function CleanCombatActionBuffer() + { + BufferCombatAction = EBAT_EMPTY; + BufferAllSteps = false; + } + + public function CancelHoldAttacks() + { + RemoveTimer( 'IsSpecialLightAttackInputHeld' ); + RemoveTimer( 'IsSpecialHeavyAttackInputHeld' ); + RemoveTimer( 'SpecialAttackLightSustainCost' ); + RemoveTimer( 'SpecialAttackHeavySustainCost' ); + RemoveTimer( 'UpdateSpecialAttackLightHeading' ); + UnblockAction( EIAB_Crossbow, 'SpecialAttack' ); + + ResumeStaminaRegen('WhirlSkill'); + + if ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_SpecialAttack && GetBehaviorVariable( 'isPerformingSpecialAttack' ) == 1.f ) + { + if( GetBehaviorVariable( 'playerAttackType' ) == (int)PAT_Light ) + { + SetAttackActionName(SkillEnumToName(S_Sword_s01)); + PushCombatActionOnBuffer( EBAT_SpecialAttack_Light, BS_Released ); + ProcessCombatActionBuffer(); + + ((W3PlayerWitcherStateCombatFists) GetState('Combat')).ResetTimeToEndCombat(); + + } + else if( GetBehaviorVariable( 'playerAttackType' ) == (int)PAT_Heavy ) + { + SetAttackActionName(SkillEnumToName(S_Sword_s02)); + PushCombatActionOnBuffer( EBAT_SpecialAttack_Heavy, BS_Released ); + ProcessCombatActionBuffer(); + + } + } + } + + 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 ); + + OnCombatActionStart(); + + playerToTargetHeading = VecHeading( actor.GetWorldPosition() - GetWorldPosition() ); + + SetCustomRotation( 'Attack', playerToTargetHeading, 0.0f, 0.3f, false ); + + return true; + } + + return false; + } + + public function SendAttackReactionEvent() + { + var reactionName : name; + + + + reactionName = 'AttackAction'; + + if ( IsNameValid(reactionName) ) + { + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, reactionName, -1.0, 8.0f, -1, 5, true ); + } + + + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'outOfMyWay', -1.0, 2.0f, -1, 5, true ); + } + + var forceCanAttackWhenNotInCombat : int; + 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 + + 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; + } + + + 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; + + thePlayer.GetVisibleEnemies( localTargets ); + size = localTargets.Size(); + + if ( size > 0 ) + { + for ( i = size-1; i>=0; i-=1 ) + { + + 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 ) ); + + 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; + } + + + + + + 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); + } + + + private final function DisallowedActionDontShowHack(action : EInputActionBlock, isTimeLock : bool) : bool + { + var locks : array< SInputActionLock >; + var i : int; + + + 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; + } + + + if( action == EIAB_ThrowBomb && ( HasBuff( EET_Hypnotized ) || HasBuff( EET_Confusion ) ) ) + { + return false; + } + + + if(isTimeLock) + return false; + + + if(action == EIAB_OpenMeditation) + return false; + + + locks = GetActionLocks(action); + for(i=0; i= 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 ) + { + m_SettlementBlockCanter += valueAdd; + } + + var countDownToStart : int; + default countDownToStart = 0; + + function DisplayRaceStart( countDownSecondsNumber : int ) + { + 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) + { + var hud : CR4ScriptedHud; + var messageModule : CR4HudModuleMessage; + + countDownToStart -= 1; + hud = (CR4ScriptedHud)theGame.GetHud(); + + if( hud ) + { + messageModule = (CR4HudModuleMessage)hud.GetHudModule("MessageModule"); + if( messageModule ) + { + messageModule.OnMessageHidden(); + } + } + + if( countDownToStart <= 0 ) + { + RemoveTimer('RaceCountdown'); + } + } + + public function GetCountDownToStart() : int + { + return countDownToStart; + } + + public function HAXE3GetContainer() : W3Container + { + return HAXE3Container; + } + + public function HAXE3SetContainer( container : W3Container) : void + { + HAXE3Container = container; + } + + public function HAXE3GetAutoLoot() : bool + { + return HAXE3bAutoLoot; + } + + public function HAXE3SetAutoLoot( value : bool ) : void + { + 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); + } + + function IsNewQuest( questGuid : CGUID ) : bool + { + var i : int; + for(i = 0; i < displayedQuestsGUID.Size(); i += 1 ) + { + if( displayedQuestsGUID[i] == questGuid ) + { + return false; + } + } + displayedQuestsGUID.PushBack(questGuid); + return true; + } + + function GetRewardMultiplierData( rewardName : name ) : SRewardMultiplier + { + var defaultReward : SRewardMultiplier; + var i : int; + + for(i = 0; i < rewardsMultiplier.Size(); i += 1 ) + { + if( rewardsMultiplier[i].rewardName == rewardName ) + { + return rewardsMultiplier[i]; + } + } + + defaultReward.rewardName = rewardName; + defaultReward.rewardMultiplier = 1.0; + defaultReward.isItemMultiplier = false; + + return defaultReward; + } + + function GetRewardMultiplier( rewardName : name ) : float + { + 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 + { + 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, optional isItemMultiplier : bool ) : void + { + var i : int; + var rewardMultiplier : SRewardMultiplier; + + for(i = 0; i < rewardsMultiplier.Size(); i += 1 ) + { + if( rewardsMultiplier[i].rewardName == rewardName ) + { + rewardsMultiplier[i].rewardMultiplier = value; + rewardsMultiplier[i].isItemMultiplier = isItemMultiplier; + return; + } + } + + rewardMultiplier.rewardName = rewardName; + rewardMultiplier.rewardMultiplier = value; + rewardMultiplier.isItemMultiplier = isItemMultiplier; + + rewardsMultiplier.PushBack(rewardMultiplier); + } + + function RemoveRewardMultiplier( rewardName : name ) : void + { + var i : int; + for(i = 0; i < rewardsMultiplier.Size(); i += 1 ) + { + if( rewardsMultiplier[i].rewardName == rewardName ) + { + rewardsMultiplier.Erase(i); + return; + } + } + } + + + + + + + + public final function TissueExtractorDischarge() : bool + { + var ids : array; + var chargesLeft, uses, curr, max, red, blue, green : int; + var i : int; + var text : string; + + ids = thePlayer.inv.GetItemsByName( 'q705_tissue_extractor' ); + if( ids.Size() == 0 ) + { + return false; + } + + curr = GetTissueExtractorChargesCurr(); + max = GetTissueExtractorChargesMax(); + + if( curr >= max ) + { + + uses = FloorF( ( ( float ) curr ) / ( ( float ) max ) ); + chargesLeft = Max( 0, curr - uses * max ); + + + inv.SetItemModifierInt( ids[0], 'charges', chargesLeft ); + + + blue = 0; + green = 0; + red = 0; + for( i=0; i 0 ) + { + inv.AddAnItem( 'Greater mutagen blue', blue, false, true ); + text += "
" + blue + "x " + GetLocStringByKey( inv.GetItemLocalizedNameByName( 'Greater mutagen blue' ) ); + } + if( green > 0 ) + { + inv.AddAnItem( 'Greater mutagen green', green, false, true ); + text += "
" + green + "x " + GetLocStringByKey( inv.GetItemLocalizedNameByName( 'Greater mutagen green' ) ); + } + if( red > 0 ) + { + inv.AddAnItem( 'Greater mutagen red', red, false, true ); + text += "
" + red + "x " + GetLocStringByKey( inv.GetItemLocalizedNameByName( 'Greater mutagen red' ) ); + } + + + theGame.GetGuiManager().ShowNotification( text ); + + + inv.SetItemModifierInt( ids[0], 'ui_notified', 0 ); + + return true; + } + else + { + + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_q705_extractor_too_few_charges" ) ); + } + + return false; + } + + public final function TissueExtractorIncCharge() + { + var ids : array; + var uiData : SInventoryItemUIData; + var curr : int; + + ids = thePlayer.inv.GetItemsByName( 'q705_tissue_extractor' ); + if( ids.Size() == 0 ) + { + return; + } + + curr = GetTissueExtractorChargesCurr() + 1; + inv.SetItemModifierInt( ids[0], 'charges', curr ); + + + if( curr >= GetTissueExtractorChargesMax() ) + { + uiData = inv.GetInventoryItemUIData( ids[0] ); + uiData.isNew = true; + inv.SetInventoryItemUIData( ids[0], uiData ); + + + if( inv.GetItemModifierInt( ids[0], 'ui_notified', 0 ) == 0 ) + { + inv.SetItemModifierInt( ids[0], 'ui_notified', 1 ); + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_q705_extractor_charged" ), , true ); + } + } + } + + public final function GetTissueExtractorChargesCurr() : int + { + var ids : array; + + ids = thePlayer.inv.GetItemsByName( 'q705_tissue_extractor' ); + if( ids.Size() == 0 ) + { + return 0; + } + + return inv.GetItemModifierInt( ids[0], 'charges', 0 ); + } + + public final function GetTissueExtractorChargesMax() : int + { + var ids : array; + var val : SAbilityAttributeValue; + + ids = thePlayer.inv.GetItemsByName( 'q705_tissue_extractor' ); + if( ids.Size() == 0 ) + { + return 0; + } + + val = inv.GetItemAttributeValue( ids[0], 'maxCharges' ); + + return FloorF( val.valueBase ); + } + + public function GetEquippedSword(steel : bool) : SItemUniqueId; + + public final function HasRequiredLevelToEquipItem(item : SItemUniqueId) : bool + { + if(HasBuff(EET_WolfHour)) + { + if((inv.GetItemLevel(item) - 2) > GetLevel() ) + return false; + } + else + { + if(inv.GetItemLevel(item) > GetLevel() ) + return false; + } + + return true; + } + + public function SkillReduceBombAmmoBonus() + { + var i, ammo, maxAmmo : int; + var items : array; + + items = inv.GetSingletonItems(); + + for(i=0; i 0) + { + maxAmmo = inv.SingletonItemGetMaxAmmo(items[i]); + + + 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; + + + category = inv.GetItemCategory(itemId); + if(category == 'edibles' || inv.ItemHasTag(itemId, 'Drinks') || ( category == 'alchemy_ingredient' && inv.ItemHasTag(itemId, 'Alcohol')) ) + { + + if(IsFistFightMinigameEnabled()) + { + DisplayActionDisallowedHudMessage(EIAB_Undefined, false, false, true); + return false; + } + + + inv.GetItemBuffs(itemId, buffs); + + for(i=0; i= cost) ); + + + if(!ret && IsSkillSign(skill) && CanUseSkill(S_Perk_09) && GetStat(BCS_Focus) >= 1) + { + ret = true; + } + + + if( !ret && IsSkillSign( skill ) && GetWitcherPlayer().HasBuff( EET_GryphonSetBonus ) ) + { + 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; + } + + + 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 + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetSkillLocalisationKeyName(skill); + + return ""; + } + + public function GetSkillLocalisationKeyDescription(skill : ESkill) : string + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetSkillLocalisationKeyDescription(skill); + + return ""; + } + + public function GetSkillIconPath(skill : ESkill) : string + { + 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 + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).CanLearnSkill(skill); + + return false; + } + + public function HasSpentEnoughPoints(skill : ESkill) : bool + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).HasSpentEnoughPoints(skill); + + return false; + } + + public function PathPointsForSkillsPath(skill : ESkill) : int + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).PathPointsSpentInSkillPathOfSkill(skill); + + return -1; + } + + public function GetPlayerSkills() : array + { + var null : array; + + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetPlayerSkills(); + + return null; + } + + public function GetPlayerSkill(s : ESkill) : SSkill + { + var null : SSkill; + + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetPlayerSkill(s); + + return null; + } + + public function GetSkillSubPathType(s : ESkill) : ESkillSubPath + { + 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; + } + + + + + 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; + } + + + 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; + } + + + 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; + } + + + public function GetSkillOnSlot(slotID : int, out skill : ESkill) : bool + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetSkillOnSlot(slotID, skill); + + skill = S_SUndefined; + return false; + } + + + public function GetFreeSkillSlot() : int + { + var i, size : int; + var skill : ESkill; + + size = ((W3PlayerAbilityManager)abilityManager).GetSkillSlotsCount(); + for(i=1; i, attackAnimationName : name, hitTime : float, weaponEntity : CItemEntity) + { + var attackAction : W3Action_Attack; + + if(!PrepareAttackAction(hitTarget, animData, weaponId, parried, countered, parriedBy, attackAnimationName, hitTime, weaponEntity, attackAction)) + return; + + 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() ); + + + 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; + + + + if( isCurrentlyDodging ) + return; + + l_stateName = GetCurrentStateName(); + + if( !attackEventInProgress && l_stateName == 'CombatFists' ) + return; + + CalcEntitySlotMatrix('r_weapon', l_slotMatrix); + + l_weaponPosition = MatrixGetTranslation( l_slotMatrix ); + + + switch( l_stateName ) + { + case 'CombatFists': + l_offset = MatrixGetAxisX( l_slotMatrix ); + l_offset = VecNormalize( l_offset ) * 0.25f; + break; + + default: + l_offset = MatrixGetAxisZ( l_slotMatrix ); + l_offset = VecNormalize( l_offset ) * 1.f; + break; + } + + l_weaponTipPos = l_weaponPosition + l_offset; + + + + if( !attackEventInProgress ) + { + + if( m_LastWeaponTipPos == Vector ( 0, 0, 0 ) ) + l_distance = 0; + else + l_distance = VecDistance( l_weaponTipPos, m_LastWeaponTipPos ) ; + + + + + m_LastWeaponTipPos = l_weaponTipPos; + if( l_distance < 0.35f ) + return; + + } + + + + m_LastWeaponTipPos = l_weaponTipPos; + + if ( !theGame.GetWorld().StaticTraceWithAdditionalInfo( l_weaponPosition, l_weaponTipPos, l_collidingPosition, l_normal, l_materialName, l_hitComponent, m_WeaponFXCollisionGroupNames ) ) + { + + 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 ); + + + switch( l_stateName ) + { + case 'CombatFists': + m_CollisionEffect.PlayEffect('fist'); + break; + default: + + 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; + case 'flesh': + m_CollisionEffect.PlayEffect('blood'); + break; + default: + m_CollisionEffect.PlayEffect('wood'); + break; + } + + } + break; + } + + + if(l_hitComponent) + { + barrel = (COilBarrelEntity)l_hitComponent.GetEntity(); + if(barrel) + { + barrel.OnFireHit(NULL); + return; + } + } + + + l_destructibleCmp = (CDestructionSystemComponent) l_hitComponent; + if( l_destructibleCmp && l_stateName != 'CombatFists' ) + { + l_destructibleCmp.ApplyFracture(); + } + + + + } + + public function ReactToReflectedAttack( target : CGameplayEntity) + { + + var hp, dmg : float; + var action : W3DamageAction; + + super.ReactToReflectedAttack(target); + + + theGame.VibrateControllerLight(); + } + + + + + + + function GetFallDist( out fallDist : float ) : bool + { + var fallDiff, jumpTotalDiff : float; + + + 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(); + + if(IsAlive()) + { + if(ShouldProcessTutorial('TutorialFallingDamage')) + { + FactsSet( "tutorial_falling_damage", 1 ); + } + + if(FactsQuerySum("tutorial_falling_damage") > 1 && ShouldProcessTutorial('TutorialFallingRoll')) + { + + tut.type = ETMT_Hint; + tut.tutorialScriptTag = 'TutorialFallingRoll'; + tut.hintPositionType = ETHPT_DefaultGlobal; + tut.hintDurationType = ETHDT_Long; + tut.canBeShownInMenus = false; + tut.glossaryLink = false; + tut.markAsSeenOnShow = true; + + + theGame.GetTutorialSystem().DisplayTutorial(tut); + } + } + } + + return hpPerc; + } + + + + 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' ); + + } + + + 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; + } + + + if ( GetAttitudeBetween( this, actor ) == AIA_Hostile ) + { + if ( usePrecalcs ) + { + distanceToTarget = Distance2DBetweenCapsuleAndPoint( actor, this ) - targetingPrecalcs.playerRadius; + } + else + { + distanceToTarget = Distance2DBetweenCapsules( this, actor ); + } + + + 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 ) + { + + 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(); + + } + + + } + + 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 ); + + + } + + 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; + } + + + 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 + { + + return GetBehaviorVariable( 'combatIdleStance' ); + } + + protected var isRotatingInPlace : bool; + event OnRotateInPlaceStart() + { + isRotatingInPlace = true; + } + + event OnRotateInPlaceEnd() + { + isRotatingInPlace = false; + } + + event OnFullyBlendedIdle() + { + if ( bLAxisReleased ) + { + ResetRawPlayerHeading(); + ResetCachedRawPlayerHeading(); + defaultLocomotionController.ResetMoveDirection(); + } + } + + private var isInIdle : bool; + + event OnPlayerIdleStart() + { + isInIdle = true; + } + + event OnPlayerIdleEnd() + { + isInIdle = false; + } + + public function IsInIdle() : bool + { + return isInIdle; + } + + event OnRunLoopStart() + { + EnableRunCamera( true ); + } + + event OnRunLoopEnd() + { + EnableRunCamera( false ); + } + + event OnCombatActionStartBehgraph() + { + var action : EBufferActionType; + var cost, delay : float; + + + + + OnCombatActionStart(); + + 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; + + default : + ; + } + + + + if( delay > 0 ) + PauseStaminaRegen( '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() + { + + + BlockAction( EIAB_UsableItem, 'OnCombatActionStart' ); + BlockAction( EIAB_CallHorse, 'OnCombatActionStart' ); + + + + LogChannel('combatActionAllowed',"FALSE OnCombatActionStart"); + SetBIsCombatActionAllowed( false ); + SetBIsInputAllowed( false, 'OnCombatActionStart' ); + + + ClearFinishableEnemyList( 0.f, 0 ); + + bIsInHitAnim = false; + + + + if ( rangedWeapon && rangedWeapon.GetCurrentStateName() != 'State_WeaponWait' ) + { + CleanCombatActionBuffer(); + SetIsAimingCrossbow( false ); + OnRangedForceHolster( false, true ); + } + + + holsterUsableItem = false; + if ( thePlayer.IsHoldingItemInLHand() ) + { + 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; + } + + + if ( GetBehaviorVariable( 'combatActionType' ) != (int)CAT_Attack && GetBehaviorVariable( 'combatActionType' ) != (int)CAT_PreAttack ) + { + RemoveTimer( 'ProcessAttackTimer' ); + RemoveTimer( 'AttackTimerEnd' ); + UnblockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' ); + } + else + { + + BlockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' ); + } + + + } + + var isInParryOrCounter : bool; + event OnParryOrCounterStart() + { + isInParryOrCounter = true; + OnCombatActionStartBehgraph(); + } + + event OnParryOrCounterEnd() + { + isInParryOrCounter = false; + OnCombatActionEnd(); + SetBIsInCombatAction( false ); + } + + + event OnCombatActionEnd() + { + var item : SItemUniqueId; + var combatActionType : float; + + super.OnCombatActionEnd(); + + + + BlockAllActions( 'OnCombatActionStart', false ); + + UnblockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' ); + + + UnblockAction( EIAB_Movement, 'CombatActionFriendly' ); + + + + + oTCameraOffset = 0.f; + oTCameraPitchOffset = 0.f; + + + SetBIsCombatActionAllowed( true ); + + + SetBIsInputAllowed( true, 'OnCombatActionEnd' ); + SetCanPlayHitAnim( true ); + EnableFindTarget( true ); + + + + + SetFinisherVictim( NULL ); + + OnBlockAllCombatTickets( false ); + + LogStamina("CombatActionEnd"); + + + + SetAttackActionName(''); + combatActionType = GetBehaviorVariable('combatActionType'); + + + if(GetBehaviorVariable('combatActionType') == (int)CAT_SpecialAttack) + { + theGame.GetGameCamera().StopAnimation( 'camera_shake_loop_lvl1_1' ); + OnSpecialAttackHeavyActionProcess(); + } + + substateManager.ReactToChanceToFallAndSlide(); + } + + event OnCombatActionFriendlyStart() + { + SetBIsInCombatActionFriendly(true); + BlockAction( EIAB_Movement, 'CombatActionFriendly', false, false, false ); + OnCombatActionStart(); + } + + event OnCombatActionFriendlyEnd() + { + SetBIsInCombatActionFriendly(false); + UnblockAction( EIAB_Movement, 'CombatActionFriendly' ); + OnCombatActionEnd(); + SetBIsInCombatAction(false); + + } + + 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(); + + + ResumeStaminaRegen( 'InsideCombatAction' ); + + if( GetHealthPercents() < 0.3f ) + { + PlayBattleCry('BattleCryBadSituation', 0.10f, true ); + } + else + { + PlayBattleCry('BattleCryBadSituation', 0.05f, true ); + } + } + + event OnHitStartSwimming() + { + OnRangedForceHolster( true, true, false ); + } + + private var finisherSaveLock : int; + event OnFinisherStart() + { + var currentEffects : array; + + theGame.CreateNoSaveLock("Finisher",finisherSaveLock,true,false); + + isInFinisher = true; + + finisherTarget = slideTarget; + OnCombatActionStart(); + + CancelHoldAttacks(); + + 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 ) ) + { + 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.EnableManualCameraControl( false, 'Finisher' ); + } + } + + 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'); + + + SetImmortalityMode( AIM_None, AIC_SyncedAnim ); + theGame.RemoveTimeScale( 'AnimEventSlomoMo' ); + AddTimer( 'FinisherEndEnableCamera', 0.5f ); + + 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(); + tempEntity = theGame.CreateEntity( (CEntityTemplate)LoadResource('finisher_blood'), bloodFxPos, bloodFxRot); + tempEntity.PlayEffect('crawl_blood'); + } + + + event OnCombatActionEndComplete() + { + var buff : CBaseGameplayEffect; + + buff = ChooseCurrentCriticalBuffForAnim(); + SetCombatAction( EBAT_EMPTY ); + + + 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(); + } + + + ReapplyCriticalBuff(); + SetBIsInputAllowed( true, 'OnCombatActionEndComplete' ); + + + ResumeStaminaRegen( 'InsideCombatAction' ); + + bIsInHitAnim = false; + + SetBIsCombatActionAllowed( true ); + + m_LastWeaponTipPos = Vector(0, 0, 0, 0 ); + + + this.AddTimer('FreeTickets',3.f,false); + + + + } + + 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(); + } + + + + 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); + } + + + event OnCombatActionStartVehicle( action : EVehicleCombatAction ) + { + this.SetBIsCombatActionAllowed( false ); + + if ( action != EHCA_ShootCrossbow ) + { + SetIsAimingCrossbow( false ); + OnRangedForceHolster(); + } + } + + event OnCombatActionEndVehicle() + { + this.SetBIsCombatActionAllowed( true ); + } + + + + + + protected function CriticalBuffInformBehavior(buff : CBaseGameplayEffect) + { + + if( !CanAnimationReactToCriticalState( buff ) ) + { + return; + } + + + + + 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; + + + buffCritical = ( W3CriticalEffect ) buff; + if( buffCritical ) + { + isHeavyCritical = buffCritical.explorationStateHandling == ECH_HandleNow; + } + else + { + buffCriticalDOT = ( W3CriticalDOTEffect ) buff; + if( buffCriticalDOT ) + { + isHeavyCritical = buffCriticalDOT.explorationStateHandling == ECH_HandleNow; + } + } + + + 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(); + + + newReqCS = newRequestedCS; + if(super.OnCriticalStateAnimStart()) + { + + RemoveTimer( 'IsItemUseInputHeld' ); + keepRequestingCriticalAnimStart = false; + CancelHoldAttacks(); + + + + + + 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(); + + + SetCustomRotation( 'Knockdown', heading, 2160.f, 0.1f, true ); + + if ( newCritical != ECST_Stagger && newCritical != ECST_LongStagger ) + substateManager.ReactOnCriticalState( true ); + } + } + + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'CriticalEffectStart', -1, 30.0f, -1.f, -1, true ); + return true; + } + + + return false; + } + + + public function StartCSAnim(buff : CBaseGameplayEffect) : bool + { + SetBehaviorVariable( 'bCriticalStopped', 0 ); + + if(super.StartCSAnim(buff)) + { + if(!CriticalBuffUsesFullBodyAnim(buff)) + { + OnCriticalStateAnimStart(); + } + + ResumeStaminaRegen( 'InsideCombatAction' ); + + keepRequestingCriticalAnimStart = true; + AddTimer('RequestCriticalAnimStart', 0, true); + + + return true; + } + + return false; + } + + public function CriticalEffectAnimationInterrupted(reason : string) : bool + { + var ret : bool; + + 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); + + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'RecoveredFromCriticalEffect', -1, 30.0f, -1.f, -1, true ); + super.CriticalStateAnimStopped(forceRemoveBuff); + + substateManager.ReactOnCriticalState( false ); + } + + + 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) + { + + + SetIsInAir(progress == 0); + } + + + event OnRagdollOnGround() + { + + 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) + { + + if (critical.GetTimeActive() >= 2.5f) + { + SetIsInAir(false); + RequestCriticalAnimStop(); + RemoveTimer('TryToEndRagdollOnGround'); + } + else + { + AddTimer('TryToEndRagdollOnGround', 0.2f, true); + } + return; + } + } + + + 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); + } + + + + + public function SimulateBuffTimePassing(simulatedTime : float) + { + effectManager.SimulateBuffTimePassing(simulatedTime); + } + + public function AddEffectDefault(effectType : EEffectType, creat : CGameplayEntity, srcName : string, optional isSignEffect : bool) : EEffectInteract + { + var params : SCustomEffectParams; + + + 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); + } + } + + + + + + public function CheatResurrect() + { + var items : array< SItemUniqueId >; + var i, size, itemLevel, maxPrice, itemPrice : int; + var itemToEquip : SItemUniqueId; + + if(IsAlive()) + return; + + + if ( !theGame.GetGuiManager().GetRootMenu() ) + { + Log(" *** Call this function after DeathScreen appears *** "); + return; + } + + SetAlive(true); + + SetKinematic(true); + + EnableFindTarget( true ); + SetBehaviorVariable( 'Ragdoll_Weight', 0.f ); + RaiseForceEvent( 'RecoverFromRagdoll' ); + SetCanPlayHitAnim( true ); + SetBehaviorVariable( 'CriticalStateType', (int)ECST_None ); + GoToStateIfNew('Exploration'); + + ( (CDismembermentComponent)this.GetComponent( 'Dismemberment' ) ).ClearVisibleWound(); + + SetIsInAir(false); + + theInput.SetContext('Exploration'); + + ResetDeathType(); + + ForceUnlockAllInputActions(false); + + theGame.CloseMenu('DeathScreenMenu'); + + + theSound.LeaveGameState(ESGS_Death); + + + abilityManager.ForceSetStat(BCS_Vitality, GetStatMax(BCS_Vitality)); + effectManager.StopVitalityRegen(); + abilityManager.ForceSetStat( BCS_Air , 100.f ); + effectManager.StopAirRegen(); + abilityManager.ForceSetStat( BCS_Stamina , 100.f ); + effectManager.StopStaminaRegen(); + abilityManager.ForceSetStat( BCS_Toxicity , 0.f ); + abilityManager.ForceSetStat( BCS_Focus , 0.f ); + GetWitcherPlayer().UpdateEncumbrance(); + + + if ( !inv.IsThereItemOnSlot( EES_SteelSword ) ) + { + items = inv.GetItemsByCategory( 'steelsword' ); + } + else if ( !inv.IsThereItemOnSlot( EES_SilverSword ) ) + { + items = inv.GetItemsByCategory( 'silversword' ); + } + + size = items.Size(); + maxPrice = -1; + for ( i = 0; i < size; i += 1 ) + { + itemPrice = inv.GetItemPrice(items[i]); + itemLevel = inv.GetItemLevel(items[i]); + if ( itemLevel <= GetLevel() && itemPrice > maxPrice ) + { + maxPrice = itemPrice; + itemToEquip = items[i]; + } + } + if( inv.IsIdValid( itemToEquip ) ) + { + EquipItem( itemToEquip , , true ); + } + + 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; + } + + + + + + 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' ); + } + + + + + 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( !RaiseForceEvent( '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 ), true ); + 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 ), true ); + 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 ); + + } + + + public function StartWaitForItemSpawnAndProccesTask() + { + AddTimer( 'WaitForItemSpawnAndProccesTask', 0.001f, true,,,,true ); + } + + + public function KillWaitForItemSpawnAndProccesTask() + { + RemoveTimer ( 'WaitForItemSpawnAndProccesTask' ); + } + + + + public function AllowUseSelectedItem() + { + m_useSelectedItemIfSpawned = true; + } + + + + timer function WaitForItemSpawnAndProccesTask( timeDelta : float , id : int ) + { + var itemEntity : W3UsableItem; + var canTaskBeKilled : bool; + canTaskBeKilled = false; + + if ( IsCastingSign() ) + { + return; + } + + + if ( selectedItemId == GetInvalidUniqueId() ) + { + canTaskBeKilled = true; + } + + itemEntity = (W3UsableItem)inv.GetItemEntityUnsafe( selectedItemId ); + if ( itemEntity && m_useSelectedItemIfSpawned ) + { + + canTaskBeKilled = true; + m_useSelectedItemIfSpawned = false; + 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'); + } + + + 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 ); + + + + + + } + 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(); + + + theTelemetry.LogWithLabel(TE_FIGHT_HERO_THROWS_BOMB, inv.GetItemName( selectedItemId )); + } + + + event OnThrowAnimStart() + { + var itemId : SItemUniqueId; + var thrownEntity : CThrowable; + + 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(thrownEntity && !thrownEntity.WasThrown()) + { + thrownEntity.BreakAttachment(); + thrownEntity.Destroy(); + } + + thrownEntity = NULL; + SetIsThrowingItem( false ); + SetIsThrowingItemWithAim( false ); + RemoveCustomOrientationTarget( 'BombThrow' ); + } + + public function ProcessCanAttackWhenNotInCombatBomb() + { + var targets : array< CGameplayEntity >; + var temp, throwVector, throwFrom, throwTo, throwVectorU : Vector; + var temp_n : name; + var throwVecLen : float; + var component : CComponent; + + + + if( FactsQuerySum( "BombThrowSpecificTargets" ) > 0 ) + { + + + + + + throwFrom = playerAiming.GetThrowStartPosition(); + throwTo = playerAiming.GetThrowPosition(); + throwVector = throwTo - throwFrom; + throwVecLen = VecDistance( throwFrom, throwTo ); + throwVectorU = throwVector / throwVecLen; + if( theGame.GetWorld().StaticTraceWithAdditionalInfo( throwFrom, throwTo + throwVectorU, temp, temp, temp_n, component ) && component && component.GetEntity().HasTag( 'BombThrowSpecificTarget' ) ) + { + SetIsShootingFriendly( false ); + } + else + { + SetIsShootingFriendly( true ); + } + } + else if( FactsQuerySum( "BombThrowDisallowSpecificTargets" ) > 0 ) + { + + throwFrom = playerAiming.GetThrowStartPosition(); + throwTo = playerAiming.GetThrowPosition(); + throwVector = throwTo - throwFrom; + throwVecLen = VecDistance( throwFrom, throwTo ); + throwVectorU = throwVector / throwVecLen; + if( theGame.GetWorld().StaticTraceWithAdditionalInfo( throwFrom, throwTo + throwVectorU, temp, temp, temp_n, component ) && component && component.GetEntity().HasTag( 'BombThrowDisallowedTarget' ) ) + { + SetIsShootingFriendly( true ); + } + else + { + SetIsShootingFriendly( false ); + } + } + else + { + SetIsShootingFriendly( false ); + } + + SetBehaviorVariable( 'isShootingFriendly', (float)( GetIsShootingFriendly() ) ); + } + + public function SetIsShootingFriendly( flag : bool ) + { + isShootingFriendly = flag; + } + + public function GetIsShootingFriendly() : bool + { + return isShootingFriendly; + } + + + protected function UsableItemStart() + { + var thrownEntity : CThrowable; + + + 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() + { + var stateName : name; + + stateName = playerAiming.GetCurrentStateName(); + OnDelayOrientationChangeOff(); + + if( GetIsShootingFriendly() || ( FactsQuerySum( "BombThrowSpecificTargets" ) > 0 && stateName != 'Aiming' ) ) + { + BombThrowAbort(); + } + else + { + SetBehaviorVariable( 'throwStage', (int)TS_End ); + + if ( stateName == 'Aiming' ) + { + SetCustomRotation( 'Throw', VecHeading( this.GetLookAtPosition() - GetWorldPosition() ), 0.0f, 0.2f, false ); + } + } + } + + protected function UsableItemRelease() + { + OnDelayOrientationChangeOff(); + SetBehaviorVariable( 'throwStage', (int)TS_End ); + RemoveCustomOrientationTarget( 'UsableItems' ); + } + + + 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(thrownEntity && !thrownEntity.WasThrown()) + { + thrownEntity.BreakAttachment(); + thrownEntity.Destroy(); + } + this.EnableRadialSlotsWithSource( true, this.radialSlots, 'throwBomb' ); + } + + public function CanSetupCombatAction_Throw() : bool + { + + if(!inv.IsIdValid( selectedItemId )) + return false; + + + if(!inv.IsItemSingletonItem(selectedItemId)) + return false; + + + if(!GetBIsInputAllowed()) + return false; + + + if(inv.GetItemQuantity(GetSelectedItemId()) <= 0 && !inv.ItemHasTag(selectedItemId, theGame.params.TAG_INFINITE_AMMO)) + return false; + + + if(!inputHandler.IsActionAllowed(EIAB_ThrowBomb) && GetCurrentStateName() != 'Swimming') + return false; + + return true; + } + + public function GetThrownEntity() : CThrowable + { + return (CThrowable)EntityHandleGet( thrownEntityHandle ); + } + + + 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; + } + + + event OnBlockAllCombatTickets( release : bool ) + { + if (!release ) + ((CR4PlayerStateCombat)GetState('Combat')).OnBlockAllCombatTickets(false); + } + event OnForceTicketUpdate() {} + + + + + + event OnProcessActionPost(action : W3DamageAction) + { + var npc : CNewNPC; + var attackAction : W3Action_Attack; + var lifeLeech : float; + + super.OnProcessActionPost(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()) + { + + IncreaseUninterruptedHitsCount(); + + + if( IsLightAttack( attackAction.GetAttackName() ) ) + { + GCameraShake(0.1, false, GetWorldPosition(), 10); + } + + + if(npc && inv.GetItemName(attackAction.GetWeaponId()) == 'PC Caretaker Shovel') + { + + 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; + } + + + + + + public function GetHorseWithInventory() : CNewNPC + { + return (CNewNPC)EntityHandleGet( horseWithInventory ); + } + public function GetHorseCurrentlyMounted() : CNewNPC + { + return currentlyMountedHorse; + } + + 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 SetIsSwimming ( toggle : bool ) + { + if( isSwimming != toggle ) + { + thePlayer.substateManager.SetBehaviorParamBool( 'isSwimmingForOverlay', toggle ); + isSwimming = toggle; + } + } + + + + + + + + public function RepairItemUsingConsumable(item, consumable : SItemUniqueId) : bool + { + var curr, max, repairValue, itemValue, repairBonus, newDurability : float; + + + if(!inv.IsIdValid(item) || !inv.IsIdValid(consumable) || !inv.HasItemDurability(item)) + return false; + + curr = inv.GetItemDurability(item); + max = inv.GetItemMaxDurability(item); + + + if(curr > max) + return false; + + + 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)) ) + { + + 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')); + + + repairValue = max * itemValue /100; + + + + newDurability = MinF(max, curr + repairValue); + + inv.SetItemDurabilityScript(item, newDurability); + + + inv.RemoveItem(consumable); + + return true; + } + return false; + } + + + + + + + + + + + private function CheckDayNightCycle() + { + var time : GameTime; + var isNight : bool; + + + isNight = theGame.envMgr.IsNight(); + if(prevDayNightIsNight != isNight) + { + if(isNight) + OnNightStarted(); + else + OnDayStarted(); + + prevDayNightIsNight = isNight; + } + + + if(isNight) + time = theGame.envMgr.GetGameTimeTillNextDay(); + else + time = theGame.envMgr.GetGameTimeTillNextNight(); + + AddGameTimeTimer('DayNightCycle', time); + } + + timer function DayNightCycle(dt : GameTime, id : int) + { + CheckDayNightCycle(); + } + + event OnNightStarted() + { + var pam : W3PlayerAbilityManager; + + if(CanUseSkill(S_Perk_01)) + { + pam = (W3PlayerAbilityManager)abilityManager; + pam.SetPerk01Abilities(false, true); + } + } + + event OnDayStarted() + { + var pam : W3PlayerAbilityManager; + + if(CanUseSkill(S_Perk_01)) + { + pam = (W3PlayerAbilityManager)abilityManager; + pam.SetPerk01Abilities(true, false); + } + } + + + + + + 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; + } + + + + + + 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(); + } + + + + + + + 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; + } + + + 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 ) ); + } + } + } + + + + public function SetWeatherDisplayDisabled( disable : bool ) + { + disableWeatherDisplay = disable; + } + + public function GetWeatherDisplayDisabled() : bool + { + return disableWeatherDisplay; + } + + + + + + public function SetCurrentMonsterHuntInvestigationArea ( area : W3MonsterHuntInvestigationArea ) + { + currentMonsterHuntInvestigationArea = area; + } + + + + + + + public function RememberCustomHead( headName : name ) + { + rememberedCustomHead = headName; + } + + public function GetRememberedCustomHead() : name + { + return rememberedCustomHead; + } + + public function ClearRememberedCustomHead() + { + rememberedCustomHead = ''; + } + + + + + + 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; + var id : SItemUniqueId; + var i : int; + + + if(inv) + { + inv.GetAllItems(items); + if(items.Size() <= 0) + { + return; + } + } + else + { + return; + } + + + 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; + var i : int; + var slot : EEquipmentSlots; + + + 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(); + + + RemoveTimer('Debug_GiveTestingItems'); + + + inv.GetAllItems(items); + + for(i=0; i; + 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; + var sword : CWitcherSword; + var healthPercentage : float; + var tmpBacklight : Vector; + + if(!skipHeldWeapon) + { + weapons = inv.GetHeldWeapons(); + + + 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 final function SetLoopingCameraShakeAnimName( n : name ) + { + loopingCameraShakeAnimName = n; + } + + 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; + } + else + { + return 0.02f; + } + } + + 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' ); + } + + + 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 ) ); + + + 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 ) ); + + + + + 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 ); } + } + } + + + 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 ); + } + } + } + + + + + + public function OnStartTeleportingPlayerToPlayableArea() + { + var FADEOUT_INTERVAL : float = 0.5; + + + 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.1; + var manager : CCommonMapManager = theGame.GetCommonMapManager(); + + thePlayer.TeleportWithRotation( manager.GetBorderTeleportPosition(), manager.GetBorderTeleportRotation() ); + thePlayer.AddTimer( 'BorderTeleportFadeInTimer', BLACKSCREEN_INTERVAL, false ); + + theGame.FadeOutAsync( 0 ); + theGame.SetFadeLock('PlayerTeleportation'); + } + + timer function BorderTeleportFadeInTimer( dt : float, id : int ) + { + theGame.ResetFadeLock('PlayerTeleportation'); + theGame.FadeOutAsync( 0 ); + theGame.FadeInAsync( 2.0f ); + } + + 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) ); + } + + 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; } + + public function SetInsideDiveAttackArea( val : bool ) { insideDiveAttackArea = val; } + public function IsInsideDiveAttackArea() : bool { return insideDiveAttackArea; } + public function SetDiveAreaNumber( val : int ) { diveAreaNumber = val; } + public function GetDiveAreaNumber() : int { return diveAreaNumber; } + + + + 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(); + } + + + + + private var forcedFinisherVictim : CActor; + + timer function PerformFinisher( time : float , id : int ) + { + var combatTarget : CActor; + var i : int; + + combatTarget = thePlayer.GetTarget(); + + if( combatTarget ) + { + combatTarget.Kill( 'AutoFinisher', false, thePlayer ); + thePlayer.SetFinisherVictim( combatTarget ); + forcedFinisherVictim = combatTarget; + thePlayer.CleanCombatActionBuffer(); + thePlayer.OnBlockAllCombatTickets( true ); + moveTargets = thePlayer.GetMoveTargets(); + + for( i = 0; i < moveTargets.Size(); i += 1 ) + { + if( combatTarget != moveTargets[i] ) + moveTargets[i].SignalGameplayEvent( 'InterruptChargeAttack' ); + } + + if( theGame.GetInGameConfigWrapper().GetVarValue( 'Gameplay', 'AutomaticFinishersEnabled' ) == "true" ) + combatTarget.AddAbility( 'ForceFinisher', false ); + + if( combatTarget.HasTag( 'ForceFinisher' ) ) + combatTarget.AddAbility( 'ForceFinisher', false ); + + combatTarget.SignalGameplayEvent( 'ForceFinisher' ); + + thePlayer.FindMoveTarget(); + + thePlayer.AddTimer( 'SignalFinisher', 0.2, false ); + } + } + + timer function SignalFinisher( time : float , id : int ) + { + forcedFinisherVictim.SignalGameplayEvent( 'Finisher' ); + forcedFinisherVictim = NULL; + } +} + +exec function ttt() +{ + thePlayer.AddTimer( 'TestTimer', 5, false ); +} diff --git a/content/scripts/local/achievementStatTrak/achievement_stats.ws b/mods/modStatTrak/content/scripts/local/achievementStatTrak/achievement_stats.ws similarity index 94% rename from content/scripts/local/achievementStatTrak/achievement_stats.ws rename to mods/modStatTrak/content/scripts/local/achievementStatTrak/achievement_stats.ws index 95be139..1879eb7 100644 --- a/content/scripts/local/achievementStatTrak/achievement_stats.ws +++ b/mods/modStatTrak/content/scripts/local/achievementStatTrak/achievement_stats.ws @@ -152,6 +152,16 @@ function getFormattedAchievementStats(statList : array) : string currentName = getAchievmentStatName(currentRawName); currentVal = getAchievementStatVal(statList[i]); + // If allowing spoilers was not toggled on + if (!theGame.GetInGameConfigWrapper().GetVarValue('ModStatTrak', 'AllowSpoilers')) + { + if (currentName == "Rad Steez, Bro!" || currentName == "Moo-rderer") + { + // Don't print and continue the loop + continue; + } + } + if (i != 0) { achievementString += "

" + currentRawName + ": " + "" + currentVal + "" + "
" + "Achievement: " + "" + currentName + ""; diff --git a/src/StatTrak.w3modproj b/src/StatTrak.w3modproj new file mode 100644 index 0000000..617ae4a --- /dev/null +++ b/src/StatTrak.w3modproj @@ -0,0 +1,8 @@ + + + + C:\Users\abheekd\Desktop\Witcher-Wkit\Projects\StatTrak\files\DLC\Bundle\dlc\stattrak\dlcstattrak.reddlc + C:\Users\abheekd\Desktop\Witcher-Wkit\Projects\StatTrak\files\DLC\Bundle\dlc\StatTrak\dlcStatTrak.reddlc + + StatTrak + \ No newline at end of file diff --git a/src/StatTrak/files/DLC/Bundle/dlc/StatTrak/dlcStatTrak.reddlc b/src/StatTrak/files/DLC/Bundle/dlc/StatTrak/dlcStatTrak.reddlc new file mode 100644 index 0000000000000000000000000000000000000000..a718832b988ca601e3f326616acfaa33cd96c0c9 GIT binary patch literal 760 zcmZ<`G74YJ00noL>u#B!U6 z4Bl*;)$kE04nz#0-n-v00`&tC!|J&wIv^^@B%NJ+oLy4WGV?M^GV}8oGE*3w{StFi z8B%hR%lMao-n9P#Y+~OEuEWwjWJXlDt JA~%PD0RUP4usr|( literal 0 HcmV?d00001 diff --git a/src/StatTrak/files/DLC/Bundle/dlc/StatTrak/gameplay/items/def_stattrak_items.xml b/src/StatTrak/files/DLC/Bundle/dlc/StatTrak/gameplay/items/def_stattrak_items.xml new file mode 100644 index 0000000000000000000000000000000000000000..9ce2b7b72c0a39c5b58018c5f015ade2b7d2cbdc GIT binary patch literal 1274 zcmbVMO;5s55S%L}{s+{nd>!&^-!7;Y6 zg*G`7;ykOxhK$|2+7$C;hkRM#t9Hm#W2e18K2`Ln;|%AlJ>_qg-xn^{!zJHt{>3RR zrd^5?dSrSlJfp>=y}~C$Ohn?|_3a;dctYPs#3#;QVKVYnscX)fIazm|Z>ku$NJ4+7 zba7GeC?~Ey<5N7ADrUr`toyBV%gxRd=C0p>)iHU-KPvpRgOWGqQ|cJ8%1#r`)Z|_q zlvIc@C8u0jAmW+E)Ty(DT6NGanI0i@URCAp+LCxcv^k-=;5ZijA$THj4`(9Ma+q{)s-r#D8A$kAY@%x#3W!B4w^C%ia4a!v@L zBThln5H2bRk__JE@npC8r;|0HCbZbOq+j?NbU7LxACgztgi|C4olr^ uW^JlkWe?dtxpQ*Lr?3&){cv}ru)*wRq;NI^yNe-Wj6$vZcTs-zAL$Fzw68Y+ literal 0 HcmV?d00001 diff --git a/src/StatTrak/files/Mod/scripts/game/components/inventoryComponent.ws b/src/StatTrak/files/Mod/scripts/game/components/inventoryComponent.ws new file mode 100644 index 0000000..acc0d79 --- /dev/null +++ b/src/StatTrak/files/Mod/scripts/game/components/inventoryComponent.ws @@ -0,0 +1,5873 @@ +/***********************************************************************/ +/** © 2015 CD PROJEKT S.A. All rights reserved. +/** THE WITCHER® is a trademark of CD PROJEKT S. A. +/** The Witcher game is based on the prose of Andrzej Sapkowski. +/***********************************************************************/ + + + + + + +class IInventoryScriptedListener +{ + event OnInventoryScriptedEvent( eventType : EInventoryEventType, itemId : SItemUniqueId, quantity : int, fromAssociatedInventory : bool ) {} +} + +import struct SItemNameProperty +{ + import editable var itemName : name; +}; + +import struct SR4LootNameProperty +{ + import editable var lootName : name; +}; + +struct SItemExt +{ + editable var itemName : SItemNameProperty; + editable var quantity : int; + default quantity = 1; +}; + +struct SCardSourceData +{ + var cardName : name; + var source : string; + var originArea : string; + var originQuest : string; + var details : string; + var coords : string; +}; + + +import struct SItemChangedData +{ + import const var itemName : name; + import const var quantity : int; + import const var informGui : bool; + import const var ids : array< SItemUniqueId >; +}; + +import class CInventoryComponent extends CComponent +{ + editable var priceMult : float; + editable var priceRepairMult : float; + editable var priceRepair : float; + editable var fundsType : EInventoryFundsType; + + private var recentlyAddedItems : array; + private var fundsMax : int; + private var daysToIncreaseFunds : int; + + default priceMult = 1.0; + default priceRepairMult = 1.0; + default priceRepair = 10.0; + default fundsType = EInventoryFunds_Avg; + default daysToIncreaseFunds = 5; + + + + + public function GetFundsType() : EInventoryFundsType + { + return fundsType; + } + + public function GetDaysToIncreaseFunds() : int + { + return daysToIncreaseFunds; + } + + public function GetFundsMax() : float + { + if ( EInventoryFunds_Broke == fundsType ) + { + return 0; + } + else if ( EInventoryFunds_Avg == fundsType ) + { + return 5000; + } + else if ( EInventoryFunds_Poor == fundsType ) + { + return 2500; + } + else if ( EInventoryFunds_Rich == fundsType ) + { + return 7500; + } + else if ( EInventoryFunds_RichQuickStart == fundsType ) + { + return 15000; + } + return -1; + } + + public function SetupFunds() + { + if ( EInventoryFunds_Broke == fundsType ) + { + AddMoney( 0 ); + } + else if ( EInventoryFunds_Poor == fundsType ) + { + AddMoney( (int)( 200 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_Avg == fundsType ) + { + AddMoney( (int)( 500 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_Rich == fundsType ) + { + AddMoney( (int)( 1000 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_RichQuickStart == fundsType ) + { + AddMoney( (int)( 5000 * GetFundsModifier() ) ); + } + } + + public function IncreaseFunds() + { + if ( GetMoney() < GetFundsMax() ) + { + if ( EInventoryFunds_Avg == fundsType ) + { + AddMoney( (int)( 150 * GetFundsModifier()) ); + } + else if ( EInventoryFunds_Poor == fundsType ) + { + AddMoney( (int)( 100 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_Rich == fundsType ) + { + AddMoney( (int)( 1000 * GetFundsModifier() ) ); + } + else if ( EInventoryFunds_RichQuickStart == fundsType ) + { + AddMoney( 1000 + (int)( 2500 * GetFundsModifier() ) ); + } + } + } + + public function GetMoney() : int + { + return GetItemQuantityByName( 'Crowns' ); + } + + public function SetMoney( amount : int ) + { + var currentMoney : int; + + if ( amount >= 0 ) + { + currentMoney = GetMoney(); + RemoveMoney( currentMoney ); + + AddAnItem( 'Crowns', amount ); + } + } + + public function AddMoney( amount : int ) + { + if ( amount > 0 ) + { + AddAnItem( 'Crowns', amount ); + + if ( thePlayer == GetEntity() ) + { + theTelemetry.LogWithValue( TE_HERO_CASH_CHANGED, amount ); + } + } + } + + public function RemoveMoney( amount : int ) + { + if ( amount > 0 ) + { + RemoveItemByName( 'Crowns', amount ); + + if ( thePlayer == GetEntity() ) + { + theTelemetry.LogWithValue( TE_HERO_CASH_CHANGED, -amount ); + } + } + } + + + + + + import final function GetItemAbilityAttributeValue( itemId : SItemUniqueId, attributeName : name, abilityName : name) : SAbilityAttributeValue; + + import final function GetItemFromSlot( slotName : name ) : SItemUniqueId; + + + import final function IsIdValid( itemId : SItemUniqueId ) : bool; + + + import final function GetItemCount( optional useAssociatedInventory : bool ) : int; + + + import final function GetItemsNames() : array< name >; + + + import final function GetAllItems( out items : array< SItemUniqueId > ); + + + import public function GetItemId( itemName : name ) : SItemUniqueId; + + + import public function GetItemsIds( itemName : name ) : array< SItemUniqueId >; + + + import final function GetItemsByTag( tag : name ) : array< SItemUniqueId >; + + + import final function GetItemsByCategory( category : name ) : array< SItemUniqueId >; + + + import final function GetSchematicIngredients(itemName : SItemUniqueId, out quantity : array, out names : array); + + + import final function GetSchematicRequiredCraftsmanType(craftName : SItemUniqueId) : name; + + + import final function GetSchematicRequiredCraftsmanLevel(craftName : SItemUniqueId) : name; + + + import final function GetNumOfStackedItems( itemUniqueId: SItemUniqueId ) : int; + + import final function InitInvFromTemplate( resource : CEntityTemplate ); + + + + + import final function SplitItem( itemID : SItemUniqueId, quantity : int ) : SItemUniqueId; + + + + import final function SetItemStackable( itemID : SItemUniqueId, flag : bool ); + + + import final function GetCategoryDefaultItem( category : name ) : name; + + + + + + + import final function GetItemLocalizedNameByName( itemName : CName ) : string; + + + import final function GetItemLocalizedDescriptionByName( itemName : CName ) : string; + + + import final function GetItemLocalizedNameByUniqueID( itemUniqueId : SItemUniqueId ) : string; + + + import final function GetItemLocalizedDescriptionByUniqueID( itemUniqueId : SItemUniqueId ) : string; + + + import final function GetItemIconPathByUniqueID( itemUniqueId : SItemUniqueId ) : string; + + + import final function GetItemIconPathByName( itemName : CName ) : string; + + import final function AddSlot( itemUniqueId : SItemUniqueId ) : bool; + + import final function GetSlotItemsLimit( itemUniqueId : SItemUniqueId ) : int; + + import private final function BalanceItemsWithPlayerLevel( playerLevel : int ); + + public function ForceSpawnItemOnStart( itemId : SItemUniqueId ) : bool + { + return ItemHasTag(itemId, 'MutagenIngredient'); + } + + + public final function GetItemArmorTotal(item : SItemUniqueId) : SAbilityAttributeValue + { + var armor, armorBonus : SAbilityAttributeValue; + var durMult : float; + + armor = GetItemAttributeValue(item, theGame.params.ARMOR_VALUE_NAME); + armorBonus = GetRepairObjectBonusValueForArmor(item); + durMult = theGame.params.GetDurabilityMultiplier( GetItemDurabilityRatio(item), false); + + return armor * durMult + armorBonus; + } + + public final function GetItemLevel(item : SItemUniqueId) : int + { + var itemCategory : name; + var itemAttributes : array; + var itemName : name; + var isWitcherGear : bool; + var isRelicGear : bool; + var level, baseLevel : int; + + itemCategory = GetItemCategory(item); + itemName = GetItemName(item); + + isWitcherGear = false; + isRelicGear = false; + if ( RoundMath(CalculateAttributeValue( GetItemAttributeValue(item, 'quality' ) )) == 5 ) isWitcherGear = true; + if ( RoundMath(CalculateAttributeValue( GetItemAttributeValue(item, 'quality' ) )) == 4 ) isRelicGear = true; + + switch(itemCategory) + { + case 'armor' : + case 'boots' : + case 'gloves' : + case 'pants' : + itemAttributes.PushBack( GetItemAttributeValue(item, 'armor') ); + break; + + case 'silversword' : + itemAttributes.PushBack( GetItemAttributeValue(item, 'SilverDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'BludgeoningDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'RendingDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'ElementalDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'FireDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'PiercingDamage') ); + break; + + case 'steelsword' : + itemAttributes.PushBack( GetItemAttributeValue(item, 'SlashingDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'BludgeoningDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'RendingDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'ElementalDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'FireDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'SilverDamage') ); + itemAttributes.PushBack( GetItemAttributeValue(item, 'PiercingDamage') ); + break; + + case 'crossbow' : + itemAttributes.PushBack( GetItemAttributeValue(item, 'attack_power') ); + break; + + default : + break; + } + + level = theGame.params.GetItemLevel(itemCategory, itemAttributes, itemName, baseLevel); + + if ( FactsQuerySum("NewGamePlus") > 0 ) + { + if ( baseLevel > GetWitcherPlayer().GetMaxLevel() ) + { + level = baseLevel; + } + } + + if ( isWitcherGear ) level = level - 2; + if ( isRelicGear ) level = level - 1; + if ( level < 1 ) level = 1; + if ( ItemHasTag(item, 'OlgierdSabre') ) level = level - 3; + if ( (isRelicGear || isWitcherGear) && ItemHasTag(item, 'EP1') ) level = level - 1; + + if ( FactsQuerySum("NewGamePlus") > 0 ) + { + if ( level > GetWitcherPlayer().GetMaxLevel() ) + { + level = GetWitcherPlayer().GetMaxLevel(); + } + } + + return level; + } + + public function GetItemLevelColorById( itemId : SItemUniqueId ) : string + { + var color : string; + + if (GetItemLevel(itemId) <= thePlayer.GetLevel()) + { + color = ""; + } + else + { + color = ""; + } + + return color; + } + + public function GetItemLevelColor( lvl_item : int ) : string + { + var color : string; + + if ( lvl_item > thePlayer.GetLevel() ) + { + color = ""; + } else + { + color = ""; + } + + return color; + } + + public final function AutoBalanaceItemsWithPlayerLevel() + { + var playerLevel : int; + + playerLevel = thePlayer.GetLevel(); + + if( playerLevel < 0 ) + { + playerLevel = 0; + } + + BalanceItemsWithPlayerLevel( playerLevel ); + } + + public function GetItemsByName(itemName : name) : array + { + var ret : array; + var i : int; + + if(!IsNameValid(itemName)) + return ret; + + GetAllItems(ret); + + for(i=ret.Size()-1; i>=0; i-=1) + { + if(GetItemName(ret[i]) != itemName) + { + ret.EraseFast( i ); + } + } + + return ret; + } + + public final function GetSingletonItems() : array + { + return GetItemsByTag(theGame.params.TAG_ITEM_SINGLETON); + } + + + import final function GetItemQuantityByName( itemName : name, optional useAssociatedInventory : bool , optional ignoreTags : array< name > ) : int; + + + import final function GetItemQuantityByCategory( itemCategory : name, optional useAssociatedInventory : bool , optional ignoreTags : array< name > ) : int; + + + import final function GetItemQuantityByTag( itemTag : name, optional useAssociatedInventory : bool , optional ignoreTags : array< name > ) : int; + + + import final function GetAllItemsQuantity( optional useAssociatedInventory : bool , optional ignoreTags : array< name > ) : int; + + + public function IsEmpty(optional bSkipNoDropNoShow : bool) : bool + { + var i : int; + var itemIds : array; + + if(bSkipNoDropNoShow) + { + GetAllItems( itemIds ); + for( i = itemIds.Size() - 1; i >= 0; i -= 1 ) + { + if( !ItemHasTag( itemIds[ i ],theGame.params.TAG_DONT_SHOW ) && !ItemHasTag( itemIds[ i ], 'NoDrop' ) ) + { + return false; + } + else if ( ItemHasTag( itemIds[ i ], 'Lootable') ) + { + return false; + } + } + + return true; + } + + return GetItemCount() <= 0; + } + + + public function GetAllHeldAndMountedItemsCategories( out heldItems : array, optional out mountedItems : array ) + { + var allItems : array; + var i : int; + + GetAllItems(allItems); + for(i=allItems.Size()-1; i >= 0; i-=1) + { + if ( IsItemHeld(allItems[i]) ) + heldItems.PushBack(GetItemCategory(allItems[i])); + else if ( IsItemMounted(allItems[i]) ) + mountedItems.PushBack(GetItemCategory(allItems[i])); + } + } + + public function GetAllHeldItemsNames( out heldItems : array ) + { + var allItems : array; + var i : int; + + GetAllItems(allItems); + for(i=allItems.Size()-1; i >= 0; i-=1) + { + if ( IsItemHeld(allItems[i]) ) + heldItems.PushBack(GetItemName(allItems[i])); + } + } + + public function HasMountedItemByTag(tag : name) : bool + { + var i : int; + var allItems : array; + + if(!IsNameValid(tag)) + return false; + + allItems = GetItemsByTag(tag); + for(i=0; i; + + if(!IsNameValid(tag)) + return false; + + allItems = GetItemsByTag(tag); + for(i=0; i ) : bool; + + + import final function GetCraftedItemName( itemId : SItemUniqueId ) : name; + + + import final function TotalItemStats( invItem : SInventoryItem ) : float; + + import final function GetItemPrice( itemId : SItemUniqueId ) : int; + + + import final function GetItemPriceModified( itemId : SItemUniqueId, optional playerSellingItem : Bool ) : int; + + + import final function GetInventoryItemPriceModified( invItem : SInventoryItem, optional playerSellingItem : Bool ) : int; + + + import final function GetItemPriceRepair( invItem : SInventoryItem, out costRepairPoint : int, out costRepairTotal : int ); + + + import final function GetItemPriceRemoveUpgrade( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceDisassemble( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceAddSlot( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceCrafting( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceEnchantItem( invItem : SInventoryItem ) : int; + + + import final function GetItemPriceRemoveEnchantment( invItem : SInventoryItem ) : int; + + import final function GetFundsModifier() : float; + + + import final function GetItemQuantity( itemId : SItemUniqueId ) : int; + + + import final function ItemHasTag( itemId : SItemUniqueId, tag : name ) : bool; + + + import final function AddItemTag( itemId : SItemUniqueId, tag : name ) : bool; + + + import final function RemoveItemTag( itemId : SItemUniqueId, tag : name ) : bool; + + + public final function ManageItemsTag( items : array, tag : name, add : bool ) + { + var i : int; + + if( add ) + { + for( i = 0 ; i < items.Size() ; i += 1 ) + { + AddItemTag( items[ i ], tag ); + } + } + else + { + for( i = 0 ; i < items.Size() ; i += 1 ) + { + RemoveItemTag( items[ i ], tag ); + } + } + } + + + import final function GetItemByItemEntity( itemEntity : CItemEntity ) : SItemUniqueId; + + + public function ItemHasAbility(item : SItemUniqueId, abilityName : name) : bool + { + var abilities : array; + + GetItemAbilities(item, abilities); + return abilities.Contains(abilityName); + } + + import final function GetItemAttributeValue( itemId : SItemUniqueId, attributeName : name, optional abilityTags : array< name >, optional withoutTags : bool ) : SAbilityAttributeValue; + + + import final function GetItemBaseAttributes( itemId : SItemUniqueId, out attributes : array ); + + + import final function GetItemAttributes( itemId : SItemUniqueId, out attributes : array ); + + + import final function GetItemAbilities( itemId : SItemUniqueId, out abilities : array ); + + + import final function GetItemContainedAbilities( itemId : SItemUniqueId, out abilities : array ); + + + public function GetItemAbilitiesWithAttribute(id : SItemUniqueId, attributeName : name, attributeVal : float) : array + { + var i : int; + var abs, ret : array; + var dm : CDefinitionsManagerAccessor; + var val : float; + var min, max : SAbilityAttributeValue; + + GetItemAbilities(id, abs); + dm = theGame.GetDefinitionsManager(); + + for(i=0; i ) + { + var i : int; + var dm : CDefinitionsManagerAccessor; + var allAbilities : array; + + dm = theGame.GetDefinitionsManager(); + GetItemAbilities(itemId, allAbilities); + + for(i=0; i; + + public final function GiveMoneyTo(otherInventory : CInventoryComponent, optional quantity : int, optional informGUI : bool ) + { + var moneyId : array; + + moneyId = GetItemsByName('Crowns'); + GiveItemTo(otherInventory, moneyId[0], quantity, false, true, informGUI); + } + + public final function GiveItemTo( otherInventory : CInventoryComponent, itemId : SItemUniqueId, optional quantity : int, optional refreshNewFlag : bool, optional forceTransferNoDrops : bool, optional informGUI : bool ) : SItemUniqueId + { + var arr : array; + var itemName : name; + var i : int; + var uiData : SInventoryItemUIData; + var isQuestItem : bool; + + + if(quantity == 0) + quantity = 1; + + quantity = Clamp(quantity, 0, GetItemQuantity(itemId)); + if(quantity == 0) + return GetInvalidUniqueId(); + + itemName = GetItemName(itemId); + + if(!forceTransferNoDrops && ( ItemHasTag(itemId, 'NoDrop') && !ItemHasTag(itemId, 'Lootable') )) + { + LogItems("Cannot transfer item <<" + itemName + ">> as it has the NoDrop tag set!!!"); + return GetInvalidUniqueId(); + } + + + if(IsItemSingletonItem(itemId)) + { + + if(otherInventory == thePlayer.inv && otherInventory.GetItemQuantityByName(itemName) > 0) + { + LogAssert(false, "CInventoryComponent.GiveItemTo: cannot add singleton item as player already has this item!"); + return GetInvalidUniqueId(); + } + + else + { + arr = GiveItem(otherInventory, itemId, quantity); + } + } + else + { + + arr = GiveItem(otherInventory, itemId, quantity); + } + + + if(otherInventory == thePlayer.inv) + { + isQuestItem = this.IsItemQuest( itemId ); + theTelemetry.LogWithLabelAndValue(TE_INV_ITEM_PICKED, itemName, quantity); + + if ( !theGame.AreSavesLocked() && ( isQuestItem || this.GetItemQuality( itemId ) >= 4 ) ) + { + theGame.RequestAutoSave( "item gained", false ); + } + } + + if (refreshNewFlag) + { + for (i = 0; i < arr.Size(); i += 1) + { + uiData = otherInventory.GetInventoryItemUIData( arr[i] ); + uiData.isNew = true; + otherInventory.SetInventoryItemUIData( arr[i], uiData ); + } + } + + return arr[0]; + } + + public final function GiveAllItemsTo(otherInventory : CInventoryComponent, optional forceTransferNoDrops : bool, optional informGUI : bool) + { + var items : array; + + GetAllItems(items); + GiveItemsTo(otherInventory, items, forceTransferNoDrops, informGUI); + } + + public final function GiveItemsTo(otherInventory : CInventoryComponent, items : array, optional forceTransferNoDrops : bool, optional informGUI : bool) : array + { + var i : int; + var ret : array; + + for( i = 0; i < items.Size(); i += 1 ) + { + ret.PushBack(GiveItemTo(otherInventory, items[i], GetItemQuantity(items[i]), true, forceTransferNoDrops, informGUI)); + } + + return ret; + } + + + import final function HasItem( item : name ) : bool; + + + + final function HasItemById(id : SItemUniqueId) : bool + { + var arr : array; + + GetAllItems(arr); + return arr.Contains(id); + } + + public function HasItemByTag(tag : name) : bool + { + var quantity : int; + + quantity = GetItemQuantityByTag( tag ); + return quantity > 0; + } + + public function HasItemByCategory(category : name) : bool + { + var quantity : int; + + quantity = GetItemQuantityByCategory( category ); + return quantity > 0; + } + + + public function HasInfiniteBolts() : bool + { + var ids : array; + var i : int; + + ids = GetItemsByTag(theGame.params.TAG_INFINITE_AMMO); + for(i=0; i; + var i : int; + + ids = GetItemsByTag(theGame.params.TAG_GROUND_AMMO); + for(i=0; i; + var i : int; + + ids = GetItemsByTag(theGame.params.TAG_UNDERWATER_AMMO); + for(i=0; i; + import private final function AddSingleItem( item : name, optional informGui : bool , optional markAsNew : bool , optional lootable : bool ) : SItemUniqueId; + + + public final function AddAnItem(item : name, optional quantity : int, optional dontInformGui : bool, optional dontMarkAsNew : bool, optional showAsRewardInUIHax : bool) : array + { + var arr : array; + var i : int; + var isReadableItem : bool; + + + if( theGame.GetDefinitionsManager().IsItemSingletonItem(item) && GetEntity() == thePlayer) + { + if(GetItemQuantityByName(item) > 0) + { + arr = GetItemsIds(item); + } + else + { + arr.PushBack(AddSingleItem(item, !dontInformGui, !dontMarkAsNew)); + } + + quantity = 1; + } + else + { + if(quantity < 2 ) + { + arr.PushBack(AddSingleItem(item, !dontInformGui, !dontMarkAsNew)); + } + else + { + arr = AddMultiItem(item, quantity, !dontInformGui, !dontMarkAsNew); + } + } + + + if(this == thePlayer.GetInventory()) + { + if(ItemHasTag(arr[0],'ReadableItem')) + UpdateInitialReadState(arr[0]); + + + if(showAsRewardInUIHax || ItemHasTag(arr[0],'GwintCard')) + thePlayer.DisplayItemRewardNotification(GetItemName(arr[0]), quantity ); + } + + return arr; + } + + + import final function RemoveItem( itemId : SItemUniqueId, optional quantity : int ) : bool; + + + private final function InternalRemoveItems(ids : array, quantity : int) + { + var i, currQuantityToTake : int; + + + for(i=0; i0, "CInventoryComponent.InternalRemoveItems(" + GetItemName(ids[i]) + "): somehow took too many items! Should be " + (-quantity) + " less... Investigate!"); + } + } + + + + public function RemoveItemByName(itemName : name, optional quantity : int) : bool + { + var totalItemCount : int; + var ids : array; + + + totalItemCount = GetItemQuantityByName(itemName); + if(totalItemCount < quantity || quantity == 0) + { + return false; + } + + if(quantity == 0) + { + quantity = 1; + } + else if(quantity < 0) + { + quantity = totalItemCount; + } + + ids = GetItemsIds(itemName); + + if(GetEntity() == thePlayer && thePlayer.GetSelectedItemId() == ids[0] ) + { + thePlayer.ClearSelectedItemId(); + } + + InternalRemoveItems(ids, quantity); + + return true; + } + + + + public function RemoveItemByCategory(itemCategory : name, optional quantity : int) : bool + { + var totalItemCount : int; + var ids : array; + var selectedItemId : SItemUniqueId; + var i : int; + + + totalItemCount = GetItemQuantityByCategory(itemCategory); + if(totalItemCount < quantity) + { + return false; + } + + if(quantity == 0) + { + quantity = 1; + } + else if(quantity < 0) + { + quantity = totalItemCount; + } + + ids = GetItemsByCategory(itemCategory); + + if(GetEntity() == thePlayer) + { + selectedItemId = thePlayer.GetSelectedItemId(); + for(i=0; i; + var i : int; + var selectedItemId : SItemUniqueId; + + + totalItemCount = GetItemQuantityByTag(itemTag); + if(totalItemCount < quantity) + { + return false; + } + + if(quantity == 0) + { + quantity = 1; + } + else if(quantity < 0) + { + quantity = totalItemCount; + } + + ids = GetItemsByTag(itemTag); + + if(GetEntity() == thePlayer) + { + selectedItemId = thePlayer.GetSelectedItemId(); + for(i=0; i ) : CEntity; + + + import final function ThrowAwayLootableItems( optional skipNoDropNoShow : bool ) : CEntity; + + + import final function GetItemRecyclingParts( itemId : SItemUniqueId ) : array; + + import final function GetItemWeight( id : SItemUniqueId ) : float; + + + public final function HasQuestItem() : bool + { + var allItems : array< SItemUniqueId >; + var i : int; + + allItems = GetItemsByTag('Quest'); + for ( i=0; i theGame.params.ITEM_DAMAGED_DURABILITY ) + { + FactsAdd( "tut_item_damaged", 1 ); + } + } + } + + SetItemDurability( itemId, durability ); + } + + + public function ReduceItemDurability(itemId : SItemUniqueId, optional forced : bool) : bool + { + var dur, value, durabilityDiff, itemToughness, indestructible : float; + var chance : int; + if(!IsIdValid(itemId) || !HasItemDurability(itemId) || ItemHasAbility(itemId, 'MA_Indestructible')) + { + return false; + } + + + if(IsItemWeapon(itemId)) + { + chance = theGame.params.DURABILITY_WEAPON_LOSE_CHANCE; + value = theGame.params.GetWeaponDurabilityLoseValue(); + } + else if(IsItemAnyArmor(itemId)) + { + chance = theGame.params.DURABILITY_ARMOR_LOSE_CHANCE; + value = theGame.params.DURABILITY_ARMOR_LOSE_VALUE; + } + + dur = GetItemDurability(itemId); + + if ( dur == 0 ) + { + return false; + } + + + if ( forced || RandRange( 100 ) < chance ) + { + itemToughness = CalculateAttributeValue( GetItemAttributeValue( itemId, 'toughness' ) ); + indestructible = CalculateAttributeValue( GetItemAttributeValue( itemId, 'indestructible' ) ); + + value = value * ( 1 - indestructible ); + + if ( itemToughness > 0.0f && itemToughness <= 1.0f ) + { + durabilityDiff = ( dur - value ) * itemToughness; + + SetItemDurabilityScript( itemId, MaxF(durabilityDiff, 0 ) ); + } + else + { + SetItemDurabilityScript( itemId, MaxF( dur - value, 0 ) ); + } + } + + return true; + } + + public function GetItemDurabilityRatio(itemId : SItemUniqueId) : float + { + if ( !IsIdValid( itemId ) || !HasItemDurability( itemId ) ) + return -1; + + return GetItemDurability(itemId) / GetItemMaxDurability(itemId); + } + + + + + + + public function GetItemResistStatWithDurabilityModifiers(itemId : SItemUniqueId, stat : ECharacterDefenseStats, out points : SAbilityAttributeValue, out percents : SAbilityAttributeValue) + { + var mult : float; + var null : SAbilityAttributeValue; + + points = null; + percents = null; + if(!IsItemAnyArmor(itemId)) + return; + + mult = theGame.params.GetDurabilityMultiplier(GetItemDurabilityRatio(itemId), false); + + points = GetItemAttributeValue(itemId, ResistStatEnumToName(stat, true)); + percents = GetItemAttributeValue(itemId, ResistStatEnumToName(stat, false)); + + points = points * mult; + percents = percents * mult; + } + + + public function GetItemResistanceTypes(id : SItemUniqueId) : array + { + var ret : array; + var i : int; + var stat : ECharacterDefenseStats; + var atts : array; + var tmpBool : bool; + + if(!IsIdValid(id)) + return ret; + + GetItemAttributes(id, atts); + for(i=0; i; + var card : array; + var iHave, shopHave, cardLimit, delta : int; + var curItem : SItemUniqueId; + var i : int; + + allItems = GetItemsByCategory('gwint'); + for(i=allItems.Size()-1; i >= 0; i-=1) + { + curItem = allItems[i]; + + attr = GetItemAttributeValue( curItem, 'max_count'); + card = thePlayer.GetInventory().GetItemsByName( GetItemName( curItem ) ); + iHave = thePlayer.GetInventory().GetItemQuantity( card[0] ); + cardLimit = RoundF(attr.valueBase); + shopHave = GetItemQuantity( curItem ); + + if (iHave > 0 && shopHave > 0) + { + delta = shopHave - (cardLimit - iHave); + + if ( delta > 0 ) + { + RemoveItem( curItem, delta ); + } + } + } + } + + function ClearTHmaps() + { + var attr : SAbilityAttributeValue; + var allItems : array; + var map : array; + var i : int; + var thCompleted : bool; + var iHave, shopHave : int; + + allItems = GetItemsByTag('ThMap'); + for(i=allItems.Size()-1; i >= 0; i-=1) + { + attr = GetItemAttributeValue( allItems[i], 'max_count'); + map = thePlayer.GetInventory().GetItemsByName( GetItemName( allItems[i] ) ); + thCompleted = FactsDoesExist(GetItemName(allItems[i])); + iHave = thePlayer.GetInventory().GetItemQuantity( map[0] ); + shopHave = RoundF(attr.valueBase); + + if ( iHave >= shopHave || thCompleted ) + { + RemoveItem( allItems[i], GetItemQuantity( allItems[i] ) ); + } + } + } + + + public final function ClearKnownRecipes() + { + var witcher : W3PlayerWitcher; + var recipes, craftRecipes : array; + var i : int; + var itemName : name; + var allItems : array; + + witcher = GetWitcherPlayer(); + if(!witcher) + return; + + + recipes = witcher.GetAlchemyRecipes(); + craftRecipes = witcher.GetCraftingSchematicsNames(); + ArrayOfNamesAppend(recipes, craftRecipes); + + + GetAllItems(allItems); + + + for(i=allItems.Size()-1; i>=0; i-=1) + { + itemName = GetItemName(allItems[i]); + if(recipes.Contains(itemName)) + RemoveItem(allItems[i], GetItemQuantity(allItems[i])); + } + } + + + + + + function LoadBooksDefinitions() : void + { + var readableArray : array; + var i : int; + + readableArray = GetItemsByTag('ReadableItem'); + + for( i = 0; i < readableArray.Size(); i += 1 ) + { + if( IsBookRead(readableArray[i])) + { + continue; + } + UpdateInitialReadState(readableArray[i]); + } + } + + function UpdateInitialReadState( item : SItemUniqueId ) + { + var abilitiesArray : array; + var i : int; + GetItemAbilities(item,abilitiesArray); + + for( i = 0; i < abilitiesArray.Size(); i += 1 ) + { + if( abilitiesArray[i] == 'WasRead' ) + { + ReadBook(item); + break; + } + } + } + + function IsBookRead( item : SItemUniqueId ) : bool + { + var bookName : name; + var bResult : bool; + + bookName = GetItemName( item ); + + bResult = IsBookReadByName( bookName ); + return bResult; + } + + function IsBookReadByName( bookName : name ) : bool + { + var bookFactName : string; + + bookFactName = GetBookReadFactName( bookName ); + if( FactsDoesExist(bookFactName) ) + { + return FactsQuerySum( bookFactName ); + } + + return false; + } + + function ReadBook( item : SItemUniqueId, optional noNotification : bool ) + { + + var bookName : name; + var abilitiesArray : array; + var i : int; + var commonMapManager : CCommonMapManager = theGame.GetCommonMapManager(); + + bookName = GetItemName( item ); + + if ( !IsBookRead ( item ) && ItemHasTag ( item, 'FastTravel' )) + { + GetItemAbilities(item, abilitiesArray); + + for ( i = 0; i < abilitiesArray.Size(); i+=1 ) + { + commonMapManager.SetEntityMapPinDiscoveredScript(true, abilitiesArray[i], true ); + } + } + ReadBookByNameId( bookName, item, false, noNotification ); + + + + + if(ItemHasTag(item, 'PerkBook')) + { + + } + } + + public function GetBookText(item : SItemUniqueId) : string + { + // modStatTrak BEGIN + if ( GetItemName( item ) != 'Gwent Almanac' && GetItemName( item ) != 'Achievement Stats' ) + { + return ReplaceTagsToIcons(GetLocStringByKeyExt(GetItemLocalizedNameByUniqueID(item)+"_text")); + } + else if ( GetItemName( item ) == 'Gwent Almanac' ) + { + return GetGwentAlmanacContents(); + } + else + { + return getFormattedAchievementStats(getAchievementStats()); + } + // modStatTrak END + } + + public function GetBookTextByName( bookName : name ) : string + { + // modStatTrak BEGIN + if( bookName != 'Gwent Almanac' && bookName != 'Achievement Stats' ) + { + return ReplaceTagsToIcons( GetLocStringByKeyExt( GetItemLocalizedNameByName( bookName ) + "_text" ) ); + } + else if ( bookName == 'Gwent Almanac' ) + { + return GetGwentAlmanacContents(); + } + else + { + return getFormattedAchievementStats(getAchievementStats()); + } + // modStatTrak END + } + + function ReadSchematicsAndRecipes( item : SItemUniqueId ) + { + var itemCategory : name; + var itemName : name; + var player : W3PlayerWitcher; + + ReadBook( item ); + + player = GetWitcherPlayer(); + if ( !player ) + { + return; + } + + itemName = GetItemName( item ); + itemCategory = GetItemCategory( item ); + if ( itemCategory == 'alchemy_recipe' ) + { + if ( player.CanLearnAlchemyRecipe( itemName ) ) + { + player.AddAlchemyRecipe( itemName ); + player.GetInventory().AddItemTag(item, 'NoShow'); + + } + } + else if ( itemCategory == 'crafting_schematic' ) + { + player.AddCraftingSchematic( itemName ); + player.GetInventory().AddItemTag(item, 'NoShow'); + + } + } + + function ReadBookByName( bookName : name , unread : bool, optional noNotification : bool ) + { + var defMgr : CDefinitionsManagerAccessor; + var bookFactName : string; + + if( IsBookReadByName( bookName ) != unread ) + { + return; + } + + bookFactName = "BookReadState_"+bookName; + bookFactName = StrReplace(bookFactName," ","_"); + + if( unread ) + { + FactsSubstract( bookFactName, 1 ); + } + else + { + FactsAdd( bookFactName, 1 ); + + + defMgr = theGame.GetDefinitionsManager(); + if(!IsAlchemyRecipe(bookName) && !IsCraftingSchematic(bookName) && !defMgr.ItemHasTag( bookName, 'Painting' ) ) + { + theGame.GetGamerProfile().IncStat(ES_ReadBooks); + + if( !noNotification ) + { + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "notification_book_moved" ), 0, false ); + } + } + + + if ( AddBestiaryFromBook(bookName) ) + return; + + + + } + } + + function ReadBookByNameId( bookName : name, itemId:SItemUniqueId, unread : bool, optional noNotification : bool ) + { + var bookFactName : string; + + if( IsBookReadByName( bookName ) != unread ) + { + return; + } + + bookFactName = "BookReadState_"+bookName; + bookFactName = StrReplace(bookFactName," ","_"); + + if( unread ) + { + FactsSubstract( bookFactName, 1 ); + } + else + { + FactsAdd( bookFactName, 1 ); + + + if( !IsAlchemyRecipe( bookName ) && !IsCraftingSchematic( bookName ) ) + { + theGame.GetGamerProfile().IncStat(ES_ReadBooks); + + if( !noNotification ) + { + + GetWitcherPlayer().AddReadBook( bookName ); + } + } + + + if ( AddBestiaryFromBook(bookName) ) + return; + else + ReadSchematicsAndRecipes( itemId ); + } + } + + + private function AddBestiaryFromBook( bookName : name ) : bool + { + var i, j, r, len : int; + var manager : CWitcherJournalManager; + var resource : array; + var entryBase : CJournalBase; + var childGroups : array; + var childEntries : array; + var descriptionGroup : CJournalCreatureDescriptionGroup; + var descriptionEntry : CJournalCreatureDescriptionEntry; + + manager = theGame.GetJournalManager(); + + switch ( bookName ) + { + case 'Beasts vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWolf" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryDog" ) ); + break; + case 'Beasts vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBear" ) ); + break; + case 'Cursed Monsters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWerewolf" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryLycanthrope" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 24'); + break; + case 'Cursed Monsters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWerebear" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryMiscreant" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 11'); + break; + case 'Draconides vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCockatrice" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBasilisk" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 3'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 23'); + break; + case 'Draconides vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWyvern" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryForktail" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 10'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 17'); + break; + case 'Hybrid Monsters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryHarpy" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryErynia" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiarySiren" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiarySuccubus" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 14'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 21'); + break; + case 'Hybrid Monsters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGriffin" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 4'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 27'); + break; + case 'Insectoids vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryEndriagaWorker" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryEndriagaTruten" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryEndriaga" ) ); + break; + case 'Insectoids vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCrabSpider" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryArmoredArachas" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryPoisonousArachas" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 2'); + break; + case 'Magical Monsters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGolem" ) ); + break; + case 'Magical Monsters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryElemental" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryIceGolem" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryFireElemental" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWhMinion" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 20'); + break; + case 'Necrophage vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGhoul" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryAlghoul" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGreaterRotFiend" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryDrowner" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 15'); + break; + case 'Necrophage vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGraveHag" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWaterHag" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryFogling" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 5'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 9'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 18'); + break; + case 'Relict Monsters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBies" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCzart" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 8'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 16'); + break; + case 'Relict Monsters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryLeshy" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiarySilvan" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 22'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 26'); + break; + case 'Specters vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryMoonwright" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryNoonwright" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryPesta" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 6'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 13'); + break; + case 'Specters vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWraith" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryHim" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 19'); + break; + case 'Ogres vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryNekker" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryIceTroll" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCaveTroll" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 12'); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 25'); + break; + case 'Ogres vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryCyclop" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryIceGiant" ) ); + break; + case 'Vampires vol 1': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryEkkima" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryHigherVampire" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 7'); + break; + case 'Vampires vol 2': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryKatakan" ) ); + GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 1'); + break; + + case 'bestiary_sharley_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiarySharley" ) ); + break; + case 'bestiary_barghest_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBarghest" ) ); + break; + case 'bestiary_garkain_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryGarkain" ) ); + break; + case 'bestiary_alp_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryAlp" ) ); + break; + case 'bestiary_bruxa_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryBruxa" ) ); + break; + case 'bestiary_spriggan_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiarySpriggan" ) ); + break; + case 'bestiary_fleder_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryFleder" ) ); + break; + case 'bestiary_wight_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryWicht" ) ); + break; + case 'bestiary_dracolizard_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryDracolizard" ) ); + break; + case 'bestiary_panther_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryPanther" ) ); + break; + case 'bestiary_kikimore_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryKikimoraWarrior" ) ); + resource.PushBack( (CJournalResource)LoadResource( "BestiaryKikimoraWorker" ) ); + break; + case 'bestiary_scolopendromorph_book': + case 'mq7023_fluff_book_scolopendromorphs': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryScolopendromorph" ) ); + break; + case 'bestiary_archespore_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryArchespore" ) ); + break; + case 'bestiary_protofleder_book': + resource.PushBack( (CJournalResource)LoadResource( "BestiaryProtofleder" ) ); + break; + default: + return false; + } + + + + + len = resource.Size(); + if( len > 0) + { + + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "panel_hud_journal_entry_bestiary_new" ), 0, true ); + theSound.SoundEvent("gui_ingame_new_journal"); + } + + for (r=0; r < len; r += 1 ) + { + if ( !resource[ r ] ) + { + + continue; + } + entryBase = resource[r].GetEntry(); + if ( entryBase ) + { + manager.ActivateEntry( entryBase, JS_Active ); + manager.SetEntryHasAdvancedInfo( entryBase, true ); + + + manager.GetAllChildren( entryBase, childGroups ); + for ( i = 0; i < childGroups.Size(); i += 1 ) + { + descriptionGroup = ( CJournalCreatureDescriptionGroup )childGroups[ i ]; + if ( descriptionGroup ) + { + manager.GetAllChildren( descriptionGroup, childEntries ); + for ( j = 0; j < childEntries.Size(); j += 1 ) + { + descriptionEntry = ( CJournalCreatureDescriptionEntry )childEntries[ j ]; + if ( descriptionEntry ) + { + manager.ActivateEntry( descriptionEntry, JS_Active ); + } + } + break; + } + } + } + } + + if ( resource.Size() > 0 ) + return true; + else + return false; + } + + + + + + + + + function GetWeaponDTNames( id : SItemUniqueId, out dmgNames : array< name > ) : int + { + var attrs : array< name >; + var i, size : int; + + dmgNames.Clear(); + + if( IsIdValid(id) ) + { + GetItemAttributes( id, attrs ); + size = attrs.Size(); + + for( i = 0; i < size; i += 1 ) + if( IsDamageTypeNameValid(attrs[i]) ) + dmgNames.PushBack( attrs[i] ); + + if(dmgNames.Size() == 0) + LogAssert(false, "CInventoryComponent.GetWeaponDTNames: weapon <<" + GetItemName(id) + ">> has no damage types defined!"); + } + return dmgNames.Size(); + } + + public function GetWeapons() : array + { + var ids, ids2 : array; + + ids = GetItemsByCategory('monster_weapon'); + ids2 = GetItemsByTag('Weapon'); + ArrayOfIdsAppend(ids, ids2); + + return ids; + } + + public function GetHeldWeapons() : array + { + var i : int; + var w : array; + + w = GetWeapons(); + + for(i=w.Size()-1; i>=0; i-=1) + { + if(!IsItemHeld(w[i])) + { + w.EraseFast( i ); + } + } + + return w; + } + + public function GetCurrentlyHeldSword() : SItemUniqueId + { + var i : int; + var w : array; + + w = GetHeldWeapons(); + + for( i = 0 ; i < w.Size() ; i+=1 ) + { + if( IsItemSteelSwordUsableByPlayer( w[i] ) || IsItemSilverSwordUsableByPlayer( w[i] ) ) + { + return w[i]; + } + } + + return GetInvalidUniqueId(); + } + + public function GetCurrentlyHeldSwordEntity( out ent : CItemEntity ) : bool + { + var id : SItemUniqueId; + + id = GetCurrentlyHeldSword(); + + if( IsIdValid( id ) ) + { + ent = GetItemEntityUnsafe( id ); + + if( ent ) + { + return true; + } + else + { + return false; + } + } + return false; + } + + public function GetHeldWeaponsWithCategory( category : name, out items : array ) + { + var i : int; + + items = GetItemsByCategory( category ); + + for ( i = items.Size()-1; i >= 0; i -= 1) + { + if ( !IsItemHeld( items[i] ) ) + { + items.EraseFast( i ); + } + } + } + + public function GetPotionItemBuffData(id : SItemUniqueId, out type : EEffectType, out customAbilityName : name) : bool + { + var size, i : int; + var arr : array; + + if(IsIdValid(id)) + { + GetItemContainedAbilities( id, arr ); + size = arr.Size(); + + for( i = 0; i < size; i += 1 ) + { + if( IsEffectNameValid(arr[i]) ) + { + EffectNameToType(arr[i], type, customAbilityName); + return true; + } + } + } + + return false; + } + + + public function RecycleItem( id : SItemUniqueId, level : ECraftsmanLevel ) : array + { + var itemsAdded : array; + var currentAdded : array; + + var parts : array; + var i : int; + + parts = GetItemRecyclingParts( id ); + + for ( i = 0; i < parts.Size(); i += 1 ) + { + if ( ECL_Grand_Master == level || ECL_Arch_Master == level ) + { + currentAdded = AddAnItem( parts[i].itemName, parts[i].quantity ); + } + else if ( ECL_Master == level && parts[i].quantity > 1 ) + { + currentAdded = AddAnItem( parts[i].itemName, RandRange( parts[i].quantity, 1 ) ); + } + else + { + currentAdded = AddAnItem( parts[i].itemName, 1 ); + } + itemsAdded.PushBack(currentAdded[0]); + } + + RemoveItem(id); + + return itemsAdded; + } + + + + + + + public function GetItemBuffs( id : SItemUniqueId, out buffs : array) : int + { + var attrs, abs, absFast : array< name >; + var i, k : int; + var type : EEffectType; + var abilityName : name; + var buff : SEffectInfo; + var dm : CDefinitionsManagerAccessor; + + buffs.Clear(); + + if( !IsIdValid(id) ) + return 0; + + + GetItemContainedAbilities(id, absFast); + if(absFast.Size() == 0) + return 0; + + GetItemAbilities(id, abs); + dm = theGame.GetDefinitionsManager(); + for(k=0; k; + var i : int; + var owner : CActor; + var bag : W3ActorRemains; + var template : CEntityTemplate; + var bagtags : array ; + var bagPosition : Vector; + var tracedPosition, tracedNormal : Vector; + + if(ItemHasTag(item, 'NoDrop')) + return; + + owner = (CActor)GetEntity(); + FindGameplayEntitiesInRange(entities, owner, 0.5, 100); + + for(i=0; i; + + + if(buffArmor) + { + items = GetItemsByTag(theGame.params.TAG_ARMOR); + } + if(buffSwords) + { + items2 = GetItemsByTag(theGame.params.TAG_PLAYER_STEELSWORD); + ArrayOfIdsAppend(items, items2); + items2.Clear(); + items2 = GetItemsByTag(theGame.params.TAG_PLAYER_SILVERSWORD); + ArrayOfIdsAppend(items, items2); + } + + upgradedSomething = false; + + for(i=0; i currAmmo) + { + SetItemModifierInt(items[i], 'repairObjectBonusAmmo', ammo); + upgradedSomething = true; + + + if(currAmmo == 0) + { + if(isArmor) + AddItemCraftedAbility(items[i], theGame.params.REPAIR_OBJECT_BONUS_ARMOR_ABILITY, false); + else + AddItemCraftedAbility(items[i], theGame.params.REPAIR_OBJECT_BONUS_WEAPON_ABILITY, false); + } + } + } + + return upgradedSomething; + } + + public final function ReduceItemRepairObjectBonusCharge(item : SItemUniqueId) + { + var currAmmo : int; + + currAmmo = GetItemModifierInt(item, 'repairObjectBonusAmmo', 0); + + if(currAmmo > 0) + { + SetItemModifierInt(item, 'repairObjectBonusAmmo', currAmmo - 1); + + if(currAmmo == 1) + { + if(IsItemAnyArmor(item)) + RemoveItemCraftedAbility(item, theGame.params.REPAIR_OBJECT_BONUS_ARMOR_ABILITY); + else + RemoveItemCraftedAbility(item, theGame.params.REPAIR_OBJECT_BONUS_WEAPON_ABILITY); + } + } + } + + + public final function GetRepairObjectBonusValueForArmor(armor : SItemUniqueId) : SAbilityAttributeValue + { + var retVal, bonusValue, baseArmor : SAbilityAttributeValue; + + if(GetItemModifierInt(armor, 'repairObjectBonusAmmo', 0) > 0) + { + bonusValue = GetItemAttributeValue(armor, theGame.params.REPAIR_OBJECT_BONUS); + baseArmor = GetItemAttributeValue(armor, theGame.params.ARMOR_VALUE_NAME); + + baseArmor.valueMultiplicative += 1; + retVal.valueAdditive = bonusValue.valueAdditive + CalculateAttributeValue(baseArmor) * bonusValue.valueMultiplicative; + } + + return retVal; + } + + + + + + + public function CanItemHaveOil(id : SItemUniqueId) : bool + { + return IsItemSteelSwordUsableByPlayer(id) || IsItemSilverSwordUsableByPlayer(id); + } + + public final function RemoveAllOilsFromItem( id : SItemUniqueId ) + { + var i : int; + var oils : array< W3Effect_Oil >; + var actor : CActor; + + actor = ( CActor ) GetEntity(); + oils = GetOilsAppliedOnItem( id ); + for( i = oils.Size() - 1; i >= 0; i -= 1 ) + { + actor.RemoveEffect( oils[ i ] ); + } + } + + public final function GetActiveOilsAppliedOnItemCount( id : SItemUniqueId ) : int + { + var oils : array< W3Effect_Oil >; + var i, count : int; + + count = 0; + oils = GetOilsAppliedOnItem( id ); + for( i=0; i 0 ) + { + count += 1; + } + } + return count; + } + + public final function RemoveOldestOilFromItem( id : SItemUniqueId ) + { + var buffToRemove : W3Effect_Oil; + var actor : CActor; + + actor = ( CActor ) GetEntity(); + if(! actor ) + return; + + buffToRemove = GetOldestOilAppliedOnItem(id, false); + + if(buffToRemove) + { + actor.RemoveEffect( buffToRemove ); + } + } + + public final function GetOilsAppliedOnItem( id : SItemUniqueId ) : array< W3Effect_Oil > + { + var i : int; + var oils : array< CBaseGameplayEffect >; + var buff : W3Effect_Oil; + var ret : array < W3Effect_Oil >; + var actor : CActor; + + actor = ( CActor ) GetEntity(); + if(! actor ) + return ret; + + oils = actor.GetBuffs( EET_Oil ); + for( i = oils.Size() - 1; i >= 0; i -= 1 ) + { + buff = ( W3Effect_Oil ) oils[ i ]; + if(buff && buff.GetSwordItemId() == id ) + { + ret.PushBack( buff ); + } + } + + return ret; + } + + public final function GetNewestOilAppliedOnItem( id : SItemUniqueId, onlyShowable : bool ) : W3Effect_Oil + { + return GetOilAppliedOnItemInternal( id, onlyShowable, true ); + } + + public final function GetOldestOilAppliedOnItem( id : SItemUniqueId, onlyShowable : bool ) : W3Effect_Oil + { + return GetOilAppliedOnItemInternal( id, onlyShowable, false ); + } + + private final function GetOilAppliedOnItemInternal( id : SItemUniqueId, onlyShowable : bool, newest : bool ) : W3Effect_Oil + { + var oils : array< W3Effect_Oil >; + var i, lastIndex : int; + + oils = GetOilsAppliedOnItem( id ); + lastIndex = -1; + + for( i=0; i oils[lastIndex].GetQueueTimer() ) + { + lastIndex = i; + } + } + + if( lastIndex == -1 ) + { + return NULL; + } + + return oils[lastIndex]; + } + + public final function ItemHasAnyActiveOilApplied( id : SItemUniqueId ) : bool + { + return GetActiveOilsAppliedOnItemCount( id ); + } + + public final function ItemHasActiveOilApplied( id : SItemUniqueId, monsterCategory : EMonsterCategory ) : bool + { + var i : int; + var oils : array< W3Effect_Oil >; + + oils = GetOilsAppliedOnItem( id ); + for( i=0; i 0 ) + { + return true; + } + } + + return false; + } + + + + + + public final function GetParamsForRunewordTooltip(runewordName : name, out i : array, out f : array, out s : array) + { + var min, max : SAbilityAttributeValue; + var val : float; + var attackRangeBase, attackRangeExt : CAIAttackRange; + + i.Clear(); + f.Clear(); + s.Clear(); + + switch(runewordName) + { + case 'Glyphword 5': + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 5 _Stats', 'glyphword5_chance', min, max); + i.PushBack( RoundMath( CalculateAttributeValue(min) * 100) ); + break; + case 'Glyphword 6' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 6 _Stats', 'glyphword6_stamina_drain_perc', min, max); + i.PushBack( RoundMath( CalculateAttributeValue(min) * 100) ); + break; + case 'Glyphword 12' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 12 _Stats', 'glyphword12_range', min, max); + val = CalculateAttributeValue(min); + s.PushBack( NoTrailZeros(val) ); + + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 12 _Stats', 'glyphword12_chance', min, max); + i.PushBack( RoundMath( min.valueAdditive * 100) ); + break; + case 'Glyphword 17' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 17 _Stats', 'quen_apply_chance', min, max); + val = CalculateAttributeValue(min); + i.PushBack( RoundMath(val * 100) ); + break; + case 'Glyphword 14' : + case 'Glyphword 18' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 18 _Stats', 'increas_duration', min, max); + val = CalculateAttributeValue(min); + s.PushBack( NoTrailZeros(val) ); + break; + + case 'Runeword 2' : + attackRangeBase = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'specialattacklight'); + attackRangeExt = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'runeword2_light'); + s.PushBack( NoTrailZeros(attackRangeExt.rangeMax - attackRangeBase.rangeMax) ); + + attackRangeBase = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'slash_long'); + attackRangeExt = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'runeword2_heavy'); + s.PushBack( NoTrailZeros(attackRangeExt.rangeMax - attackRangeBase.rangeMax) ); + + break; + case 'Runeword 4' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue('Runeword 4 _Stats', 'max_bonus', min, max); + i.PushBack( RoundMath(max.valueMultiplicative * 100) ); + break; + case 'Runeword 6' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 6 _Stats', 'runeword6_duration_bonus', min, max ); + i.PushBack( RoundMath(min.valueMultiplicative * 100) ); + break; + case 'Runeword 7' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 7 _Stats', 'stamina', min, max ); + i.PushBack( RoundMath(min.valueMultiplicative * 100) ); + break; + case 'Runeword 10' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 10 _Stats', 'stamina', min, max ); + i.PushBack( RoundMath(min.valueMultiplicative * 100) ); + break; + case 'Runeword 11' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 11 _Stats', 'duration', min, max ); + s.PushBack( NoTrailZeros(min.valueAdditive) ); + break; + case 'Runeword 12' : + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 12 _Stats', 'focus', min, max ); + f.PushBack(min.valueAdditive); + f.PushBack(max.valueAdditive); + break; + default: + break; + } + } + + public final function GetPotionAttributesForTooltip(potionId : SItemUniqueId, out tips : array):void + { + var i, j, settingsSize : int; + var buffType : EEffectType; + var abilityName : name; + var abs, attrs : array; + var val : SAbilityAttributeValue; + var newAttr : SAttributeTooltip; + var attributeString : string; + + + if(!( IsItemPotion(potionId) || IsItemFood(potionId) ) ) + return; + + + GetItemContainedAbilities(potionId, abs); + for(i=0; i, out localizedFluff : string) + { + if( !IsIdValid(itemId) ) + { + return; + } + localizedName = GetItemLocalizedNameByUniqueID(itemId); + localizedDescription = GetItemLocalizedDescriptionByUniqueID(itemId); + localizedFluff = "IMPLEMENT ME - fluff text"; + price = GetItemPriceModified( itemId, false ); + localizedCategory = GetItemCategoryLocalisedString(GetItemCategory(itemId)); + GetItemStats(itemId, itemStats); + } + + + public function GetItemBaseStats(itemId : SItemUniqueId, out itemStats : array) + { + var attributes : array; + + var dm : CDefinitionsManagerAccessor; + var oilAbilities, oilAttributes : array; + var weights : array; + var i, j : int; + var tmpI, tmpJ : int; + + var idx : int; + var oilStatsCount : int; + var oilName : name; + var oilStats : array; + var oilStatFirst : SAttributeTooltip; + var oils : array< W3Effect_Oil >; + + GetItemBaseAttributes(itemId, attributes); + + + oils = GetOilsAppliedOnItem( itemId ); + dm = theGame.GetDefinitionsManager(); + for( i=0; i) + { + var attributes : array; + + GetItemAttributes(itemId, attributes); + GetItemTooltipAttributes(itemId, attributes, itemStats); + } + + private function GetItemTooltipAttributes(itemId : SItemUniqueId, attributes : array, out itemStats : array):void + { + var itemCategory:name; + var i, j, settingsSize : int; + var attributeString : string; + var attributeColor : string; + var attributeName : name; + var isPercentageValue : string; + var primaryStatLabel : string; + var statLabel : string; + + var stat : SAttributeTooltip; + var attributeVal : SAbilityAttributeValue; + + settingsSize = theGame.tooltipSettings.GetNumRows(); + itemStats.Clear(); + itemCategory = GetItemCategory(itemId); + for(i=0; i) + { + var itemCategory : name; + var i, j, settingsSize : int; + var attributeString : string; + var attributeColor : string; + var attributeName : name; + var isPercentageValue : string; + var attributes, itemAbilities, tmpArray : array; + var weights : array; + var stat : SAttributeTooltip; + var attributeVal, min, max : SAbilityAttributeValue; + var dm : CDefinitionsManagerAccessor; + var primaryStatLabel : string; + var statLabel : string; + + settingsSize = theGame.tooltipSettings.GetNumRows(); + dm = theGame.GetDefinitionsManager(); + dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, weights, i, j); + attributes = dm.GetAbilitiesAttributes(itemAbilities); + + itemStats.Clear(); + itemCategory = dm.GetItemCategory(itemName); + for(i=0; i ) : bool + { + var i : int; + var currItemName : name; + + currItemName = GetItemName( itemID ); + + for ( i = 0; i < excludedItems.Size(); i+=1 ) + { + if ( currItemName == excludedItems[i].itemName ) + { + return true; + } + } + return false; + } + + + public function GetItemPrimaryStat(itemId : SItemUniqueId, out attributeLabel : string, out attributeVal : float ) : void + { + var attributeName : name; + var attributeValue:SAbilityAttributeValue; + + GetItemPrimaryStatImplById(itemId, attributeLabel, attributeVal, attributeName); + + attributeValue = GetItemAttributeValue(itemId, attributeName); + + if(attributeValue.valueBase != 0) + { + attributeVal = attributeValue.valueBase; + } + if(attributeValue.valueMultiplicative != 0) + { + attributeVal = attributeValue.valueMultiplicative; + } + if(attributeValue.valueAdditive != 0) + { + attributeVal = attributeValue.valueAdditive; + } + } + + public function GetItemStatByName(itemName : name, statName : name, out resultValue : float) : void + { + var dm : CDefinitionsManagerAccessor; + var attributes, itemAbilities : array; + var min, max, attributeValue : SAbilityAttributeValue; + var tmpInt : int; + var tmpArray : array; + + dm = theGame.GetDefinitionsManager(); + dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, tmpArray, tmpInt, tmpInt); + attributes = dm.GetAbilitiesAttributes(itemAbilities); + + dm.GetAbilitiesAttributeValue(itemAbilities, statName, min, max); + attributeValue = GetAttributeRandomizedValue(min, max); + + if(attributeValue.valueBase != 0) + { + resultValue = attributeValue.valueBase; + } + if(attributeValue.valueMultiplicative != 0) + { + resultValue = attributeValue.valueMultiplicative; + } + if(attributeValue.valueAdditive != 0) + { + resultValue = attributeValue.valueAdditive; + } + } + + public function GetItemPrimaryStatFromName(itemName : name, out attributeLabel : string, out attributeVal : float, out primAttrName : name) : void + { + var dm : CDefinitionsManagerAccessor; + var attributeName : name; + var attributes, itemAbilities : array; + var attributeValue, min, max : SAbilityAttributeValue; + + var tmpInt : int; + var tmpArray : array; + + dm = theGame.GetDefinitionsManager(); + + GetItemPrimaryStatImpl(dm.GetItemCategory(itemName), attributeLabel, attributeVal, attributeName); + dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, tmpArray, tmpInt, tmpInt); + attributes = dm.GetAbilitiesAttributes(itemAbilities); + for (tmpInt = 0; tmpInt < attributes.Size(); tmpInt += 1) + if (attributes[tmpInt] == attributeName) + { + dm.GetAbilitiesAttributeValue(itemAbilities, attributeName, min, max); + attributeValue = GetAttributeRandomizedValue(min, max); + primAttrName = attributeName; + break; + } + + if(attributeValue.valueBase != 0) + { + attributeVal = attributeValue.valueBase; + } + if(attributeValue.valueMultiplicative != 0) + { + attributeVal = attributeValue.valueMultiplicative; + } + if(attributeValue.valueAdditive != 0) + { + attributeVal = attributeValue.valueAdditive; + } + + } + + public function IsPrimaryStatById(itemId : SItemUniqueId, attributeName : name, out attributeLabel : string) : bool + { + var attrValue : float; + var attrName : name; + + GetItemPrimaryStatImplById(itemId, attributeLabel, attrValue, attrName); + return attrName == attributeName; + } + + private function GetItemPrimaryStatImplById(itemId : SItemUniqueId, out attributeLabel : string, out attributeVal : float, out attributeName : name ) : void + { + var itemOnSlot : SItemUniqueId; + var categoryName : name; + var abList : array; + + attributeName = ''; + attributeLabel = ""; + categoryName = GetItemCategory(itemId); + + + if (categoryName == 'bolt' || categoryName == 'petard') + { + GetItemAttributes(itemId, abList); + if (abList.Contains('FireDamage')) + { + attributeName = 'FireDamage'; + } + else if (abList.Contains('PiercingDamage')) + { + attributeName = 'PiercingDamage'; + } + else if (abList.Contains('PiercingDamage')) + { + attributeName = 'PiercingDamage'; + } + else if (abList.Contains('PoisonDamage')) + { + attributeName = 'PoisonDamage'; + } + else if (abList.Contains('BludgeoningDamage')) + { + attributeName = 'BludgeoningDamage'; + } + else + { + attributeName = 'PhysicalDamage'; + } + attributeLabel = GetAttributeNameLocStr(attributeName, false); + } + else if (categoryName == 'secondary') + { + GetItemAttributes(itemId, abList); + if (abList.Contains('BludgeoningDamage')) + { + attributeName = 'BludgeoningDamage'; + } + else + { + attributeName = 'PhysicalDamage'; + } + attributeLabel = GetAttributeNameLocStr(attributeName, false); + } + else if (categoryName == 'steelsword') + { + GetItemAttributes(itemId, abList); + if (abList.Contains('SlashingDamage')) + { + attributeName = 'SlashingDamage'; + attributeLabel = GetLocStringByKeyExt("panel_inventory_tooltip_damage"); + } + else if (abList.Contains('BludgeoningDamage')) + { + attributeName = 'BludgeoningDamage'; + } + else if (abList.Contains('PiercingDamage')) + { + attributeName = 'PiercingDamage'; + } + else + { + attributeName = 'PhysicalDamage'; + } + if (attributeLabel == "") + { + attributeLabel = GetAttributeNameLocStr(attributeName, false); + } + } + else + { + GetItemPrimaryStatImpl(categoryName, attributeLabel, attributeVal, attributeName); + } + } + + public function IsPrimaryStat(categoryName : name, attributeName : name, out attributeLabel : string) : bool + { + var attrValue : float; + var attrName : name; + + GetItemPrimaryStatImpl(categoryName, attributeLabel, attrValue, attrName); + return attrName == attributeName; + } + + private function GetItemPrimaryStatImpl(categoryName : name, out attributeLabel : string, out attributeVal : float, out attributeName : name ) : void + { + attributeName = ''; + attributeLabel = ""; + switch (categoryName) + { + case 'steelsword': + attributeName = 'SlashingDamage'; + attributeLabel = GetLocStringByKeyExt("panel_inventory_tooltip_damage"); + break; + case 'silversword': + attributeName = 'SilverDamage'; + attributeLabel = GetLocStringByKeyExt("panel_inventory_tooltip_damage"); + break; + case 'armor': + case 'gloves': + case 'gloves': + case 'boots': + case 'pants': + attributeName = 'armor'; + break; + case 'potion': + case 'oil': + + break; + case 'bolt': + case 'petard': + attributeName = 'PhysicalDamage'; + break; + case 'crossbow': + default: + attributeLabel = ""; + attributeVal = 0; + return; + break; + } + + if (attributeLabel == "") + { + attributeLabel = GetAttributeNameLocStr(attributeName, false); + } + } + + public function CanBeCompared(itemId : SItemUniqueId) : bool + { + var wplayer : W3PlayerWitcher; + var itemSlot : EEquipmentSlots; + var equipedItem : SItemUniqueId; + var horseManager : W3HorseManager; + + var isArmorOrWeapon : bool; + + if (IsItemHorseItem(itemId)) + { + horseManager = GetWitcherPlayer().GetHorseManager(); + + if (!horseManager) + { + return false; + } + + if (horseManager.IsItemEquipped(itemId)) + { + return false; + } + + itemSlot = GetHorseSlotForItem(itemId); + equipedItem = horseManager.GetItemInSlot(itemSlot); + if (!horseManager.GetInventoryComponent().IsIdValid(equipedItem)) + { + return false; + } + } + else + { + isArmorOrWeapon = IsItemAnyArmor(itemId) || IsItemWeapon(itemId); + if (!isArmorOrWeapon) + { + return false; + } + + wplayer = GetWitcherPlayer(); + if (wplayer.IsItemEquipped(itemId)) + { + return false; + } + + itemSlot = GetSlotForItemId(itemId); + wplayer.GetItemEquippedOnSlot(itemSlot, equipedItem); + if (!wplayer.inv.IsIdValid(equipedItem)) + { + return false; + } + } + + return true; + } + + public function GetHorseSlotForItem(id : SItemUniqueId) : EEquipmentSlots + { + var tags : array; + + GetItemTags(id, tags); + + if(tags.Contains('Saddle')) return EES_HorseSaddle; + else if(tags.Contains('HorseBag')) return EES_HorseBag; + else if(tags.Contains('Trophy')) return EES_HorseTrophy; + else if(tags.Contains('Blinders')) return EES_HorseBlinders; + else return EES_InvalidSlot; + } + + + + + + public final function SingletonItemRefillAmmo( id : SItemUniqueId, optional alchemyTableUsed : bool ) + { + var l_bed : W3WitcherBed; + var refilledByBed : bool; + + refilledByBed = false; + + + if( FactsQuerySum( "PlayerInsideOuterWitcherHouse" ) >= 1 && FactsQuerySum( "AlchemyTableExists" ) >= 1 && !IsItemMutagenPotion( id ) ) + { + l_bed = (W3WitcherBed)theGame.GetEntityByTag( 'witcherBed' ); + + if( l_bed.GetWasUsed() || alchemyTableUsed ) + { + SetItemModifierInt( id, 'ammo_current', SingletonItemGetMaxAmmo(id) + theGame.params.QUANTITY_INCREASED_BY_ALCHEMY_TABLE ) ; + refilledByBed = true; + if( !l_bed.GetWereItemsRefilled() ) + { + l_bed.SetWereItemsRefilled( true ); + } + } + } + + + if( !refilledByBed && SingletonItemGetAmmo( id ) < SingletonItemGetMaxAmmo( id ) ) + { + SetItemModifierInt(id, 'ammo_current', SingletonItemGetMaxAmmo(id)); + } + + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged ); + } + + public function SingletonItemSetAmmo(id : SItemUniqueId, quantity : int) + { + var amount : int; + + if(ItemHasTag(id, theGame.params.TAG_INFINITE_AMMO)) + { + amount = -1; + } + else + { + amount = Clamp(quantity, 0, SingletonItemGetMaxAmmo(id)); + } + + SetItemModifierInt(id, 'ammo_current', amount); + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged ); + } + + public function SingletonItemAddAmmo(id : SItemUniqueId, quantity : int) + { + var ammo : int; + + if(quantity <= 0) + return; + + ammo = GetItemModifierInt(id, 'ammo_current'); + + if(ammo == -1) + return; + + ammo = Clamp(ammo + quantity, 0, SingletonItemGetMaxAmmo(id)); + SetItemModifierInt(id, 'ammo_current', ammo); + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged ); + } + + public function SingletonItemsRefillAmmo( optional alchemyTableUsed : bool ) : bool + { + var i : int; + var singletonItems : array; + var alco : SItemUniqueId; + var arrStr : array; + var witcher : W3PlayerWitcher; + var itemLabel : string; + + witcher = GetWitcherPlayer(); + if(GetEntity() == witcher && HasNotFilledSingletonItem( alchemyTableUsed ) ) + { + alco = witcher.GetAlcoholForAlchemicalItemsRefill(); + + if(!IsIdValid(alco)) + { + + theGame.GetGuiManager().ShowNotification(GetLocStringByKeyExt("message_common_alchemy_items_cannot_refill")); + theSound.SoundEvent("gui_global_denied"); + + return false; + } + else + { + + arrStr.PushBack(GetItemName(alco)); + itemLabel = GetLocStringByKeyExt(GetItemLocalizedNameByUniqueID(alco)); + theGame.GetGuiManager().ShowNotification( itemLabel + " - " + GetLocStringByKeyExtWithParams("message_common_alchemy_items_refilled", , , arrStr)); + theSound.SoundEvent("gui_alchemy_brew"); + + if(!ItemHasTag(alco, theGame.params.TAG_INFINITE_USE)) + RemoveItem(alco); + } + } + + singletonItems = GetSingletonItems(); + for(i=0; i; + var alco : SItemUniqueId; + var arrStr : array; + var witcher : W3PlayerWitcher; + var itemLabel : string; + + witcher = GetWitcherPlayer(); + if(!dontUpdateUI && GetEntity() == witcher && HasNotFilledSingletonItem()) + { + + arrStr.PushBack(GetItemName(alco)); + itemLabel = GetLocStringByKeyExt(GetItemLocalizedNameByUniqueID(alco)); + theGame.GetGuiManager().ShowNotification( itemLabel + " - " + GetLocStringByKeyExtWithParams("message_common_alchemy_items_refilled", , , arrStr)); + theSound.SoundEvent("gui_alchemy_brew"); + } + + singletonItems = GetSingletonItems(); + for(i=0; i; + var hasLab : bool; + var l_bed : W3WitcherBed; + + + hasLab = false; + if( FactsQuerySum( "PlayerInsideOuterWitcherHouse" ) >= 1 && FactsQuerySum( "AlchemyTableExists" ) >= 1 ) + { + l_bed = (W3WitcherBed)theGame.GetEntityByTag( 'witcherBed' ); + if( l_bed.GetWasUsed() || alchemyTableUsed ) + { + hasLab = true; + } + } + + singletonItems = GetSingletonItems(); + for(i=0; i 0) + { + FactsAdd('tut_alch_refill', 1); + } + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged ); + } + + public function SingletonItemGetAmmo(itemID : SItemUniqueId) : int + { + if(!IsItemSingletonItem(itemID)) + return 0; + + return GetItemModifierInt(itemID, 'ammo_current'); + } + + public function SingletonItemGetMaxAmmo(itemID : SItemUniqueId) : int + { + var ammo, i : int; + var perk20Bonus, min, max : SAbilityAttributeValue; + var atts : array; + var canUseSkill : bool; + + ammo = RoundMath(CalculateAttributeValue(GetItemAttributeValue(itemID, 'ammo'))); + + if( !ItemHasTag( itemID, 'NoAdditionalAmmo' ) ) + { + if(GetEntity() == GetWitcherPlayer() && ammo > 0) + { + if(IsItemBomb(itemID) && thePlayer.CanUseSkill(S_Alchemy_s08) ) + { + ammo += thePlayer.GetSkillLevel(S_Alchemy_s08); + } + + if(thePlayer.HasBuff(EET_Mutagen03) && (IsItemBomb(itemID) || (!IsItemMutagenPotion(itemID) && IsItemPotion(itemID))) ) + { + ammo += 1; + } + + if( GetWitcherPlayer().IsSetBonusActive( EISB_RedWolf_2 ) && !IsItemMutagenPotion(itemID) ) + { + theGame.GetDefinitionsManager().GetAbilityAttributeValue( GetSetBonusAbility( EISB_RedWolf_2 ), 'amount', min, max); + ammo += (int)min.valueAdditive; + } + + + if( IsItemBomb( itemID ) && thePlayer.CanUseSkill( S_Perk_20 ) && GetItemName( itemID ) != 'Snow Ball' ) + { + GetItemAttributes( itemID, atts ); + canUseSkill = thePlayer.CanUseSkill( S_Alchemy_s10 ); + perk20Bonus = GetWitcherPlayer().GetSkillAttributeValue( S_Perk_20, 'stack_multiplier', false, false ); + + for( i=0 ; i; + var l_i : int; + var l_haveBombOrPot : bool; + + l_items = GetSingletonItems(); + + for( l_i = 0 ; l_i < l_items.Size() ; l_i += 1 ) + { + if( IsItemPotion( l_items[ l_i ] ) || IsItemBomb( l_items[ l_i ] ) ) + { + l_haveBombOrPot = true; + if( SingletonItemGetMaxAmmo( l_items[ l_i ] ) >= SingletonItemGetAmmo( l_items[ l_i ] ) ) + { + if( SingletonItemsRefillAmmo( true ) ) + { + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_applied" ),, true ); + } + + return; + } + } + } + + if( !l_haveBombOrPot ) + { + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_no_items" ),, true ); + return; + } + + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_already_on" ),, true ); + } + + + + + + public final function IsItemSteelSwordUsableByPlayer(item : SItemUniqueId) : bool + { + return ItemHasTag(item, theGame.params.TAG_PLAYER_STEELSWORD) && !ItemHasTag(item, 'SecondaryWeapon'); + } + + public final function IsItemSilverSwordUsableByPlayer(item : SItemUniqueId) : bool + { + return ItemHasTag(item, theGame.params.TAG_PLAYER_SILVERSWORD) && !ItemHasTag(item, 'SecondaryWeapon'); + } + + public final function IsItemFists(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'fist';} + public final function IsItemWeapon(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Weapon') || ItemHasTag(item, 'WeaponTab');} + public final function IsItemCrossbow(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'crossbow';} + public final function IsItemChestArmor(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'armor';} + public final function IsItemBody(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Body');} + public final function IsRecipeOrSchematic( item : SItemUniqueId ) : bool {return GetItemCategory(item) == 'alchemy_recipe' || GetItemCategory(item) == 'crafting_schematic'; } + public final function IsItemBoots(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'boots';} + public final function IsItemGloves(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'gloves';} + public final function IsItemPants(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'trousers' || GetItemCategory(item) == 'pants';} + public final function IsItemTrophy(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'trophy';} + public final function IsItemMask(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'mask';} + public final function IsItemBomb(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'petard';} + public final function IsItemBolt(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'bolt';} + public final function IsItemUpgrade(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'upgrade';} + public final function IsItemTool(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'tool';} + public final function IsItemPotion(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Potion');} + public final function IsItemOil(item : SItemUniqueId) : bool {return ItemHasTag(item, 'SilverOil') || ItemHasTag(item, 'SteelOil');} + public final function IsItemAnyArmor(item : SItemUniqueId) : bool {return ItemHasTag(item, theGame.params.TAG_ARMOR);} + public final function IsItemUpgradeable(item : SItemUniqueId) : bool {return ItemHasTag(item, theGame.params.TAG_ITEM_UPGRADEABLE);} + public final function IsItemIngredient(item : SItemUniqueId) : bool {return ItemHasTag(item, 'AlchemyIngredient') || ItemHasTag(item, 'CraftingIngredient');} + public final function IsItemDismantleKit(item : SItemUniqueId) : bool {return ItemHasTag(item, 'DismantleKit');} + public final function IsItemHorseBag(item : SItemUniqueId) : bool {return ItemHasTag(item, 'HorseBag');} + public final function IsItemReadable(item : SItemUniqueId) : bool {return ItemHasTag(item, 'ReadableItem');} + public final function IsItemAlchemyItem(item : SItemUniqueId) : bool {return IsItemOil(item) || IsItemPotion(item) || IsItemBomb(item); } + public final function IsItemSingletonItem(item : SItemUniqueId) : bool {return ItemHasTag(item, theGame.params.TAG_ITEM_SINGLETON);} + public final function IsItemQuest(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Quest');} + public final function IsItemFood(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Edibles') || ItemHasTag(item, 'Drinks');} + public final function IsItemSecondaryWeapon(item : SItemUniqueId) : bool {return ItemHasTag(item, 'SecondaryWeapon');} + public final function IsItemHorseItem(item: SItemUniqueId) : bool {return ItemHasTag(item, 'Saddle') || ItemHasTag(item, 'HorseBag') || ItemHasTag(item, 'Trophy') || ItemHasTag(item, 'Blinders'); } + public final function IsItemSaddle(item: SItemUniqueId) : bool {return ItemHasTag(item, 'Saddle');} + public final function IsItemBlinders(item: SItemUniqueId) : bool {return ItemHasTag(item, 'Blinders');} + public final function IsItemDye( item : SItemUniqueId ) : bool { return ItemHasTag( item, 'mod_dye' ); } + public final function IsItemUsable( item : SItemUniqueId ) : bool { return GetItemCategory( item ) == 'usable'; } + public final function IsItemJunk( item : SItemUniqueId ) : bool { return ItemHasTag( item,'junk' ) || GetItemCategory( item ) == 'junk' ; } + public final function IsItemAlchemyIngredient(item : SItemUniqueId) : bool { return ItemHasTag( item, 'AlchemyIngredient' ); } + public final function IsItemCraftingIngredient(item : SItemUniqueId) : bool { return ItemHasTag( item, 'CraftingIngredient' ); } + public final function IsItemArmorReapairKit(item : SItemUniqueId) : bool { return ItemHasTag( item, 'ArmorReapairKit' ); } + public final function IsItemWeaponReapairKit(item : SItemUniqueId) : bool { return ItemHasTag( item, 'WeaponReapairKit' ); } + public final function IsQuickSlotItem( item : SItemUniqueId ) : bool { return ItemHasTag( item, 'QuickSlot' ); } + + public final function IsItemNew( item : SItemUniqueId ) : bool + { + var uiData : SInventoryItemUIData; + + uiData = GetInventoryItemUIData( item ); + return uiData.isNew; + } + + public final function IsItemMutagenPotion(item : SItemUniqueId) : bool + { + return IsItemPotion(item) && ItemHasTag(item, 'Mutagen'); + } + + public final function CanItemBeColored( item : SItemUniqueId) : bool + { + if ( RoundMath( CalculateAttributeValue( GetItemAttributeValue( item, 'quality' ) ) ) == 5 ) + { + return true; + } + return false; + } + + public final function IsItemSetItem(item : SItemUniqueId) : bool + { + return + ItemHasTag(item, theGame.params.ITEM_SET_TAG_BEAR) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_GRYPHON) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_LYNX) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_WOLF) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_RED_WOLF) || + ItemHasTag( item, theGame.params.ITEM_SET_TAG_VAMPIRE ) || + ItemHasTag(item, theGame.params.ITEM_SET_TAG_VIPER); + } + + public function GetArmorType(item : SItemUniqueId) : EArmorType + { + var isItemEquipped : bool; + + isItemEquipped = GetWitcherPlayer().IsItemEquipped(item); + + + if( thePlayer.HasAbility('Glyphword 2 _Stats', true) && isItemEquipped ) + {return EAT_Light;} + if( thePlayer.HasAbility('Glyphword 3 _Stats', true) && isItemEquipped ) + {return EAT_Medium;} + if( thePlayer.HasAbility('Glyphword 4 _Stats', true) && isItemEquipped ) + {return EAT_Heavy;} + + if(ItemHasTag(item, 'LightArmor')) + return EAT_Light; + else if(ItemHasTag(item, 'MediumArmor')) + return EAT_Medium; + else if(ItemHasTag(item, 'HeavyArmor')) + return EAT_Heavy; + + return EAT_Undefined; + } + + public final function GetAlchemyCraftableItems() : array + { + var items : array; + var i : int; + + GetAllItems(items); + + for(i=items.Size()-1; i>=0; i-=1) + { + if(!IsItemPotion(items[i]) && !IsItemBomb(items[i]) && !IsItemOil(items[i])) + items.EraseFast(i); + } + + return items; + } + + public function IsItemEncumbranceItem(item : SItemUniqueId) : bool + { + if(ItemHasTag(item, theGame.params.TAG_ENCUMBRANCE_ITEM_FORCE_YES)) + return true; + + if(ItemHasTag(item, theGame.params.TAG_ENCUMBRANCE_ITEM_FORCE_NO)) + return false; + + + if ( + IsRecipeOrSchematic( item ) + || IsItemBody( item ) + + + + + + + + + + + + + ) + return false; + + return true; + } + + public function GetItemEncumbrance(item : SItemUniqueId) : float + { + var itemCategory : name; + if ( IsItemEncumbranceItem( item ) ) + { + itemCategory = GetItemCategory( item ); + if ( itemCategory == 'quest' || itemCategory == 'key' ) + { + return 0.01 * GetItemQuantity( item ); + } + else if ( itemCategory == 'usable' || itemCategory == 'upgrade' || itemCategory == 'junk' ) + { + return 0.01 + GetItemWeight( item ) * GetItemQuantity( item ) * 0.2; + } + else if ( IsItemAlchemyItem( item ) || IsItemIngredient( item ) || IsItemFood( item ) || IsItemReadable( item ) ) + { + return 0.0; + } + else + { + return 0.01 + GetItemWeight( item ) * GetItemQuantity( item ) * 0.5; + } + } + return 0; + } + + public function GetFilterTypeByItem( item : SItemUniqueId ) : EInventoryFilterType + { + var filterType : EInventoryFilterType; + + if( ItemHasTag( item, 'Quest' ) ) + { + return IFT_QuestItems; + } + else if( IsItemIngredient( item ) ) + { + return IFT_Ingredients; + } + else if( IsItemAlchemyItem(item) ) + { + return IFT_AlchemyItems; + } + else if( IsItemAnyArmor(item) ) + { + return IFT_Armors; + } + else if( IsItemWeapon( item ) ) + { + return IFT_Weapons; + } + else + { + return IFT_Default; + } + } + + + public function IsItemQuickslotItem(item : SItemUniqueId) : bool + { + return IsSlotQuickslot( GetSlotForItemId(item) ); + } + + public function GetCrossbowAmmo(id : SItemUniqueId) : int + { + if(!IsItemCrossbow(id)) + return -1; + + return (int)CalculateAttributeValue(GetItemAttributeValue(id, 'ammo')); + } + + + + public function GetSlotForItemId(item : SItemUniqueId) : EEquipmentSlots + { + var tags : array; + var player : W3PlayerWitcher; + var slot : EEquipmentSlots; + + player = ((W3PlayerWitcher)GetEntity()); + + GetItemTags(item, tags); + slot = GetSlotForItem( GetItemCategory(item), tags, player ); + + if(!player) + return slot; + + if(IsMultipleSlot(slot)) + { + if(slot == EES_Petard1 && player.IsAnyItemEquippedOnSlot(slot)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_Petard2)) + slot = EES_Petard2; + } + else if(slot == EES_Quickslot1 && player.IsAnyItemEquippedOnSlot(slot)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_Quickslot2)) + slot = EES_Quickslot2; + } + else if(slot == EES_Potion1 && player.IsAnyItemEquippedOnSlot(EES_Potion1)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_Potion2)) + { + slot = EES_Potion2; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_Potion3)) + { + slot = EES_Potion3; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_Potion4)) + { + slot = EES_Potion4; + } + } + } + } + else if(slot == EES_PotionMutagen1 && player.IsAnyItemEquippedOnSlot(slot)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_PotionMutagen2)) + { + slot = EES_PotionMutagen2; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_PotionMutagen3)) + { + slot = EES_PotionMutagen3; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_PotionMutagen4)) + { + slot = EES_PotionMutagen4; + } + } + } + } + else if(slot == EES_SkillMutagen1 && player.IsAnyItemEquippedOnSlot(slot)) + { + if(!player.IsAnyItemEquippedOnSlot(EES_SkillMutagen2)) + { + slot = EES_SkillMutagen2; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_SkillMutagen3)) + { + slot = EES_SkillMutagen3; + } + else + { + if(!player.IsAnyItemEquippedOnSlot(EES_SkillMutagen4)) + { + slot = EES_SkillMutagen4; + } + } + } + } + } + + return slot; + } + + + + public function GetAllWeapons() : array + { + return GetItemsByTag('Weapon'); + } + + + public function GetSpecifiedPlayerItemsQuest(steelSword, silverSword, armor, boots, gloves, pants, trophy, mask, bombs, crossbow, secondaryWeapon, equippedOnly : bool) : array + { + var items, allItems : array; + var i : int; + + GetAllItems(allItems); + + for(i=0; i; + var witcher : W3PlayerWitcher; + var refill : W3RefillableContainer; + + witcher = GetWitcherPlayer(); + + if(GetEntity() == witcher) + { + + + + + + if(IsItemCrossbow(itemId) && HasInfiniteBolts()) + { + crossbows = GetItemsByCategory('crossbow'); + crossbows.Remove(itemId); + + if(crossbows.Size() == 0) + { + RemoveItemByName('Bodkin Bolt', GetItemQuantityByName('Bodkin Bolt')); + RemoveItemByName('Harpoon Bolt', GetItemQuantityByName('Harpoon Bolt')); + } + } + else if(IsItemBolt(itemId) && witcher.IsItemEquipped(itemId) && witcher.inv.GetItemQuantity(itemId) == quantity) + { + + witcher.UnequipItem(itemId); + } + + + if(IsItemCrossbow(itemId) && witcher.IsItemEquipped(itemId) && witcher.rangedWeapon) + { + witcher.rangedWeapon.ClearDeployedEntity(true); + witcher.rangedWeapon = NULL; + } + if( GetItemCategory(itemId) == 'usable' ) + { + if(witcher.IsHoldingItemInLHand() && itemId == witcher.currentlyEquipedItemL ) + { + witcher.HideUsableItem(true); + } + } + if( IsItemSteelSwordUsableByPlayer( itemId ) || IsItemSilverSwordUsableByPlayer( itemId ) ) + { + RemoveAllOilsFromItem( itemId ); + } + + + if(witcher.IsItemEquipped(itemId) && quantity >= witcher.inv.GetItemQuantity(itemId)) + witcher.UnequipItem(itemId); + } + + + if(GetEntity() == thePlayer && IsItemWeapon(itemId) && (IsItemHeld(itemId) || IsItemMounted(itemId) )) + { + thePlayer.OnHolsteredItem(GetItemCategory(itemId),'r_weapon'); + } + + + ent = (CGameplayEntity)GetEntity(); + if(ent) + ent.OnItemTaken( itemId, quantity ); + + + if(IsLootRenewable()) + { + refill = (W3RefillableContainer)GetEntity(); + if(refill) + refill.AddTimer('Refill', 20, true); + } + } + + + function GenerateItemLevel( item : SItemUniqueId, rewardItem : bool ) + { + var stat : SAbilityAttributeValue; + var playerLevel : int; + var lvl, i : int; + var quality : int; + var ilMin, ilMax : int; + + playerLevel = GetWitcherPlayer().GetLevel(); + + lvl = playerLevel - 1; + + + if ( ( W3MerchantNPC )GetEntity() ) + { + lvl = RoundF( playerLevel + RandRangeF( 2, 0 ) ); + AddItemTag( item, 'AutogenUseLevelRange' ); + } + else if ( rewardItem ) + { + lvl = RoundF( playerLevel + RandRangeF( 1, 0 ) ); + } + else if ( ItemHasTag( item, 'AutogenUseLevelRange') ) + { + quality = RoundMath( CalculateAttributeValue( GetItemAttributeValue( item, 'quality' ) ) ); + ilMin = RoundMath(CalculateAttributeValue( GetItemAttributeValue( item, 'item_level_min' ) )); + ilMax = RoundMath(CalculateAttributeValue( GetItemAttributeValue( item, 'item_level_max' ) )); + + lvl += 1; + if ( !ItemHasTag( item, 'AutogenForceLevel') ) + lvl += RoundMath(RandRangeF( 1, -1 )); + + if ( FactsQuerySum("NewGamePlus") > 0 ) + { + if ( lvl < ilMin + theGame.params.GetNewGamePlusLevel() ) lvl = ilMin + theGame.params.GetNewGamePlusLevel(); + if ( lvl > ilMax + theGame.params.GetNewGamePlusLevel() ) lvl = ilMax + theGame.params.GetNewGamePlusLevel(); + } + else + { + if ( lvl < ilMin ) lvl = ilMin; + if ( lvl > ilMax ) lvl = ilMax; + } + + if ( quality == 5 ) lvl += 2; + if ( quality == 4 ) lvl += 1; + if ( (quality == 5 || quality == 4) && ItemHasTag(item, 'EP1') ) lvl += 1; + } + else if ( !ItemHasTag( item, 'AutogenForceLevel') ) + { + quality = RoundMath( CalculateAttributeValue( GetItemAttributeValue( item, 'quality' ) ) ); + + if ( quality == 5 ) + { + lvl = RoundF( playerLevel + RandRangeF( 2, 0 ) ); + } + else if ( quality == 4 ) + { + lvl = RoundF( playerLevel + RandRangeF( 1, -2 ) ); + } + else if ( quality == 3 ) + { + lvl = RoundF( playerLevel + RandRangeF( -1, -3 ) ); + + if ( RandF() > 0.9 ) + { + lvl = playerLevel; + } + } + else if ( quality == 2 ) + { + lvl = RoundF( playerLevel + RandRangeF( -2, -5 ) ); + + if ( RandF() > 0.95 ) + { + lvl = playerLevel; + } + } + else + { + lvl = RoundF( playerLevel + RandRangeF( -2, -8 ) ); + + if ( RandF() == 0 ) + { + lvl = playerLevel; + } + } + } + + if (FactsQuerySum("StandAloneEP1") > 0) + lvl = GetWitcherPlayer().GetLevel() - 1; + + + if ( FactsQuerySum("NewGamePlus") > 0 && !ItemHasTag( item, 'AutogenUseLevelRange') ) + { + if ( quality == 5 ) lvl += 2; + if ( quality == 4 ) lvl += 1; + } + + if ( lvl < 1 ) lvl = 1; + if ( lvl > GetWitcherPlayer().GetMaxLevel() ) lvl = GetWitcherPlayer().GetMaxLevel(); + + if ( ItemHasTag( item, 'PlayerSteelWeapon' ) && !( ItemHasAbility( item, 'autogen_steel_base' ) || ItemHasAbility( item, 'autogen_fixed_steel_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_steel_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_steel_base' ); + else + AddItemCraftedAbility(item, 'autogen_steel_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_steel_dmg', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag(item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_steel_dmg', true ); + else + AddItemCraftedAbility(item, 'autogen_steel_dmg', true ); + } + } + else if ( ItemHasTag( item, 'PlayerSilverWeapon' ) && !( ItemHasAbility( item, 'autogen_silver_base' ) || ItemHasAbility( item, 'autogen_fixed_silver_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_silver_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_silver_base' ); + else + AddItemCraftedAbility(item, 'autogen_silver_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_silver_dmg', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag(item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_silver_dmg', true ); + else + AddItemCraftedAbility(item, 'autogen_silver_dmg', true ); + } + } + else if ( GetItemCategory( item ) == 'armor' && !( ItemHasAbility( item, 'autogen_armor_base' ) || ItemHasAbility( item, 'autogen_fixed_armor_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_armor_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_armor_base' ); + else + AddItemCraftedAbility(item, 'autogen_armor_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_armor_armor', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag( item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_armor_armor', true ); + else + AddItemCraftedAbility(item, 'autogen_armor_armor', true ); + } + } + else if ( ( GetItemCategory( item ) == 'boots' || GetItemCategory( item ) == 'pants' ) && !( ItemHasAbility( item, 'autogen_pants_base' ) || ItemHasAbility( item, 'autogen_fixed_pants_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_pants_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_pants_base' ); + else + AddItemCraftedAbility(item, 'autogen_pants_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_pants_armor', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag( item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_pants_armor', true ); + else + AddItemCraftedAbility(item, 'autogen_pants_armor', true ); + } + } + else if ( GetItemCategory( item ) == 'gloves' && !( ItemHasAbility( item, 'autogen_gloves_base' ) || ItemHasAbility( item, 'autogen_fixed_gloves_base' ) ) ) + { + if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_gloves_base') ) + return; + + if ( ItemHasTag(item, 'AutogenUseLevelRange') ) + AddItemCraftedAbility(item, 'autogen_fixed_gloves_base' ); + else + AddItemCraftedAbility(item, 'autogen_gloves_base' ); + + for( i=0; i 0) + { + AddItemCraftedAbility(item, 'autogen_fixed_gloves_armor', true ); + continue; + } + + if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag(item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 ) + AddItemCraftedAbility(item, 'autogen_fixed_gloves_armor', true ); + else + AddItemCraftedAbility(item, 'autogen_gloves_armor', true ); + } + } + } + + + event OnItemAdded(data : SItemChangedData) + { + var i, j : int; + var ent : CGameplayEntity; + var allCardsNames, foundCardsNames : array; + var allStringNamesOfCards : array; + var foundCardsStringNames : array; + var gwintCards : array; + var itemName : name; + var witcher : W3PlayerWitcher; + var itemCategory : name; + var dm : CDefinitionsManagerAccessor; + var locKey : string; + var leaderCardsHack : array; + + var hud : CR4ScriptedHud; + var journalUpdateModule : CR4HudModuleJournalUpdate; + var itemId : SItemUniqueId; + + var isItemShematic : bool; + + var ngp : bool; + + ent = (CGameplayEntity)GetEntity(); + + itemId = data.ids[0]; + + + if( data.informGui ) + { + recentlyAddedItems.PushBack( itemId ); + if( ItemHasTag( itemId, 'FocusObject' ) ) + { + GetWitcherPlayer().GetMedallion().Activate( true, 3.0); + } + } + + + if ( ItemHasTag(itemId, 'Autogen') ) + { + GenerateItemLevel( itemId, false ); + } + + witcher = GetWitcherPlayer(); + + + if(ent == witcher || ((W3MerchantNPC)ent) ) + { + ngp = FactsQuerySum("NewGamePlus") > 0; + for(i=0; i= allStringNamesOfCards.Size()) + { + foundCardsNames.Clear(); + for(j=0; j= allStringNamesOfCards.Size()) + { + theGame.GetGamerProfile().AddAchievement(EA_GwintCollector); + FactsAdd("gwint_all_cards_collected", 1, -1); + } + } + + if(!FactsDoesExist("fix_for_gwent_achievement_bug_121588")) + FactsAdd("fix_for_gwent_achievement_bug_121588", 1, -1); + } + + itemCategory = GetItemCategory( itemId ); + isItemShematic = itemCategory == 'alchemy_recipe' || itemCategory == 'crafting_schematic'; + + if( isItemShematic ) + { + ReadSchematicsAndRecipes( itemId ); + } + + + if( ItemHasTag( data.ids[i], 'GwintCard')) + { + witcher.AddGwentCard(GetItemName(data.ids[i]), data.quantity); + } + + + + if( !isItemShematic && ( this.ItemHasTag( itemId, 'ReadableItem' ) || this.ItemHasTag( itemId, 'Painting' ) ) && !this.ItemHasTag( itemId, 'NoNotification' ) ) + { + hud = (CR4ScriptedHud)theGame.GetHud(); + if( hud ) + { + journalUpdateModule = (CR4HudModuleJournalUpdate)hud.GetHudModule( "JournalUpdateModule" ); + if( journalUpdateModule ) + { + journalUpdateModule.AddQuestBookInfo( itemId ); + } + } + } + } + } + + + if( IsItemSingletonItem( itemId ) ) + { + for(i=0; i 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkArmorAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkArmorAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'gloves' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_gloves'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkGlovesAbility(), true); + break; + case 3 : + ability = 'quality_magical_gloves'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalGlovesAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkGlovesAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalGlovesAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkGlovesAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'pants' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_pants'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkPantsAbility(), true); + break; + case 3 : + ability = 'quality_magical_pants'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalPantsAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkPantsAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalPantsAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkPantsAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'boots' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_boots'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkBootsAbility(), true); + break; + case 3 : + ability = 'quality_magical_boots'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalBootsAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkBootsAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalBootsAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkBootsAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'steelsword' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_steelsword'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + break; + case 3 : + ability = 'quality_magical_steelsword'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + break; + default : break; + } + } + else if ( itemCategory == 'silversword' ) + { + switch ( itemQuality ) + { + case 2 : + ability = 'quality_masterwork_silversword'; + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + break; + case 3 : + ability = 'quality_magical_silversword'; + if ( ItemHasTag(item, 'EP1') ) + { + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true); + break; + } + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + + if ( RandF() > 0.5 ) + AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true); + else + AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true); + break; + + default : break; + } + } + + if(IsNameValid(ability)) + { + AddItemCraftedAbility(item, ability, false); + SetItemModifierInt(item, 'ItemQualityModified', 1); + } + } + + public function IncreaseNGPItemlevel(item : SItemUniqueId) + { + var i, diff : int; + + diff = theGame.params.NewGamePlusLevelDifference(); + + if (diff > 0) + { + if ( ItemHasTag( item, 'PlayerSteelWeapon' ) ) + { + for( i=0; i; + var tempItemQualityAtribute : SAbilityAttributeValue; + + + excludedTags.PushBack(theGame.params.OIL_ABILITY_TAG); + itemQualityAtribute = GetItemAttributeValue( itemId, 'quality', excludedTags, true ); + + itemQuality = itemQualityAtribute.valueAdditive; + if( itemQuality == 0 ) + { + itemQuality = 1; + } + return RoundMath(itemQuality); + } + + public function GetItemQualityFromName( itemName : name, out min : int, out max : int) + { + var dm : CDefinitionsManagerAccessor; + var attributeName : name; + var attributes, itemAbilities : array; + var attributeMin, attributeMax : SAbilityAttributeValue; + + var tmpInt : int; + var tmpArray : array; + + dm = theGame.GetDefinitionsManager(); + + dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, tmpArray, tmpInt, tmpInt); + attributes = dm.GetAbilitiesAttributes(itemAbilities); + for (tmpInt = 0; tmpInt < attributes.Size(); tmpInt += 1) + { + if (attributes[tmpInt] == 'quality') + { + dm.GetAbilitiesAttributeValue(itemAbilities, 'quality', attributeMin, attributeMax); + min = RoundMath(CalculateAttributeValue(attributeMin)); + max = RoundMath(CalculateAttributeValue(attributeMax)); + break; + } + } + } + + public function GetRecentlyAddedItems() : array + { + return recentlyAddedItems; + } + + public function GetRecentlyAddedItemsListSize() : int + { + return recentlyAddedItems.Size(); + } + + public function RemoveItemFromRecentlyAddedList( itemId : SItemUniqueId ) : bool + { + var i : int; + + for( i = 0; i < recentlyAddedItems.Size(); i += 1 ) + { + if( recentlyAddedItems[i] == itemId ) + { + recentlyAddedItems.EraseFast( i ); + return true; + } + } + + return false; + } + + + + + import final function NotifyScriptedListeners( notify : bool ); + + var listeners : array< IInventoryScriptedListener >; + + function AddListener( listener : IInventoryScriptedListener ) + { + if ( listeners.FindFirst( listener ) == -1 ) + { + listeners.PushBack( listener ); + if ( listeners.Size() == 1 ) + { + NotifyScriptedListeners( true ); + } + } + } + + function RemoveListener( listener : IInventoryScriptedListener ) + { + if ( listeners.Remove( listener ) ) + { + if ( listeners.Size() == 0 ) + { + NotifyScriptedListeners( false ); + } + } + } + + event OnInventoryScriptedEvent( eventType : EInventoryEventType, itemId : SItemUniqueId, quantity : int, fromAssociatedInventory : bool ) + { + var i, size : int; + + size = listeners.Size(); + for (i=size-1; i>=0; i-=1 ) + { + listeners[i].OnInventoryScriptedEvent( eventType, itemId, quantity, fromAssociatedInventory ); + } + + + if(GetEntity() == GetWitcherPlayer() && (eventType == IET_ItemRemoved || eventType == IET_ItemQuantityChanged) ) + GetWitcherPlayer().UpdateEncumbrance(); + } + + + + + public final function GetMutationResearchPoints( color : ESkillColor, item : SItemUniqueId ) : int + { + var val : SAbilityAttributeValue; + var colorAttribute : name; + + + if( color == SC_None || color == SC_Yellow || !IsIdValid( item ) ) + { + return 0; + } + + + switch( color ) + { + case SC_Red: + colorAttribute = 'mutation_research_points_red'; + break; + case SC_Blue: + colorAttribute = 'mutation_research_points_blue'; + break; + case SC_Green: + colorAttribute = 'mutation_research_points_green'; + break; + } + + + val = GetItemAttributeValue( item, colorAttribute ); + + return ( int )val.valueAdditive; + } + + public function GetSkillMutagenColor(item : SItemUniqueId) : ESkillColor + { + var abs : array; + + + if(!ItemHasTag(item, 'MutagenIngredient')) + return SC_None; + + GetItemAbilities(item, abs); + + if(abs.Contains('mutagen_color_green')) return SC_Green; + if(abs.Contains('mutagen_color_blue')) return SC_Blue; + if(abs.Contains('mutagen_color_red')) return SC_Red; + if(abs.Contains('lesser_mutagen_color_green')) return SC_Green; + if(abs.Contains('lesser_mutagen_color_blue')) return SC_Blue; + if(abs.Contains('lesser_mutagen_color_red')) return SC_Red; + if(abs.Contains('greater_mutagen_color_green')) return SC_Green; + if(abs.Contains('greater_mutagen_color_blue')) return SC_Blue; + if(abs.Contains('greater_mutagen_color_red')) return SC_Red; + + return SC_None; + } + + + + + + + + + + import final function GetItemEnhancementSlotsCount( itemId : SItemUniqueId ) : int; + import final function GetItemEnhancementItems( itemId : SItemUniqueId, out names : array< name > ); + import final function GetItemEnhancementCount( itemId : SItemUniqueId ) : int; + import final function GetItemColor( itemId : SItemUniqueId ) : name; + import final function IsItemColored( itemId : SItemUniqueId ) : bool; + import final function SetPreviewColor( itemId : SItemUniqueId, colorId : int ); + import final function ClearPreviewColor( itemId : SItemUniqueId ) : bool; + import final function ColorItem( itemId : SItemUniqueId, dyeId : SItemUniqueId ); + import final function ClearItemColor( itemId : SItemUniqueId ) : bool; + import final function EnchantItem( enhancedItemId : SItemUniqueId, enchantmentName : name, enchantmentStat : name ) : bool; + import final function GetEnchantment( enhancedItemId : SItemUniqueId ) : name; + import final function IsItemEnchanted( enhancedItemId : SItemUniqueId ) : bool; + import final function UnenchantItem( enhancedItemId : SItemUniqueId ) : bool; + import private function EnhanceItem( enhancedItemId : SItemUniqueId, extensionItemId : SItemUniqueId ) : bool; + import private function RemoveItemEnhancementByIndex( enhancedItemId : SItemUniqueId, slotIndex : int ) : bool; + import private function RemoveItemEnhancementByName( enhancedItemId : SItemUniqueId, extensionItemName : name ) : bool; + import final function PreviewItemAttributeAfterUpgrade( baseItemId : SItemUniqueId, upgradeItemId : SItemUniqueId, attributeName : name, optional baseInventory : CInventoryComponent, optional upgradeInventory : CInventoryComponent ) : SAbilityAttributeValue; + import final function HasEnhancementItemTag( enhancedItemId : SItemUniqueId, slotIndex : int, tag : name ) : bool; + + + function NotifyEnhancedItem( enhancedItemId : SItemUniqueId ) + { + var weapons : array; + var sword : CWitcherSword; + var i : int; + + sword = (CWitcherSword) GetItemEntityUnsafe( enhancedItemId ); + sword.UpdateEnhancements( this ); + } + + function EnhanceItemScript( enhancedItemId : SItemUniqueId, extensionItemId : SItemUniqueId ) : bool + { + var i : int; + var enhancements : array; + var runeword : Runeword; + + if ( EnhanceItem( enhancedItemId, extensionItemId ) ) + { + NotifyEnhancedItem( enhancedItemId ); + + GetItemEnhancementItems( enhancedItemId, enhancements ); + if ( theGame.runewordMgr.GetRuneword( enhancements, runeword ) ) + { + for ( i = 0; i < runeword.abilities.Size(); i+=1 ) + { + AddItemBaseAbility( enhancedItemId, runeword.abilities[i] ); + } + } + return true; + } + return false; + } + + function RemoveItemEnhancementByIndexScript( enhancedItemId : SItemUniqueId, slotIndex : int ) : bool + { + var i : int; + var enhancements : array; + var runeword : Runeword; + var hasRuneword : bool; + var names : array< name >; + + GetItemEnhancementItems( enhancedItemId, enhancements ); + hasRuneword = theGame.runewordMgr.GetRuneword( enhancements, runeword ); + + GetItemEnhancementItems( enhancedItemId, names ); + + if ( RemoveItemEnhancementByIndex( enhancedItemId, slotIndex ) ) + { + NotifyEnhancedItem( enhancedItemId ); + + + + if ( hasRuneword ) + { + + for ( i = 0; i < runeword.abilities.Size(); i+=1 ) + { + RemoveItemBaseAbility( enhancedItemId, runeword.abilities[i] ); + } + } + return true; + } + return false; + } + + + function RemoveItemEnhancementByNameScript( enhancedItemId : SItemUniqueId, extensionItemName : name ) : bool + { + var i : int; + var enhancements : array; + var runeword : Runeword; + var hasRuneword : bool; + + GetItemEnhancementItems( enhancedItemId, enhancements ); + hasRuneword = theGame.runewordMgr.GetRuneword( enhancements, runeword ); + + + if ( RemoveItemEnhancementByName( enhancedItemId, extensionItemName ) ) + { + NotifyEnhancedItem( enhancedItemId ); + + + AddAnItem( extensionItemName, 1, true, true ); + if ( hasRuneword ) + { + + for ( i = 0; i < runeword.abilities.Size(); i+=1 ) + { + RemoveItemBaseAbility( enhancedItemId, runeword.abilities[i] ); + } + } + return true; + } + return false; + } + + function RemoveAllItemEnhancements( enhancedItemId : SItemUniqueId ) + { + var count, i : int; + + count = GetItemEnhancementCount( enhancedItemId ); + for ( i = count - 1; i >= 0; i-=1 ) + { + RemoveItemEnhancementByIndexScript( enhancedItemId, i ); + } + } + + function GetHeldAndMountedItems( out items : array< SItemUniqueId > ) + { + var allItems : array< SItemUniqueId >; + var i : int; + var itemName : name; + + GetAllItems( allItems ); + + items.Clear(); + for( i = 0; i < allItems.Size(); i += 1 ) + { + if ( IsItemHeld( allItems[ i ] ) || IsItemMounted( allItems[ i ] ) ) + { + items.PushBack( allItems[ i ] ); + } + } + } + + + public function GetHasValidDecorationItems( items : array, decoration : W3HouseDecorationBase ) : bool + { + var i, size : int; + + size = items.Size(); + + + if(size == 0 ) + { + LogChannel( 'houseDecorations', "No items with valid tag were found!" ); + return false; + } + + + for( i=0; i < size; i+= 1 ) + { + + if( GetWitcherPlayer().IsItemEquipped( items[i] ) ) + { + LogChannel( 'houseDecorations', "Found item is equipped, erasing..." ); + continue; + } + + + if( IsItemQuest( items[i] ) && decoration.GetAcceptQuestItems() == false ) + { + LogChannel( 'houseDecorations', "Found item is quest item, and quest items are not accepted, erasing..." ); + continue; + } + + + if( decoration.GetItemHasForbiddenTag( items[i] ) ) + { + LogChannel( 'houseDecorations', "Found item has a forbidden tag, erasing..." ); + continue; + } + + LogChannel( 'houseDecorations', "Item checks out: "+ GetItemName( items[i] ) ); + return true; + } + LogChannel( 'houseDecorations', "No valid items were found!" ); + + return false; + } + + + function GetMissingCards() : array< name > + { + var defMgr : CDefinitionsManagerAccessor = theGame.GetDefinitionsManager(); + var allCardNames : array< name > = defMgr.GetItemsWithTag(theGame.params.GWINT_CARD_ACHIEVEMENT_TAG); + var playersCards : array< SItemUniqueId > = GetItemsByTag(theGame.params.GWINT_CARD_ACHIEVEMENT_TAG); + var playersCardLocs : array< string >; + var missingCardLocs : array< string >; + var missingCards : array< name >; + var i, j : int; + var found : bool; + + + for ( i = 0; i < allCardNames.Size(); i+=1 ) + { + found = false; + + for ( j = 0; j < playersCards.Size(); j+=1 ) + { + if ( allCardNames[i] == GetItemName( playersCards[j] ) ) + { + found = true; + playersCardLocs.PushBack( defMgr.GetItemLocalisationKeyName ( allCardNames[i] ) ); + break; + } + } + + if ( !found ) + { + missingCardLocs.PushBack( defMgr.GetItemLocalisationKeyName( allCardNames[i] ) ); + missingCards.PushBack( allCardNames[i] ); + } + } + + if( missingCardLocs.Size() < 2 ) + { + return missingCards; + } + + + for ( i = missingCardLocs.Size()-1 ; i >= 0 ; i-=1 ) + { + for ( j = 0 ; j < playersCardLocs.Size() ; j+=1 ) + { + if ( missingCardLocs[i] == playersCardLocs[j] + && missingCardLocs[i] != "gwint_name_emhyr" && missingCardLocs[i] != "gwint_name_foltest" + && missingCardLocs[i] != "gwint_name_francesca" && missingCardLocs[i] != "gwint_name_eredin" ) + { + missingCardLocs.EraseFast( i ); + missingCards.EraseFast( i ); + break; + } + } + } + + return missingCards; + } + + public function FindCardSources( missingCards : array< name > ) : array< SCardSourceData > + { + var sourceCSV : C2dArray; + var sourceTable : array< SCardSourceData >; + var sourceRemaining : array< SCardSourceData >; + var sourceCount, i, j : int; + + if ( theGame.IsFinalBuild() ) + { + sourceCSV = LoadCSV("gameplay\globals\card_sources.csv"); + } + else + { + sourceCSV = LoadCSV("qa\card_sources.csv"); + } + + sourceCount = sourceCSV.GetNumRows(); + sourceTable.Resize(sourceCount); + + for ( i = 0 ; i < sourceCount ; i+=1 ) + { + sourceTable[i].cardName = sourceCSV.GetValueAsName("CardName",i); + sourceTable[i].source = sourceCSV.GetValue("Source",i); + sourceTable[i].originArea = sourceCSV.GetValue("OriginArea",i); + sourceTable[i].originQuest = sourceCSV.GetValue("OriginQuest",i); + sourceTable[i].details = sourceCSV.GetValue("Details",i); + sourceTable[i].coords = sourceCSV.GetValue("Coords",i); + } + + for ( i = 0 ; i < missingCards.Size() ; i+=1 ) + { + for ( j = 0 ; j < sourceCount ; j+=1 ) + { + if ( sourceTable[j].cardName == missingCards[i] ) + { + sourceRemaining.PushBack( sourceTable[j] ); + } + } + } + + return sourceRemaining; + } + + public function GetGwentAlmanacContents() : string + { + var sourcesRemaining : array< SCardSourceData >; + var missingCards : array< string >; + var almanacContents : string; + var i : int; + var NML, Novigrad, Skellige, Prologue, Vizima, KaerMorhen, Random : int; + + sourcesRemaining = FindCardSources( GetMissingCards() ); + + for ( i = 0 ; i < sourcesRemaining.Size() ; i+=1 ) + { + switch ( sourcesRemaining[i].originArea ) + { + case "NML": + NML += 1; + break; + case "Novigrad": + Novigrad += 1; + break; + case "Skellige": + Skellige += 1; + break; + case "Prologue": + Prologue += 1; + break; + case "Vizima": + Vizima += 1; + break; + case "KaerMorhen": + KaerMorhen += 1; + break; + case "Random": + Random += 1; + break; + default: + break; + } + } + + if ( NML + Novigrad + Skellige + Prologue + Vizima + KaerMorhen + Random == 0 ) + { + almanacContents = GetLocStringByKeyExt( "gwent_almanac_text" ) + "
"; + almanacContents += GetLocStringByKeyExt( "gwent_almanac_completed_text" ); + } + else + { + almanacContents = GetLocStringByKeyExt( "gwent_almanac_text" ) + "
"; + if ( NML > 0 ) + { + almanacContents += GetLocStringByKeyExt( "location_name_velen" ) + ": " + NML + "
"; + } + if ( Novigrad > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_novigrad" ) + ": " + Novigrad + "
"; + } + if ( Skellige > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_skellige" ) + ": " + Skellige + "
"; + } + if ( Prologue > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_prolog_village" ) + ": " + Prologue + "
"; + } + if ( Vizima > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_wyzima_castle" ) + ": " + Vizima + "
"; + } + if ( KaerMorhen > 0 ) + { + almanacContents += GetLocStringByKeyExt( "map_location_kaer_morhen" ) + ": " + KaerMorhen + "
"; + } + almanacContents += GetLocStringByKeyExt( "gwent_source_random" ) + ": " + Random; + } + + return almanacContents; + } + + public function GetUnusedMutagensCount(itemName:name):int + { + var items : array; + var equippedOnSlot : EEquipmentSlots; + var availableCount : int; + var res, i : int = 0; + + items = thePlayer.inv.GetItemsByName(itemName); + + for(i=0; i; + var equippedOnSlot : EEquipmentSlots; + var availableCount : int; + var res, i : int = 0; + + items = thePlayer.inv.GetItemsByName(itemName); + + for(i=0; i; + var curItem : SItemUniqueId; + var equippedOnSlot : EEquipmentSlots; + + var i : int; + var itemRemoved : int; + var availableToRemoved : int; + var removedRes : bool; + + itemRemoved = 0; + items = thePlayer.inv.GetItemsByName( itemName ); + + for( i=0; i < items.Size(); i+=1 ) + { + curItem = items[ i ]; + equippedOnSlot = GetWitcherPlayer().GetItemSlot( curItem ); + + if( equippedOnSlot == EES_InvalidSlot ) + { + availableToRemoved = Min( thePlayer.inv.GetItemQuantity( curItem ), ( count - itemRemoved ) ); + removedRes = thePlayer.inv.RemoveItem(items[i], availableToRemoved); + + if (removedRes) + { + itemRemoved = itemRemoved + availableToRemoved; + + if (itemRemoved >= count) + { + return; + } + } + + } + } + } + +} + +exec function findMissingCards( optional card : name ) +{ + var inv : CInventoryComponent = thePlayer.GetInventory(); + var sourcesRemaining : array< SCardSourceData >; + var missingCards : array< name >; + var i : int; + var sourceLogString : string; + + if ( card != '' ) + { + missingCards.PushBack( card ); + } + else + { + missingCards = inv.GetMissingCards(); + } + + sourcesRemaining = inv.FindCardSources( missingCards ); + + for ( i = 0 ; i < sourcesRemaining.Size() ; i+=1 ) + { + sourceLogString = sourcesRemaining[i].cardName + " is a " + sourcesRemaining[i].source ; + if ( sourcesRemaining[i].originArea == "Random" ) + { + sourceLogString += " card from a random merchant."; + } + else + { + sourceLogString += " item in " + sourcesRemaining[i].originArea + " from "; + + if ( sourcesRemaining[i].originQuest != "" ) + { + sourceLogString += sourcesRemaining[i].originQuest + " , "; + } + + sourceLogString += sourcesRemaining[i].details; + } + Log( sourceLogString ); + + if ( sourcesRemaining[i].coords != "" ) + { + Log( sourcesRemaining[i].coords ); + } + } +} + +exec function slotTest() +{ + var inv : CInventoryComponent = thePlayer.inv; + var weaponItemId : SItemUniqueId; + var upgradeItemId : SItemUniqueId; + var i : int; + + LogChannel('SlotTest', "----------------------------------------------------------------"); + + + inv.AddAnItem( 'Perun rune', 1); + inv.AddAnItem( 'Svarog rune', 1); + + + for ( i = 0; i < 2; i += 1 ) + { + + if ( !GetItem( inv, 'steelsword', weaponItemId ) || + !GetItem( inv, 'upgrade', upgradeItemId ) ) + { + return; + } + + + PrintItem( inv, weaponItemId ); + + + if ( inv.EnhanceItemScript( weaponItemId, upgradeItemId ) ) + { + LogChannel('SlotTest', "Enhanced item"); + } + else + { + LogChannel('SlotTest', "Failed to enhance item!"); + } + } + + + if ( !GetItem( inv, 'steelsword', weaponItemId ) ) + { + return; + } + + + PrintItem( inv, weaponItemId ); + + + if ( inv.RemoveItemEnhancementByNameScript( weaponItemId, 'Svarog rune' ) ) + { + LogChannel('SlotTest', "Removed enhancement"); + } + else + { + LogChannel('SlotTest', "Failed to remove enhancement!"); + } + + + if ( !GetItem( inv, 'steelsword', weaponItemId ) ) + { + return; + } + + + PrintItem( inv, weaponItemId ); + + + if ( inv.RemoveItemEnhancementByIndexScript( weaponItemId, 0 ) ) + { + LogChannel('SlotTest', "Removed enhancement"); + } + else + { + LogChannel('SlotTest', "Failed to remove enhancement!"); + } + + + if ( !GetItem( inv, 'steelsword', weaponItemId ) ) + { + return; + } + + + PrintItem( inv, weaponItemId ); +} + +function GetItem( inv : CInventoryComponent, category : name, out itemId : SItemUniqueId ) : bool +{ + var itemIds : array< SItemUniqueId >; + + itemIds = inv.GetItemsByCategory( category ); + if ( itemIds.Size() > 0 ) + { + itemId = itemIds[ 0 ]; + return true; + } + LogChannel( 'SlotTest', "Failed to get item with GetItemsByCategory( '" + category + "' )" ); + return false; +} + +function PrintItem( inv : CInventoryComponent, weaponItemId : SItemUniqueId ) +{ + var names : array< name >; + var tags : array< name >; + var i : int; + var line : string; + var attribute : SAbilityAttributeValue; + + LogChannel('SlotTest', "Slots: " + inv.GetItemEnhancementCount( weaponItemId ) + "/" + inv.GetItemEnhancementSlotsCount( weaponItemId ) ); + inv.GetItemEnhancementItems( weaponItemId, names ); + if ( names.Size() > 0 ) + { + for ( i = 0; i < names.Size(); i += 1 ) + { + if ( i == 0 ) + { + line += "["; + } + line += names[ i ]; + if ( i < names.Size() - 1 ) + { + line += ", "; + } + if ( i == names.Size() - 1 ) + { + line += "]"; + } + } + } + else + { + line += "[]"; + } + LogChannel('SlotTest', "Upgrade item names " + line ); + + tags.PushBack('Upgrade'); + + attribute = inv.GetItemAttributeValue( weaponItemId, 'PhysicalDamage' ); + LogChannel('SlotTest', "Attribute '" + 'PhysicalDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + attribute = inv.GetItemAttributeValue( weaponItemId, 'SilverDamage' ); + LogChannel('SlotTest', "Attribute '" + 'SilverDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + + attribute = inv.GetItemAttributeValue( weaponItemId, 'PhysicalDamage', tags, true ); + LogChannel('SlotTest', "Attribute '" + 'PhysicalDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + attribute = inv.GetItemAttributeValue( weaponItemId, 'SilverDamage', tags, true ); + LogChannel('SlotTest', "Attribute '" + 'SilverDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + + attribute = inv.GetItemAttributeValue( weaponItemId, 'PhysicalDamage', tags ); + LogChannel('SlotTest', "Attribute '" + 'PhysicalDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + attribute = inv.GetItemAttributeValue( weaponItemId, 'SilverDamage', tags ); + LogChannel('SlotTest', "Attribute '" + 'SilverDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive ); + +} + +function PlayItemEquipSound( itemCategory : name ) : void +{ + switch( itemCategory ) + { + case 'steelsword' : + theSound.SoundEvent("gui_inventory_steelsword_attach"); + return; + case 'silversword' : + theSound.SoundEvent("gui_inventory_silversword_attach"); + return; + case 'secondary' : + theSound.SoundEvent("gui_inventory_weapon_attach"); + return; + case 'armor' : + theSound.SoundEvent("gui_inventory_armor_attach"); + return; + case 'pants' : + theSound.SoundEvent("gui_inventory_pants_attach"); + return; + case 'boots' : + theSound.SoundEvent("gui_inventory_boots_attach"); + return; + case 'gloves' : + theSound.SoundEvent("gui_inventory_gauntlet_attach"); + return; + case 'potion' : + theSound.SoundEvent("gui_inventory_potion_attach"); + return; + case 'petard' : + theSound.SoundEvent("gui_inventory_bombs_attach"); + return; + case 'ranged' : + theSound.SoundEvent("gui_inventory_ranged_attach"); + return; + case 'herb' : + theSound.SoundEvent("gui_pick_up_herbs"); + return; + case 'trophy' : + case 'horse_bag' : + theSound.SoundEvent("gui_inventory_horse_bage_attach"); + return; + case 'horse_blinder' : + theSound.SoundEvent("gui_inventory_horse_blinder_attach"); + return; + case 'horse_saddle' : + theSound.SoundEvent("gui_inventory_horse_saddle_attach"); + return; + default : + theSound.SoundEvent("gui_inventory_other_attach"); + return; + } +} + +function PlayItemUnequipSound( itemCategory : name ) : void +{ + switch( itemCategory ) + { + case 'steelsword' : + theSound.SoundEvent("gui_inventory_steelsword_back"); + return; + case 'silversword' : + theSound.SoundEvent("gui_inventory_silversword_back"); + return; + case 'secondary' : + theSound.SoundEvent("gui_inventory_weapon_back"); + return; + case 'armor' : + theSound.SoundEvent("gui_inventory_armor_back"); + return; + case 'pants' : + theSound.SoundEvent("gui_inventory_pants_back"); + return; + case 'boots' : + theSound.SoundEvent("gui_inventory_boots_back"); + return; + case 'gloves' : + theSound.SoundEvent("gui_inventory_gauntlet_back"); + return; + case 'petard' : + theSound.SoundEvent("gui_inventory_bombs_back"); + return; + case 'potion' : + theSound.SoundEvent("gui_inventory_potion_back"); + return; + case 'ranged' : + theSound.SoundEvent("gui_inventory_ranged_back"); + return; + case 'trophy' : + case 'horse_bag' : + theSound.SoundEvent("gui_inventory_horse_bage_back"); + return; + case 'horse_blinder' : + theSound.SoundEvent("gui_inventory_horse_blinder_back"); + return; + case 'horse_saddle' : + theSound.SoundEvent("gui_inventory_horse_saddle_back"); + return; + default : + theSound.SoundEvent("gui_inventory_other_back"); + return; + } +} + +function PlayItemConsumeSound( item : SItemUniqueId ) : void +{ + if( thePlayer.GetInventory().ItemHasTag( item, 'Drinks' ) || thePlayer.GetInventory().ItemHasTag( item, 'Alcohol' ) ) + { + theSound.SoundEvent('gui_inventory_drink'); + } + else + { + theSound.SoundEvent('gui_inventory_eat'); + } +} \ No newline at end of file diff --git a/src/StatTrak/files/Mod/scripts/game/player/r4player.ws b/src/StatTrak/files/Mod/scripts/game/player/r4player.ws new file mode 100644 index 0000000..1d634d6 --- /dev/null +++ b/src/StatTrak/files/Mod/scripts/game/player/r4player.ws @@ -0,0 +1,14676 @@ +/***********************************************************************/ +/** © 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 abstract import class CR4Player extends CPlayer +{ + + protected var pcGamePlayInitialized : bool; + + + private var pcMode : bool; + default pcMode = true; + + + protected saved var weaponHolster : WeaponHolster; + public var rangedWeapon : Crossbow; + public var crossbowDontPopStateHack : bool; default crossbowDontPopStateHack = false; + + private var hitReactTransScale : float; + + private var bIsCombatActionAllowed : bool; + private var currentCombatAction : EBufferActionType; + + private var uninterruptedHitsCount : int; + private var uninterruptedHitsCameraStarted : bool; + private var uninterruptedHitsCurrentCameraEffect : name; + + private var counterTimestamps : array; + + private var hitReactionEffect : bool; + + private var lookAtPosition : Vector; + private var orientationTarget : EOrientationTarget; + private var customOrientationTarget : EOrientationTarget; + protected var customOrientationStack : array; + + public var delayOrientationChange : bool; + protected var delayCameraOrientationChange : bool; + private var actionType : int; + private var customOrientationStackIndex : int; + + private var emptyMoveTargetTimer : float; + + private var onlyOneEnemyLeft : bool; + + public var isInFinisher : bool; + private var finisherTarget : CGameplayEntity; + + private var combatStance : EPlayerCombatStance; + + public var approachAttack : int; + 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; + + public var specialHeavyChargeDuration : float; + public var specialHeavyStartEngineTime : EngineTime; + public var playedSpecialAttackMissingResourceSound : bool; + public function SetPlayedSpecialAttackMissingResourceSound(b : bool) {playedSpecialAttackMissingResourceSound = b;} + + public var counterCollisionGroupNames : array; + + public saved var lastInstantKillTime : GameTime; + + + private var noSaveLockCombatActionName : string; default noSaveLockCombatActionName = 'combat_action'; + private var noSaveLockCombatAction : int; + private var deathNoSaveLock : int; + private var noSaveLock : int; + + + protected saved var newGamePlusInitialized : bool; + default newGamePlusInitialized = false; + + + 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; + + + private var keepRequestingCriticalAnimStart : bool; + + default keepRequestingCriticalAnimStart = false; + + + private var currentCustomAction : EPlayerExplorationAction; + public var substateManager : CExplorationStateManager; + protected var isOnBoat : bool; + 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; + + + + 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; + + + private var gwintAiDifficulty : EGwintDifficultyMode; default gwintAiDifficulty = EGDM_Easy; + private var gwintAiAggression : EGwintAggressionMode; default gwintAiAggression = EGAM_Defensive; + private var gwintMinigameState : EMinigameState; default gwintMinigameState = EMS_None; + + + import private var horseWithInventory : EntityHandle; + private var currentlyMountedHorse : CNewNPC; + private var horseSummonTimeStamp : float; + private saved var isHorseRacing : bool; + private var horseCombatSlowMo : bool; + default isHorseRacing = false; + default horseCombatSlowMo = true; + + + private var HudMessages : array ; + protected var fShowToLowStaminaIndication : float; + public var showTooLowAdrenaline : bool; + private var HAXE3Container : W3Container; + private var HAXE3bAutoLoot: bool; + private var bShowHud : bool; + private var dodgeFeedbackTarget : CActor; + + default HAXE3bAutoLoot = false; + default fShowToLowStaminaIndication = 0.0f; + default bShowHud = true; + + saved var displayedQuestsGUID : array< CGUID >; + saved var rewardsMultiplier : array< SRewardMultiplier >; + saved var glossaryImageOverride : array< SGlossaryImageOverride >; + + + private var prevRawLeftJoyRot : float; + protected var explorationInputContext : name; + protected var combatInputContext : name; + protected var combatFistsInputContext : name; + + + private var isInsideInteraction : bool; + private var isInsideHorseInteraction : bool; + public var horseInteractionSource : CEntity; + public var nearbyLockedContainersNoKey : array; + + + private var bMoveTargetChangeAllowed : bool; default bMoveTargetChangeAllowed = true; + private var moveAdj : CMovementAdjustor; + private var defaultLocomotionController : CR4LocomotionPlayerControllerScript; + + + 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; + + + var navQuery : CNavigationReachabilityQueryInterface; + + + public saved var rememberedCustomHead : name; + + + public saved var disableWeatherDisplay : bool; + + + public saved var proudWalk : bool; + private var etherealCount : int; + default etherealCount = 0; + + + public saved var injuredWalk : bool; + public saved var tiedWalk : bool; + private var insideDiveAttackArea : bool; + default insideDiveAttackArea = false; + private var diveAreaNumber : int; + default diveAreaNumber = -1; + + + private var flyingBossCamera : bool; + default flyingBossCamera = false; + + public function SetFlyingBossCamera( val : bool ) { flyingBossCamera = val; } + public function GetFlyingBossCamera() : bool { return flyingBossCamera; } + + + public saved var upscaledTooltipState : bool; + default upscaledTooltipState = false; + + + private var phantomWeaponMgr : CPhantomWeaponManager; + + + + 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; + } + + + editable var delayBetweenIllusionOneliners : float; + + hint delayBetweenIllusionOneliners = "delay in secs between oneliners about illusionary objects"; + + default delayBetweenIllusionOneliners = 5; + + + 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; + + + private var previousWeather : name; + private var previousRainStrength : float; + + + protected var receivedDamageInCombat : bool; + protected var prevDayNightIsNight : bool; + public var failedFundamentalsFirstAchievementCondition : bool; + + private var spawnedTime : float; + + public var currentMonsterHuntInvestigationArea : W3MonsterHuntInvestigationArea; + + private var isPerformingPhaseChangeAnimation : bool; + default isPerformingPhaseChangeAnimation = false; + + default receivedDamageInCombat = false; + + + public var playerMode : W3PlayerMode; + + + protected saved var selectedItemId : SItemUniqueId; + protected saved var blockedRadialSlots : array < SRadialSlotDef >; + + + public var enemyCollectionDist : float; + public var findMoveTargetDistMin : float; + public var findMoveTargetDistMax : float; + private var findMoveTargetScaledFrame : float; + public var interactDist : float; + protected var bCanFindTarget : bool; + private var bIsConfirmingEmptyTarget : bool; + private var displayTarget : CGameplayEntity; + private var isShootingFriendly : bool; + + default findMoveTargetDistMax = 18.f; + default findMoveTargetScaledFrame = 0.5f; + default interactDist = 3.5f; + + + private var currentSelectedTarget : CActor; + private var selectedTargetToConfirm : CActor; + private var bConfirmTargetTimerIsEnabled : bool; + + + public saved var thrownEntityHandle : EntityHandle; + private var isThrowingItemWithAim : bool; + private saved var isThrowingItem : bool; + private var isThrowHoldPressed : bool; + + + private var isAimingCrossbow : bool; + + default isThrowingItemWithAim = false; + + + public var playerAiming : PlayerAiming; + + + public var forceDismember : bool; + public var forceDismemberName : name; + public var forceDismemberChance : int; + public var forceDismemberExplosion : bool; + + + private var finisherVictim : CActor; + public var forceFinisher : bool; + public var forceFinisherAnimName : name; + public var forceFinisherChance : int; + public var forcedStance : bool; + + + 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; + + + 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; + } + + + + + + public var horseOnNavMesh : bool; + default horseOnNavMesh = true; + + public function SetHorseNav( val : bool ) { horseOnNavMesh = val; } + + + public var testAdjustRequestedMovementDirection : bool; + default testAdjustRequestedMovementDirection = false; + + + default autoState = 'Exploration'; + + + + + + + import final function GetEnemiesInRange( out enemies : array< CActor > ); + import final function GetVisibleEnemies( out enemies : array< CActor > ); + import final function IsEnemyVisible( enemy : CActor ) : bool; + + + import final function SetupEnemiesCollection( range, heightTolerance : float, + maxEnemies : int, + optional tag : name, + optional flags : int ); + + 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; + } + + + + + 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'); + AddAnimEventCallback('MoveNoise', 'OnAnimEvent_MoveNoise'); + + AddItemPerLevelList(); + + enemyCollectionDist = findMoveTargetDistMax; + + + theGame.RemoveTimeScale('horse_melee'); + + + if(!spawnData.restored && !((W3ReplacerCiri)this) ) + { + AddTimer('GiveStartingItems', 0.00001, true, , , true); + + if(!theGame.IsFinalBuild()) + { + + AddAbility('GeraltSkills_Testing'); + AddTimer('Debug_GiveTestingItems',0.0001,true); + } + + + FactsAdd("tut_stash_fresh_playthrough"); + } + + InitTargeting(); + + + if( spawnData.restored ) + { + + + + theGame.GameplayFactsRemove( "in_combat" ); + } + + + + if ( !weaponHolster ) + { + weaponHolster = new WeaponHolster in this; + } + + weaponHolster.Initialize( this, spawnData.restored ); + + if ( !interiorTracker ) + { + interiorTracker = new CPlayerInteriorTracker in this; + } + interiorTracker.Init( spawnData.restored ); + + + super.OnSpawned( spawnData ); + + + medallion = new W3MedallionFX in this; + + playerMode = new W3PlayerMode in this; + playerMode.Initialize( this ); + + + playerAiming = new PlayerAiming in this; + playerAiming.Initialize( this ); + + + navQuery = new CNavigationReachabilityQueryInterface in this; + + + EnableFindTarget( true ); + AddTimer( 'CombatCheck', 0.2f, true ); + + + substateManager = ( CExplorationStateManager ) GetComponentByClassName( 'CExplorationStateManager' ); + + findMoveTargetDist = findMoveTargetDistMax; + + SetupEnemiesCollection( enemyCollectionDist, findMoveTargetDist, 10, 'None', FLAG_Attitude_Neutral + FLAG_Attitude_Hostile + FLAG_Attitude_Friendly + FLAG_OnlyAliveActors ); + + + inputHandler.RemoveLocksOnSpawn(); + + + ((CActor) this ).SetInteractionPriority( IP_Prio_0 ); + + prevDayNightIsNight = theGame.envMgr.IsNight(); + CheckDayNightCycle(); + + + EnableVisualDebug( SHOW_AI, true ); + + + 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'); + } + + + 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(); + + + SetImmortalityMode( AIM_None, AIC_SyncedAnim ); + + + theGame.GetDefinitionsManager().GetContainedAbilities('DwimeritiumBomb_3', atts); + for(i=0; i 0) + BlockAllActions('mq3036', false); + + spawnedTime = theGame.GetEngineTimeAsSeconds(); + + if ( theGame.GetInGameConfigWrapper().GetVarValue('Gameplay', 'EnableUberMovement' ) == "1" ) + theGame.EnableUberMovement( true ); + else + theGame.EnableUberMovement( false ); + + + if ( !FactsDoesExist("gwent_difficulty") ) + FactsAdd("gwent_difficulty", 2); + + + if(!newGamePlusInitialized && FactsQuerySum("NewGamePlus") > 0) + { + NewGamePlusInitialize(); + } + + + if( lastInstantKillTime > theGame.GetGameTime() ) + { + SetLastInstantKillTime( GameTimeCreate(0) ); + } + + // modStatTrak BEGIN + if (!this.GetInventory().HasItem('Achievement Stats')) + { + this.GetInventory().AddAnItem('Achievement Stats', 1, 0, 0); + } + //modStatTrak END + } + + public function NewGamePlusInitialize() + { + + SetLastInstantKillTime( GameTimeCreate(0) ); + } + + 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(); + + + theGame.ReleaseNoSaveLock( noSaveLock ); + } + + + + + + public function GetBlockedSlots () : array < SRadialSlotDef > + { + return blockedRadialSlots; + } + + public function ClearBlockedSlots() + { + var i : int; + + + + 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; + } + } + } + + + + } + + 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; + } + + + + + + + public function RepairItem ( rapairKitId : SItemUniqueId, usedOnItem : SItemUniqueId ); + public function HasRepairAbleGearEquiped () : bool; + public function HasRepairAbleWaponEquiped () : bool; + public function IsItemRepairAble ( item : SItemUniqueId ) : bool; + + + + + + + public final function ReduceAllOilsAmmo( id : SItemUniqueId ) + { + var i : int; + var oils : array< W3Effect_Oil >; + + oils = inv.GetOilsAppliedOnItem( id ); + + for( i=0; i; + var buff, recentOil : W3Effect_Oil; + var i : int; + + item = GetEquippedSword( steel ); + oils = GetBuffs( EET_Oil ); + + if( oils.Size() > 1 ) + { + + + recentOil = inv.GetNewestOilAppliedOnItem( item, false ); + } + + for( i=0; i; + var buff : W3Effect_Oil; + var i : int; + + item = GetEquippedSword( isSteel ); + oils = GetBuffs( EET_Oil ); + + for( i=0; i; + var ammo, ammoBonus : float; + var dm : CDefinitionsManagerAccessor; + var buffParams : SCustomEffectParams; + var oilParams : W3OilBuffParams; + var oilName : name; + var min, max : SAbilityAttributeValue; + var i : int; + var oils : array< W3Effect_Oil >; + var existingOil : W3Effect_Oil; + + if( !CanApplyOilOnItem( oilId, usedOnItem ) ) + { + return false; + } + + dm = theGame.GetDefinitionsManager(); + inv.GetItemAbilitiesWithTag( oilId, theGame.params.OIL_ABILITY_TAG, oilAbilities ); + oilName = inv.GetItemName( oilId ); + oils = inv.GetOilsAppliedOnItem( usedOnItem ); + + + for( i=0; i= CalculateAttributeValue( max ) ) + { + inv.RemoveOldestOilFromItem( usedOnItem ); + } + } + } + + + ammo = CalculateAttributeValue(inv.GetItemAttributeValue(oilId, 'ammo')); + if(CanUseSkill(S_Alchemy_s06)) + { + ammoBonus = CalculateAttributeValue(GetSkillAttributeValue(S_Alchemy_s06, 'ammo_bonus', false, false)); + ammo *= 1 + ammoBonus * GetSkillLevel(S_Alchemy_s06); + } + + + if( existingOil ) + { + existingOil.Reapply( RoundMath( ammo ) ); + } + else + { + buffParams.effectType = EET_Oil; + buffParams.creator = this; + oilParams = new W3OilBuffParams in this; + oilParams.iconPath = dm.GetItemIconPath( oilName ); + oilParams.localizedName = dm.GetItemLocalisationKeyName( oilName ); + oilParams.localizedDescription = dm.GetItemLocalisationKeyName( oilName ); + oilParams.sword = usedOnItem; + oilParams.maxCount = RoundMath( ammo ); + oilParams.currCount = RoundMath( ammo ); + oilParams.oilAbilityName = oilAbilities[ 0 ]; + oilParams.oilItemName = oilName; + buffParams.buffSpecificParams = oilParams; + + AddEffectCustom( buffParams ); + + delete oilParams; + } + + LogOils("Added oil <<" + oilName + ">> to <<" + inv.GetItemName( usedOnItem ) + ">>"); + + + SetFailedFundamentalsFirstAchievementCondition( true ); + + theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnOilApplied ); + + if( !inv.IsItemHeld( usedOnItem ) ) + { + PauseOilBuffs( inv.IsItemSteelSwordUsableByPlayer( usedOnItem ) ); + } + + return true; + } + + + public final function IsEquippedSwordUpgradedWithOil(steel : bool, optional oilName : name) : bool + { + var sword : SItemUniqueId; + var i : int; + var oils : array< W3Effect_Oil >; + + sword = GetEquippedSword( steel ); + if( !inv.IsIdValid( sword ) ) + { + return false; + } + + if( oilName == '' ) + { + return inv.ItemHasAnyActiveOilApplied( sword ); + } + + oils = inv.GetOilsAppliedOnItem( sword ); + for( i=0; i 0.1f; + } + + function HandleMovement( deltaTime : float ) + { + + + + + 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; + } + + + if ( !ignoreRepeatCheck ) + { + if( battlecry_lastTry == _BattleCry ) + return; + } + + battlecry_lastTry = _BattleCry; + + l_randValue = RandF(); + + + if( l_randValue < _Chance && ( _IgnoreDelay || BattleCryIsReady() ) ) + { + thePlayer.PlayVoiceset( 90, _BattleCry ); + + 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(); + } + } + + + + playerTickTimerPhase = ( playerTickTimerPhase + 1 ) % 3; + + focusModeController = theGame.GetFocusModeController(); + focusModeController.UpdateFocusInteractions( deltaTime ); + + + cnt = (int)( effectManager.GetCriticalBuffsCount() > 0 ); + SetBehaviorVariable('hasCriticalBuff', cnt); + } + + event OnDeath( damageAction : W3DamageAction ) + { + super.OnDeath( damageAction ); + + RemoveTimer('RequestCriticalAnimStart'); + + EnableFindTarget( false ); + BlockAllActions('Death', true); + + EnableHardLock( false ); + + theGame.CreateNoSaveLock( 'player_death', deathNoSaveLock, false, false ); + theGame.SetDeathSaveLockId( deathNoSaveLock ); + + ClearHostileEnemiesList(); + RemoveReactions(); + SetPlayerCombatTarget(NULL); + OnEnableAimingMode( false ); + + theGame.EnableFreeCamera( false ); + } + + + 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(); + } + + + + + + + public function AddCounterTimeStamp(time : EngineTime) {counterTimestamps.PushBack(time);} + + + public function CheckCounterSpamming(attacker : CActor) : bool + { + var counterWindowStartTime : EngineTime; + var i, spamCounter : int; + var reflexAction : bool; + var testEngineTime : EngineTime; + + if(!attacker) + return false; + + counterWindowStartTime = ((CNewNPC)attacker).GetCounterWindowStartTime(); + spamCounter = 0; + reflexAction = false; + + + if ( counterWindowStartTime == testEngineTime ) + { + return false; + } + + for(i = counterTimestamps.Size() - 1; i>=0; i-=1) + { + + if(counterTimestamps[i] >= (counterWindowStartTime - EngineTimeFromFloat(0.4)) ) + { + spamCounter += 1; + } + + else + { + counterTimestamps.Remove(counterTimestamps[i]); + continue; + } + + + if(!reflexAction && (counterTimestamps[i] >= counterWindowStartTime)) + reflexAction = true; + } + + + 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, mutation8TriggerHP : float; + var effectType : EEffectType; + var repelType : EPlayerRepelType = PRT_Random; + var params : SCustomEffectParams; + var thisPos, attackerPos : Vector; + var fistFightCheck, isMutation8 : 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; + var min, max : SAbilityAttributeValue; + var npc : CNewNPC; + + 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 ) + { + + validCounter = CheckCounterSpamming(parryInfo.attacker); + + if(validCounter) + { + if ( IsInCombatActionFriendly() ) + RaiseEvent('CombatActionFriendlyEnd'); + + SetBehaviorVariable( 'parryType', ChooseParryTypeIndex( parryInfo ) ); + SetBehaviorVariable( 'counter', (float)validCounter); + + + + SetBehaviorVariable( 'parryType', ChooseParryTypeIndex( parryInfo ) ); + SetBehaviorVariable( 'counter', (float)validCounter); + this.SetBehaviorVariable( 'combatActionType', (int)CAT_Parry ); + + + if ( !fistFightCounter ) + { + attackerInventory = parryInfo.attacker.GetInventory(); + weaponId = attackerInventory.GetItemFromSlot('r_weapon'); + attackerInventory.GetItemTags( weaponId , weaponTags ); + + if( GetWitcherPlayer().IsMutationActive( EPMT_Mutation8 ) ) + { + isMutation8 = true; + theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Mutation8', 'hp_perc_trigger', min, max ); + mutation8TriggerHP = min.valueMultiplicative; + } + + + + npc = (CNewNPC)parryInfo.attacker; + + + if ( parryInfo.attacker.HasAbility('mon_gravehag') ) + { + repelType = PRT_Slash; + parryInfo.attacker.AddEffectDefault(EET_CounterStrikeHit, this, 'ReflexParryPerformed'); + + } + else if ( npc && !npc.IsHuman() && !npc.HasTag( 'dettlaff_vampire' ) ) + { + repelType = PRT_SideStepSlash; + } + else if ( weaponTags.Contains('spear2h') ) + { + repelType = PRT_SideStepSlash; + parryInfo.attacker.AddEffectDefault(EET_CounterStrikeHit, this, "ReflexParryPerformed"); + parryInfo.attacker.SignalGameplayEvent( 'SpearDestruction'); + } + else if( isMutation8 && npc && !npc.IsImmuneToMutation8Finisher() ) + { + repelType = PRT_RepelToFinisher; + npc.AddEffectDefault( EET_CounterStrikeHit, this, "ReflexParryPerformed" ); + + + SetTarget( npc, true ); + + PerformFinisher( 0.f, 0 ); + } + else + { + + 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; + + ragdollTarget = parryInfo.attacker; + AddTimer( 'ApplyCounterRagdollTimer', 0.3 ); + } + else + { + useKnockdown = false; + if ( CanUseSkill(S_Sword_s11) ) + { + if( GetSkillLevel(S_Sword_s11) > 1 && RandRangeF(3,0) < GetWitcherPlayer().GetStat(BCS_Focus) ) + { + duration = CalculateAttributeValue(GetSkillAttributeValue(S_Sword_s11, 'duration', false, true)); + useKnockdown = true; + } + } + else if ( parryInfo.attacker.IsHuman() ) + { + + 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'); + + + 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"); + } + + + 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(); + + + 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'); + } + } + + + + + 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; + + + 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; + } + } + + + 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 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; + + + 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); + + + 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); + IncHitCounter(); + + 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 ); + } + } + + + public function ReceivedCombatDamage() + { + receivedDamageInCombat = true; + } + + + + + + + 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); + + + AddTimer('UninterruptedHitsResetOnIdle', 4.f, false); + } + + timer function StartUninterruptedBlurr(dt : float, id : int) + { + var changed : bool; + var movingAgent : CMovingPhysicalAgentComponent; + var target : CActor; + + + if(uninterruptedHitsCount < 4) + { + LogUnitAtt("Stopping camera effect"); + thePlayer.StopEffect(uninterruptedHitsCurrentCameraEffect); + uninterruptedHitsCurrentCameraEffect = ''; + uninterruptedHitsCameraStarted = false; + RemoveTimer('StartUninterruptedBlurr'); + } + else + { + target = GetTarget(); + + if( target ) + { + movingAgent = ( (CMovingPhysicalAgentComponent) (target.GetMovingAgentComponent()) ); + } + + if(!uninterruptedHitsCameraStarted) + { + LogUnitAtt("Starting camera effect"); + AddTimer('StartUninterruptedBlurr', 0.001, true); + 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(changed) + { + + thePlayer.StopEffect(uninterruptedHitsCurrentCameraEffect); + + + 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; + + + thePlayer.PlayEffect(uninterruptedHitsCurrentCameraEffect); + } + } + } + } + + + + + + 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; + } + + + 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 ); + } + } + } + + + public function UnregisterForPlayerAction( listener : CGameplayEntity, isLockedByPlace : bool ) + { + playerActionEventListeners.Remove( listener ); + playerActionEventBlockingListeners.Remove( listener ); + if ( playerActionEventBlockingListeners.Size() == 0 ) + { + PlayerActionBlockGameplayActions( 'PlayerAction', false, isLockedByPlace ); + } + } + + event OnPlayerActionStart() + { + + 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; + + + 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 ( 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(); + } + } + + + + + + public function CanPerformPlayerAction(optional alsoOutsideExplorationState : bool) : bool + { + + if(!alsoOutsideExplorationState && GetCurrentStateName() != 'Exploration') + return false; + + if( isInAir || (substateManager && !substateManager.CanInteract()) || IsInCombatAction() || GetCriticalBuffsCount() > 0) + return false; + + return true; + } + + + 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(); + + + 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]); + } + } + } + + + 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; + + + CheckOfirItems(GetInventory(), hasArmor, hasBoots, hasGloves, hasPants, hasSword, hasSaddle, hasBag, hasBlinders); + + + 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; + + inv.GetAllItems(items); + dm = theGame.GetDefinitionsManager(); + + for(i=0; i; + var min, max : SAbilityAttributeValue; + + if(!inv.IsItemAlchemyItem(itemID)) + return; + + + currLevel = (int)CalculateAttributeValue(inv.GetItemAttributeValue(itemID, 'level')); + + + if(currLevel == 3 || currLevel == 2 || currLevel < 2 || currLevel > 3) + return; + + + currAbilities = inv.GetItemAbilitiesWithAttribute(itemID, 'level', currLevel); + + + inv.GetItemContainedAbilities(itemID, abs); + dm = theGame.GetDefinitionsManager(); + for(j=0; j> on item <<" + inv.GetItemName(itemID) + ">> !!!"); + } + else + { + for(j=0; j 0 ) + angles = VecToRotation( VecFromHeading( customOrientationInfoStack[ customOrientationInfoStack.Size() - 1 ].customHeading ) ); + else + angles = VecToRotation( GetHeadingVector() ); + + + dir = RotForward( angles ); + lookAtTarget = dir * 30.f + this.GetWorldPosition(); + 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; + } + lookAtTarget += theCamera.GetCameraDirection() * 100.f; + lookAtActive = 1.0f; + } + else if ( localOrientationTarget == OT_CameraOffset ) + { + + + dir = theCamera.GetCameraDirection(); + angles = VecToRotation( dir ); + angles.Pitch = -angles.Pitch + oTCameraPitchOffset; + angles.Yaw -= oTCameraOffset; + dir = RotForward( angles ); + + lookAtTarget = dir * 30.f + this.GetWorldPosition(); + 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 ) + + 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 + { + + + if ( slideTarget ) + { + lookAtTarget = ProcessLookAtTargetPosition( slideTarget, useTorsoBone ); + } + else + { + target = GetTarget(); + if ( target ) + { + lookAtTarget = ProcessLookAtTargetPosition( target, useTorsoBone ); + } + } + + lookAtActive = 1.0f; + } + + if ( !slideTarget && !IsUsingVehicle() ) + { + + playerRot = GetWorldRotation(); + lookAtTarget = GetWorldPosition() + VecFromHeading( playerRot.Yaw ) * 100.0f; + lookAtActive = 0.0f; + } + + if ( useTorsoBone ) + lookAtTarget.Z += 0.2f; + } + + + + + 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 ); + 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; + } + + + + + + event OnBlockingSceneEnded( optional output : CStorySceneOutput) + { + + SetImmortalityMode( AIM_None, AIC_SyncedAnim ); + super.OnBlockingSceneEnded(output); + } + + + + + + 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' && (category == 'steelsword' || category == 'silversword') ) + { + if( category == 'silversword' ) + { + ManageAerondightBuff( false ); + } + + GetBuff( EET_LynxSetBonus ).Pause( 'drawing weapon' ); + + PauseOilBuffs( category == 'steelsword' ); + } + + 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 ); + + + + m_RefreshWeaponFXType = true; + } + + event OnHolsterLeftHandItem() + { + weaponHolster.OnHolsterLeftHandItem(); + } + + timer function DelayedTryToReequipWeapon( dt: float, id : int ) + { + var weaponType : EPlayerWeapon; + + if( IsInCombat() && GetTarget() ) + { + weaponType = GetMostConvenientMeleeWeapon( GetTarget() ); + + if ( weaponType == PW_Steel || weaponType == PW_Silver ) + weaponHolster.OnEquipMeleeWeapon( weaponType, false ); + } + } + + 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(); + + + { + weaponType = GetCurrentMeleeWeaponType(); + + if ( weaponType == PW_None ) + { + + weaponType = GetMostConvenientMeleeWeapon( target ); + } + + + 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; + } + + + if( !ShouldGoToCombat( enemy ) ) + { + return false; + } + + weaponType = this.GetCurrentMeleeWeaponType(); + + if ( weaponType == PW_None || ( reevaluateCurrentWeapon && weaponType == PW_Fists ) || ( !IsInCombat() && weaponHolster.IsOnTheMiddleOfHolstering() ) ) + { + + weaponType = weaponHolster.GetMostConvenientMeleeWeapon( enemy ); + reevaluateCurrentWeapon = false; + } + + + 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() ) ) + { + + weaponType = weaponHolster.GetMostConvenientMeleeWeapon( enemy ); + } + + + GoToCombat( weaponType ); + + + return true; + } + + public function GoToExplorationIfNeeded() : bool + { + + + if( ! IsInCombatState() ) + { + return false; + } + + if( !ShouldGoToExploration() ) + { + return false; + } + + + weaponHolster.EndedCombat(); + + + GotoState( 'Exploration' ); + return true; + } + + event OnStateCanGoToCombat() + { + return false; + } + + event OnStateCanUpdateExplorationSubstates() + { + return false; + } + + private function ShouldGoToCombat( optional enemy : CActor ) : bool + { + var currentStateName : name; + + + if( !OnStateCanGoToCombat() ) + { + return false; + } + + currentStateName = GetCurrentStateName(); + + if( currentStateName == 'AimThrow' ) + { + return false; + } + + if( currentStateName == 'Swimming' ) + { + return false; + } + + if( currentStateName == 'TraverseExploration' ) + { + return false; + } + + + + + + + if ( !enemy ) + { + return playerMode.combatMode; + } + + + + + + return true; + } + + private function ShouldGoToExploration() : bool + { + if ( IsInCombat() ) + { + 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 ) + { + + 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 ); + } + } + + + public function GotoState( newState : name, optional keepStack : bool, optional forceEvents : bool ) + { + + + super.GotoState( newState, keepStack, forceEvents ); + + } + + 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(); + } + } + } + + + + + protected var disableActionBlend : bool; + + + + + 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 ) + { + + ( (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 maxSlideDistance : 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.MaxLocationAdjustmentSpeed( slideTicket, 1000000 ); + movementAdjustor.ScaleAnimation( slideTicket ); + minSlideDistance = ((CMovingPhysicalAgentComponent)this.GetMovingAgentComponent()).GetCapsuleRadius()+((CMovingPhysicalAgentComponent)slideNPC.GetMovingAgentComponent()).GetCapsuleRadius(); + if( IsInCombatFist() ) + { + maxSlideDistance = 1000.0f; + } + else + { + maxSlideDistance = minSlideDistance; + } + movementAdjustor.SlideTowards( slideTicket, slideTarget, minSlideDistance, maxSlideDistance ); + } + else if( !slideNPC.GetGameplayVisibility() ) + { + movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor(); + movementAdjustor.CancelByName( 'SlideToTarget' ); + slideNPC = NULL; + } + else + { + movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor(); + movementAdjustor.SlideTowards( slideTicket, slideTarget, minSlideDistance, maxSlideDistance ); + } + } + + event OnAnimEvent_ActionBlend( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + } + + + event OnAnimEvent_SubstateManager( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + + 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.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 ) + { + + } + + + event OnAnimEvent_pad_vibration( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + var witcher : W3PlayerWitcher; + + theGame.VibrateControllerHard(); + + + 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; + } + } + } + + + event OnAnimEvent_pad_vibration_light( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + + } + + event OnAnimEvent_KillWithRagdoll( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + + + } + + 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 OnAnimEvent_MoveNoise( animEventName : name, animEventType : EAnimationEventType, animInfo : SAnimationEventAnimInfo ) + { + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'MoveNoise', -1, 30.0f, -1.f, -1, true ); + } + + + 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' ) + { + + rotationRate = GetRotationRateFromAnimEvent( variant.enumValue ); + + movementAdjustor = GetMovingAgentComponent().GetMovementAdjustor(); + if ( animEventType == AET_DurationStart || animEventType == AET_DurationStartInTheMiddle ) + { + + + if (! movementAdjustor.IsRequestActive( movementAdjustor.GetRequest( 'RotateToTarget' ) ) ) + { + + ticket = movementAdjustor.CreateNewRequest( 'RotateToTarget' ); + + + if ((int)rotationRate == 0) + movementAdjustor.AdjustmentDuration( ticket, animEventDuration ); + else + { + movementAdjustor.Continuous( ticket ); + movementAdjustor.BindToEvent( ticket, 'RotateToTarget' ); + } + + movementAdjustor.DontUseSourceAnimation( ticket ); + movementAdjustor.ReplaceRotation( ticket ); + } + else + { + + ticket = movementAdjustor.GetRequest( 'RotateToTarget' ); + } + MovAdjRotateToTarget( ticket ); + + if ((int)rotationRate > 0) + { + movementAdjustor.MaxRotationAdjustmentSpeed( ticket, (float)((int)rotationRate) ); + } + } + else if ( animEventType == AET_DurationEnd ) + { + + + } + else + { + + ticket = movementAdjustor.GetRequest( 'RotateToTarget' ); + MovAdjRotateToTarget( ticket ); + } + } + super.OnEnumAnimEvent(animEventName, variant, animEventType, animEventDuration, animInfo); + } + + event OnTeleported() + { + if( substateManager ) + { + substateManager.OnTeleported(); + } + } + + + + + + + event OnStartFistfightMinigame() + { + super.OnStartFistfightMinigame(); + + + 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 ); + } + } + + + + + 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, forceFaction : eGwintFaction ) + { + var gwintManager:CR4GwintManager; + gwintManager = theGame.GetGwintManager(); + + gwintMinigameState = EMS_None; + + gwintManager.SetEnemyDeckByName(deckName); + gwintManager.SetForcedFaction(forceFaction); + + if (gwintManager.GetHasDoneTutorial() || !theGame.GetTutorialSystem().AreMessagesEnabled()) + { + gwintManager.gameRequested = true; + theGame.RequestMenu( 'DeckBuilder' ); + } + else + { + theGame.GetGuiManager().ShowUserDialog( UMID_SkipGwintTutorial, "gwint_tutorial_play_query_title", "gwint_tutorial_play_query", UDB_YesNo ); + } + } + + public function StartGwint_TutorialOrSkip( skipTutorial : bool ) + { + var gwintManager : CR4GwintManager; + + if( skipTutorial ) + { + gwintManager = theGame.GetGwintManager(); + gwintManager.gameRequested = true; + gwintManager.SetHasDoneTutorial(true); + gwintManager.SetHasDoneDeckTutorial(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; + } + + + + + 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; + } + + + if( substateManager.UpdateCameraIfNeeded( moveData, dt ) ) + { + return true; + } + + + if ( theGame.IsFocusModeActive() ) + { + theGame.GetGameCamera().ChangePivotRotationController( 'Exploration' ); + theGame.GetGameCamera().ChangePivotDistanceController( 'Default' ); + theGame.GetGameCamera().ChangePivotPositionController( 'Default' ); + + + moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController(); + moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController(); + moveData.pivotPositionController = theGame.GetGameCamera().GetActivePivotPositionController(); + + + + 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; + } + + + + + 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 ); + + } + + + if( customCameraStack.Size() > 0 ) + { + + + } + + 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 ( 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' ); + + + moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController(); + moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController(); + moveData.pivotPositionController = theGame.GetGameCamera().GetActivePivotPositionController(); + + + 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 ); + + + + 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 ( playerMoveType >= PMT_Run ) + { + + camDist = -0.5f; + camOffset = 0.25; + + if ( !wasRunning ) + { + smoothTime = 1.f; + wasRunning = true; + } + DampFloatSpring( smoothTime, vel, 0.1, 0.5, timeDelta ); + } + else + { + + camDist = 0.f; + camOffset = 0.4f; + smoothTime = 0.2f; + wasRunning = false; + } + + + + DampVectorSpring( moveData.cameraLocalSpaceOffset, moveData.cameraLocalSpaceOffsetVel, Vector( 0.3f, camDist, 0.3f ), smoothTime, 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' ); + + moveData.pivotRotationController = theGame.GetGameCamera().GetActivePivotRotationController(); + moveData.pivotDistanceController = theGame.GetGameCamera().GetActivePivotDistanceController(); + + + 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; + + } + else if ( oTCameraOffset == rightOffset ) + { + screenSpaceOffset = -0.65f; + oTCameraPitchOffset = 13.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; + } + } + 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; + } + else + { + angles = VecToRotation( GetHeadingVector() ); + heading = angles.Yaw + oTCameraOffset; + pitch = -angles.Pitch - oTCameraPitchOffset; + } + + if ( !wasBRAxisPushed && ( !bRAxisReleased ) ) + 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 ); + 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(); + + + cameraOffsetLeft = 30.f; + cameraOffsetRight = -30.f; + + + + + + + + theGame.GetGameCamera().ChangePivotRotationController( 'SignChannel' ); + theGame.GetGameCamera().ChangePivotDistanceController( 'SignChannel' ); + + 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 ) + { + + if( thePlayer.GetAutoCameraCenter() ) + { + theGame.GetGameCamera().ForceManualControlVerTimeout(); + } + + playerToCamAngle = AbsF( AngleDistance( GetHeading(), moveData.pivotRotationValue.Yaw ) ); + + + useExplorationSprintCam = false; + + if ( useExplorationSprintCam ) + { + if ( playerToCamAngle <= 45 ) + { + theGame.GetGameCamera().ChangePivotRotationController( 'Sprint' ); + + 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 + { + + 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_CastSign + && ( GetEquippedSign() == ST_Aard || GetEquippedSign() == ST_Yrden ) + && GetBehaviorVariable( 'alternateSignCast' ) == 1 ) + { + + theGame.GetGameCamera().ForceManualControlVerTimeout(); + pitch = -20.f; + + + } + + + + + + + + if ( IsCurrentSignChanneled() && GetCurrentlyCastSign() == ST_Quen ) + { + pitch = moveData.pivotRotationValue.Pitch; + } + + moveData.pivotRotationController.SetDesiredHeading( heading, ); + moveData.pivotRotationController.SetDesiredPitch( pitch ); + } + } + + + + event OnGameCameraExplorationRotCtrlChange() + { + if( substateManager ) + { + return substateManager.OnGameCameraExplorationRotCtrlChange( ); + } + + return false; + } + + + + + + + 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 ); + } + } + + + 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; + } + + + 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() ) + newCustomOrientationTarget = OT_Camera; + else if ( lastAxisInputIsMovement ) + { + if ( this.IsSwimming() ) + { + + + newCustomOrientationTarget = OT_Camera; + + + } + 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() ) ) + { + + heading = VecHeading( GetDisplayTarget().GetWorldPosition() - GetWorldPosition() ); + + + } + 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 ); + } + } + + + event OnDelayOrientationChangeOff() + { + delayOrientationChange = false; + delayCameraOrientationChange = false; + RemoveTimer( 'DelayOrientationChangeTimer' ); + + + + } + + 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 ) ) + { + 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(); + } + } + } + + + + + + + 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; + + + + + 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; + private var hostileMonsters : array; + 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( 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; + public function GetMoveTargets() : array { return moveTargets; } + public function GetNumberOfMoveTargets() : int { return moveTargets.Size(); } + public function GetHostileEnemies() : array { return hostileEnemies; } + public function GetHostileEnemiesCount() : int { return hostileEnemies.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 ( GetCurrentStateName() != 'PlayerDialogScene' && IsAlive() ) + { + GetVisibleEnemies( actors ); + + + if ( hostileEnemies.Size() > 0 ) + { + for( i=0; i < hostileEnemies.Size() ; i+=1 ) + { + if ( !actors.Contains( hostileEnemies[i] ) ) + actors.PushBack( hostileEnemies[i] ); + } + } + + + if ( finishableEnemiesList.Size() > 0 ) + { + for( i=0; i < finishableEnemiesList.Size() ; i+=1 ) + { + if ( !actors.Contains( finishableEnemiesList[i] ) ) + actors.PushBack( finishableEnemiesList[i] ); + } + } + + + if ( moveTarget && !actors.Contains( moveTarget ) ) + actors.PushBack( moveTarget ); + + FilterActors( actors, onlyThreatTargets, false ); + + + 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; + } + } + } + } + + + 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; + + else + setIsThreatened = false; + + + if ( setIsThreatened ) + { + enemyCollectionDist = 50.f; + SetIsThreatened( true ); + } + else + { + if ( IsThreatened() ) + AddTimer( 'finishableEnemiesList', 1.f ); + + enemyCollectionDist = findMoveTargetDistMax; + SetIsThreatened( false ); + } + + moveTargets = actors; + potentialMoveTargets = moveTargets; + + + 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 ); + 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 && ( 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 ); + + + if ( IsThreatened() && !IsInFistFightMiniGame() ) + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'CombatNearbyAction', 5.0, 18.0f, -1.f, -1, true ); + else + theGame.GetBehTreeReactionManager().RemoveReactionEvent( this, 'CombatNearbyAction'); + + + 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 ( 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' ) + { + 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 ( 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 navDistLimit : float = findMoveTargetDist; + 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; + } + + + public function LockToMoveTarget( lockTime : float ) + { + + } + + private timer function DisableLockToMoveTargetTimer( time : float , id : int) + { + if ( !this.IsActorLockedToTarget() ) + { + SetMoveTargetChangeAllowed( true ); + } + } + + public function SetMoveTargetChangeAllowed( flag : bool ) + { + + } + + 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; + } + + nonActorTargetMult = 1.25; + + + 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' ) + 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 ); + } + } + + + 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; + var sourceToTargetDists : array; + var i : int; + var targetingInfo : STargetingInfo; + + + + 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; + + + + + 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; + } + } + + + + 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 ); + + + targetingDist = softLockDistVehicle; + + if ( targets.Size() > 0 ) + { + targetingInfo.source = this; + targetingInfo.canBeTargetedCheck = true; + targetingInfo.coneCheck = false; + targetingInfo.coneHalfAngleCos = 0.86602540378f; + 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; + + 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 ); + + + } + } + + 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 ) + 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; + + + if ( info.canBeTargetedCheck && !targetActor.CanBeTargeted() ) + { + return false; + } + + + if ( info.invisibleCheck && !targetActor.GetGameplayVisibility() ) + { + return false; + } + + sourcePosition = sourceActor.GetWorldPosition(); + targetPosition = targetEntity.GetWorldPosition(); + + if ( targetActor ) + { + { + targetNPC = (CNewNPC)targetActor; + if ( targetNPC ) + { + if ( targetNPC.IsHorse() && !targetNPC.GetHorseComponent().IsDismounted() ) + { + return false; + } + } + } + } + + if ( info.distCheck || info.knockDownCheck ) + { + if ( usePrecalcs ) + { + if ( targetActor ) + { + + 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 ); + } + } + } + + + if ( info.distCheck ) + { + if ( sourceToTargetDist >= info.coneDist ) + { + return false; + } + } + + + if ( info.coneCheck || info.rsHeadingCheck ) + { + direction = VecNormalize2D( targetPosition - sourcePosition ); + } + + + if ( info.coneCheck ) + { + if ( VecDot2D( direction, info.coneHeadingVector ) < info.coneHalfAngleCos ) + { + return false; + } + } + + + 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; + } + } + } + + + if ( info.inFrameCheck && !WasVisibleInScaledFrame( targetEntity, info.frameScaleX, info.frameScaleY ) ) + { + return false; + } + + + 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; + } + } + + + if ( info.knockDownCheck ) + { + + if ( targetActor && !targetActor.IsAlive() ) + { + + finishEnabled = targetActor.GetComponent( 'Finish' ).IsEnabled(); + if ( finishEnabled ) + { + + if ( finishableEnemiesList.Contains( targetActor ) ) + { + + 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 ); + } + } + + + 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; + + + 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 ); + + + 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; + } + else + { + if ( IsSwimming() ) + { + if ( usePrecalcs ) + { + coneHeading = targetingPrecalcs.cameraHeading; + } + else + { + coneHeading = theGame.GetGameCamera().GetHeading(); + } + coneHalfAngleDot = 0.17364817766f; + } + else if ( bLAxisReleased ) + { + if( IsInCombatAction() ) + { + coneHeading = GetCombatActionHeading(); + } + else + { + if ( ShouldUsePCModeTargeting() ) + coneHeading = theGame.GetGameCamera().GetHeading(); + else + coneHeading = cachedRawPlayerHeading; + } + + if ( IsInCombat() ) + { + if ( ShouldUsePCModeTargeting() ) + coneHalfAngleDot = -1; + else + coneHalfAngleDot = 0.17364817766f; + } + else + { + coneHalfAngleDot = -1.0f; + } + } + else + { + if( IsInCombatAction() ) + { + coneHeading = GetCombatActionHeading(); + } + else + { + if ( ShouldUsePCModeTargeting() ) + coneHeading = theGame.GetGameCamera().GetHeading(); + else + coneHeading = cachedRawPlayerHeading; + } + + if ( ShouldUsePCModeTargeting() ) + coneHalfAngleDot = -1; + else + coneHalfAngleDot = 0.17364817766f; + } + + 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; + } + + + + + 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; + 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; + + + + 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; + + 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; + } + } + } + + + 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() ) + { + + 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; + } + + + 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 ) + { + + 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(); + + + if ( nonCombatCheck ) + { + info.coneHeadingVector = targetingPrecalcs.playerHeadingVector; + if ( lastAxisInputIsMovement ) + { + info.coneHeadingVector = selectionHeadingVector; + info.invisibleCheck = false; + info.coneCheck = true; + info.coneHalfAngleCos = 0.76604444311f; + } + else + { + info.invisibleCheck = false; + info.frameScaleX = 0.9f; + info.frameScaleY = 0.9f; + } + } + else + { + info.coneHeadingVector = Vector( 0.0f, 0.0f, 0.0f ); + + + if ( IsInCombat() ) + { + info.inFrameCheck = false; + } + else + { + if ( !bLAxisReleased ) + { + info.coneCheck = true; + + if ( this.IsSwimming() ) + info.coneHalfAngleCos = -1; + else + info.coneHalfAngleCos = 0.86602540378f; + + info.coneHeadingVector = targetingIn.rawPlayerHeadingVector; + } + } + } + + cameraPosition = theCamera.GetCameraPosition(); + cameraDirection = targetingPrecalcs.cameraDirection; + playerToCamPlaneDist = VecDot2D( cameraDirection, this.GetWorldPosition() - cameraPosition ); + + + 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 ) + { + + 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(); + + + 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' ) ) )) + { + 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 ( 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 ]; + } + } + + + 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() ) + { + 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 ) + { + selectionWeights.angleWeight = 0.55f; + selectionWeights.distanceWeight = 0.45f; + selectionWeights.distanceRingWeight = 0.f; + } + else + { + selectionWeights.angleWeight = 0.75f; + selectionWeights.distanceWeight = 0.25f; + selectionWeights.distanceRingWeight = 0.f; + } + } + 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 ); + + 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 ); + + + + } + } + + + public function SetSlideTarget( actor : CGameplayEntity ) + { + + + + 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' ); + } + + 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 ( !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 ) + { + if( flag && GetTarget().HasTag( 'NoHardLock' ) ) + return; + + 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' ); + + SetIsCameraLockedToTarget( flag ); + } + else if ( !flag && IsCameraLockedToTarget() ) + { + thePlayer.EnableManualCameraControl( true, 'LockCameraToTarget' ); + + SetIsCameraLockedToTarget( flag ); + } + } + + public function LockActorToTarget( flag : bool, optional withoutIcon : bool ) + { + var displayTargetActor : CActor; + + if ( flag ) + { + if ( !IsActorLockedToTarget() ) + { + + 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 ); + } + } + + + + + + + protected function PlayHitAnimation(damageAction : W3DamageAction, animType : EHitReactionType) + { + var hitRotation : float; + var onHitCounter : SAbilityAttributeValue; + var counter : int; + + 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) + { + super.PlayHitAnimation( damageAction, animType ); + if ( damageAction.attacker.HasAbility( 'IncreaseHitReactionSeverityWithHitCounter' ) ) + { + counter = GetHitCounter(); + switch ( counter ) + { + case 2 : + SetBehaviorVariable( 'HitReactionType', 2 ); + break; + + case 3 : + AddEffectDefault( EET_Stagger, damageAction.attacker, damageAction.attacker.GetName() ); + break; + + case 4 : + AddEffectDefault( EET_Knockdown, damageAction.attacker, damageAction.attacker.GetName() ); + break; + + default : + break; + } + } + SetHitReactionDirection(damageAction.attacker); + SetDetailedHitReaction(damageAction.GetSwingType(), damageAction.GetSwingDirection()); + } + + RaiseForceEvent( 'Hit' ); + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'ActorInHitReaction', -1, 30.0f, -1.f, -1, true ); + + 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; + + + SetCustomRotation( 'Hit', hitRotation, 1080.f, 0.1f, false ); + } + + CriticalEffectAnimationInterrupted("PlayHitAnimation"); + } + + public function ReduceDamage( out damageData : W3DamageAction) + { + super.ReduceDamage(damageData); + + + 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; + } + } + + + public function GetCriticalHitChance( isLightAttack : bool, isHeavyAttack : bool, target : CActor, victimMonsterCategory : EMonsterCategory, isBolt : bool ) : float + { + var critChance : float; + var oilChanceAttribute : name; + var weapons : array< SItemUniqueId >; + var i : int; + var holdsCrossbow : bool; + var critVal : SAbilityAttributeValue; + + critChance = 0; + + + if( FactsQuerySum( 'debug_fact_critical_boy' ) > 0 ) + { + critChance += 1; + } + + if( IsInState( 'HorseRiding' ) && ( ( CActor )GetUsedVehicle() ).GetMovingAgentComponent().GetRelativeMoveSpeed() >= 4.0 ) + { + critChance += 1; + } + + + critChance += CalculateAttributeValue( GetAttributeValue( theGame.params.CRITICAL_HIT_CHANCE ) ); + + + weapons = inv.GetHeldWeapons(); + for( i=0; i 0 && !((W3Effect_Toxicity)damageAction.causer)) + ReceivedCombatDamage(); + + + if(FactsQuerySum("tut_fight_use_slomo") > 0) + { + theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_TutorialFight) ); + FactsRemove("tut_fight_slomo_ON"); + } + + + if( !substateManager.ReactOnBeingHit( damageAction ) ) + { + GoToCombatIfNeeded(); + + } + + return sup; + } + + protected function ShouldPauseHealthRegenOnHit() : bool + { + return true; + } + + public function PlayHitEffect(damageAction : W3DamageAction) + { + super.PlayHitEffect(damageAction); + + + 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; + } + + + + + + + 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' ; + var counter : int; + var onHitCounter : SAbilityAttributeValue; + + + + + if(CanParryAttack() && FistFightCheck( parryInfo.target, parryInfo.attacker, fistFightParry ) ) + { + parryHeading = GetParryHeading( parryInfo, parryDir ) ; + + 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(); + IncDefendCounter(); + } + } + else + { + counter = GetDefendCounter(); + onHitCounter = parryInfo.attacker.GetAttributeValue( 'break_through_parry_on_hit_counter' ); + if ( onHitCounter.valueBase > 0 && counter == onHitCounter.valueBase ) + { + AddEffectDefault( EET_Stagger, parryInfo.attacker, "Break through parry" ); + } + else if ( RaiseForceEvent( 'PerformParry' ) ) + { + OnCombatActionStart(); + ClearCustomOrientationInfoStack(); + SetSlideTarget( parryInfo.attacker ); + SetCustomRotation( 'Parry', parryHeading, 1080.f, 0.1f, false ); + IncDefendCounter(); + } + else + return false; + } + } + else + { + AddEffectDefault(EET_Stagger, parryInfo.attacker, "Parry"); + return true; + } + + 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 + 90; + } + else if( currToTargetAttackerAngleDiff <= -45 && currToTargetAttackerAngleDiff > -135 ) + { + parryDir = PPD_Left; + + return targetToAttackerHeading - 90; + } + else + { + parryDir = PPD_Back; + + 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.HasTag( 'NoHardLock' ) ) + return false; + + if ( newLockTarget ) + tempLockTarget = newLockTarget; + else + { + incomingAttacker = GetClosestIncomingAttacker(); + if ( incomingAttacker && incomingAttacker.IsAlive() && IsUsingVehicle() ) + { + tempLockTarget = incomingAttacker; + useIncomingAttacker = false; + } + + if ( !useIncomingAttacker ) + { + target = GetTarget(); + if( target.HasTag('ForceHardLock')) + { + return true; + } + else 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.HasTag( 'NoHardLock' ) ) + return false; + + 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; + } + + + + + + event OnTaskSyncAnim( npc : CNewNPC, animNameLeft : name ) {} + + + 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; + + + if(FactsQuerySum('player_is_the_boss') > 0) + { + + + SetDebugAttackRange(data.rangeName); + RemoveTimer('PostAttackDebugRangeClear'); + + return ret; + } + + ret = super.TestParryAndCounter(data, weaponId, parried, countered); + + + if(parried) + theGame.GetGamerProfile().ResetStat(ES_CounterattackChain); + + return ret; + } + + public function SetSpecialAttackTimeRatio(f : float) + { + LogSpecialHeavy(f); + specialAttackTimeRatio = f; + } + + public function GetSpecialAttackTimeRatio() : float + { + return specialAttackTimeRatio; + } + + + public function OnSpecialAttackHeavyActionProcess() + { + + 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; + + + 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); + } + + 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); + } + + + + 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); + + if ( stance == PCS_AlertNear ) + this.SetBehaviorVariable('isInCombatForOverlay',1.f); + else + this.SetBehaviorVariable('isInCombatForOverlay',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; + + 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 ); + } + } + + + + + + 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 ) + ResetCachedRawPlayerHeading(); + + processedActionHeading = cachedRawPlayerHeading; + + return processedActionHeading; + } + + + function ResetRawPlayerHeading() + { + if ( GetDisplayTarget() ) + rawPlayerHeading = VecHeading( GetDisplayTarget().GetWorldPosition() - this.GetWorldPosition() ); + else + rawPlayerHeading = GetHeading(); + + + } + + 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 ( !this.IsUsingVehicle() ) + FindTarget( true, action, true ); + else + ((CR4PlayerStateUseGenericVehicle)this.GetState( 'UseGenericVehicle' )).FindTarget(); + + return GetTarget(); + } + } + + + 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; + } + + + 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; + 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; + 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; + } + + + public function SetupCombatAction( action : EBufferActionType, stage : EButtonStage ) + { + var weaponType : EPlayerWeapon; + var canAttackTarget : CGameplayEntity; + var target : CActor; + + + 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 ); + + + if ( weaponType != weaponHolster.GetCurrentMeleeWeapon() ) + { + + if ( !( weaponType == PW_None && weaponHolster.GetCurrentMeleeWeapon() == PW_Fists ) ) + return; + } + } + + + 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'); + this.SignalGameplayEvent( 'FriendlyAttackAction' ); + return false; + } + } + + return true; + } + + + + 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'); + } + + + 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 || action == EBAT_Roll ) ) + { + SetIsCurrentlyDodging(false); + } + + SetCombatActionHeading( ProcessCombatActionHeading( action ) ); + + + + if ( action == EBAT_ItemUse && GetInventory().IsItemCrossbow( selectedItemId ) ) + { + + 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" ); + + + 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 : + { + + + + + + + DrainStamina(ESAT_LightAttack); + + + 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 : + { + + + + + + DrainStamina(ESAT_HeavyAttack); + + + + thePlayer.BreakPheromoneEffect(); + actionResult = this.OnPerformAttack(theGame.params.ATTACK_NAME_HEAVY); + + } break; + + case BS_Pressed : + { + if ( this.GetCurrentStateName() == 'CombatFists' ) + { + + + + + + DrainStamina(ESAT_HeavyAttack); + + + + thePlayer.BreakPheromoneEffect(); + actionResult = this.OnPerformAttack(theGame.params.ATTACK_NAME_HEAVY); + + } + } break; + + default : + { + actionResult = false; + + } break; + } + } break; + + case EBAT_ItemUse : + { + switch ( stage ) + { + case BS_Pressed : + { + if ( !( (W3PlayerWitcher)this ) || + ( !IsInCombatActionFriendly() && !( !GetBIsCombatActionAllowed() && ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_Attack || GetBehaviorVariable( 'combatActionType' ) == (int)CAT_CastSign ) ) ) ) + + { + if ( inv.IsItemCrossbow( selectedItemId ) ) + { + rangedWeapon = ( Crossbow )( inv.GetItemEntityUnsafe( selectedItemId ) ); + rangedWeapon.OnRangedWeaponPress(); + GetTarget().SignalGameplayEvent( 'Approach' ); + GetTarget().SignalGameplayEvent( 'ShootingCrossbow' ); + } + else if(inv.IsItemBomb(selectedItemId) && this.inv.SingletonItemGetAmmo(selectedItemId) > 0 ) + { + if( ((W3PlayerWitcher)this).GetBombDelay( ((W3PlayerWitcher)this).GetItemSlot( selectedItemId ) ) <= 0.0f ) + { + 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 ) ) ) ) ) + + { + if ( inv.IsItemCrossbow( selectedItemId ) ) + { + + 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; + + + + 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; + } + + + CleanCombatActionBuffer(); + + if (actionResult) + { + SetCombatAction( action ) ; + + if(GetWitcherPlayer().IsInFrenzy()) + GetWitcherPlayer().SkillFrenzyFinish(0); + } + + return true; + } + + public function CleanCombatActionBuffer() + { + BufferCombatAction = EBAT_EMPTY; + BufferAllSteps = false; + } + + public function CancelHoldAttacks() + { + RemoveTimer( 'IsSpecialLightAttackInputHeld' ); + RemoveTimer( 'IsSpecialHeavyAttackInputHeld' ); + RemoveTimer( 'SpecialAttackLightSustainCost' ); + RemoveTimer( 'SpecialAttackHeavySustainCost' ); + RemoveTimer( 'UpdateSpecialAttackLightHeading' ); + UnblockAction( EIAB_Crossbow, 'SpecialAttack' ); + + ResumeStaminaRegen('WhirlSkill'); + + if ( GetBehaviorVariable( 'combatActionType' ) == (int)CAT_SpecialAttack && GetBehaviorVariable( 'isPerformingSpecialAttack' ) == 1.f ) + { + if( GetBehaviorVariable( 'playerAttackType' ) == (int)PAT_Light ) + { + SetAttackActionName(SkillEnumToName(S_Sword_s01)); + PushCombatActionOnBuffer( EBAT_SpecialAttack_Light, BS_Released ); + ProcessCombatActionBuffer(); + + ((W3PlayerWitcherStateCombatFists) GetState('Combat')).ResetTimeToEndCombat(); + + } + else if( GetBehaviorVariable( 'playerAttackType' ) == (int)PAT_Heavy ) + { + SetAttackActionName(SkillEnumToName(S_Sword_s02)); + PushCombatActionOnBuffer( EBAT_SpecialAttack_Heavy, BS_Released ); + ProcessCombatActionBuffer(); + + } + } + } + + 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 ); + + OnCombatActionStart(); + + playerToTargetHeading = VecHeading( actor.GetWorldPosition() - GetWorldPosition() ); + + SetCustomRotation( 'Attack', playerToTargetHeading, 0.0f, 0.3f, false ); + + return true; + } + + return false; + } + + public function SendAttackReactionEvent() + { + var reactionName : name; + + + + reactionName = 'AttackAction'; + + if ( IsNameValid(reactionName) ) + { + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, reactionName, -1.0, 8.0f, -1, 5, true ); + } + + + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'outOfMyWay', -1.0, 2.0f, -1, 5, true ); + } + + var forceCanAttackWhenNotInCombat : int; + 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 + + 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; + } + + + 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; + + thePlayer.GetVisibleEnemies( localTargets ); + size = localTargets.Size(); + + if ( size > 0 ) + { + for ( i = size-1; i>=0; i-=1 ) + { + + 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 ) ); + + 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; + } + + + + + + 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); + } + + + private final function DisallowedActionDontShowHack(action : EInputActionBlock, isTimeLock : bool) : bool + { + var locks : array< SInputActionLock >; + var i : int; + + + 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; + } + + + if( action == EIAB_ThrowBomb && ( HasBuff( EET_Hypnotized ) || HasBuff( EET_Confusion ) ) ) + { + return false; + } + + + if(isTimeLock) + return false; + + + if(action == EIAB_OpenMeditation) + return false; + + + locks = GetActionLocks(action); + for(i=0; i= 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 ) + { + m_SettlementBlockCanter += valueAdd; + } + + var countDownToStart : int; + default countDownToStart = 0; + + function DisplayRaceStart( countDownSecondsNumber : int ) + { + 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) + { + var hud : CR4ScriptedHud; + var messageModule : CR4HudModuleMessage; + + countDownToStart -= 1; + hud = (CR4ScriptedHud)theGame.GetHud(); + + if( hud ) + { + messageModule = (CR4HudModuleMessage)hud.GetHudModule("MessageModule"); + if( messageModule ) + { + messageModule.OnMessageHidden(); + } + } + + if( countDownToStart <= 0 ) + { + RemoveTimer('RaceCountdown'); + } + } + + public function GetCountDownToStart() : int + { + return countDownToStart; + } + + public function HAXE3GetContainer() : W3Container + { + return HAXE3Container; + } + + public function HAXE3SetContainer( container : W3Container) : void + { + HAXE3Container = container; + } + + public function HAXE3GetAutoLoot() : bool + { + return HAXE3bAutoLoot; + } + + public function HAXE3SetAutoLoot( value : bool ) : void + { + 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); + } + + function IsNewQuest( questGuid : CGUID ) : bool + { + var i : int; + for(i = 0; i < displayedQuestsGUID.Size(); i += 1 ) + { + if( displayedQuestsGUID[i] == questGuid ) + { + return false; + } + } + displayedQuestsGUID.PushBack(questGuid); + return true; + } + + function GetRewardMultiplierData( rewardName : name ) : SRewardMultiplier + { + var defaultReward : SRewardMultiplier; + var i : int; + + for(i = 0; i < rewardsMultiplier.Size(); i += 1 ) + { + if( rewardsMultiplier[i].rewardName == rewardName ) + { + return rewardsMultiplier[i]; + } + } + + defaultReward.rewardName = rewardName; + defaultReward.rewardMultiplier = 1.0; + defaultReward.isItemMultiplier = false; + + return defaultReward; + } + + function GetRewardMultiplier( rewardName : name ) : float + { + 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 + { + 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, optional isItemMultiplier : bool ) : void + { + var i : int; + var rewardMultiplier : SRewardMultiplier; + + for(i = 0; i < rewardsMultiplier.Size(); i += 1 ) + { + if( rewardsMultiplier[i].rewardName == rewardName ) + { + rewardsMultiplier[i].rewardMultiplier = value; + rewardsMultiplier[i].isItemMultiplier = isItemMultiplier; + return; + } + } + + rewardMultiplier.rewardName = rewardName; + rewardMultiplier.rewardMultiplier = value; + rewardMultiplier.isItemMultiplier = isItemMultiplier; + + rewardsMultiplier.PushBack(rewardMultiplier); + } + + function RemoveRewardMultiplier( rewardName : name ) : void + { + var i : int; + for(i = 0; i < rewardsMultiplier.Size(); i += 1 ) + { + if( rewardsMultiplier[i].rewardName == rewardName ) + { + rewardsMultiplier.Erase(i); + return; + } + } + } + + + + + + + + public final function TissueExtractorDischarge() : bool + { + var ids : array; + var chargesLeft, uses, curr, max, red, blue, green : int; + var i : int; + var text : string; + + ids = thePlayer.inv.GetItemsByName( 'q705_tissue_extractor' ); + if( ids.Size() == 0 ) + { + return false; + } + + curr = GetTissueExtractorChargesCurr(); + max = GetTissueExtractorChargesMax(); + + if( curr >= max ) + { + + uses = FloorF( ( ( float ) curr ) / ( ( float ) max ) ); + chargesLeft = Max( 0, curr - uses * max ); + + + inv.SetItemModifierInt( ids[0], 'charges', chargesLeft ); + + + blue = 0; + green = 0; + red = 0; + for( i=0; i 0 ) + { + inv.AddAnItem( 'Greater mutagen blue', blue, false, true ); + text += "
" + blue + "x " + GetLocStringByKey( inv.GetItemLocalizedNameByName( 'Greater mutagen blue' ) ); + } + if( green > 0 ) + { + inv.AddAnItem( 'Greater mutagen green', green, false, true ); + text += "
" + green + "x " + GetLocStringByKey( inv.GetItemLocalizedNameByName( 'Greater mutagen green' ) ); + } + if( red > 0 ) + { + inv.AddAnItem( 'Greater mutagen red', red, false, true ); + text += "
" + red + "x " + GetLocStringByKey( inv.GetItemLocalizedNameByName( 'Greater mutagen red' ) ); + } + + + theGame.GetGuiManager().ShowNotification( text ); + + + inv.SetItemModifierInt( ids[0], 'ui_notified', 0 ); + + return true; + } + else + { + + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_q705_extractor_too_few_charges" ) ); + } + + return false; + } + + public final function TissueExtractorIncCharge() + { + var ids : array; + var uiData : SInventoryItemUIData; + var curr : int; + + ids = thePlayer.inv.GetItemsByName( 'q705_tissue_extractor' ); + if( ids.Size() == 0 ) + { + return; + } + + curr = GetTissueExtractorChargesCurr() + 1; + inv.SetItemModifierInt( ids[0], 'charges', curr ); + + + if( curr >= GetTissueExtractorChargesMax() ) + { + uiData = inv.GetInventoryItemUIData( ids[0] ); + uiData.isNew = true; + inv.SetInventoryItemUIData( ids[0], uiData ); + + + if( inv.GetItemModifierInt( ids[0], 'ui_notified', 0 ) == 0 ) + { + inv.SetItemModifierInt( ids[0], 'ui_notified', 1 ); + theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_q705_extractor_charged" ), , true ); + } + } + } + + public final function GetTissueExtractorChargesCurr() : int + { + var ids : array; + + ids = thePlayer.inv.GetItemsByName( 'q705_tissue_extractor' ); + if( ids.Size() == 0 ) + { + return 0; + } + + return inv.GetItemModifierInt( ids[0], 'charges', 0 ); + } + + public final function GetTissueExtractorChargesMax() : int + { + var ids : array; + var val : SAbilityAttributeValue; + + ids = thePlayer.inv.GetItemsByName( 'q705_tissue_extractor' ); + if( ids.Size() == 0 ) + { + return 0; + } + + val = inv.GetItemAttributeValue( ids[0], 'maxCharges' ); + + return FloorF( val.valueBase ); + } + + public function GetEquippedSword(steel : bool) : SItemUniqueId; + + public final function HasRequiredLevelToEquipItem(item : SItemUniqueId) : bool + { + if(HasBuff(EET_WolfHour)) + { + if((inv.GetItemLevel(item) - 2) > GetLevel() ) + return false; + } + else + { + if(inv.GetItemLevel(item) > GetLevel() ) + return false; + } + + return true; + } + + public function SkillReduceBombAmmoBonus() + { + var i, ammo, maxAmmo : int; + var items : array; + + items = inv.GetSingletonItems(); + + for(i=0; i 0) + { + maxAmmo = inv.SingletonItemGetMaxAmmo(items[i]); + + + 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; + + + category = inv.GetItemCategory(itemId); + if(category == 'edibles' || inv.ItemHasTag(itemId, 'Drinks') || ( category == 'alchemy_ingredient' && inv.ItemHasTag(itemId, 'Alcohol')) ) + { + + if(IsFistFightMinigameEnabled()) + { + DisplayActionDisallowedHudMessage(EIAB_Undefined, false, false, true); + return false; + } + + + inv.GetItemBuffs(itemId, buffs); + + for(i=0; i= cost) ); + + + if(!ret && IsSkillSign(skill) && CanUseSkill(S_Perk_09) && GetStat(BCS_Focus) >= 1) + { + ret = true; + } + + + if( !ret && IsSkillSign( skill ) && GetWitcherPlayer().HasBuff( EET_GryphonSetBonus ) ) + { + 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; + } + + + 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 + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetSkillLocalisationKeyName(skill); + + return ""; + } + + public function GetSkillLocalisationKeyDescription(skill : ESkill) : string + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetSkillLocalisationKeyDescription(skill); + + return ""; + } + + public function GetSkillIconPath(skill : ESkill) : string + { + 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 + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).CanLearnSkill(skill); + + return false; + } + + public function HasSpentEnoughPoints(skill : ESkill) : bool + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).HasSpentEnoughPoints(skill); + + return false; + } + + public function PathPointsForSkillsPath(skill : ESkill) : int + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).PathPointsSpentInSkillPathOfSkill(skill); + + return -1; + } + + public function GetPlayerSkills() : array + { + var null : array; + + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetPlayerSkills(); + + return null; + } + + public function GetPlayerSkill(s : ESkill) : SSkill + { + var null : SSkill; + + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetPlayerSkill(s); + + return null; + } + + public function GetSkillSubPathType(s : ESkill) : ESkillSubPath + { + 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; + } + + + + + 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; + } + + + 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; + } + + + 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; + } + + + public function GetSkillOnSlot(slotID : int, out skill : ESkill) : bool + { + if(abilityManager && abilityManager.IsInitialized()) + return ((W3PlayerAbilityManager)abilityManager).GetSkillOnSlot(slotID, skill); + + skill = S_SUndefined; + return false; + } + + + public function GetFreeSkillSlot() : int + { + var i, size : int; + var skill : ESkill; + + size = ((W3PlayerAbilityManager)abilityManager).GetSkillSlotsCount(); + for(i=1; i, attackAnimationName : name, hitTime : float, weaponEntity : CItemEntity) + { + var attackAction : W3Action_Attack; + + if(!PrepareAttackAction(hitTarget, animData, weaponId, parried, countered, parriedBy, attackAnimationName, hitTime, weaponEntity, attackAction)) + return; + + 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() ); + + + 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; + + + + if( isCurrentlyDodging ) + return; + + l_stateName = GetCurrentStateName(); + + if( !attackEventInProgress && l_stateName == 'CombatFists' ) + return; + + CalcEntitySlotMatrix('r_weapon', l_slotMatrix); + + l_weaponPosition = MatrixGetTranslation( l_slotMatrix ); + + + switch( l_stateName ) + { + case 'CombatFists': + l_offset = MatrixGetAxisX( l_slotMatrix ); + l_offset = VecNormalize( l_offset ) * 0.25f; + break; + + default: + l_offset = MatrixGetAxisZ( l_slotMatrix ); + l_offset = VecNormalize( l_offset ) * 1.f; + break; + } + + l_weaponTipPos = l_weaponPosition + l_offset; + + + + if( !attackEventInProgress ) + { + + if( m_LastWeaponTipPos == Vector ( 0, 0, 0 ) ) + l_distance = 0; + else + l_distance = VecDistance( l_weaponTipPos, m_LastWeaponTipPos ) ; + + + + + m_LastWeaponTipPos = l_weaponTipPos; + if( l_distance < 0.35f ) + return; + + } + + + + m_LastWeaponTipPos = l_weaponTipPos; + + if ( !theGame.GetWorld().StaticTraceWithAdditionalInfo( l_weaponPosition, l_weaponTipPos, l_collidingPosition, l_normal, l_materialName, l_hitComponent, m_WeaponFXCollisionGroupNames ) ) + { + + 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 ); + + + switch( l_stateName ) + { + case 'CombatFists': + m_CollisionEffect.PlayEffect('fist'); + break; + default: + + 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; + case 'flesh': + m_CollisionEffect.PlayEffect('blood'); + break; + default: + m_CollisionEffect.PlayEffect('wood'); + break; + } + + } + break; + } + + + if(l_hitComponent) + { + barrel = (COilBarrelEntity)l_hitComponent.GetEntity(); + if(barrel) + { + barrel.OnFireHit(NULL); + return; + } + } + + + l_destructibleCmp = (CDestructionSystemComponent) l_hitComponent; + if( l_destructibleCmp && l_stateName != 'CombatFists' ) + { + l_destructibleCmp.ApplyFracture(); + } + + + + } + + public function ReactToReflectedAttack( target : CGameplayEntity) + { + + var hp, dmg : float; + var action : W3DamageAction; + + super.ReactToReflectedAttack(target); + + + theGame.VibrateControllerLight(); + } + + + + + + + function GetFallDist( out fallDist : float ) : bool + { + var fallDiff, jumpTotalDiff : float; + + + 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(); + + if(IsAlive()) + { + if(ShouldProcessTutorial('TutorialFallingDamage')) + { + FactsSet( "tutorial_falling_damage", 1 ); + } + + if(FactsQuerySum("tutorial_falling_damage") > 1 && ShouldProcessTutorial('TutorialFallingRoll')) + { + + tut.type = ETMT_Hint; + tut.tutorialScriptTag = 'TutorialFallingRoll'; + tut.hintPositionType = ETHPT_DefaultGlobal; + tut.hintDurationType = ETHDT_Long; + tut.canBeShownInMenus = false; + tut.glossaryLink = false; + tut.markAsSeenOnShow = true; + + + theGame.GetTutorialSystem().DisplayTutorial(tut); + } + } + } + + return hpPerc; + } + + + + 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' ); + + } + + + 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; + } + + + if ( GetAttitudeBetween( this, actor ) == AIA_Hostile ) + { + if ( usePrecalcs ) + { + distanceToTarget = Distance2DBetweenCapsuleAndPoint( actor, this ) - targetingPrecalcs.playerRadius; + } + else + { + distanceToTarget = Distance2DBetweenCapsules( this, actor ); + } + + + 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 ) + { + + 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(); + + } + + + } + + 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 ); + + + } + + 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; + } + + + 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 + { + + return GetBehaviorVariable( 'combatIdleStance' ); + } + + protected var isRotatingInPlace : bool; + event OnRotateInPlaceStart() + { + isRotatingInPlace = true; + } + + event OnRotateInPlaceEnd() + { + isRotatingInPlace = false; + } + + event OnFullyBlendedIdle() + { + if ( bLAxisReleased ) + { + ResetRawPlayerHeading(); + ResetCachedRawPlayerHeading(); + defaultLocomotionController.ResetMoveDirection(); + } + } + + private var isInIdle : bool; + + event OnPlayerIdleStart() + { + isInIdle = true; + } + + event OnPlayerIdleEnd() + { + isInIdle = false; + } + + public function IsInIdle() : bool + { + return isInIdle; + } + + event OnRunLoopStart() + { + EnableRunCamera( true ); + } + + event OnRunLoopEnd() + { + EnableRunCamera( false ); + } + + event OnCombatActionStartBehgraph() + { + var action : EBufferActionType; + var cost, delay : float; + + + + + OnCombatActionStart(); + + 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; + + default : + ; + } + + + + if( delay > 0 ) + PauseStaminaRegen( '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() + { + + + BlockAction( EIAB_UsableItem, 'OnCombatActionStart' ); + BlockAction( EIAB_CallHorse, 'OnCombatActionStart' ); + + + + LogChannel('combatActionAllowed',"FALSE OnCombatActionStart"); + SetBIsCombatActionAllowed( false ); + SetBIsInputAllowed( false, 'OnCombatActionStart' ); + + + ClearFinishableEnemyList( 0.f, 0 ); + + bIsInHitAnim = false; + + + + if ( rangedWeapon && rangedWeapon.GetCurrentStateName() != 'State_WeaponWait' ) + { + CleanCombatActionBuffer(); + SetIsAimingCrossbow( false ); + OnRangedForceHolster( false, true ); + } + + + holsterUsableItem = false; + if ( thePlayer.IsHoldingItemInLHand() ) + { + 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; + } + + + if ( GetBehaviorVariable( 'combatActionType' ) != (int)CAT_Attack && GetBehaviorVariable( 'combatActionType' ) != (int)CAT_PreAttack ) + { + RemoveTimer( 'ProcessAttackTimer' ); + RemoveTimer( 'AttackTimerEnd' ); + UnblockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' ); + } + else + { + + BlockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' ); + } + + + } + + var isInParryOrCounter : bool; + event OnParryOrCounterStart() + { + isInParryOrCounter = true; + OnCombatActionStartBehgraph(); + } + + event OnParryOrCounterEnd() + { + isInParryOrCounter = false; + OnCombatActionEnd(); + SetBIsInCombatAction( false ); + } + + + event OnCombatActionEnd() + { + var item : SItemUniqueId; + var combatActionType : float; + + super.OnCombatActionEnd(); + + + + BlockAllActions( 'OnCombatActionStart', false ); + + UnblockAction( EIAB_DrawWeapon, 'OnCombatActionStart_Attack' ); + + + UnblockAction( EIAB_Movement, 'CombatActionFriendly' ); + + + + + oTCameraOffset = 0.f; + oTCameraPitchOffset = 0.f; + + + SetBIsCombatActionAllowed( true ); + + + SetBIsInputAllowed( true, 'OnCombatActionEnd' ); + SetCanPlayHitAnim( true ); + EnableFindTarget( true ); + + + + + SetFinisherVictim( NULL ); + + OnBlockAllCombatTickets( false ); + + LogStamina("CombatActionEnd"); + + + + SetAttackActionName(''); + combatActionType = GetBehaviorVariable('combatActionType'); + + + if(GetBehaviorVariable('combatActionType') == (int)CAT_SpecialAttack) + { + theGame.GetGameCamera().StopAnimation( 'camera_shake_loop_lvl1_1' ); + OnSpecialAttackHeavyActionProcess(); + } + + substateManager.ReactToChanceToFallAndSlide(); + } + + event OnCombatActionFriendlyStart() + { + SetBIsInCombatActionFriendly(true); + BlockAction( EIAB_Movement, 'CombatActionFriendly', false, false, false ); + OnCombatActionStart(); + } + + event OnCombatActionFriendlyEnd() + { + SetBIsInCombatActionFriendly(false); + UnblockAction( EIAB_Movement, 'CombatActionFriendly' ); + OnCombatActionEnd(); + SetBIsInCombatAction(false); + + } + + 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(); + + + ResumeStaminaRegen( 'InsideCombatAction' ); + + if( GetHealthPercents() < 0.3f ) + { + PlayBattleCry('BattleCryBadSituation', 0.10f, true ); + } + else + { + PlayBattleCry('BattleCryBadSituation', 0.05f, true ); + } + } + + event OnHitStartSwimming() + { + OnRangedForceHolster( true, true, false ); + } + + private var finisherSaveLock : int; + event OnFinisherStart() + { + var currentEffects : array; + + theGame.CreateNoSaveLock("Finisher",finisherSaveLock,true,false); + + isInFinisher = true; + + finisherTarget = slideTarget; + OnCombatActionStart(); + + CancelHoldAttacks(); + + 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 ) ) + { + 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.EnableManualCameraControl( false, 'Finisher' ); + } + } + + 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'); + + + SetImmortalityMode( AIM_None, AIC_SyncedAnim ); + theGame.RemoveTimeScale( 'AnimEventSlomoMo' ); + AddTimer( 'FinisherEndEnableCamera', 0.5f ); + + 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(); + tempEntity = theGame.CreateEntity( (CEntityTemplate)LoadResource('finisher_blood'), bloodFxPos, bloodFxRot); + tempEntity.PlayEffect('crawl_blood'); + } + + + event OnCombatActionEndComplete() + { + var buff : CBaseGameplayEffect; + + buff = ChooseCurrentCriticalBuffForAnim(); + SetCombatAction( EBAT_EMPTY ); + + + 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(); + } + + + ReapplyCriticalBuff(); + SetBIsInputAllowed( true, 'OnCombatActionEndComplete' ); + + + ResumeStaminaRegen( 'InsideCombatAction' ); + + bIsInHitAnim = false; + + SetBIsCombatActionAllowed( true ); + + m_LastWeaponTipPos = Vector(0, 0, 0, 0 ); + + + this.AddTimer('FreeTickets',3.f,false); + + + + } + + 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(); + } + + + + 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); + } + + + event OnCombatActionStartVehicle( action : EVehicleCombatAction ) + { + this.SetBIsCombatActionAllowed( false ); + + if ( action != EHCA_ShootCrossbow ) + { + SetIsAimingCrossbow( false ); + OnRangedForceHolster(); + } + } + + event OnCombatActionEndVehicle() + { + this.SetBIsCombatActionAllowed( true ); + } + + + + + + protected function CriticalBuffInformBehavior(buff : CBaseGameplayEffect) + { + + if( !CanAnimationReactToCriticalState( buff ) ) + { + return; + } + + + + + 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; + + + buffCritical = ( W3CriticalEffect ) buff; + if( buffCritical ) + { + isHeavyCritical = buffCritical.explorationStateHandling == ECH_HandleNow; + } + else + { + buffCriticalDOT = ( W3CriticalDOTEffect ) buff; + if( buffCriticalDOT ) + { + isHeavyCritical = buffCriticalDOT.explorationStateHandling == ECH_HandleNow; + } + } + + + 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(); + + + newReqCS = newRequestedCS; + if(super.OnCriticalStateAnimStart()) + { + + RemoveTimer( 'IsItemUseInputHeld' ); + keepRequestingCriticalAnimStart = false; + CancelHoldAttacks(); + + + + + + 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(); + + + SetCustomRotation( 'Knockdown', heading, 2160.f, 0.1f, true ); + + if ( newCritical != ECST_Stagger && newCritical != ECST_LongStagger ) + substateManager.ReactOnCriticalState( true ); + } + } + + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'CriticalEffectStart', -1, 30.0f, -1.f, -1, true ); + return true; + } + + + return false; + } + + + public function StartCSAnim(buff : CBaseGameplayEffect) : bool + { + SetBehaviorVariable( 'bCriticalStopped', 0 ); + + if(super.StartCSAnim(buff)) + { + if(!CriticalBuffUsesFullBodyAnim(buff)) + { + OnCriticalStateAnimStart(); + } + + ResumeStaminaRegen( 'InsideCombatAction' ); + + keepRequestingCriticalAnimStart = true; + AddTimer('RequestCriticalAnimStart', 0, true); + + + return true; + } + + return false; + } + + public function CriticalEffectAnimationInterrupted(reason : string) : bool + { + var ret : bool; + + 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); + + theGame.GetBehTreeReactionManager().CreateReactionEventIfPossible( this, 'RecoveredFromCriticalEffect', -1, 30.0f, -1.f, -1, true ); + super.CriticalStateAnimStopped(forceRemoveBuff); + + substateManager.ReactOnCriticalState( false ); + } + + + 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) + { + + + SetIsInAir(progress == 0); + } + + + event OnRagdollOnGround() + { + + 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) + { + + if (critical.GetTimeActive() >= 2.5f) + { + SetIsInAir(false); + RequestCriticalAnimStop(); + RemoveTimer('TryToEndRagdollOnGround'); + } + else + { + AddTimer('TryToEndRagdollOnGround', 0.2f, true); + } + return; + } + } + + + 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); + } + + + + + public function SimulateBuffTimePassing(simulatedTime : float) + { + effectManager.SimulateBuffTimePassing(simulatedTime); + } + + public function AddEffectDefault(effectType : EEffectType, creat : CGameplayEntity, srcName : string, optional isSignEffect : bool) : EEffectInteract + { + var params : SCustomEffectParams; + + + 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); + } + } + + + + + + public function CheatResurrect() + { + var items : array< SItemUniqueId >; + var i, size, itemLevel, maxPrice, itemPrice : int; + var itemToEquip : SItemUniqueId; + + if(IsAlive()) + return; + + + if ( !theGame.GetGuiManager().GetRootMenu() ) + { + Log(" *** Call this function after DeathScreen appears *** "); + return; + } + + SetAlive(true); + + SetKinematic(true); + + EnableFindTarget( true ); + SetBehaviorVariable( 'Ragdoll_Weight', 0.f ); + RaiseForceEvent( 'RecoverFromRagdoll' ); + SetCanPlayHitAnim( true ); + SetBehaviorVariable( 'CriticalStateType', (int)ECST_None ); + GoToStateIfNew('Exploration'); + + ( (CDismembermentComponent)this.GetComponent( 'Dismemberment' ) ).ClearVisibleWound(); + + SetIsInAir(false); + + theInput.SetContext('Exploration'); + + ResetDeathType(); + + ForceUnlockAllInputActions(false); + + theGame.CloseMenu('DeathScreenMenu'); + + + theSound.LeaveGameState(ESGS_Death); + + + abilityManager.ForceSetStat(BCS_Vitality, GetStatMax(BCS_Vitality)); + effectManager.StopVitalityRegen(); + abilityManager.ForceSetStat( BCS_Air , 100.f ); + effectManager.StopAirRegen(); + abilityManager.ForceSetStat( BCS_Stamina , 100.f ); + effectManager.StopStaminaRegen(); + abilityManager.ForceSetStat( BCS_Toxicity , 0.f ); + abilityManager.ForceSetStat( BCS_Focus , 0.f ); + GetWitcherPlayer().UpdateEncumbrance(); + + + if ( !inv.IsThereItemOnSlot( EES_SteelSword ) ) + { + items = inv.GetItemsByCategory( 'steelsword' ); + } + else if ( !inv.IsThereItemOnSlot( EES_SilverSword ) ) + { + items = inv.GetItemsByCategory( 'silversword' ); + } + + size = items.Size(); + maxPrice = -1; + for ( i = 0; i < size; i += 1 ) + { + itemPrice = inv.GetItemPrice(items[i]); + itemLevel = inv.GetItemLevel(items[i]); + if ( itemLevel <= GetLevel() && itemPrice > maxPrice ) + { + maxPrice = itemPrice; + itemToEquip = items[i]; + } + } + if( inv.IsIdValid( itemToEquip ) ) + { + EquipItem( itemToEquip , , true ); + } + + 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; + } + + + + + + 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' ); + } + + + + + 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( !RaiseForceEvent( '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 ), true ); + 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 ), true ); + 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 ); + + } + + + public function StartWaitForItemSpawnAndProccesTask() + { + AddTimer( 'WaitForItemSpawnAndProccesTask', 0.001f, true,,,,true ); + } + + + public function KillWaitForItemSpawnAndProccesTask() + { + RemoveTimer ( 'WaitForItemSpawnAndProccesTask' ); + } + + + + public function AllowUseSelectedItem() + { + m_useSelectedItemIfSpawned = true; + } + + + + timer function WaitForItemSpawnAndProccesTask( timeDelta : float , id : int ) + { + var itemEntity : W3UsableItem; + var canTaskBeKilled : bool; + canTaskBeKilled = false; + + if ( IsCastingSign() ) + { + return; + } + + + if ( selectedItemId == GetInvalidUniqueId() ) + { + canTaskBeKilled = true; + } + + itemEntity = (W3UsableItem)inv.GetItemEntityUnsafe( selectedItemId ); + if ( itemEntity && m_useSelectedItemIfSpawned ) + { + + canTaskBeKilled = true; + m_useSelectedItemIfSpawned = false; + 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'); + } + + + 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 ); + + + + + + } + 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(); + + + theTelemetry.LogWithLabel(TE_FIGHT_HERO_THROWS_BOMB, inv.GetItemName( selectedItemId )); + } + + + event OnThrowAnimStart() + { + var itemId : SItemUniqueId; + var thrownEntity : CThrowable; + + 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(thrownEntity && !thrownEntity.WasThrown()) + { + thrownEntity.BreakAttachment(); + thrownEntity.Destroy(); + } + + thrownEntity = NULL; + SetIsThrowingItem( false ); + SetIsThrowingItemWithAim( false ); + RemoveCustomOrientationTarget( 'BombThrow' ); + } + + public function ProcessCanAttackWhenNotInCombatBomb() + { + var targets : array< CGameplayEntity >; + var temp, throwVector, throwFrom, throwTo, throwVectorU : Vector; + var temp_n : name; + var throwVecLen : float; + var component : CComponent; + + + + if( FactsQuerySum( "BombThrowSpecificTargets" ) > 0 ) + { + + + + + + throwFrom = playerAiming.GetThrowStartPosition(); + throwTo = playerAiming.GetThrowPosition(); + throwVector = throwTo - throwFrom; + throwVecLen = VecDistance( throwFrom, throwTo ); + throwVectorU = throwVector / throwVecLen; + if( theGame.GetWorld().StaticTraceWithAdditionalInfo( throwFrom, throwTo + throwVectorU, temp, temp, temp_n, component ) && component && component.GetEntity().HasTag( 'BombThrowSpecificTarget' ) ) + { + SetIsShootingFriendly( false ); + } + else + { + SetIsShootingFriendly( true ); + } + } + else if( FactsQuerySum( "BombThrowDisallowSpecificTargets" ) > 0 ) + { + + throwFrom = playerAiming.GetThrowStartPosition(); + throwTo = playerAiming.GetThrowPosition(); + throwVector = throwTo - throwFrom; + throwVecLen = VecDistance( throwFrom, throwTo ); + throwVectorU = throwVector / throwVecLen; + if( theGame.GetWorld().StaticTraceWithAdditionalInfo( throwFrom, throwTo + throwVectorU, temp, temp, temp_n, component ) && component && component.GetEntity().HasTag( 'BombThrowDisallowedTarget' ) ) + { + SetIsShootingFriendly( true ); + } + else + { + SetIsShootingFriendly( false ); + } + } + else + { + SetIsShootingFriendly( false ); + } + + SetBehaviorVariable( 'isShootingFriendly', (float)( GetIsShootingFriendly() ) ); + } + + public function SetIsShootingFriendly( flag : bool ) + { + isShootingFriendly = flag; + } + + public function GetIsShootingFriendly() : bool + { + return isShootingFriendly; + } + + + protected function UsableItemStart() + { + var thrownEntity : CThrowable; + + + 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() + { + var stateName : name; + + stateName = playerAiming.GetCurrentStateName(); + OnDelayOrientationChangeOff(); + + if( GetIsShootingFriendly() || ( FactsQuerySum( "BombThrowSpecificTargets" ) > 0 && stateName != 'Aiming' ) ) + { + BombThrowAbort(); + } + else + { + SetBehaviorVariable( 'throwStage', (int)TS_End ); + + if ( stateName == 'Aiming' ) + { + SetCustomRotation( 'Throw', VecHeading( this.GetLookAtPosition() - GetWorldPosition() ), 0.0f, 0.2f, false ); + } + } + } + + protected function UsableItemRelease() + { + OnDelayOrientationChangeOff(); + SetBehaviorVariable( 'throwStage', (int)TS_End ); + RemoveCustomOrientationTarget( 'UsableItems' ); + } + + + 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(thrownEntity && !thrownEntity.WasThrown()) + { + thrownEntity.BreakAttachment(); + thrownEntity.Destroy(); + } + this.EnableRadialSlotsWithSource( true, this.radialSlots, 'throwBomb' ); + } + + public function CanSetupCombatAction_Throw() : bool + { + + if(!inv.IsIdValid( selectedItemId )) + return false; + + + if(!inv.IsItemSingletonItem(selectedItemId)) + return false; + + + if(!GetBIsInputAllowed()) + return false; + + + if(inv.GetItemQuantity(GetSelectedItemId()) <= 0 && !inv.ItemHasTag(selectedItemId, theGame.params.TAG_INFINITE_AMMO)) + return false; + + + if(!inputHandler.IsActionAllowed(EIAB_ThrowBomb) && GetCurrentStateName() != 'Swimming') + return false; + + return true; + } + + public function GetThrownEntity() : CThrowable + { + return (CThrowable)EntityHandleGet( thrownEntityHandle ); + } + + + 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; + } + + + event OnBlockAllCombatTickets( release : bool ) + { + if (!release ) + ((CR4PlayerStateCombat)GetState('Combat')).OnBlockAllCombatTickets(false); + } + event OnForceTicketUpdate() {} + + + + + + event OnProcessActionPost(action : W3DamageAction) + { + var npc : CNewNPC; + var attackAction : W3Action_Attack; + var lifeLeech : float; + + super.OnProcessActionPost(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()) + { + + IncreaseUninterruptedHitsCount(); + + + if( IsLightAttack( attackAction.GetAttackName() ) ) + { + GCameraShake(0.1, false, GetWorldPosition(), 10); + } + + + if(npc && inv.GetItemName(attackAction.GetWeaponId()) == 'PC Caretaker Shovel') + { + + 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; + } + + + + + + public function GetHorseWithInventory() : CNewNPC + { + return (CNewNPC)EntityHandleGet( horseWithInventory ); + } + public function GetHorseCurrentlyMounted() : CNewNPC + { + return currentlyMountedHorse; + } + + 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 SetIsSwimming ( toggle : bool ) + { + if( isSwimming != toggle ) + { + thePlayer.substateManager.SetBehaviorParamBool( 'isSwimmingForOverlay', toggle ); + isSwimming = toggle; + } + } + + + + + + + + public function RepairItemUsingConsumable(item, consumable : SItemUniqueId) : bool + { + var curr, max, repairValue, itemValue, repairBonus, newDurability : float; + + + if(!inv.IsIdValid(item) || !inv.IsIdValid(consumable) || !inv.HasItemDurability(item)) + return false; + + curr = inv.GetItemDurability(item); + max = inv.GetItemMaxDurability(item); + + + if(curr > max) + return false; + + + 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)) ) + { + + 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')); + + + repairValue = max * itemValue /100; + + + + newDurability = MinF(max, curr + repairValue); + + inv.SetItemDurabilityScript(item, newDurability); + + + inv.RemoveItem(consumable); + + return true; + } + return false; + } + + + + + + + + + + + private function CheckDayNightCycle() + { + var time : GameTime; + var isNight : bool; + + + isNight = theGame.envMgr.IsNight(); + if(prevDayNightIsNight != isNight) + { + if(isNight) + OnNightStarted(); + else + OnDayStarted(); + + prevDayNightIsNight = isNight; + } + + + if(isNight) + time = theGame.envMgr.GetGameTimeTillNextDay(); + else + time = theGame.envMgr.GetGameTimeTillNextNight(); + + AddGameTimeTimer('DayNightCycle', time); + } + + timer function DayNightCycle(dt : GameTime, id : int) + { + CheckDayNightCycle(); + } + + event OnNightStarted() + { + var pam : W3PlayerAbilityManager; + + if(CanUseSkill(S_Perk_01)) + { + pam = (W3PlayerAbilityManager)abilityManager; + pam.SetPerk01Abilities(false, true); + } + } + + event OnDayStarted() + { + var pam : W3PlayerAbilityManager; + + if(CanUseSkill(S_Perk_01)) + { + pam = (W3PlayerAbilityManager)abilityManager; + pam.SetPerk01Abilities(true, false); + } + } + + + + + + 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; + } + + + + + + 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(); + } + + + + + + + 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; + } + + + 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 ) ); + } + } + } + + + + public function SetWeatherDisplayDisabled( disable : bool ) + { + disableWeatherDisplay = disable; + } + + public function GetWeatherDisplayDisabled() : bool + { + return disableWeatherDisplay; + } + + + + + + public function SetCurrentMonsterHuntInvestigationArea ( area : W3MonsterHuntInvestigationArea ) + { + currentMonsterHuntInvestigationArea = area; + } + + + + + + + public function RememberCustomHead( headName : name ) + { + rememberedCustomHead = headName; + } + + public function GetRememberedCustomHead() : name + { + return rememberedCustomHead; + } + + public function ClearRememberedCustomHead() + { + rememberedCustomHead = ''; + } + + + + + + 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; + var id : SItemUniqueId; + var i : int; + + + if(inv) + { + inv.GetAllItems(items); + if(items.Size() <= 0) + { + return; + } + } + else + { + return; + } + + + 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; + var i : int; + var slot : EEquipmentSlots; + + + 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(); + + + RemoveTimer('Debug_GiveTestingItems'); + + + inv.GetAllItems(items); + + for(i=0; i; + 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; + var sword : CWitcherSword; + var healthPercentage : float; + var tmpBacklight : Vector; + + if(!skipHeldWeapon) + { + weapons = inv.GetHeldWeapons(); + + + 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 final function SetLoopingCameraShakeAnimName( n : name ) + { + loopingCameraShakeAnimName = n; + } + + 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; + } + else + { + return 0.02f; + } + } + + 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' ); + } + + + 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 ) ); + + + 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 ) ); + + + + + 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 ); } + } + } + + + 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 ); + } + } + } + + + + + + public function OnStartTeleportingPlayerToPlayableArea() + { + var FADEOUT_INTERVAL : float = 0.5; + + + 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.1; + var manager : CCommonMapManager = theGame.GetCommonMapManager(); + + thePlayer.TeleportWithRotation( manager.GetBorderTeleportPosition(), manager.GetBorderTeleportRotation() ); + thePlayer.AddTimer( 'BorderTeleportFadeInTimer', BLACKSCREEN_INTERVAL, false ); + + theGame.FadeOutAsync( 0 ); + theGame.SetFadeLock('PlayerTeleportation'); + } + + timer function BorderTeleportFadeInTimer( dt : float, id : int ) + { + theGame.ResetFadeLock('PlayerTeleportation'); + theGame.FadeOutAsync( 0 ); + theGame.FadeInAsync( 2.0f ); + } + + 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) ); + } + + 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; } + + public function SetInsideDiveAttackArea( val : bool ) { insideDiveAttackArea = val; } + public function IsInsideDiveAttackArea() : bool { return insideDiveAttackArea; } + public function SetDiveAreaNumber( val : int ) { diveAreaNumber = val; } + public function GetDiveAreaNumber() : int { return diveAreaNumber; } + + + + 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(); + } + + + + + private var forcedFinisherVictim : CActor; + + timer function PerformFinisher( time : float , id : int ) + { + var combatTarget : CActor; + var i : int; + + combatTarget = thePlayer.GetTarget(); + + if( combatTarget ) + { + combatTarget.Kill( 'AutoFinisher', false, thePlayer ); + thePlayer.SetFinisherVictim( combatTarget ); + forcedFinisherVictim = combatTarget; + thePlayer.CleanCombatActionBuffer(); + thePlayer.OnBlockAllCombatTickets( true ); + moveTargets = thePlayer.GetMoveTargets(); + + for( i = 0; i < moveTargets.Size(); i += 1 ) + { + if( combatTarget != moveTargets[i] ) + moveTargets[i].SignalGameplayEvent( 'InterruptChargeAttack' ); + } + + if( theGame.GetInGameConfigWrapper().GetVarValue( 'Gameplay', 'AutomaticFinishersEnabled' ) == "true" ) + combatTarget.AddAbility( 'ForceFinisher', false ); + + if( combatTarget.HasTag( 'ForceFinisher' ) ) + combatTarget.AddAbility( 'ForceFinisher', false ); + + combatTarget.SignalGameplayEvent( 'ForceFinisher' ); + + thePlayer.FindMoveTarget(); + + thePlayer.AddTimer( 'SignalFinisher', 0.2, false ); + } + } + + timer function SignalFinisher( time : float , id : int ) + { + forcedFinisherVictim.SignalGameplayEvent( 'Finisher' ); + forcedFinisherVictim = NULL; + } +} + +exec function ttt() +{ + thePlayer.AddTimer( 'TestTimer', 5, false ); +} diff --git a/src/StatTrak/files/Mod/scripts/local/achievementStatTrak/achievement_stats.ws b/src/StatTrak/files/Mod/scripts/local/achievementStatTrak/achievement_stats.ws new file mode 100644 index 0000000..1879eb7 --- /dev/null +++ b/src/StatTrak/files/Mod/scripts/local/achievementStatTrak/achievement_stats.ws @@ -0,0 +1,212 @@ +// TODO: Multiple functions: one returns array of stuff, another formats, and one final exec function + +// Function to get the stats in a formatted string +function getAchievementStats() : array +{ + // Integer to be later used in the for loop + var i : int; + + // Array to store the achievement stats + var stats : array; + + // String where all the achievements go + var achievementString : string; + + // Set achievement string empty to be later added on to + achievementString = ""; + + // Add all stats to the array + stats.PushBack(ES_CharmedNPCKills); + stats.PushBack(ES_AardFallKills); + stats.PushBack(ES_EnvironmentKills); + stats.PushBack(ES_CounterattackChain); + stats.PushBack(ES_DragonsDreamTriggers); + stats.PushBack(ES_KnownPotionRecipes); + stats.PushBack(ES_KnownBombRecipes); + stats.PushBack(ES_ReadBooks); + stats.PushBack(ES_HeadShotKills); + stats.PushBack(ES_BleedingBurnedPoisoned); + stats.PushBack(ES_DestroyedNests); + stats.PushBack(ES_FundamentalsFirstKills); + stats.PushBack(ES_FinesseKills); + stats.PushBack(ES_SelfArrowKills); + stats.PushBack(ES_ActivePotions); + stats.PushBack(ES_KilledCows); + stats.PushBack(ES_SlideTime); + + // Return the array of stats + return stats; +} + +function getAchievementStatVal(statEnum : EStatistic) : int +{ + // Get value from enum + return theGame.GetGamerProfile().GetStatValue(statEnum); +} + +function getAchievementStatNameRaw(statEnum : EStatistic) : string +{ + // Get raw name from enum + return StatisticEnumToName(statEnum); +} + +function getAchievmentStatName(rawStatName : string) : string +{ + var formattedStatName : string; + + // Set Steam/GOG achievement name from name + switch (rawStatName) + { + case "statistic_charmed_kills": + formattedStatName = "The Enemy of My Enemy"; + break; + + case "statistic_aardfall_kills": + formattedStatName = "Humpty Dumpty"; + break; + + case "statistic_environment_kills": + formattedStatName = "Environmentally Unfriendly"; + break; + + case "statistic_bleed_burn_poison": + formattedStatName = "Overkill"; + break; + + case "statistic_counterattack_chain": + formattedStatName = "Kaer Morhen Trained"; + break; + + case "statistic_burning_gas_triggers": + formattedStatName = "That Is the Evilest Thing"; + break; + + case "statistic_known_potions": + formattedStatName = "Let's Cook!"; + break; + + case "statistic_known_bombs": + formattedStatName = "Bombardier"; + break; + + case "statistic_head_shot_kills": + formattedStatName = "Master Marksman"; + break; + + case "statistic_read_books": + formattedStatName = "Bookworm"; + break; + + case "statistic_destroyed_nests": + formattedStatName = "Fire in the Hole"; + break; + + case "statistic_fundamentals_kills": + formattedStatName = ""; // Don't know what achievement this corresponds to + break; + + case "statistic_finesse_kills": + formattedStatName = ""; // Don't know what achievement this corresponds to + break; + + case "statistic_self_arrow_kills": + formattedStatName = "Return to Sender"; + break; + + case "statistic_active_potions": + formattedStatName = "Can Quit Anytime I Want"; + break; + + case "statistic_killed_cows": + formattedStatName = "Moo-rderer"; + break; + + case "statistic_slide_time": + formattedStatName = "Rad Steez, Bro!"; + break; + + default: + formattedStatName = ""; + break; + } + + // Return Steam/GOG achievement name + return formattedStatName; +} + +function getFormattedAchievementStats(statList : array) : string +{ + // Vars for formatted string + var achievementString : string; + var currentRawName : string; + var currentName : string; + var currentVal : int; + var i : int; + achievementString = ""; + + // Loop through each stat to create a final string that goes in the Gwent book + for (i = 0; i < statList.Size(); i += 1) + { + // Use other functions to get data + currentRawName = getAchievementStatNameRaw(statList[i]); + currentName = getAchievmentStatName(currentRawName); + currentVal = getAchievementStatVal(statList[i]); + + // If allowing spoilers was not toggled on + if (!theGame.GetInGameConfigWrapper().GetVarValue('ModStatTrak', 'AllowSpoilers')) + { + if (currentName == "Rad Steez, Bro!" || currentName == "Moo-rderer") + { + // Don't print and continue the loop + continue; + } + } + + if (i != 0) + { + achievementString += "

" + currentRawName + ": " + "" + currentVal + "" + "
" + "Achievement: " + "" + currentName + ""; + } + else + { + // Don't add beginning newline for first element + achievementString += currentRawName + ": " + "" + currentVal + "" + "
" + "Achievement: " + "" + currentName + ""; + } + } + + // Return final formatted string + return achievementString; +} + +//------------------------ +// EXEC FUNCTIONS +//------------------------ +exec function getAllAchievementStats() +{ + // Define vars for adding notification for all achievement stats + var statList : array; + var formattedStats : string; + + // Get data + statList = getAchievementStats(); + formattedStats = getFormattedAchievementStats(statList); + + // Add notification + theGame.GetGuiManager().ShowNotification(formattedStats); +} + +// TODO: Fix getting a single achievement stat +/*exec function getAchievementStat(statEnum : EStatistic) +{ + // Define vars for adding notification for specific stat + var rawName : string; + var achName : string; + var val : int; + + // Get data + rawName = getAchievementStatNameRaw(statEnum); + achName = getAchievementStatVal(statEnum); + val = getAchievementStatVal(statEnum); + + // Print to notification + theGame.GetGuiManager().ShowNotification(rawName + ": " + "" + val + "" + "
" + "Achievement: " + "" + val); +}*/ \ No newline at end of file diff --git a/strings/csv/en.w3strings.csv b/strings/csv/en.w3strings.csv new file mode 100644 index 0000000..28e944b --- /dev/null +++ b/strings/csv/en.w3strings.csv @@ -0,0 +1,8 @@ +;meta[language=en] +; id |key(hex)|key(str)| text +; +; Achievement book name +2116720001| |item_name_ach_stats|StatTrak +2116720002| |option_dlc_stattrak|StatTrak +2116720003| |option_AllowSpoilers|Allow Spoilers +2116720004| |panel_ModStatTrak|StatTrak \ No newline at end of file