Advertisement
Guest User

Merged file Script Compilation Error - Game doesn't start?

a guest
Jun 24th, 2016
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 139.11 KB | None | 0 0
  1. /***********************************************************************/
  2. /** Player skills are divided into trees/groups (sword, alchemy, signs).
  3. /** Each skill tree has its ring levels (reflecting the rings in GUI, where
  4. /** the innermost ring is the highest one). In order to learn a skill of
  5. /***********************************************************************/
  6. /** Modified by Elys ( 16 June 2016) for AllSkillsActive v1.0
  7. /** Some skills have a ring level of -1 -> this means that this is a skill
  8. /** that is learned automatically without spending skill points (e.g. some
  9. /** mastery skill).
  10. /**
  11. /** Skills are grouped in skill definitions. A definition holds information
  12. /** about which skills are available, to which trees and rings they belong
  13. /** etc. Basically if you would like to make several character classes then
  14. /** each of them would use a different skill definition (e.g. mage, warrior).
  15. /** Each definition can make it's own skill placement so for example skill A
  16. /** might be a sword tree ring 2 skill in warriors definition and a combat
  17. /** tree ring 5 skill in rogue definition.
  18. /** This manager loads whole definition and caches it - that's all the skill
  19. /** data you need for this player object.
  20. /**
  21. /** This can be used in multiplayer, addons or for replacers.
  22. /***********************************************************************/
  23. /** Copyright © 2012-2014
  24. /** Author : Tomek Kozera
  25. /** Bartosz Bigaj
  26. /***********************************************************************/
  27.  
  28. class W3PlayerAbilityManager extends W3AbilityManager
  29. {
  30. private saved var skills : array<SSkill>; //all skills in all skill trees
  31.  
  32. private saved var resistStatsItems : array<array<SResistanceValue>>; //holds cached resist stats from items
  33. private saved var toxicityOffset : float; //mutagens, locked percent of max toxicity
  34. private var pathPointsSpent : array<int>; //amount of skillpoints spent in each skill path
  35. private saved var skillSlots : array<SSkillSlot>; //skill slots for skills chosen by player
  36. protected saved var skillAbilities : array<name>; //cached list of non-blocked non-GlobalPassive skill abilities
  37. private var totalSkillSlotsCount, orgTotalSkillSlotsCount : int;
  38. private var tempSkills : array<ESkill>; //list of temporarily added skills
  39. private saved var mutagenSlots : array<SMutagenSlot>; //list of mutagen slots
  40. private var temporaryTutorialSkills : array<STutorialTemporarySkill>; //temp skills added for duration of mutagens tutorial in character panel
  41. private saved var ep1SkillsInitialized : bool;
  42. private saved var ep2SkillsInitialized : bool;
  43. private saved var baseGamePerksGUIPosUpdated : bool;
  44. private saved var mutagenBonuses : array< SMutagenBonusAlchemy19 >; //bonuses granted by S_Alchemy_s19 skill
  45. private saved var alchemy19OptimizationDone : bool; //if optimization for alchemy 19 was updated in existing save
  46.  
  47. //mutation system
  48. private saved var isMutationSystemEnabled : bool; //if system was unlocked through quest
  49. private saved var equippedMutation : EPlayerMutationType; //currently active mutation
  50. private saved var mutations : array< SMutation >; //all mutations
  51. private saved var mutationUnlockedSlotsIndexes : array< int >; //array holding indexes of skillSlots that can be unlocked via Master Mutation
  52. private saved var mutationSkillSlotsInitialized : bool; //if mutation skill slots were initialized
  53. public saved var equippedMutations: array< EPlayerMutationType >; //zur13 modSSS
  54. //PerksActive
  55. private var activeSkills : array<ESkill>;
  56. //PerksActive
  57.  
  58. //consts
  59. private const var LINK_BONUS_BLUE, LINK_BONUS_GREEN, LINK_BONUS_RED : name; //ability added on link color match
  60. private const var MUTATION_SKILL_GROUP_ID : int; //group id for skill slots unlocked by Mutation System
  61.  
  62. default LINK_BONUS_BLUE = 'SkillLinkBonus_Blue';
  63. default LINK_BONUS_GREEN = 'SkillLinkBonus_Green';
  64. default LINK_BONUS_RED = 'SkillLinkBonus_Red';
  65. default MUTATION_SKILL_GROUP_ID = 5;
  66.  
  67. default ep1SkillsInitialized = false;
  68. default ep2SkillsInitialized = false;
  69. default baseGamePerksGUIPosUpdated = false;
  70. public saved var unlockAllSkillSlots : bool; //zur13 modSSS
  71.  
  72.  
  73. public final function Init(ownr : CActor, cStats : CCharacterStats, isFromLoad : bool, diff : EDifficultyMode) : bool
  74. {
  75. var skillDefs : array<name>;
  76. var i : int;
  77.  
  78. isInitialized = false;
  79.  
  80. if(!ownr)
  81. {
  82. LogAssert(false, "W3PlayerAbilityManager.Init: owner is NULL!!!!");
  83. return false;
  84. }
  85. else if(!( (CPlayer)ownr ))
  86. {
  87. LogAssert(false, "W3PlayerAbilityManager.Init: trying to create for non-player object!! Aborting!!");
  88. return false;
  89. }
  90.  
  91. //array init
  92. resistStatsItems.Resize(EnumGetMax('EEquipmentSlots')+1);
  93. pathPointsSpent.Resize(EnumGetMax('ESkillPath')+1);
  94.  
  95. //add default player character ability
  96. ownr.AddAbility(theGame.params.GLOBAL_PLAYER_ABILITY);
  97.  
  98. if(!super.Init(ownr,cStats, isFromLoad, diff))
  99. return false;
  100.  
  101. LogChannel('CHR', "Init W3PlayerAbilityManager "+isFromLoad);
  102.  
  103. // init skills
  104. InitSkillSlots( isFromLoad );
  105.  
  106. if(!isFromLoad)
  107. {
  108. //set skill definitions
  109. skillDefs = charStats.GetAbilitiesWithTag('SkillDefinitionName');
  110. LogAssert(skillDefs.Size()>0, "W3PlayerAbilityManager.Init: actor <<" + owner + ">> has no skills!!");
  111.  
  112. for(i=0; i<skillDefs.Size(); i+=1)
  113. CacheSkills(skillDefs[i], skills);
  114.  
  115. LoadMutagenSlotsDataFromXML();
  116.  
  117. //GetSkillGroupsCount() is set inside LoadMutagenSlotsDataFromXML
  118. mutagenBonuses.Resize( GetSkillGroupsCount() + 1 );
  119.  
  120. //add initial skills
  121. InitSkills();
  122.  
  123. PrecacheModifierSkills();
  124. }
  125. else
  126. {
  127. tempSkills.Clear();
  128. temporaryTutorialSkills.Clear();
  129.  
  130. if ( !ep1SkillsInitialized && theGame.GetDLCManager().IsEP1Available() )
  131. {
  132. ep1SkillsInitialized = FixMissingSkills();
  133. }
  134. if ( !ep2SkillsInitialized && theGame.GetDLCManager().IsEP2Available() )
  135. {
  136. ep2SkillsInitialized = FixMissingSkills();
  137. }
  138. if ( !baseGamePerksGUIPosUpdated )
  139. {
  140. baseGamePerksGUIPosUpdated = FixBaseGamePerksGUIPos();
  141. }
  142. if( !alchemy19OptimizationDone )
  143. {
  144. Alchemy19OptimizationRetro();
  145. alchemy19OptimizationDone = true;
  146. }
  147. }
  148.  
  149. //load mutations
  150. LoadMutationData();
  151.  
  152. isInitialized = true;
  153.  
  154. orgTotalSkillSlotsCount = 16;
  155.  
  156. //Cleaning skills from AllSkillsActive previous version
  157. if ( (!isMutationSystemEnabled) && ( totalSkillSlotsCount > 12) )
  158. for(i=12; i < orgTotalSkillSlotsCount; i+=1)
  159. {
  160. UnequipSkill(skillSlots[i].id);
  161. skillSlots[i].unlockedOnLevel = 0;
  162. skillSlots[i].groupID = MUTATION_SKILL_GROUP_ID;
  163. skillSlots[i].unlocked = false;
  164.  
  165. }
  166.  
  167.  
  168. for(i=0; i<skills.Size(); i+=1)
  169. {
  170. if( MustEquipSkill(skills[i].skillType) )
  171. ForceEquipSkill(skills[i].skillType);
  172. }
  173.  
  174. return true;
  175. }
  176.  
  177. private function FixMissingSkills() : bool
  178. {
  179. var i : int;
  180. var newSkills : array<SSkill>;
  181. var skillDefs : array<name>;
  182. var fixedSomething : bool;
  183.  
  184. skillDefs = charStats.GetAbilitiesWithTag('SkillDefinitionName');
  185. LogAssert(skillDefs.Size()>0, "W3PlayerAbilityManager.Init: actor <<" + owner + ">> has no skills!!");
  186. fixedSomething = false;
  187.  
  188. for( i = 0; i < skillDefs.Size(); i+=1 )
  189. CacheSkills(skillDefs[i], newSkills);
  190.  
  191. for(i=0; i<newSkills.Size(); i+=1)
  192. {
  193. //completely new skill
  194. if(i >= skills.Size())
  195. {
  196. skills.PushBack( newSkills[i] );
  197. fixedSomething = true;
  198. continue;
  199. }
  200.  
  201. //missing skill in the middle of array
  202. if(skills[i].skillType == S_SUndefined && newSkills[i].skillType != S_SUndefined)
  203. {
  204. skills[i] = newSkills[i];
  205. fixedSomething = true;
  206. }
  207. }
  208.  
  209. return fixedSomething;
  210. }
  211.  
  212. private final function FixBaseGamePerksGUIPos() : bool
  213. {
  214. var i, j, size, size2, tmpInt : int;
  215. var fixedSomething : bool;
  216. var dm : CDefinitionsManagerAccessor;
  217. var sks, main : SCustomNode;
  218. var skillType : ESkill;
  219. var tmpName : name;
  220.  
  221. dm = theGame.GetDefinitionsManager();
  222. sks = dm.GetCustomDefinition('skills');
  223.  
  224. //find definition
  225. size = sks.subNodes.Size();
  226. for( i = 0; i < size; i += 1 )
  227. {
  228. if(dm.GetCustomNodeAttributeValueName(sks.subNodes[i], 'def_name', tmpName))
  229. {
  230. if(tmpName == 'GeraltSkills')
  231. {
  232. main = sks.subNodes[i];
  233. size2 = main.subNodes.Size();
  234. for( j = 0; j < size2; j += 1 )
  235. {
  236. dm.GetCustomNodeAttributeValueName(main.subNodes[j], 'skill_name', tmpName);
  237. skillType = SkillNameToEnum(tmpName);
  238.  
  239. switch( skillType )
  240. {
  241. case S_Perk_01 :
  242. case S_Perk_02 :
  243. case S_Perk_03 :
  244. case S_Perk_04 :
  245. case S_Perk_05 :
  246. case S_Perk_06 :
  247. case S_Perk_07 :
  248. case S_Perk_08 :
  249. case S_Perk_09 :
  250. case S_Perk_10 :
  251. case S_Perk_11 :
  252. case S_Perk_12 :
  253. dm.GetCustomNodeAttributeValueInt(main.subNodes[j], 'guiPositionID', tmpInt);
  254. skills[ skillType ].positionID = tmpInt;
  255. fixedSomething = true;
  256. }
  257. }
  258. break;
  259. }
  260. }
  261. }
  262.  
  263. return fixedSomething;
  264. }
  265.  
  266. public function OnOwnerRevived()
  267. {
  268. var i : int;
  269.  
  270. super.OnOwnerRevived();
  271.  
  272. if(owner == GetWitcherPlayer())
  273. GetWitcherPlayer().RemoveTemporarySkills();
  274. }
  275.  
  276. private final function PrecacheModifierSkills()
  277. {
  278. var i, j : int;
  279. var dm : CDefinitionsManagerAccessor;
  280. var skill : SSkill;
  281. var skillIT : int;
  282.  
  283. dm = theGame.GetDefinitionsManager();
  284. if( !dm )
  285. {
  286. return;
  287. }
  288.  
  289. for( skillIT = 0; skillIT < skills.Size(); skillIT += 1 )
  290. {
  291. //skill = skills[ skillIT ];
  292.  
  293. for( i = 0; i < skills.Size(); i += 1 )
  294. {
  295. if( i != skillIT )
  296. {
  297. for( j = 0; j < skills[ skillIT ].modifierTags.Size(); j += 1)
  298. {
  299. //if skill has modifier tag
  300. if( dm.AbilityHasTag( skills[ i ].abilityName, skills[ skillIT ].modifierTags[ j ] ) )
  301. {
  302. skills[ skillIT ].precachedModifierSkills.PushBack( i );
  303. }
  304. }
  305. }
  306. }
  307. }
  308. }
  309.  
  310. // Called after Init() when other managers are initialized (since effect manager is and must be initialized after ability manager)
  311. public final function PostInit()
  312. {
  313. var i, playerLevel : int;
  314.  
  315. if(CanUseSkill(S_Sword_5))
  316. AddPassiveSkillBuff(S_Sword_5);
  317.  
  318. //fill skill slot availability
  319. if( (W3PlayerWitcher)owner )
  320. {
  321. playerLevel = ((W3PlayerWitcher)owner).GetLevel();
  322. for(i=0; i<skillSlots.Size(); i+=1)
  323. {
  324. if( skillSlots[ i ].groupID != MUTATION_SKILL_GROUP_ID )
  325. {
  326. skillSlots[i].unlocked = ( playerLevel >= skillSlots[i].unlockedOnLevel);
  327. }
  328. }
  329. }
  330.  
  331. //retrofix
  332. if( FactsQuerySum( "154531" ) <= 0 )
  333. {
  334. mutationUnlockedSlotsIndexes.Clear();
  335. FactsAdd( "154531" );
  336. }
  337.  
  338. // +++++++++++++++++ Added by God Mode mod - Module: Set Toxicity +++++++++++++++++
  339. if(gmConfig().enableSetToxicityGet())
  340. {
  341. ForceSetStat(BCS_Toxicity, GetStatMax(BCS_Toxicity) * gmConfig().percentSetToxicityGet() * .01);
  342. toxicityOffset = 0;
  343. RemoveToxicityOffset(10000);
  344. }
  345. // ----------------- Added by God Mode mod - Module: Set Toxicity -----------------
  346.  
  347. if( mutationUnlockedSlotsIndexes.Size() == 0 )
  348. {
  349. for( i=0; i<skillSlots.Size(); i+=1 )
  350. {
  351. if( skillSlots[ i ].groupID == MUTATION_SKILL_GROUP_ID )
  352. {
  353. mutationUnlockedSlotsIndexes.PushBack( skillSlots[i].id );
  354. }
  355. }
  356. }
  357.  
  358. //inital lock of all mutation related skill slots
  359. {
  360. isMutationSystemEnabled = true;
  361. UpdateMutationSkillSlots();
  362. mutationSkillSlotsInitialized = true;
  363. }
  364. SSS_UnlockSkillSlots();//zur13
  365. //PerksActive
  366. activeSkills.Clear();
  367. activeSkills.PushBack(S_Perk_01);
  368. activeSkills.PushBack(S_Perk_02);
  369. activeSkills.PushBack(S_Perk_04);
  370. activeSkills.PushBack(S_Perk_05);
  371. activeSkills.PushBack(S_Perk_06);
  372. activeSkills.PushBack(S_Perk_07);
  373. activeSkills.PushBack(S_Perk_09);
  374. activeSkills.PushBack(S_Perk_10);
  375. activeSkills.PushBack(S_Perk_11);
  376. activeSkills.PushBack(S_Perk_12);
  377. activeSkills.PushBack(S_Perk_13);
  378. activeSkills.PushBack(S_Perk_14);
  379. activeSkills.PushBack(S_Perk_15);
  380. activeSkills.PushBack(S_Perk_16);
  381. activeSkills.PushBack(S_Perk_17);
  382. activeSkills.PushBack(S_Perk_18);
  383. activeSkills.PushBack(S_Perk_19);
  384. activeSkills.PushBack(S_Perk_20);
  385. activeSkills.PushBack(S_Perk_21);
  386. activeSkills.PushBack(S_Perk_22);
  387. //PerksActive
  388.  
  389. }
  390.  
  391. public final function GetPlayerSkills() : array<SSkill> //#B
  392. {
  393. return skills;
  394. }
  395.  
  396. public final function AddTempNonAlchemySkills() : array<SSimpleSkill>
  397. {
  398. var i, cnt, j : int;
  399. var ret : array<SSimpleSkill>;
  400. var temp : SSimpleSkill;
  401.  
  402. tempSkills.Clear();
  403.  
  404. for(i=0; i<skills.Size(); i+=1)
  405. {
  406. if(skills[i].skillPath == ESP_Signs && skills[i].level < skills[i].maxLevel)
  407. {
  408. temp.skillType = skills[i].skillType;
  409. temp.level = skills[i].level;
  410. ret.PushBack(temp);
  411.  
  412. tempSkills.PushBack(skills[i].skillType);
  413.  
  414. cnt = skills[i].maxLevel - skills[i].level;
  415. for(j=0; j<cnt; j+=1)
  416. AddSkill(skills[i].skillType, true);
  417. }
  418. }
  419.  
  420. return ret;
  421. }
  422.  
  423. public final function GetPlayerSkill(type : ESkill) : SSkill //#B
  424. {
  425. return skills[type];
  426. }
  427.  
  428. // Adds a passive skill Buff from given skill
  429. private final function AddPassiveSkillBuff(skill : ESkill)
  430. {
  431. if(skill == S_Sword_5 && GetStat(BCS_Focus) >= 1)
  432. owner.AddEffectDefault(EET_BattleTrance, owner, "BattleTranceSkill");
  433. }
  434.  
  435. private final function ReloadAcquiredSkills(out acquiredSkills : array<SRestoredSkill>)
  436. {
  437. var i, j : int;
  438.  
  439. for(j=acquiredSkills.Size()-1; j>=0; j-=1)
  440. {
  441. for(i=0; i<skills.Size(); i+=1)
  442. {
  443. if(skills[i].skillType == acquiredSkills[j].skillType)
  444. {
  445. skills[i].level = acquiredSkills[j].level;
  446. skills[i].isNew = acquiredSkills[j].isNew;
  447. skills[i].remainingBlockedTime = acquiredSkills[j].remainingBlockedTime;
  448.  
  449. if(!skills[i].isCoreSkill)
  450. pathPointsSpent[skills[i].skillPath] = pathPointsSpent[skills[i].skillPath] + 1;
  451.  
  452. acquiredSkills.Erase(j);
  453.  
  454. break;
  455. }
  456. }
  457. }
  458. }
  459.  
  460. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  461. ////////////////////////////////// ---=== @EVENTS ===--- ////////////////////////////////////////////////////////////////////////
  462. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  463.  
  464. // Called when Focus Stat current value has changed
  465. protected final function OnFocusChanged()
  466. {
  467. var points : float;
  468. var buff : W3Effect_Toxicity;
  469.  
  470.  
  471. // +++++++++++++++++ Added by God Mode mod - Module: Max Focus +++++++++++++++++
  472. if( gmConfig().enableMaxFocusGet() && !gmConfig().enableSetToxicityGet() ) { UnequipSkill(GetSkillSlotID(S_Perk_13)); }
  473. if( gmConfig().enableMaxFocusGet() ) { thePlayer.ForceSetStat(BCS_Focus, 3); }
  474. // ----------------- Added by God Mode mod - Module: Max Focus -----------------
  475.  
  476. points = GetStat(BCS_Focus);
  477.  
  478. if(points < 1 && owner.HasBuff(EET_BattleTrance))
  479. {
  480. owner.RemoveBuff(EET_BattleTrance);
  481. }
  482. else if(points >= 1 && !owner.HasBuff(EET_BattleTrance))
  483. {
  484. if(CanUseSkill(S_Sword_5))
  485. owner.AddEffectDefault(EET_BattleTrance, owner, "BattleTranceSkill");
  486. }
  487.  
  488. if ( points >= owner.GetStatMax(BCS_Focus) && owner.HasAbility('Runeword 8 _Stats', true) && !owner.HasBuff(EET_Runeword8) )
  489. {
  490. owner.AddEffectDefault(EET_Runeword8, owner, "max focus");
  491. }
  492.  
  493. //mutation 5
  494. if( points >= 1.f && GetWitcherPlayer().IsMutationActive( EPMT_Mutation5 ) && !owner.HasBuff( EET_Mutation5 ) && owner.IsInCombat() )
  495. {
  496. owner.AddEffectDefault( EET_Mutation5, owner, "", false );
  497. }
  498. else if( points < 1.f && GetWitcherPlayer().IsMutationActive( EPMT_Mutation5 ) )
  499. {
  500. owner.RemoveBuff( EET_Mutation5 );
  501. }
  502. }
  503.  
  504. // Called when Vitality Stat current value has changed
  505. protected final function OnVitalityChanged()
  506. {
  507. var vitPerc : float;
  508.  
  509. vitPerc = GetStatPercents(BCS_Vitality);
  510.  
  511. if(vitPerc < theGame.params.LOW_HEALTH_EFFECT_SHOW && !owner.HasBuff(EET_LowHealth))
  512. owner.AddEffectDefault(EET_LowHealth, owner, 'vitality_change');
  513. else if(vitPerc >= theGame.params.LOW_HEALTH_EFFECT_SHOW && owner.HasBuff(EET_LowHealth))
  514. owner.RemoveBuff(EET_LowHealth);
  515.  
  516. if(vitPerc < 1.f)
  517. ResetOverhealBonus();
  518.  
  519. theTelemetry.SetCommonStatFlt(CS_VITALITY, GetStat(BCS_Vitality));
  520.  
  521. if( gmConfig().enableTakeNoDamageGet() ) { thePlayer.ForceSetStat(BCS_Vitality, thePlayer.GetStatMax( BCS_Vitality )); } // ===== Added by God Mode mod - Module: Take No Damage =====
  522. }
  523. // Called when Air Stat current value has changed
  524. protected final function OnAirChanged()
  525. {
  526. if(GetStat(BCS_Air) > 0)
  527. {
  528. if ( owner.HasBuff(EET_Drowning) )
  529. owner.RemoveBuff(EET_Drowning);
  530.  
  531. if( owner.HasBuff(EET_Choking) )
  532. owner.RemoveBuff(EET_Choking);
  533. }
  534. }
  535.  
  536. // Called when Toxicity Stat current value has changed
  537. protected final function OnToxicityChanged()
  538. {
  539. var tox : float;
  540. var enemies : array< CActor >;
  541.  
  542. if( !((W3PlayerWitcher)owner) )
  543. return;
  544.  
  545. tox = GetStat(BCS_Toxicity);
  546.  
  547. //apply toxicity debuff
  548. // +++++++++++++++++ Added by God Mode mod - Module: Set Toxicity & Max Focus +++++++++++++++++
  549. if(gmConfig().enableSetToxicityGet())
  550. {
  551. if(!gmConfig().enableMaxFocusGet()) { UnequipSkill(GetSkillSlotID(S_Perk_13)); }
  552.  
  553. ForceSetStat(BCS_Toxicity, GetStatMax(BCS_Toxicity) * gmConfig().percentSetToxicityGet() * .01);
  554. RemoveToxicityOffset(10000);
  555. tox = GetStatMax(BCS_Toxicity) * gmConfig().percentSetToxicityGet() * .01;
  556. return;
  557. }
  558. // ----------------- Added by God Mode mod - Module: Set Toxicity & Max Focus-----------------
  559.  
  560. if( tox == 0.f && owner.HasBuff( EET_Toxicity ) )
  561. {
  562. owner.RemoveBuff( EET_Toxicity );
  563. }
  564. else if(tox > 0.f && !owner.HasBuff(EET_Toxicity))
  565. {
  566. owner.AddEffectDefault(EET_Toxicity,owner,'toxicity_change');
  567. }
  568.  
  569. //mutation 10 buff
  570. if( tox == 0.f )
  571. {
  572. owner.RemoveBuff( EET_Mutation10 );
  573. }
  574. else if( (W3PlayerWitcher)owner && GetWitcherPlayer().IsMutationActive( EPMT_Mutation10 ) && !owner.HasBuff( EET_Mutation10 ) && owner.IsInCombat() )
  575. {
  576. enemies = GetWitcherPlayer().GetEnemies();
  577.  
  578. //after we kill last enemy we are still in combat for 1-2sec
  579. if( enemies.Size() > 0 )
  580. {
  581. owner.AddEffectDefault( EET_Mutation10, NULL, "Mutation 10" );
  582. }
  583. }
  584.  
  585. theTelemetry.SetCommonStatFlt(CS_TOXICITY, GetStat(BCS_Toxicity));
  586. }
  587.  
  588. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  589. ////////////////////////////////// ---=== @MUTAGENS ===--- /////////////////////////////////////////////////////////////////////
  590. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  591.  
  592. public final function GetPlayerSkillMutagens() : array<SMutagenSlot>
  593. {
  594. return mutagenSlots;
  595. }
  596.  
  597. public final function GetSkillGroupIdOfMutagenSlot(eqSlot : EEquipmentSlots) : int
  598. {
  599. var i : int;
  600.  
  601. i = GetMutagenSlotIndex(eqSlot);
  602. if(i<0)
  603. return -1;
  604.  
  605. return mutagenSlots[i].skillGroupID;
  606. }
  607.  
  608. //returns true if given mutagen slot is unlocked and can be used
  609. public final function IsSkillMutagenSlotUnlocked( eqSlot : EEquipmentSlots ) : bool
  610. {
  611. var i : int;
  612.  
  613. i = GetMutagenSlotIndex( eqSlot );
  614. if( i<0 )
  615. {
  616. return false;
  617. }
  618.  
  619. /*
  620. if( equippedMutation != EPMT_None )
  621. {
  622. return false;
  623. }
  624. */
  625.  
  626.  
  627. // +++++++++++++++++ Added by God Mode mod - Module: Mutagen Unlock +++++++++++++++++
  628. if(gmConfig().enableMutagenUnlockGet() && ((W3PlayerWitcher)owner).GetLevel() >= gmConfig().levelMutagenUnlockGet())
  629. return true;
  630. else
  631. return ((W3PlayerWitcher)owner ).GetLevel() >= mutagenSlots[ i ].unlockedAtLevel;
  632. // ----------------- Added by God Mode mod - Module: Mutagen Unlock -----------------
  633.  
  634. }
  635.  
  636. private final function GetMutagenSlotForGroupId(groupID : int) : EEquipmentSlots
  637. {
  638. var i : int;
  639.  
  640. for(i=0; i<mutagenSlots.Size(); i+=1)
  641. {
  642. if(mutagenSlots[i].skillGroupID == groupID)
  643. {
  644. return mutagenSlots[i].equipmentSlot;
  645. }
  646. }
  647.  
  648. return EES_InvalidSlot;
  649. }
  650.  
  651. public final function GetSkillGroupsCount() : int
  652. {
  653. return mutagenSlots.Size();
  654. }
  655.  
  656. public final function GetSkillGroupIDFromIndex(idx : int) : int
  657. {
  658. if(idx >= 0 && idx <mutagenSlots.Size())
  659. return mutagenSlots[idx].skillGroupID;
  660.  
  661. return -1;
  662. }
  663.  
  664. //returns index of mutagen slot paired with given equipment slot
  665. private final function GetMutagenSlotIndex(eqSlot : EEquipmentSlots) : int
  666. {
  667. var i : int;
  668.  
  669. for(i=0; i<mutagenSlots.Size(); i+=1)
  670. if(mutagenSlots[i].equipmentSlot == eqSlot)
  671. return i;
  672.  
  673. return -1;
  674. }
  675.  
  676. //returns index of mutagen slot paired with given item
  677. private final function GetMutagenSlotIndexFromItemId(item : SItemUniqueId) : int
  678. {
  679. var i : int;
  680.  
  681. for(i=0; i<mutagenSlots.Size(); i+=1)
  682. if(mutagenSlots[i].item == item)
  683. return i;
  684.  
  685. return -1;
  686. }
  687.  
  688. public final function OnSkillMutagenEquipped(item : SItemUniqueId, slot : EEquipmentSlots, prevColor : ESkillColor)
  689. {
  690. var i : int;
  691. var newColor : ESkillColor;
  692. var tutState : W3TutorialManagerUIHandlerStateCharDevMutagens;
  693.  
  694. i = GetMutagenSlotIndex(slot);
  695. if(i<0)
  696. return;
  697.  
  698. mutagenSlots[i].item = item;
  699.  
  700. //update link
  701. newColor = GetSkillGroupColor(mutagenSlots[i].skillGroupID);
  702. LinkUpdate(newColor, prevColor );
  703.  
  704. //"synergy" skill bonus
  705. if(CanUseSkill(S_Alchemy_s19))
  706. {
  707. MutagensSyngergyBonusUpdate( mutagenSlots[i].skillGroupID, GetSkillLevel( S_Alchemy_s19) );
  708. }
  709.  
  710. //tutorial
  711. if(ShouldProcessTutorial('TutorialCharDevMutagens'))
  712. {
  713. tutState = (W3TutorialManagerUIHandlerStateCharDevMutagens)theGame.GetTutorialSystem().uiHandler.GetCurrentState();
  714. if(tutState)
  715. {
  716. tutState.EquippedMutagen();
  717. }
  718. }
  719.  
  720. theTelemetry.LogWithValueStr(TE_HERO_MUTAGEN_USED, owner.GetInventory().GetItemName( item ) );
  721.  
  722. //trial of grasses achievement
  723. theGame.GetGamerProfile().CheckTrialOfGrasses();
  724. }
  725.  
  726. public final function OnSkillMutagenUnequipped(item : SItemUniqueId, slot : EEquipmentSlots, prevColor : ESkillColor)
  727. {
  728. var i : int;
  729. var newColor : ESkillColor;
  730.  
  731. i = GetMutagenSlotIndex(slot);
  732. if(i<0)
  733. return;
  734.  
  735. //"synergy" skill bonus
  736. if(CanUseSkill(S_Alchemy_s19))
  737. {
  738. MutagensSyngergyBonusUpdate( mutagenSlots[i].skillGroupID, GetSkillLevel( S_Alchemy_s19) );
  739. }
  740.  
  741. mutagenSlots[i].item = GetInvalidUniqueId();
  742.  
  743. newColor = GetSkillGroupColor(mutagenSlots[i].skillGroupID);
  744. LinkUpdate(newColor, prevColor);
  745. }
  746.  
  747. //called after mutagens were swapped (without equip/unequip handling)
  748. public final function OnSwappedMutagensPost(a : SItemUniqueId, b : SItemUniqueId)
  749. {
  750. var oldSlotIndexA, oldSlotIndexB : int;
  751. var oldColorA, oldColorB, newColorA, newColorB : ESkillColor;
  752.  
  753. oldSlotIndexA = GetMutagenSlotIndexFromItemId(a);
  754. oldSlotIndexB = GetMutagenSlotIndexFromItemId(b);
  755.  
  756. oldColorA = GetSkillGroupColor(mutagenSlots[oldSlotIndexA].skillGroupID);
  757. oldColorB = GetSkillGroupColor(mutagenSlots[oldSlotIndexB].skillGroupID);
  758.  
  759. mutagenSlots[oldSlotIndexA].item = b;
  760. mutagenSlots[oldSlotIndexB].item = a;
  761.  
  762. newColorA = GetSkillGroupColor(mutagenSlots[oldSlotIndexA].skillGroupID);
  763. newColorB = GetSkillGroupColor(mutagenSlots[oldSlotIndexB].skillGroupID);
  764.  
  765. LinkUpdate(newColorA, oldColorA);
  766. LinkUpdate(newColorB, oldColorB);
  767. }
  768.  
  769. private final function Alchemy19OptimizationRetro()
  770. {
  771. var i : int;
  772. var mutagenItemID : SItemUniqueId;
  773.  
  774. //remove existing bonuses
  775. for( i=0; i<mutagenSlots.Size(); i+=1 )
  776. {
  777. mutagenItemID = GetMutagenItemIDFromGroupID( mutagenSlots[i].skillGroupID );
  778. if( owner.GetInventory().IsIdValid( mutagenItemID ) )
  779. {
  780. owner.RemoveAbilityAll( GetMutagenBonusAbilityName( mutagenItemID ) );
  781. }
  782. }
  783.  
  784. //initialize system
  785. mutagenBonuses.Resize( GetSkillGroupsCount() + 1 );
  786.  
  787. //add existing bonuses
  788. if( CanUseSkill( S_Alchemy_s19 ) )
  789. {
  790. MutagensSyngergyBonusUpdate( -1, GetSkillLevel( S_Alchemy_s19 ) );
  791. }
  792. }
  793.  
  794. //Called to update mutagen bonus from S_Alchemy_s19 skill.
  795. //skillGroupID == -1 means all slots
  796. private final function MutagensSyngergyBonusUpdate( skillGroupID : int, skillLevel : int )
  797. {
  798. var i : int;
  799.  
  800. if( skillGroupID != -1 )
  801. {
  802. MutagensSyngergyBonusUpdateSingle( skillGroupID, skillLevel );
  803. }
  804. else
  805. {
  806. for( i=0; i<mutagenSlots.Size(); i+=1 )
  807. {
  808. MutagensSyngergyBonusUpdateSingle( mutagenSlots[i].skillGroupID, skillLevel );
  809. }
  810. }
  811. }
  812.  
  813. //Called to update mutagen bonus from S_Alchemy_s19 skill for given slot group
  814. private final function MutagensSyngergyBonusUpdateSingle( skillGroupID : int, skillLevel : int )
  815. {
  816. var current : SMutagenBonusAlchemy19;
  817. var color : ESkillColor;
  818. var mutagenItemID : SItemUniqueId;
  819. var delta : int;
  820.  
  821. if( skillGroupID < 0 )
  822. {
  823. return;
  824. }
  825.  
  826. //calculate current bonus
  827. mutagenItemID = GetMutagenItemIDFromGroupID( skillGroupID );
  828.  
  829. if( owner.GetInventory().IsIdValid( mutagenItemID ) )
  830. {
  831. current.abilityName = GetMutagenBonusAbilityName( mutagenItemID );
  832.  
  833. if( skillLevel > 0 )
  834. {
  835. color = owner.GetInventory().GetSkillMutagenColor( mutagenItemID );
  836. current.count = skillLevel * GetSkillGroupColorCount(color, skillGroupID);
  837. }
  838. }
  839.  
  840. //if now has different type of bonus
  841. if( current.abilityName != mutagenBonuses[skillGroupID].abilityName )
  842. {
  843. //remove old if had any
  844. if( IsNameValid( mutagenBonuses[skillGroupID].abilityName ) && mutagenBonuses[skillGroupID].count > 0 )
  845. {
  846. owner.RemoveAbilityMultiple( mutagenBonuses[skillGroupID].abilityName, mutagenBonuses[skillGroupID].count );
  847. }
  848.  
  849. //add new if has any
  850. if( IsNameValid( current.abilityName ) && current.count > 0 )
  851. {
  852. owner.AddAbilityMultiple( current.abilityName, current.count );
  853. }
  854. }
  855. //if bonus type was not changed and it is any bonus
  856. else if( IsNameValid( current.abilityName ) )
  857. {
  858. //update count
  859. delta = current.count - mutagenBonuses[skillGroupID].count;
  860.  
  861. if( delta > 0 )
  862. {
  863. owner.AddAbilityMultiple( current.abilityName, delta );
  864. }
  865. else if( delta < 0 )
  866. {
  867. owner.RemoveAbilityMultiple( current.abilityName, -delta );
  868. }
  869. }
  870.  
  871. //save current bonus value
  872. mutagenBonuses[skillGroupID] = current;
  873. }
  874.  
  875. //returns name of ability holding "syngery" skill bonus for this mutagen
  876. public final function GetMutagenBonusAbilityName(mutagenItemId : SItemUniqueId) : name
  877. {
  878. var i : int;
  879. var abs : array<name>;
  880. owner.GetInventory().GetItemContainedAbilities(mutagenItemId, abs);
  881.  
  882. for(i=0; i<abs.Size(); i+=1)
  883. {
  884. if(theGame.GetDefinitionsManager().AbilityHasTag(abs[i], 'alchemy_s19'))
  885. return abs[i];
  886. }
  887. return '';
  888. }
  889.  
  890. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  891. ////////////////////////////////// ---=== @LINKS BETWEEN SKILLSLOTS ===--- //////////////////////////////////////////////////////
  892. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  893. /*
  894. private final function GetLinkColor(skillSlotIndex : int, dir : EDirectionZ) : ESkillColor
  895. {
  896. var ind : int;
  897. var color : ESkillColor;
  898.  
  899. ind = GetSkillIndex(skillSlots[skillSlotIndex].socketedSkill);
  900. if(ind < 0)
  901. return SC_Undefined;
  902.  
  903. if(dir == DZ_Left)
  904. color = skills[ind].linkLeft;
  905. else if(dir == DZ_Right)
  906. color = skills[ind].linkRight;
  907. else if(dir == DZ_Up || dir == DZ_Down)
  908. color = skills[ind].linkVertical;
  909.  
  910. if(color == SC_Socketable && HasSkillMutagen(skills[ind].skillType))
  911. color = theGame.GetDefinitionsManager().GetMutagenIngredientColor(skills[ind].equippedMutagenName);
  912.  
  913. return color;
  914. }
  915.  
  916. //given skill slot index and direction returns color of the opposite slot's link
  917. private final function GetLinkOppositeColor(skillSlotIndex : int, dir : EDirectionZ) : ESkillColor
  918. {
  919. var neighbourSlotID, neighbourSkillIndex : int;
  920.  
  921. switch(dir)
  922. {
  923. case DZ_Down :
  924. neighbourSlotID = skillSlots[skillSlotIndex].neighbourDown;
  925. break;
  926. case DZ_Up :
  927. neighbourSlotID = skillSlots[skillSlotIndex].neighbourUp;
  928. break;
  929. case DZ_Left :
  930. neighbourSlotID = skillSlots[skillSlotIndex].neighbourLeft;
  931. break;
  932. case DZ_Right :
  933. neighbourSlotID = skillSlots[skillSlotIndex].neighbourRight;
  934. break;
  935. }
  936.  
  937.  
  938. if(neighbourSlotID < 0)
  939. return SC_Undefined;
  940.  
  941. neighbourSkillIndex = GetSkillIndexFromSlotID(neighbourSlotID);
  942. if(neighbourSkillIndex < 0)
  943. return SC_Undefined;
  944.  
  945. switch(dir)
  946. {
  947. case DZ_Up :
  948. case DZ_Down : return skills[neighbourSkillIndex].linkVertical;
  949. case DZ_Left : return skills[neighbourSkillIndex].linkLeft;
  950. case DZ_Right : return skills[neighbourSkillIndex].linkRight;
  951. }
  952. }*/
  953.  
  954. public final function GetSkillGroupIdFromSkill( skillType : ESkill ) : int
  955. {
  956. var i : int;
  957.  
  958. for(i=0; i<skillSlots.Size(); i+=1)
  959. {
  960. if(skillSlots[i].socketedSkill == skillType)
  961. {
  962. return skillSlots[i].groupID;
  963. }
  964. }
  965.  
  966. return -1;
  967. }
  968.  
  969. public final function GetSkillGroupIdFromSkillSlotId(skillSlotId : int) : int
  970. {
  971. var i : int;
  972.  
  973. for(i=0; i<skillSlots.Size(); i+=1)
  974. {
  975. if(skillSlots[i].id == skillSlotId)
  976. {
  977. return skillSlots[i].groupID;
  978. }
  979. }
  980.  
  981. return -1;
  982. }
  983.  
  984. public final function GetMutagenItemIDFromGroupID( skillGroupID : int ) : SItemUniqueId
  985. {
  986. var i : int;
  987.  
  988. for( i=0; i<mutagenSlots.Size(); i+=1 )
  989. {
  990. if( mutagenSlots[i].skillGroupID == skillGroupID )
  991. {
  992. return mutagenSlots[i].item;
  993. }
  994. }
  995.  
  996. return GetInvalidUniqueId();
  997. }
  998.  
  999. public function GetMutagenSlotIDFromGroupID(groupID : int) : int
  1000. {
  1001. return GetMutagenSlotForGroupId(groupID);
  1002. }
  1003.  
  1004. public final function GetGroupBonus(groupID : int) : name
  1005. {
  1006. var groupColor : ESkillColor;
  1007. var item : SItemUniqueId;
  1008.  
  1009. groupColor = GetSkillGroupColor(groupID);
  1010.  
  1011. /*if(groupColor != SC_None)
  1012. {
  1013. //if mutagen overrides color then there is no basic bonus
  1014. if(GetWitcherPlayer().GetItemEquippedOnSlot(GetMutagenSlotForGroupId(groupID), item))
  1015. return '';
  1016. }*/
  1017.  
  1018. switch (groupColor)
  1019. {
  1020. case SC_None: return '';
  1021. case SC_Blue: return LINK_BONUS_BLUE;
  1022. case SC_Green: return LINK_BONUS_GREEN;
  1023. case SC_Red: return LINK_BONUS_RED;
  1024. }
  1025. }
  1026.  
  1027. //returns color of the whole group
  1028. public final function GetSkillGroupColor(groupID : int) : ESkillColor
  1029. {
  1030. var i : int;
  1031. var commonColor : ESkillColor;
  1032. var mutagenSlot : EEquipmentSlots;
  1033. var skillColors : array<ESkillColor>;
  1034. var item : SItemUniqueId;
  1035.  
  1036. //get skills' colors
  1037. for(i=0; i<skillSlots.Size(); i+=1)
  1038. {
  1039. if(skillSlots[i].unlocked && skillSlots[i].groupID == groupID)
  1040. {
  1041. skillColors.PushBack(GetSkillColor(skillSlots[i].socketedSkill));
  1042. }
  1043. }
  1044.  
  1045. //check for common color
  1046. commonColor = SC_None;
  1047. for(i=0; i<skillColors.Size(); i+=1)
  1048. {
  1049. if(skillColors[i] != SC_None && skillColors[i] != SC_Yellow) //color not set (bug?) or perk
  1050. {
  1051. if(commonColor == SC_None)
  1052. {
  1053. commonColor = skillColors[i];
  1054. }
  1055. else if(skillColors[i] != commonColor)
  1056. {
  1057. //bonus broken
  1058. commonColor = SC_None;
  1059. break;
  1060. }
  1061. }
  1062. }
  1063.  
  1064. //no bonus
  1065. if(commonColor == SC_None)
  1066. return SC_None;
  1067.  
  1068. //if bonus, check for mutagen override
  1069. mutagenSlot = GetMutagenSlotForGroupId(groupID);
  1070. if(IsSkillMutagenSlotUnlocked(mutagenSlot))
  1071. {
  1072. if(GetWitcherPlayer().GetItemEquippedOnSlot(mutagenSlot, item))
  1073. return owner.GetInventory().GetSkillMutagenColor( item );
  1074. }
  1075.  
  1076. return commonColor;
  1077. }
  1078.  
  1079. //returns color of the whole group - how many common color
  1080. public final function GetSkillGroupColorCount(commonColor : ESkillColor, groupID : int) : ESkillColor
  1081. {
  1082. var count, i : int;
  1083. var mutagenSlot : EEquipmentSlots;
  1084. var skillColors : array<ESkillColor>;
  1085. var item : SItemUniqueId;
  1086.  
  1087. //get skills' colors
  1088. for(i=0; i<skillSlots.Size(); i+=1)
  1089. {
  1090. if(skillSlots[i].unlocked && skillSlots[i].groupID == groupID && skillSlots[i].socketedSkill != S_SUndefined )
  1091. {
  1092. skillColors.PushBack(GetSkillColor(skillSlots[i].socketedSkill));
  1093. }
  1094. }
  1095.  
  1096. //check for common color
  1097. count = 0;
  1098. for(i=0; i<skillColors.Size(); i+=1)
  1099. {
  1100. if(skillColors[i] == commonColor ) //color not set (bug?) or perk
  1101. {
  1102. count = count + 1;
  1103. }
  1104. }
  1105.  
  1106. return count;
  1107. }
  1108.  
  1109. //checks which bonus to update on given link and calls update
  1110. private final function LinkUpdate(newColor : ESkillColor, prevColor : ESkillColor)
  1111. {
  1112. //no change
  1113. if(newColor == prevColor)
  1114. return;
  1115.  
  1116. //remove previous link and add current
  1117. UpdateLinkBonus(prevColor, false);
  1118. UpdateLinkBonus(newColor, true);
  1119. }
  1120.  
  1121. //updates link bonus
  1122. private final function UpdateLinkBonus(a : ESkillColor, added : bool)
  1123. {
  1124. return;
  1125. if(added)
  1126. {
  1127. if(a == SC_Blue)
  1128. charStats.AddAbility(LINK_BONUS_BLUE, true);
  1129. else if(a == SC_Green)
  1130. charStats.AddAbility(LINK_BONUS_GREEN, true);
  1131. else if(a == SC_Red)
  1132. charStats.AddAbility(LINK_BONUS_RED, true);
  1133. }
  1134. else
  1135. {
  1136. if(a == SC_Blue)
  1137. charStats.RemoveAbility(LINK_BONUS_BLUE);
  1138. else if(a == SC_Green)
  1139. charStats.RemoveAbility(LINK_BONUS_GREEN);
  1140. else if(a == SC_Red)
  1141. charStats.RemoveAbility(LINK_BONUS_RED);
  1142. }
  1143. }
  1144.  
  1145. public final function GetSkillColor(skill : ESkill) : ESkillColor
  1146. {
  1147. switch(skills[skill].skillPath)
  1148. {
  1149. case ESP_Sword : return SC_Red;
  1150. case ESP_Signs : return SC_Blue;
  1151. case ESP_Alchemy : return SC_Green;
  1152. case ESP_Perks : return SC_Yellow;
  1153. default : return SC_None;
  1154. }
  1155. }
  1156.  
  1157. /*
  1158. public final function GetSkillLinkColorVertical(skill : ESkill, out color : ESkillColor, out isJoker : bool)
  1159. {
  1160. var ind : int;
  1161.  
  1162. ind = GetSkillIndex(skill);
  1163. if(ind < 0)
  1164. {
  1165. isJoker = false;
  1166. color = SC_Undefined;
  1167. }
  1168. else
  1169. {
  1170. //TODO
  1171. color = skills[ind].linkVertical;
  1172. isJoker = false;
  1173. }
  1174. }
  1175.  
  1176. public final function GetSkillLinkColorLeft(skill : ESkill, out color : ESkillColor, out isJoker : bool)
  1177. {
  1178. var ind : int;
  1179.  
  1180. ind = GetSkillIndex(skill);
  1181. if(ind < 0)
  1182. {
  1183. isJoker = false;
  1184. color = SC_Undefined;
  1185. }
  1186. else
  1187. {
  1188. //TODO
  1189. color = skills[ind].linkLeft;
  1190. isJoker = false;
  1191. }
  1192. }
  1193.  
  1194. public final function GetSkillLinkColorRight(skill : ESkill, out color : ESkillColor, out isJoker : bool)
  1195. {
  1196. var ind : int;
  1197.  
  1198.  
  1199. ind = GetSkillIndex(skill);
  1200. if(ind < 0)
  1201. {
  1202. isJoker = false;
  1203. color = SC_Undefined;
  1204. }
  1205. else
  1206. {
  1207. //TODO
  1208. color = skills[ind].linkRight;
  1209. isJoker = false;
  1210. }
  1211. }*/
  1212.  
  1213. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1214. ////////////////////////////////// ---=== @SKILLS ===--- ///////////////////////////////////////////////////////////////////////
  1215. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1216.  
  1217. public final function GetSkillLevel(skill : ESkill) : int
  1218. {
  1219. return skills[skill].level;
  1220. }
  1221.  
  1222. public final function GetBoughtSkillLevel(skill : ESkill) : int
  1223. {
  1224. return skills[skill].level;
  1225. }
  1226.  
  1227. public final function GetSkillMaxLevel(skill : ESkill) : int
  1228. {
  1229. return skills[skill].maxLevel;
  1230. }
  1231.  
  1232. public final function GetSkillStaminaUseCost(skill : ESkill, optional isPerSec : bool) : float
  1233. {
  1234. var reductionCounter : int;
  1235. var ability, attributeName : name;
  1236. var ret, costReduction : SAbilityAttributeValue;
  1237.  
  1238. ability = '';
  1239.  
  1240. //search skills
  1241. if(CanUseSkill(skill))
  1242. ability = GetSkillAbilityName(skill);
  1243.  
  1244. if(isPerSec)
  1245. attributeName = theGame.params.STAMINA_COST_PER_SEC_DEFAULT;
  1246. else
  1247. attributeName = theGame.params.STAMINA_COST_DEFAULT;
  1248.  
  1249. ret = GetSkillAttributeValue(ability, attributeName, true, true);
  1250.  
  1251. //cost reduction
  1252. reductionCounter = GetSkillLevel(skill) - 1;
  1253. if(reductionCounter > 0)
  1254. {
  1255. costReduction = GetSkillAttributeValue(ability, 'stamina_cost_reduction_after_1', false, false) * reductionCounter;
  1256. ret -= costReduction;
  1257. }
  1258.  
  1259. if(gmConfig().enableMaxStaminaGet()) { return 0; } // ===== Added by God Mode mod - Module: Max Stamina =====
  1260.  
  1261. else
  1262. return CalculateAttributeValue(ret);
  1263. }
  1264.  
  1265. public final function GetSkillAttributeValue(abilityName: name, attributeName : name, addBaseCharAttribute : bool, addSkillModsAttribute : bool) : SAbilityAttributeValue
  1266. {
  1267. // OPTIMIZE
  1268. var min, max, ret : SAbilityAttributeValue;
  1269. var i, j : int;
  1270. var dm : CDefinitionsManagerAccessor;
  1271. var skill : SSkill;
  1272. var skillEnum : ESkill;
  1273. var skillLevel : int;
  1274.  
  1275. //value from skill ability
  1276. ret = super.GetSkillAttributeValue(abilityName, attributeName, addBaseCharAttribute, addSkillModsAttribute);
  1277.  
  1278. //bonus from other skills that modify this value
  1279. if(addSkillModsAttribute)
  1280. {
  1281. //find skill/perk/bookperk structure for given ability
  1282.  
  1283. skillEnum = SkillNameToEnum( abilityName );
  1284. if( skillEnum != S_SUndefined )
  1285. {
  1286. skill = skills[skillEnum];
  1287. }
  1288. else
  1289. {
  1290. LogAssert(false, "W3PlayerAbilityManager.GetSkillAttributeValue: cannot find skill for ability <<" + abilityName + ">>! Aborting");
  1291. return min;
  1292. }
  1293.  
  1294. dm = theGame.GetDefinitionsManager();
  1295.  
  1296. for( j = 0; j < skill.precachedModifierSkills.Size(); j += 1 )
  1297. {
  1298. i = skill.precachedModifierSkills[ j ];
  1299.  
  1300. if( CanUseSkill( skills[i].skillType ) )
  1301. {
  1302. dm.GetAbilityAttributeValue(skills[i].abilityName, attributeName, min, max);
  1303.  
  1304. skillLevel = GetSkillLevel(i);
  1305. ret += GetAttributeRandomizedValue( min * skillLevel, max * skillLevel );
  1306. }
  1307. }
  1308. }
  1309.  
  1310. //value from character stats
  1311. if(addBaseCharAttribute)
  1312. {
  1313. ret += GetAttributeValueInternal(attributeName);
  1314. }
  1315.  
  1316. return ret;
  1317. }
  1318.  
  1319. protected final function GetStaminaActionCostInternal(action : EStaminaActionType, isPerSec : bool, out cost : SAbilityAttributeValue, out delay : SAbilityAttributeValue, optional abilityName : name)
  1320. {
  1321. var attributeName : name;
  1322. var skill : ESkill;
  1323. var blizzard : W3Potion_Blizzard;
  1324.  
  1325. super.GetStaminaActionCostInternal(action, isPerSec, cost, delay, abilityName);
  1326.  
  1327. // +++++++++++++++++ Added by God Mode mod - Module: Max Stamina +++++++++++++++++
  1328. if(!gmConfig().enableMaxStaminaGet())
  1329. {
  1330. if(isPerSec)
  1331. {
  1332. attributeName = theGame.params.STAMINA_COST_PER_SEC_DEFAULT;
  1333. }
  1334. else
  1335. {
  1336. attributeName = theGame.params.STAMINA_COST_DEFAULT;
  1337. }
  1338.  
  1339. if(action == ESAT_LightAttack && CanUseSkill(S_Sword_1) )
  1340. cost += GetSkillAttributeValue(SkillEnumToName(S_Sword_1), attributeName, false, true);
  1341. else if(action == ESAT_HeavyAttack && CanUseSkill(S_Sword_2) )
  1342. cost += GetSkillAttributeValue(SkillEnumToName(S_Sword_2), attributeName, false, true);
  1343. else if ((action == ESAT_Sprint || action == ESAT_Jump) && thePlayer.HasBuff(EET_Mutagen24) && !thePlayer.IsInCombat())
  1344. {
  1345. cost.valueAdditive = 0;
  1346. cost.valueBase = 0;
  1347. cost.valueMultiplicative = 0;
  1348. }
  1349.  
  1350. //level 3 blizzard potion removes stamina cost if you also have battle trance and blizzard slowmo is active
  1351. if( thePlayer.HasBuff( EET_Blizzard ) && owner == GetWitcherPlayer() && GetWitcherPlayer().GetPotionBuffLevel( EET_Blizzard ) == 3 && thePlayer.HasBuff( EET_BattleTrance ) )
  1352. {
  1353. blizzard = ( W3Potion_Blizzard )thePlayer.GetBuff( EET_Blizzard );
  1354. if( blizzard.IsSlowMoActive() )
  1355. {
  1356. cost.valueAdditive = 0;
  1357. cost.valueBase = 0;
  1358. cost.valueMultiplicative = 0;
  1359. }
  1360. }
  1361. }
  1362. // ----------------- Added by God Mode mod - Module: Max Stamina -----------------
  1363. }
  1364. TK - apparently not wanted currently - commenting out entire final function
  1365.  
  1366. //returns action's stamina cost and delay
  1367. public final function GetStaminaActionCost(action : EStaminaActionType, out cost : float, out delay : float, optional fixedCost : float, optional fixedDelay : float, optional abilityName : name, optional dt : float, optional costMult : float)
  1368. {
  1369. super.GetStaminaActionCost(action, cost, delay, fixedCost, fixedDelay, abilityName, dt, costMult);
  1370.  
  1371. if(dt == 0)
  1372. {
  1373. //round up to full stamina segments if not a continuous mode
  1374. //cost = CeilF(cost / theGame.params.STAMINA_SEGMENT_SIZE) * theGame.params.STAMINA_SEGMENT_SIZE;
  1375. //i commented it because it was taking 10 stamina instead of 0.2.../ PF - which is as intended...
  1376. }
  1377. }
  1378. */
  1379.  
  1380. /*
  1381. Returns list of skill related abilities that the character has:
  1382. - only known skills
  1383. - only unblocked abilities
  1384. - all abilities having one of the tags passed (can be empty)
  1385. */
  1386. protected final function GetNonBlockedSkillAbilitiesList( optional tags : array<name> ) : array<name>
  1387. {
  1388. var i, j : int;
  1389. var ret : array<name>;
  1390. var dm : CDefinitionsManagerAccessor;
  1391. var abilityName : name;
  1392.  
  1393. if(tags.Size() == 0)
  1394. return ret;
  1395.  
  1396. dm = theGame.GetDefinitionsManager();
  1397. for(i=0; i<skillAbilities.Size(); i+=1) //skill abilities holds only abilities of equipped skills
  1398. {
  1399. abilityName = skillAbilities[i];
  1400.  
  1401. for(j=0; j<tags.Size(); j+=1)
  1402. {
  1403. if(dm.AbilityHasTag(abilityName, tags[j]))
  1404. {
  1405. ret.PushBack(abilityName);
  1406. }
  1407. }
  1408. }
  1409.  
  1410. return ret;
  1411. }
  1412.  
  1413. public final function IsSkillBlocked(skill : ESkill) : bool
  1414. {
  1415. return skills[skill].remainingBlockedTime != 0;
  1416. }
  1417.  
  1418. //returns true if lock changed state
  1419. public final function BlockSkill(skill : ESkill, block : bool, optional cooldown : float) : bool
  1420. {
  1421. var i : int;
  1422. var min : float;
  1423.  
  1424. if(block)
  1425. {
  1426. if(skills[skill].remainingBlockedTime == -1 || (cooldown > 0 && cooldown <= skills[skill].remainingBlockedTime) )
  1427. return false; //already locked for good or locked for longer
  1428.  
  1429. //lock
  1430. if(cooldown > 0)
  1431. skills[skill].remainingBlockedTime = cooldown;
  1432. else
  1433. skills[skill].remainingBlockedTime = -1;
  1434.  
  1435. //find next timer call time
  1436. min = 1000000;
  1437. for(i=0; i<skills.Size(); i+=1)
  1438. {
  1439. if(skills[i].remainingBlockedTime > 0)
  1440. {
  1441. min = MinF(min, skills[i].remainingBlockedTime);
  1442. }
  1443. }
  1444.  
  1445. //schedule next update
  1446. if(min != 1000000)
  1447. GetWitcherPlayer().AddTimer('CheckBlockedSkills', min, , , , true);
  1448.  
  1449. //also block skill's ability
  1450. if(theGame.GetDefinitionsManager().IsAbilityDefined(skills[skill].abilityName) && charStats.HasAbility(skills[skill].abilityName))
  1451. BlockAbility(GetSkillAbilityName(skill), block, cooldown);
  1452.  
  1453. if(IsSkillEquipped(skill))
  1454. OnSkillUnequip(skill);
  1455.  
  1456. return true;
  1457. }
  1458. else
  1459. {
  1460. if(skills[skill].remainingBlockedTime == 0)
  1461. return false; //already unlocked
  1462.  
  1463. skills[skill].remainingBlockedTime = 0;
  1464.  
  1465. if(theGame.GetDefinitionsManager().IsAbilityDefined(skills[skill].abilityName) && charStats.HasAbility(skills[skill].abilityName))
  1466. BlockAbility(GetSkillAbilityName(skill), false);
  1467.  
  1468. if(IsSkillEquipped(skill))
  1469. OnSkillEquip(skill);
  1470.  
  1471. return true;
  1472. }
  1473. }
  1474.  
  1475. // Runs through all skills and checks their cooldowns. Unblocks those that have their cooldown finished.
  1476. // Returns time till next call or -1 if no calls needed
  1477. public final function CheckBlockedSkills(dt : float) : float
  1478. {
  1479. var i : int;
  1480. var cooldown, min : float;
  1481.  
  1482. min = 1000000;
  1483. for(i=0; i<skills.Size(); i+=1)
  1484. {
  1485. if(skills[i].remainingBlockedTime > 0)
  1486. {
  1487. skills[i].remainingBlockedTime = MaxF(0, skills[i].remainingBlockedTime - dt);
  1488.  
  1489. if(skills[i].remainingBlockedTime == 0)
  1490. {
  1491. BlockSkill(skills[i].skillType, false);
  1492. }
  1493. else
  1494. {
  1495. min = MinF(min, skills[i].remainingBlockedTime);
  1496. }
  1497. }
  1498. }
  1499.  
  1500. if(min == 1000000)
  1501. min = -1;
  1502.  
  1503. return min;
  1504. }
  1505.  
  1506. //@Override
  1507. public final function BlockAbility(abilityName : name, block : bool, optional cooldown : float) : bool
  1508. {
  1509. var i : int;
  1510.  
  1511. if( super.BlockAbility(abilityName, block, cooldown))
  1512. {
  1513. //if ability was blocked then remove it from cached arrays
  1514. if(block)
  1515. {
  1516. skillAbilities.Remove(abilityName);
  1517. }
  1518. else
  1519. {
  1520. //if added then if it's a skill ability then put it to proper cached array
  1521. for(i=0; i<skills.Size(); i+=1)
  1522. {
  1523. if(skills[i].abilityName == abilityName)
  1524. {
  1525. if(!theGame.GetDefinitionsManager().AbilityHasTag(skills[i].abilityName, theGame.params.SKILL_GLOBAL_PASSIVE_TAG))
  1526. skillAbilities.PushBack(abilityName);
  1527.  
  1528. break;
  1529. }
  1530. }
  1531. }
  1532.  
  1533. return true;
  1534. }
  1535.  
  1536. return false;
  1537. }
  1538.  
  1539. //adds all initial skills to the player
  1540. protected final function InitSkills()
  1541. {
  1542. var atts : array<name>;
  1543. var i, size : int;
  1544. var skillEnum : ESkill;
  1545.  
  1546. charStats.GetAllContainedAbilities(atts);
  1547. size = atts.Size();
  1548. for( i = 0; i < size; i += 1 )
  1549. {
  1550. skillEnum = SkillNameToEnum( atts[i] );
  1551. if( skillEnum != S_SUndefined )
  1552. {
  1553. if( !IsAbilityBlocked( atts[i] ) )
  1554. {
  1555. AddSkillInternal( skillEnum, false, false, true );
  1556. }
  1557. continue;
  1558. }
  1559. }
  1560. }
  1561.  
  1562. protected final function IsCoreSkill(skill : ESkill) : bool
  1563. {
  1564. return skills[skill].isCoreSkill;
  1565. }
  1566.  
  1567. // Loads a single skill definition for this player from the XML and caches it (basically loads all skills data)
  1568. protected final function CacheSkills(skillDefinitionName : name, out cache : array<SSkill>)
  1569. {
  1570. var dm : CDefinitionsManagerAccessor;
  1571. var main, sks : SCustomNode;
  1572. var i, size, size2, j : int;
  1573. var skillType : ESkill;
  1574. var bFound : bool;
  1575. var tmpName : name;
  1576. var skillDefs : array<name>;
  1577.  
  1578. dm = theGame.GetDefinitionsManager();
  1579. sks = dm.GetCustomDefinition('skills');
  1580.  
  1581. //find definition
  1582. bFound = false;
  1583. size = sks.subNodes.Size();
  1584. cache.Clear();
  1585. cache.Resize( S_Perk_MAX );
  1586. for( i = 0; i < size; i += 1 )
  1587. {
  1588. if(dm.GetCustomNodeAttributeValueName(sks.subNodes[i], 'def_name', tmpName))
  1589. {
  1590. if(tmpName == skillDefinitionName)
  1591. {
  1592. bFound = true;
  1593. main = sks.subNodes[i];
  1594.  
  1595. //do the caching
  1596. size2 = main.subNodes.Size();
  1597. for( j = 0; j < size2; j += 1 )
  1598. {
  1599. dm.GetCustomNodeAttributeValueName(main.subNodes[j], 'skill_name', tmpName);
  1600. skillType = SkillNameToEnum(tmpName);
  1601.  
  1602. if( skillType != S_SUndefined )
  1603. {
  1604. if( cache[skillType].skillType == skillType )
  1605. {
  1606. LogChannel('Skills', "W3AbilityManager.CacheSkills: actor's <<" + this + ">> skill <<" + skillType + ">> is already defined!!! Skipping!!!");
  1607. continue;
  1608. }
  1609.  
  1610. CacheSkill( skillType, tmpName, main.subNodes[j], cache[skillType] );
  1611. }
  1612. else
  1613. {
  1614. LogAssert(false, "W3PlayerAbilityManager.CacheSkills: skill <<" + tmpName + ">> is not defined in PST enum, ignoring skill!");
  1615. }
  1616. }
  1617. }
  1618. }
  1619. }
  1620.  
  1621. if( !bFound )
  1622. {
  1623. LogAssert(false, "W3AbilityManager.CacheSkills: cannot find skill definition named <<" + skillDefinitionName + ">> aborting!");
  1624. }
  1625. }
  1626.  
  1627. private final function CacheSkill( skillType : int, abilityName : name, definitionNode : SCustomNode, out skill : SSkill )
  1628. {
  1629. var dm : CDefinitionsManagerAccessor = theGame.GetDefinitionsManager();
  1630. var modifiers, reqSkills : SCustomNode;
  1631. var pathType : ESkillPath;
  1632. var subpathType : ESkillSubPath;
  1633. var tmpName : name;
  1634. var tmpInt, k, size : int;
  1635. var tmpString : string;
  1636. var tmpBool : bool;
  1637.  
  1638. skill.wasEquippedOnUIEnter = false;
  1639. skill.level = 0;
  1640.  
  1641. //skill type
  1642. skill.skillType = skillType;
  1643. skill.abilityName = abilityName;
  1644.  
  1645. //path type
  1646. if(dm.GetCustomNodeAttributeValueName(definitionNode, 'pathType_name', tmpName))
  1647. {
  1648. pathType = SkillPathNameToType(tmpName);
  1649. if(pathType != ESP_NotSet)
  1650. skill.skillPath = pathType;
  1651. else if(skill.skillType != S_Perk_08) //perk 08 is a hidden skill now
  1652. LogAssert(false, "W3PlayerAbilityManager.CacheSkill: skill <<" + skill.skillType + ">> has wrong path type set <<" + tmpName + ">>");
  1653. }
  1654.  
  1655. //subpath type
  1656. if(dm.GetCustomNodeAttributeValueName(definitionNode, 'subpathType_name', tmpName))
  1657. {
  1658. subpathType = SkillSubPathNameToType(tmpName);
  1659. if(subpathType != ESSP_NotSet)
  1660. skill.skillSubPath = subpathType;
  1661. else if(skill.skillType != S_Perk_08) //perk 08 is a hidden skill now
  1662. LogAssert(false, "W3PlayerAbilityManager.CacheSkill: skill <<" + skill.skillType + ">> has wrong subpath type set <<" + tmpName + ">>");
  1663. }
  1664.  
  1665. //required skills list
  1666. reqSkills = dm.GetCustomDefinitionSubNode(definitionNode,'required_skills');
  1667. if(reqSkills.values.Size() > 0)
  1668. {
  1669. size = reqSkills.values.Size();
  1670. for(k=0; k<size; k+=1)
  1671. {
  1672. if(IsNameValid(reqSkills.values[k]))
  1673. {
  1674. skill.requiredSkills.PushBack(SkillNameToEnum(reqSkills.values[k]));
  1675. }
  1676. }
  1677. }
  1678.  
  1679. //required skills 'mode'
  1680. if(dm.GetCustomNodeAttributeValueBool(reqSkills, 'isAlternative', tmpBool))
  1681. skill.requiredSkillsIsAlternative = tmpBool;
  1682.  
  1683. //skill priority used for autoleveling
  1684. if(dm.GetCustomNodeAttributeValueInt(definitionNode, 'priority', tmpInt))
  1685. skill.priority = tmpInt;
  1686.  
  1687. //required points spent in same path
  1688. if(dm.GetCustomNodeAttributeValueInt(definitionNode, 'requiredPointsSpent', tmpInt))
  1689. skill.requiredPointsSpent = tmpInt;
  1690.  
  1691. //localisation
  1692. if(dm.GetCustomNodeAttributeValueString(definitionNode, 'localisationName', tmpString))
  1693. skill.localisationNameKey = tmpString;
  1694. if(dm.GetCustomNodeAttributeValueString(definitionNode, 'localisationDescription', tmpString))
  1695. skill.localisationDescriptionKey = tmpString;
  1696. if(dm.GetCustomNodeAttributeValueString(definitionNode, 'localisationDescriptionLevel2', tmpString))
  1697. skill.localisationDescriptionLevel2Key = tmpString;
  1698. if(dm.GetCustomNodeAttributeValueString(definitionNode, 'localisationDescriptionLevel3', tmpString))
  1699. skill.localisationDescriptionLevel3Key = tmpString;
  1700.  
  1701. //cost
  1702. if(dm.GetCustomNodeAttributeValueInt(definitionNode, 'cost', tmpInt))
  1703. skill.cost = tmpInt;
  1704.  
  1705. //maxLevel
  1706. if(dm.GetCustomNodeAttributeValueInt(definitionNode, 'maxLevel', tmpInt))
  1707. skill.maxLevel = tmpInt;
  1708. else
  1709. skill.maxLevel = 1;
  1710.  
  1711. //is core skill
  1712. if(dm.GetCustomNodeAttributeValueBool(definitionNode, 'isCoreSkill', tmpBool))
  1713. skill.isCoreSkill = tmpBool;
  1714.  
  1715. //GUI ID
  1716. if(dm.GetCustomNodeAttributeValueInt(definitionNode, 'guiPositionID', tmpInt))
  1717. skill.positionID = tmpInt;
  1718.  
  1719. //modifier tags
  1720. modifiers = dm.GetCustomDefinitionSubNode(definitionNode,'modifier_tags');
  1721. if(modifiers.values.Size() > 0)
  1722. {
  1723. size = modifiers.values.Size();
  1724. for(k=0; k<size; k+=1)
  1725. {
  1726. if(IsNameValid(modifiers.values[k]))
  1727. {
  1728. skill.modifierTags.PushBack(modifiers.values[k]);
  1729. }
  1730. }
  1731. }
  1732.  
  1733. //icon
  1734. if(dm.GetCustomNodeAttributeValueString(definitionNode, 'iconPath', tmpString))
  1735. skill.iconPath = tmpString;
  1736.  
  1737. //link colors
  1738. /*
  1739. if(!skill.isCoreSkill)
  1740. {
  1741. if(dm.GetCustomNodeAttributeValueString(main.subNodes[i], 'linkVertical', tmpString))
  1742. skill.linkVertical = LinkStringToType(tmpString);
  1743.  
  1744. if(dm.GetCustomNodeAttributeValueString(main.subNodes[i], 'linkLeft', tmpString))
  1745. skill.linkLeft = LinkStringToType(tmpString);
  1746.  
  1747. if(dm.GetCustomNodeAttributeValueString(main.subNodes[i], 'linkRight', tmpString))
  1748. skill.linkRight = LinkStringToType(tmpString);
  1749. }*/
  1750. }
  1751.  
  1752. private final function LoadMutagenSlotsDataFromXML()
  1753. {
  1754. var mut : SCustomNode;
  1755. var i : int;
  1756. var mutagen : SMutagenSlot;
  1757. var dm : CDefinitionsManagerAccessor;
  1758.  
  1759. // +++++++++++++++++ Added by God Mode mod - Module: Mutagen Unlock +++++++++++++++++
  1760. var minLevelUnlock : int;
  1761. minLevelUnlock = gmConfig().levelMutagenUnlockGet();
  1762. // ----------------- Added by God Mode mod - Module: Mutagen Unlock -----------------
  1763.  
  1764. dm = theGame.GetDefinitionsManager();
  1765. mut = dm.GetCustomDefinition('mutagen_slots');
  1766.  
  1767. for(i=0; i<mut.subNodes.Size(); i+=1)
  1768. {
  1769. dm.GetCustomNodeAttributeValueInt(mut.subNodes[i], 'skillGroup', mutagen.skillGroupID);
  1770.  
  1771. // +++++++++++++++++ Added by God Mode mod - Module: Mutagen Unlock +++++++++++++++++
  1772. if(gmConfig().enableMutagenUnlockGet())
  1773. dm.GetCustomNodeAttributeValueInt(mut.subNodes[i], 'unlockedAtLevel', minLevelUnlock);
  1774. else
  1775. dm.GetCustomNodeAttributeValueInt(mut.subNodes[i], 'unlockedAtLevel', mutagen.unlockedAtLevel);
  1776. // ----------------- Added by God Mode mod - Module: Mutagen Unlock -----------------
  1777.  
  1778. mutagen.item = GetInvalidUniqueId();
  1779. mutagen.equipmentSlot = EES_SkillMutagen1 + i;
  1780.  
  1781. if(mutagen.equipmentSlot > EES_SkillMutagen4)
  1782. {
  1783. LogAssert(false, "W3PlayerAbilityManager.LoadMutagenSlotsDataFromXML: too many slots defined in XML!!! Aborting");
  1784. return;
  1785. }
  1786.  
  1787. mutagenSlots.PushBack(mutagen);
  1788. }
  1789. }
  1790.  
  1791. //Acquires skill.
  1792. //The temporary flag informs that the skill was not developed through character development but as a temporary bonus and will be lost soon
  1793. public final function AddSkill(skill : ESkill, isTemporary : bool)
  1794. {
  1795. var i : int;
  1796. var learnedAll, ret : bool;
  1797. var tree : ESkillPath;
  1798. var uiStateCharDev : W3TutorialManagerUIHandlerStateCharacterDevelopment;
  1799. var uiStateSpecialAttacks : W3TutorialManagerUIHandlerStateSpecialAttacks;
  1800.  
  1801. ret = AddSkillInternal(skill, true, isTemporary);
  1802.  
  1803. if(!ret)
  1804. return;
  1805.  
  1806. //dendrology achievement - fully develop one skill tree
  1807. if( !isTemporary )
  1808. {
  1809. learnedAll = true;
  1810. tree = GetSkillPathType(skill);
  1811. for(i=0; i<skills.Size(); i+=1)
  1812. {
  1813. if( skills[i].skillPath == tree && ( skills[i].level == 0 || skills[i].isTemporary ) )
  1814. {
  1815. learnedAll = false;
  1816. break;
  1817. }
  1818. }
  1819.  
  1820. if(learnedAll)
  1821. theGame.GetGamerProfile().AddAchievement(EA_Dendrology);
  1822. }
  1823.  
  1824. //tutorial
  1825. if(ShouldProcessTutorial('TutorialCharDevBuySkill'))
  1826. {
  1827. uiStateCharDev = (W3TutorialManagerUIHandlerStateCharacterDevelopment)theGame.GetTutorialSystem().uiHandler.GetCurrentState();
  1828. if(uiStateCharDev)
  1829. {
  1830. uiStateCharDev.OnBoughtSkill(skill);
  1831. }
  1832. }
  1833. if(ShouldProcessTutorial('TutorialSpecialAttacks') || ShouldProcessTutorial('TutorialAlternateSigns'))
  1834. {
  1835. uiStateSpecialAttacks = (W3TutorialManagerUIHandlerStateSpecialAttacks)theGame.GetTutorialSystem().uiHandler.GetCurrentState();
  1836. if(uiStateSpecialAttacks)
  1837. uiStateSpecialAttacks.OnBoughtSkill(skill);
  1838. }
  1839.  
  1840. if( MustEquipSkill(skill) )
  1841. ForceEquipSkill(skill);
  1842.  
  1843. }
  1844.  
  1845. protected final function AddSkillInternal(skill : ESkill, spendPoints : bool, isTemporary : bool, optional skipTutorialMessages : bool) : bool
  1846. {
  1847. if(skill == S_SUndefined )
  1848. {
  1849. LogAssert(false,"W3AbilityManager.AddSkill: trying to add undefined skill, aborting!");
  1850. return false;
  1851. }
  1852. if(HasLearnedSkill(skill) && skills[skill].level >= skills[skill].maxLevel)
  1853. {
  1854. LogAssert(false,"W3AbilityManager.AddSkill: trying to add skill already known <<" + SkillEnumToName(skill) + ">>, aborting!");
  1855. return false;
  1856. }
  1857.  
  1858. //add skill
  1859. skills[skill].level += 1;
  1860. skills[skill].isTemporary = isTemporary;
  1861.  
  1862. //add path point spent if not core skill
  1863. if(!skills[skill].isCoreSkill)
  1864. pathPointsSpent[skills[skill].skillPath] = pathPointsSpent[skills[skill].skillPath] + 1;
  1865.  
  1866. if(!isTemporary)
  1867. {
  1868. LogSkills("Skill <<" + skills[skill].abilityName + ">> learned");
  1869.  
  1870. if(spendPoints)
  1871. ((W3PlayerWitcher)owner).levelManager.SpendPoints(ESkillPoint, skills[skill].cost);
  1872. if ( this.IsSkillEquipped(skill) )
  1873. OnSkillEquippedLevelChange(skill, GetSkillLevel(skill) - 1, GetSkillLevel(skill));
  1874. theTelemetry.LogWithValueStr(TE_HERO_SKILL_UP, SkillEnumToName(skill));
  1875. }
  1876.  
  1877. //PerksActive
  1878. if(activeSkills.Contains(skill))
  1879. {
  1880. if(skills[skill].level > 1) OnSkillUnequip(skill);
  1881. OnSkillEquip(skill);
  1882. }
  1883. //PerksActive
  1884.  
  1885. return true;
  1886. }
  1887.  
  1888. //removes temporary skill granted through another skill's bonus
  1889. //FIXME - update for skill slots - used by non-tutorial testing fakes and skill_swors_s19
  1890. public final function RemoveTemporarySkill(skill : SSimpleSkill) : bool
  1891. {
  1892. var ind : int;
  1893.  
  1894. LogAssert( skill.skillType >= S_SUndefined, "W3AbilityManager.RemoveTemporarySkill: trying to remove undefined skill" );
  1895.  
  1896. if(!skills[skill.skillType].isCoreSkill)
  1897. pathPointsSpent[skills[skill.skillType].skillPath] = pathPointsSpent[skills[skill.skillType].skillPath] - (skills[skill.skillType].level - skill.level);
  1898.  
  1899. skills[skill.skillType].level = skill.level;
  1900.  
  1901. if(skills[skill.skillType].level < 1)
  1902. {
  1903. ind = GetSkillSlotID(skill.skillType);
  1904. if(ind >= 0)
  1905. UnequipSkill(ind);
  1906. }
  1907.  
  1908. tempSkills.Remove(skill.skillType);
  1909. return true;
  1910. }
  1911.  
  1912. public final function HasLearnedSkill(skill : ESkill) : bool
  1913. {
  1914. return skills[skill].level > 0;
  1915. }
  1916.  
  1917. private final function GetSkillFromAbilityName(abilityName : name) : ESkill
  1918. {
  1919. var i : int;
  1920.  
  1921. for(i=0; i<skills.Size(); i+=1)
  1922. if(skills[i].abilityName == abilityName)
  1923. return skills[i].skillType;
  1924.  
  1925. return S_SUndefined;
  1926. }
  1927.  
  1928. public final function CanLearnSkill(skill : ESkill) : bool
  1929. {
  1930. var j : int;
  1931. var hasSomeRequiredSkill : bool;
  1932.  
  1933. //if skill type is valid at all
  1934. if(skill == S_SUndefined)
  1935. return false;
  1936.  
  1937. //if skill is already known
  1938. if(skills[skill].level >= skills[skill].maxLevel)
  1939. return false;
  1940.  
  1941. //if requirements are not met
  1942. // #J removed this logic since it does not apply to current design
  1943. /*if(skills[skill].requiredSkills.Size() > 0)
  1944. {
  1945. if(skills[skill].requiredSkillsIsAlternative)
  1946. hasSomeRequiredSkill = false;
  1947. else
  1948. hasSomeRequiredSkill = true;
  1949.  
  1950. for(j=0; j<skills[skill].requiredSkills.Size(); j+=1)
  1951. {
  1952. if(skills[skill].requiredSkillsIsAlternative)
  1953. {
  1954. if(HasLearnedSkill(skills[skill].requiredSkills[j]))
  1955. {
  1956. hasSomeRequiredSkill = true;
  1957. break;
  1958. }
  1959. }
  1960. else if(!HasLearnedSkill(skills[skill].requiredSkills[j]))
  1961. {
  1962. return false; //conjunction check and some skill is missing
  1963. }
  1964. }
  1965.  
  1966. if(!hasSomeRequiredSkill)
  1967. return false; //alternative check and no skill is known
  1968. }*/
  1969.  
  1970. //path spent points requirement
  1971. if(skills[skill].requiredPointsSpent > 0 && pathPointsSpent[skills[skill].skillPath] < skills[skill].requiredPointsSpent)
  1972. return false;
  1973.  
  1974. //cost
  1975. if(((W3PlayerWitcher)owner).levelManager.GetPointsFree(ESkillPoint) < skills[skill].cost)
  1976. return false;
  1977.  
  1978. //all conditions ok
  1979. return true;
  1980. }
  1981.  
  1982. public final function HasSpentEnoughPoints(skill : ESkill) : bool // #J
  1983. {
  1984. if (skills[skill].requiredPointsSpent > 0 && pathPointsSpent[skills[skill].skillPath] < skills[skill].requiredPointsSpent)
  1985. {
  1986. return false;
  1987. }
  1988.  
  1989. return true;
  1990. }
  1991.  
  1992. public final function GetPathPointsSpent(skillPath : ESkillPath) : int
  1993. {
  1994. return pathPointsSpent[skillPath];
  1995. }
  1996.  
  1997. public final function PathPointsSpentInSkillPathOfSkill(skill : ESkill) : int // #J
  1998. {
  1999. return pathPointsSpent[skills[skill].skillPath];
  2000. }
  2001.  
  2002. // Returns ability name that this skill grants
  2003. public final function GetSkillAbilityName(skill : ESkill) : name
  2004. {
  2005. return skills[skill].abilityName;
  2006. }
  2007.  
  2008. public final function GetSkillLocalisationKeyName(skill : ESkill) : string //#B
  2009. {
  2010. return skills[skill].localisationNameKey;
  2011. }
  2012.  
  2013. public final function GetSkillLocalisationKeyDescription(skill : ESkill, optional level : int) : string //#B
  2014. {
  2015. switch (level)
  2016. {
  2017. case 2:
  2018. return skills[skill].localisationDescriptionLevel2Key;
  2019. case 3:
  2020. return skills[skill].localisationDescriptionLevel3Key;
  2021. case 4:
  2022. return skills[skill].localisationDescriptionLevel3Key;
  2023. case 5:
  2024. return skills[skill].localisationDescriptionLevel3Key;
  2025. default:
  2026. return skills[skill].localisationDescriptionKey;
  2027. }
  2028. }
  2029.  
  2030. public final function GetSkillIconPath(skill : ESkill) : string //#B
  2031. {
  2032. return skills[skill].iconPath;
  2033. }
  2034.  
  2035. public final function GetSkillSubPathType(skill : ESkill) : ESkillSubPath
  2036. {
  2037. return skills[skill].skillSubPath;
  2038. }
  2039.  
  2040. public final function GetSkillPathType(skill : ESkill) : ESkillPath
  2041. {
  2042. return skills[skill].skillPath;
  2043. }
  2044.  
  2045. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2046. ////////////////////////////////// ---=== @RESISTS ===--- //////////////////////////////////////////////////////////////////////
  2047. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2048.  
  2049. protected function GetItemResistStatIndex( slot : EEquipmentSlots, stat : ECharacterDefenseStats ) : int
  2050. {
  2051. var i, size : int;
  2052. size = resistStatsItems[slot].Size();
  2053. for ( i = 0; i < size; i+=1 )
  2054. {
  2055. if ( resistStatsItems[slot][i].type == stat )
  2056. {
  2057. return i;
  2058. }
  2059. }
  2060. return -1;
  2061. }
  2062.  
  2063. //@Override
  2064. //updates resist stat value - Overrides parent, we need to take armor durability into considreation
  2065. protected final function RecalcResistStat(stat : ECharacterDefenseStats)
  2066. {
  2067. var witcher : W3PlayerWitcher;
  2068. var item : SItemUniqueId;
  2069. var slot, idxItems : int;
  2070. var itemResists : array<ECharacterDefenseStats>;
  2071. var resistStat : SResistanceValue;
  2072.  
  2073. //take all resists
  2074. super.RecalcResistStat(stat);
  2075.  
  2076. //check if character can have item slots => durability
  2077. witcher = (W3PlayerWitcher)owner;
  2078. if(!witcher)
  2079. return;
  2080.  
  2081. GetResistStat( stat, resistStat );
  2082.  
  2083. for(slot=0; slot < resistStatsItems.Size(); slot+=1)
  2084. {
  2085. //get item if it has durability
  2086. if( witcher.GetItemEquippedOnSlot(slot, item) && witcher.inv.HasItemDurability(item))
  2087. {
  2088. itemResists = witcher.inv.GetItemResistanceTypes(item);
  2089. //check if item boosts resist stat
  2090. if(itemResists.Contains(stat))
  2091. {
  2092. //remove resists from items
  2093. resistStat.points.valueBase -= CalculateAttributeValue(witcher.inv.GetItemAttributeValue(item, ResistStatEnumToName(stat, true)));
  2094. resistStat.percents.valueBase -= CalculateAttributeValue(witcher.inv.GetItemAttributeValue(item, ResistStatEnumToName(stat, false)));
  2095.  
  2096. //calculate item durability modified resistances
  2097. SetItemResistStat(slot, stat);
  2098.  
  2099. //then add resists from items with durability modification
  2100. idxItems = GetItemResistStatIndex( slot, stat );
  2101. if(idxItems >= 0)
  2102. {
  2103. resistStat.percents.valueBase += CalculateAttributeValue(resistStatsItems[slot][idxItems].percents);
  2104. resistStat.points.valueBase += CalculateAttributeValue(resistStatsItems[slot][idxItems].points);
  2105. }
  2106. }
  2107. }
  2108. }
  2109.  
  2110. SetResistStat( stat, resistStat );
  2111. }
  2112.  
  2113. // Updates cached durability-modified item resist
  2114. private final function SetItemResistStat(slot : EEquipmentSlots, stat : ECharacterDefenseStats)
  2115. {
  2116. var item : SItemUniqueId;
  2117. var tempResist : SResistanceValue;
  2118. var witcher : W3PlayerWitcher;
  2119. var i : int;
  2120.  
  2121. witcher = (W3PlayerWitcher)owner;
  2122. if(!witcher)
  2123. return;
  2124.  
  2125. //get cached stat index
  2126. i = GetItemResistStatIndex( slot, stat );
  2127.  
  2128. //get equipped item
  2129. if( witcher.GetItemEquippedOnSlot(slot, item) && witcher.inv.HasItemDurability(item) )
  2130. {
  2131. //set item resist with durability
  2132. if(i >= 0)
  2133. {
  2134. //if this resist is already cached then update the value
  2135. witcher.inv.GetItemResistStatWithDurabilityModifiers(item, stat, resistStatsItems[slot][i].points, resistStatsItems[slot][i].percents);
  2136. }
  2137. else
  2138. {
  2139. //if this resist is not cached then add it to cached array
  2140. witcher.inv.GetItemResistStatWithDurabilityModifiers(item, stat, tempResist.points, tempResist.percents);
  2141. tempResist.type = stat;
  2142. resistStatsItems[slot].PushBack(tempResist);
  2143. }
  2144. }
  2145. else if(i >= 0)
  2146. {
  2147. //no item in that slot but something cached - delete the cached item resist
  2148. resistStatsItems[slot].Erase(i);
  2149. }
  2150. }
  2151.  
  2152. // called when item durability has changed to update the cached durability-modified resists from that item
  2153. public final function RecalcItemResistDurability(slot : EEquipmentSlots, itemId : SItemUniqueId)
  2154. {
  2155. var i : int;
  2156. var witcher : W3PlayerWitcher;
  2157. var itemResists : array<ECharacterDefenseStats>;
  2158.  
  2159. witcher = (W3PlayerWitcher)owner;
  2160. if(!witcher)
  2161. return;
  2162.  
  2163. itemResists = witcher.inv.GetItemResistanceTypes(itemId);
  2164. for(i=0; i<itemResists.Size(); i+=1)
  2165. {
  2166. if(itemResists[i] != CDS_None)
  2167. {
  2168. RecalcResistStatFromItem(itemResists[i], slot);
  2169. }
  2170. }
  2171. }
  2172.  
  2173. // updates resistances of given type from given item. When we call this we know that the item HAS NOT CHANGED
  2174. private final function RecalcResistStatFromItem(stat : ECharacterDefenseStats, slot : EEquipmentSlots)
  2175. {
  2176. var deltaResist, prevCachedResist : SResistanceValue;
  2177. var idx : int;
  2178. var resistStat : SResistanceValue;
  2179.  
  2180. idx = GetItemResistStatIndex( slot, stat );
  2181. prevCachedResist = resistStatsItems[slot][idx];
  2182.  
  2183. //calculate new item durability modified resistances
  2184. SetItemResistStat(slot, stat);
  2185.  
  2186. //get diff
  2187. deltaResist.points = resistStatsItems[slot][idx].points - prevCachedResist.points;
  2188. deltaResist.percents = resistStatsItems[slot][idx].percents - prevCachedResist.percents;
  2189.  
  2190. //update global resist
  2191. if ( GetResistStat( stat, resistStat ) )
  2192. {
  2193. resistStat.percents += deltaResist.percents;
  2194. resistStat.points += deltaResist.points;
  2195. SetResistStat( stat, resistStat );
  2196. }
  2197. }
  2198.  
  2199. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2200. ////////////////////////////////// ---=== @STATS ===--- ////////////////////////////////////////////////////////////////////////
  2201. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2202.  
  2203. public final function DrainStamina(action : EStaminaActionType, optional fixedCost : float, optional fixedDelay : float, optional abilityName : name, optional dt : float, optional costMult : float) : float
  2204. {
  2205. var cost : float;
  2206. var mutagen : W3Mutagen21_Effect;
  2207. var min, max : SAbilityAttributeValue;
  2208. var signEntity : W3SignEntity;
  2209.  
  2210. if(FactsDoesExist("debug_fact_stamina_boy"))
  2211. return 0;
  2212.  
  2213. if(gmConfig().enableMaxStaminaGet()) { return 0; } // ===== Added by God Mode mod - Module: Max Stamina =====
  2214.  
  2215. cost = super.DrainStamina(action, fixedCost, fixedDelay, abilityName, dt, costMult);
  2216.  
  2217. if(cost > 0 && dt > 0)
  2218. {
  2219. //if it's continuous cost then set up a timer that will do the flooring once the continuous cost stops
  2220. owner.AddTimer('AbilityManager_FloorStaminaSegment', 0.1, , , , true);
  2221. }
  2222.  
  2223. // Mutagen 21 - action costing stamina heal geralt, Whirl and Rend handled separately due to their hacks
  2224. if (cost > 0 && dt <= 0 && owner == thePlayer && thePlayer.HasBuff(EET_Mutagen21) && abilityName != 'sword_s1' && abilityName != 'sword_s2')
  2225. {
  2226. mutagen = (W3Mutagen21_Effect)thePlayer.GetBuff(EET_Mutagen21);
  2227. mutagen.Heal();
  2228. }
  2229.  
  2230. //Force abort sign cast if stamina reached 0. Otherwise if we have regen, stamina might regenerate before it is checked in
  2231. //next tick and as a result making even per tick test will always see your stamina >0
  2232. if(owner == GetWitcherPlayer() && GetStat(BCS_Stamina, true) <= 0.f)
  2233. {
  2234. signEntity = GetWitcherPlayer().GetSignEntity(GetWitcherPlayer().GetCurrentlyCastSign());
  2235.  
  2236. //don't abort if it's Quen from Mutation 11
  2237. if( !( ( W3QuenEntity ) signEntity ) || !owner.HasBuff( EET_Mutation11Buff ))// || !gmConfig().enableQuenNoBreakGet()) // ===== Added by God Mode mod - Module: Quen No Break =====
  2238. {
  2239. signEntity.OnSignAborted(true);
  2240. }
  2241. }
  2242.  
  2243. return cost;
  2244. }
  2245.  
  2246. public function GainStat( stat : EBaseCharacterStats, amount : float )
  2247. {
  2248. //while under runeword 8 effect, don't add focus
  2249. if(stat == BCS_Focus && owner.HasBuff(EET_Runeword8))
  2250. return;
  2251.  
  2252. super.GainStat(stat, amount);
  2253. }
  2254.  
  2255. //floors current stamina to full segment
  2256. public final function FloorStaminaSegment()
  2257. {
  2258. //someone forgot to disable stamina segments when they disabled stamina segments... I want to strangle them...
  2259. /*
  2260. var wastedStamina : float;
  2261.  
  2262. wastedStamina = ModF(GetStat(BCS_Stamina, true), theGame.params.STAMINA_SEGMENT_SIZE);
  2263. InternalReduceStat(BCS_Stamina, wastedStamina);
  2264. */
  2265. }
  2266.  
  2267. //needs to make a locked stamina check
  2268. public final function GetStat(stat : EBaseCharacterStats, optional skipLock : bool) : float
  2269. {
  2270. var value, lock : float;
  2271. var i : int;
  2272.  
  2273. value = super.GetStat(stat, skipLock);
  2274.  
  2275. if(stat == BCS_Toxicity && !skipLock && toxicityOffset > 0)
  2276. {
  2277. value += toxicityOffset;
  2278. }
  2279.  
  2280. // +++++++++++++++++ Added by God Mode mod - Module: Set Toxicity +++++++++++++++++
  2281. if(stat == BCS_Toxicity && gmConfig().enableSetToxicityGet())
  2282. {
  2283. value = GetStatMax(BCS_Toxicity) * gmConfig().percentSetToxicityGet() * .01;
  2284. }
  2285. // ----------------- Added by God Mode mod - Module: Set Toxicity ----------------
  2286.  
  2287. return value;
  2288. }
  2289.  
  2290. public final function AddToxicityOffset(val : float)
  2291. {
  2292. if(val > 0)
  2293. toxicityOffset += val;
  2294.  
  2295. // +++++++++++++++++ Added by God Mode mod - Module: Set Toxicity +++++++++++++++++
  2296. if(gmConfig().enableSetToxicityGet())
  2297. {
  2298. ForceSetStat(BCS_Toxicity, GetStatMax(BCS_Toxicity) * gmConfig().percentSetToxicityGet() * .01);
  2299. toxicityOffset = 0;
  2300. }
  2301. // ----------------- Added by God Mode mod - Module: Set Toxicity ----------------
  2302. }
  2303.  
  2304. public final function SetToxicityOffset( val : float)
  2305. {
  2306. if(val >= 0)
  2307. toxicityOffset = val;
  2308.  
  2309. // +++++++++++++++++ Added by God Mode mod - Module: Set Toxicity +++++++++++++++++
  2310. if(gmConfig().enableSetToxicityGet())
  2311. {
  2312. toxicityOffset = 0;
  2313. }
  2314. // ----------------- Added by God Mode mod - Module: Set Toxicity ----------------
  2315. }
  2316.  
  2317. public final function RemoveToxicityOffset(val : float)
  2318. {
  2319. if(val > 0)
  2320. toxicityOffset -= val;
  2321.  
  2322. if (toxicityOffset < 0)
  2323. toxicityOffset = 0;
  2324.  
  2325. // +++++++++++++++++ Added by God Mode mod - Module: Set Toxicity +++++++++++++++++
  2326. if(gmConfig().enableSetToxicityGet())
  2327. {
  2328. ForceSetStat(BCS_Toxicity, GetStatMax(BCS_Toxicity) * gmConfig().percentSetToxicityGet() * .01);
  2329. toxicityOffset = 0;
  2330. }
  2331. // ----------------- Added by God Mode mod - Module: Set Toxicity ----------------
  2332. }
  2333.  
  2334. // #Y TODO: Implement calculation
  2335. public final function GetOffenseStat():int
  2336. {
  2337. var steelDmg, silverDmg : float;
  2338. var steelCritChance, steelCritDmg : float;
  2339. var silverCritChance, silverCritDmg : float;
  2340. var attackPower : SAbilityAttributeValue;
  2341. var item : SItemUniqueId;
  2342. var value : SAbilityAttributeValue;
  2343.  
  2344. // steel and silve ap bonus
  2345. if (CanUseSkill(S_Sword_s04))
  2346. attackPower += GetSkillAttributeValue(SkillEnumToName(S_Sword_s04), PowerStatEnumToName(CPS_AttackPower), false, true) * GetSkillLevel(S_Sword_s04);
  2347. if (CanUseSkill(S_Sword_s21))
  2348. attackPower += GetSkillAttributeValue(SkillEnumToName(S_Sword_s21), PowerStatEnumToName(CPS_AttackPower), false, true) * GetSkillLevel(S_Sword_s21);
  2349. attackPower = attackPower * 0.5;
  2350.  
  2351. // steel and silve crit and crit dmg bonus
  2352. if (CanUseSkill(S_Sword_s08))
  2353. {
  2354. steelCritChance += CalculateAttributeValue(GetSkillAttributeValue(SkillEnumToName(S_Sword_s08), theGame.params.CRITICAL_HIT_CHANCE, false, true)) * GetSkillLevel(S_Sword_s08);
  2355. steelCritDmg += CalculateAttributeValue(GetSkillAttributeValue(SkillEnumToName(S_Sword_s08), theGame.params.CRITICAL_HIT_DAMAGE_BONUS, false, true)) * GetSkillLevel(S_Sword_s08);
  2356. }
  2357. if (CanUseSkill(S_Sword_s17))
  2358. {
  2359. steelCritChance += CalculateAttributeValue(GetSkillAttributeValue(SkillEnumToName(S_Sword_s17), theGame.params.CRITICAL_HIT_CHANCE, false, true)) * GetSkillLevel(S_Sword_s17);
  2360. steelCritDmg += CalculateAttributeValue(GetSkillAttributeValue(SkillEnumToName(S_Sword_s17), theGame.params.CRITICAL_HIT_DAMAGE_BONUS, false, true)) * GetSkillLevel(S_Sword_s17);
  2361. }
  2362. steelCritChance /= 2;
  2363. steelCritDmg /= 2;
  2364. silverCritChance = steelCritChance;
  2365. silverCritDmg = steelCritDmg;
  2366.  
  2367. if (GetWitcherPlayer().GetItemEquippedOnSlot(EES_SteelSword, item))
  2368. {
  2369. value = thePlayer.GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_SLASHING);
  2370. steelDmg += value.valueBase;
  2371. steelCritChance += CalculateAttributeValue(thePlayer.GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_CHANCE));
  2372. steelCritDmg += CalculateAttributeValue(thePlayer.GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
  2373. }
  2374. else
  2375. {
  2376. steelDmg += 0;
  2377. steelCritChance += 0;
  2378. steelCritDmg +=0;
  2379. }
  2380.  
  2381. if (GetWitcherPlayer().GetItemEquippedOnSlot(EES_SilverSword, item))
  2382. {
  2383. value = thePlayer.GetInventory().GetItemAttributeValue(item, theGame.params.DAMAGE_NAME_SILVER);
  2384. silverDmg += value.valueBase;
  2385. silverCritChance += CalculateAttributeValue(thePlayer.GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_CHANCE));
  2386. silverCritDmg += CalculateAttributeValue(thePlayer.GetInventory().GetItemAttributeValue(item, theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
  2387. }
  2388. else
  2389. {
  2390. silverDmg += 0;
  2391. silverCritChance += 0;
  2392. silverCritDmg +=0;
  2393. }
  2394.  
  2395. steelCritChance += CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue(theGame.params.CRITICAL_HIT_CHANCE));
  2396. silverCritChance += CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue(theGame.params.CRITICAL_HIT_CHANCE));
  2397. steelCritDmg += CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue(theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
  2398. silverCritDmg += CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue(theGame.params.CRITICAL_HIT_DAMAGE_BONUS));
  2399. attackPower += GetWitcherPlayer().GetPowerStatValue(CPS_AttackPower);
  2400.  
  2401. steelCritChance *= 100;
  2402. silverCritChance *= 100;
  2403. steelDmg = steelDmg * (100 - steelCritChance) + steelDmg * (1 + steelCritDmg) * steelCritChance;
  2404. steelDmg *= attackPower.valueMultiplicative;
  2405. steelDmg /= 100;
  2406. silverDmg = silverDmg * (100 - silverCritChance) + silverDmg * (1 + silverCritDmg) * silverCritChance;
  2407. silverDmg *= attackPower.valueMultiplicative;
  2408. silverDmg /= 100;
  2409. return RoundMath((steelDmg + silverDmg)/2);
  2410. }
  2411.  
  2412. // #Y TODO: Implement calculation
  2413. public final function GetDefenseStat():int
  2414. {
  2415. var valArmor : SAbilityAttributeValue;
  2416. var valResists : float;
  2417. var fVal1, fVal2 : float;
  2418.  
  2419. valArmor = thePlayer.GetTotalArmor();
  2420. thePlayer.GetResistValue(CDS_SlashingRes, fVal1, fVal2);
  2421. valResists += fVal2;
  2422. thePlayer.GetResistValue(CDS_PiercingRes, fVal1, fVal2);
  2423. valResists += fVal2;
  2424. thePlayer.GetResistValue(CDS_BludgeoningRes, fVal1, fVal2);
  2425. valResists += fVal2;
  2426. thePlayer.GetResistValue(CDS_RendingRes, fVal1, fVal2);
  2427. valResists += fVal2;
  2428. thePlayer.GetResistValue(CDS_ElementalRes, fVal1, fVal2);
  2429. valResists += fVal2;
  2430.  
  2431. valResists = valResists / 5;
  2432.  
  2433. fVal1 = 100 - valArmor.valueBase;
  2434. fVal1 *= valResists;
  2435. fVal1 += valArmor.valueBase;
  2436.  
  2437. return RoundMath(fVal1);
  2438. }
  2439.  
  2440. // #Y TODO: Implement calculation
  2441. public final function GetSignsStat():float
  2442. {
  2443. var sp : SAbilityAttributeValue;
  2444.  
  2445. sp += thePlayer.GetSkillAttributeValue(S_Magic_1, PowerStatEnumToName(CPS_SpellPower), true, true);
  2446. sp += thePlayer.GetSkillAttributeValue(S_Magic_2, PowerStatEnumToName(CPS_SpellPower), true, true);
  2447. sp += thePlayer.GetSkillAttributeValue(S_Magic_3, PowerStatEnumToName(CPS_SpellPower), true, true);
  2448. sp += thePlayer.GetSkillAttributeValue(S_Magic_4, PowerStatEnumToName(CPS_SpellPower), true, true);
  2449. sp += thePlayer.GetSkillAttributeValue(S_Magic_5, PowerStatEnumToName(CPS_SpellPower), true, true);
  2450. sp.valueMultiplicative /= 5;
  2451.  
  2452. return sp.valueMultiplicative;
  2453. }
  2454.  
  2455. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2456. ////////////////////////////////////////////// @SLOTS //////////////////////////////////////////////////////////////////////////
  2457. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2458.  
  2459. event OnLevelGained(currentLevel : int)
  2460. {
  2461. var i : int;
  2462.  
  2463. for(i=0; i<skillSlots.Size(); i+=1)
  2464. {
  2465. if(currentLevel >= skillSlots[i].unlockedOnLevel)
  2466. skillSlots[i].unlocked = true;
  2467. }
  2468. }
  2469.  
  2470. //loads skill slots data from XML
  2471. private final function InitSkillSlots( isFromLoad : bool )
  2472. {
  2473. var slot : SSkillSlot;
  2474. var dm : CDefinitionsManagerAccessor;
  2475. var main : SCustomNode;
  2476. var i, j : int;
  2477. var inGame : bool;
  2478. var xmlSlots : array< SSkillSlot >;
  2479.  
  2480. dm = theGame.GetDefinitionsManager();
  2481. main = dm.GetCustomDefinition( 'skill_slots' );
  2482.  
  2483. for( i=0; i<main.subNodes.Size(); i+=1 )
  2484. {
  2485. if( !dm.GetCustomNodeAttributeValueInt( main.subNodes[ i ], 'id', slot.id ) )
  2486. {
  2487. LogAssert( false, "W3PlayerAbilityManager.InitSkillSlots: slot definition is not valid!" );
  2488. continue;
  2489. }
  2490.  
  2491. if( !dm.GetCustomNodeAttributeValueInt( main.subNodes[ i ], 'unlockedOnLevel', slot.unlockedOnLevel ) )
  2492. {
  2493. slot.unlockedOnLevel = 0;
  2494. }
  2495.  
  2496. if( !dm.GetCustomNodeAttributeValueInt( main.subNodes[ i ], 'group', slot.groupID ) )
  2497. {
  2498. slot.groupID = -1;
  2499. }
  2500.  
  2501. //slot.unlocked = cannot set it now since LevelManager does not exist yet. Instead it's set in PostLoad
  2502. totalSkillSlotsCount = Max( totalSkillSlotsCount, slot.id );
  2503. LogChannel( 'CHR', "Init W3PlayerAbilityManager, totalSkillSlotsCount " + totalSkillSlotsCount );
  2504. xmlSlots.PushBack( slot );
  2505.  
  2506. slot.id = -1;
  2507. slot.unlockedOnLevel = 0;
  2508. slot.groupID = -1;
  2509. }
  2510.  
  2511. if( !isFromLoad )
  2512. {
  2513. //first init ever - all xml slots go into game
  2514. skillSlots = xmlSlots;
  2515. }
  2516. else
  2517. {
  2518. //player already was initialized - we only add new slots
  2519. for( i=0; i<xmlSlots.Size(); i+=1 )
  2520. {
  2521. //check if given slot is already present in the game
  2522. inGame = false;
  2523. for( j=0; j<skillSlots.Size(); j+=1 )
  2524. {
  2525. if( xmlSlots[ i ].id == skillSlots[ j ].id )
  2526. {
  2527. inGame = true;
  2528. break;
  2529. }
  2530. }
  2531.  
  2532. //if not already in game, add
  2533. if( !inGame )
  2534. {
  2535. skillSlots.PushBack( xmlSlots[ i ] );
  2536. }
  2537. }
  2538. }
  2539. }
  2540.  
  2541. //returns skill slot ID for given equipped skill
  2542. public final function GetSkillSlotID(skill : ESkill) : int
  2543. {
  2544. var i : int;
  2545.  
  2546. if(skill == S_SUndefined)
  2547. return -1;
  2548.  
  2549. for(i=0; i<skillSlots.Size(); i+=1)
  2550. {
  2551. if(skillSlots[i].socketedSkill == skill)
  2552. {
  2553. if(skillSlots[i].unlocked)
  2554. return skillSlots[i].id;
  2555. else
  2556. return -1;
  2557. }
  2558. }
  2559.  
  2560. return -1;
  2561. }
  2562.  
  2563. public final function GetSkillSlotIDFromIndex(skillSlotIndex : int) : int
  2564. {
  2565. if(skillSlotIndex >= 0 && skillSlotIndex < skillSlots.Size())
  2566. return skillSlots[skillSlotIndex].id;
  2567.  
  2568. return -1;
  2569. }
  2570.  
  2571. /*
  2572. Returns index of skillSlot for given slot ID.
  2573. Returns -1 if not found.
  2574. If checkIfUnlocked flag is set will return -1 if given slot in locked.
  2575. */
  2576. public final function GetSkillSlotIndex(slotID : int, checkIfUnlocked : bool) : int
  2577. {
  2578. var i : int;
  2579.  
  2580. for(i=0; i<skillSlots.Size(); i+=1)
  2581. {
  2582. if(skillSlots[i].id == slotID)
  2583. {
  2584. if(!checkIfUnlocked)
  2585. return i;
  2586.  
  2587. if(skillSlots[i].unlocked)
  2588. return i;
  2589. else
  2590. return -1;
  2591. }
  2592. }
  2593.  
  2594. return -1;
  2595. }
  2596.  
  2597. public final function GetSkillSlotIndexFromSkill(skill : ESkill) : int
  2598. {
  2599. var i : int;
  2600.  
  2601. for(i=0; i<skillSlots.Size(); i+=1)
  2602. if(skillSlots[i].socketedSkill == skill)
  2603. return i;
  2604.  
  2605. return -1;
  2606. }
  2607.  
  2608. //returns true if succeeded
  2609. public final function EquipSkill(skill : ESkill, slotID : int) : bool
  2610. {
  2611. var idx, i : int;
  2612. var prevColor : ESkillColor;
  2613.  
  2614. //PerksActive
  2615. if(activeSkills.Contains(skill))
  2616. return false;
  2617. //PerksActive
  2618.  
  2619. if(!HasLearnedSkill(skill) || IsCoreSkill(skill))
  2620. return false;
  2621.  
  2622. idx = GetSkillSlotIndex(slotID, true);
  2623.  
  2624. if(idx < 0)
  2625. return false;
  2626.  
  2627. if(IsSkillEquipped(skill))
  2628. {
  2629. i = GetSkillSlotID(skill);
  2630. if (i > orgTotalSkillSlotsCount)
  2631. UnequipSkill(i);
  2632. }
  2633.  
  2634. prevColor = GetSkillGroupColor(skillSlots[idx].groupID);
  2635.  
  2636. UnequipSkill(slotID);
  2637.  
  2638. skillSlots[idx].socketedSkill = skill;
  2639.  
  2640. LinkUpdate(GetSkillGroupColor(skillSlots[idx].groupID), prevColor);
  2641. OnSkillEquip(skill);
  2642.  
  2643. return true;
  2644. }
  2645.  
  2646. //returns true if succeeded
  2647. public final function UnequipSkill(slotID : int) : bool
  2648. {
  2649. var idx : int;
  2650. var prevColor : ESkillColor;
  2651. var skill : ESkill;
  2652.  
  2653. idx = GetSkillSlotIndex(slotID, true);
  2654. if(idx < 0)
  2655. return false;
  2656.  
  2657. //nothing equipped on that slot so nothing to do
  2658. skill = skillSlots[idx].socketedSkill;
  2659. if( skill == S_SUndefined )
  2660. {
  2661. return false;
  2662. }
  2663.  
  2664. //update links
  2665. skillSlots[idx].socketedSkill = S_SUndefined;
  2666. prevColor = GetSkillGroupColor(skillSlots[idx].groupID);
  2667. LinkUpdate(GetSkillGroupColor(skillSlots[idx].groupID), prevColor);
  2668. OnSkillUnequip(skill);
  2669.  
  2670. if ( idx <= orgTotalSkillSlotsCount )
  2671. {
  2672. if( MustEquipSkill(skill) )
  2673. ForceEquipSkill(skill);
  2674. }
  2675.  
  2676. return true;
  2677. }
  2678.  
  2679. //called when char panel closes and a skill equip was done
  2680. private final function OnSkillEquip(skill : ESkill)
  2681. {
  2682. var skillName : name;
  2683. var names, abs : array<name>;
  2684. var buff : W3Effect_Toxicity;
  2685. var witcher : W3PlayerWitcher;
  2686. var i, skillLevel : int;
  2687. var isPassive, isNight : bool;
  2688. var m_alchemyManager : W3AlchemyManager;
  2689. var recipe : SAlchemyRecipe;
  2690. var uiState : W3TutorialManagerUIHandlerStateCharacterDevelopment;
  2691. var battleTrance : W3Effect_BattleTrance;
  2692. var mutagens : array<CBaseGameplayEffect>;
  2693. var trophy : SItemUniqueId;
  2694. var horseManager : W3HorseManager;
  2695. var weapon, armor : W3RepairObjectEnhancement;
  2696. var foodBuff : W3Effect_WellFed;
  2697. var commonMenu : CR4CommonMenu;
  2698. var guiMan : CR4GuiManager;
  2699. var shrineBuffs : array<CBaseGameplayEffect>;
  2700. var shrineTimeLeft, highestShrineTime : float;
  2701. var shrineEffectIndex : int;
  2702. var hud : CR4ScriptedHud;
  2703.  
  2704. //always active
  2705. if(IsCoreSkill(skill))
  2706. return;
  2707.  
  2708. witcher = GetWitcherPlayer();
  2709.  
  2710. //add passive Buff that this skill grants
  2711. AddPassiveSkillBuff(skill);
  2712.  
  2713. //cache skill ability
  2714. isPassive = theGame.GetDefinitionsManager().AbilityHasTag(skills[skill].abilityName, theGame.params.SKILL_GLOBAL_PASSIVE_TAG);
  2715.  
  2716. for( i = 0; i < GetSkillLevel(skill); i += 1 )
  2717. {
  2718. if(isPassive)
  2719. owner.AddAbility(skills[skill].abilityName, true);
  2720. else
  2721. skillAbilities.PushBack(skills[skill].abilityName);
  2722. }
  2723.  
  2724. //M.J. - adrenaline hack for sword skills
  2725. if(GetSkillPathType(skill) == ESP_Sword)
  2726. {
  2727. owner.AddAbilityMultiple('sword_adrenalinegain', GetSkillLevel(skill) );
  2728. }
  2729.  
  2730. //some stamina hack for magic skills
  2731. if(GetSkillPathType(skill) == ESP_Signs)
  2732. {
  2733. owner.AddAbilityMultiple('magic_staminaregen', GetSkillLevel(skill) );
  2734. }
  2735.  
  2736. //M.J. - potion duration hack for alchemy skills
  2737. if(GetSkillPathType(skill) == ESP_Alchemy)
  2738. {
  2739. owner.AddAbilityMultiple('alchemy_potionduration', GetSkillLevel(skill) );
  2740. }
  2741.  
  2742. // Update Synergy bonus
  2743. if ( CanUseSkill(S_Alchemy_s19) )
  2744. {
  2745. MutagensSyngergyBonusUpdate( GetSkillGroupIdFromSkill( skill ), GetSkillLevel(S_Alchemy_s19) );
  2746. }
  2747. else if(skill == S_Alchemy_s20)
  2748. {
  2749. if ( GetWitcherPlayer().GetStatPercents(BCS_Toxicity) >= GetWitcherPlayer().GetToxicityDamageThreshold() )
  2750. owner.AddEffectDefault(EET_IgnorePain, owner, 'IgnorePain');
  2751. }
  2752. //custom instant skill checks
  2753. if(skill == S_Alchemy_s18)
  2754. {
  2755. m_alchemyManager = new W3AlchemyManager in this;
  2756. m_alchemyManager.Init();
  2757. names = witcher.GetAlchemyRecipes();
  2758. skillName = SkillEnumToName(S_Alchemy_s18);
  2759. for(i=0; i<names.Size(); i+=1)
  2760. {
  2761. m_alchemyManager.GetRecipe(names[i], recipe);
  2762. if ((recipe.cookedItemType != EACIT_Bolt) && (recipe.cookedItemType != EACIT_Undefined) && (recipe.level <= GetSkillLevel(S_Alchemy_s18)))
  2763. charStats.AddAbility(skillName, true);
  2764. }
  2765. }
  2766. else if(skill == S_Alchemy_s15 && owner.HasBuff(EET_Toxicity))
  2767. {
  2768. buff = (W3Effect_Toxicity)owner.GetBuff(EET_Toxicity);
  2769. buff.RecalcEffectValue();
  2770. }
  2771. else if(skill == S_Alchemy_s13)
  2772. {
  2773. mutagens = GetWitcherPlayer().GetDrunkMutagens();
  2774. if(mutagens.Size() > 0)
  2775. {
  2776. charStats.AddAbilityMultiple( GetSkillAbilityName( skill ), (GetSkillLevel( skill ) * mutagens.Size() ));
  2777. }
  2778. }
  2779. else if(skill == S_Alchemy_s06)
  2780. {
  2781. hud = (CR4ScriptedHud)theGame.GetHud();
  2782. if ( hud )
  2783. {
  2784. hud.OnRelevantSkillChanged( skill, true );
  2785. }
  2786. }
  2787. else if(skill == S_Magic_s11) //yrden damaging
  2788. {
  2789. ((W3YrdenEntity) (witcher.GetSignEntity(ST_Yrden))).SkillEquipped(skill);
  2790. }
  2791. else if(skill == S_Magic_s07) //battle trance spell power bonus
  2792. {
  2793. if(owner.HasBuff(EET_BattleTrance))
  2794. owner.AddAbility( GetSkillAbilityName(S_Magic_s07) );
  2795. }
  2796. else if(skill == S_Perk_08)
  2797. {
  2798. //change level 3 items abilities from 2 to 3
  2799. thePlayer.ChangeAlchemyItemsAbilities(true);
  2800. }
  2801. else if(skill == S_Alchemy_s19)
  2802. {
  2803. MutagensSyngergyBonusUpdate( -1, GetSkillLevel(S_Alchemy_s19) );
  2804. }
  2805. else if(skill == S_Perk_01)
  2806. {
  2807. isNight = theGame.envMgr.IsNight();
  2808. SetPerk01Abilities(!isNight, isNight);
  2809. }
  2810. else if(skill == S_Perk_05)
  2811. {
  2812. SetPerkArmorBonus(S_Perk_05);
  2813. }
  2814. else if(skill == S_Perk_06)
  2815. {
  2816. SetPerkArmorBonus(S_Perk_06);
  2817. }
  2818. else if(skill == S_Perk_07)
  2819. {
  2820. SetPerkArmorBonus(S_Perk_07);
  2821. }
  2822. else if(skill == S_Perk_11)
  2823. {
  2824. battleTrance = (W3Effect_BattleTrance)owner.GetBuff(EET_BattleTrance);
  2825. if(battleTrance)
  2826. battleTrance.OnPerk11Equipped();
  2827. }
  2828. else if( skill == S_Perk_14 )
  2829. {
  2830. highestShrineTime = 0.f;
  2831. shrineBuffs = GetWitcherPlayer().GetShrineBuffs();
  2832. for( i = 0; i<shrineBuffs.Size() ; i+=1 )
  2833. {
  2834. shrineTimeLeft = shrineBuffs[i].GetDurationLeft();
  2835. if( shrineTimeLeft > highestShrineTime )
  2836. {
  2837. highestShrineTime = shrineTimeLeft;
  2838. shrineEffectIndex = i;
  2839. }
  2840. }
  2841. for( i = 0; i<shrineBuffs.Size() ; i+=1 )
  2842. {
  2843. if( i != shrineEffectIndex )
  2844. {
  2845. GetWitcherPlayer().RemoveEffect( shrineBuffs[i] );
  2846. }
  2847. }
  2848. }
  2849. else if(skill == S_Perk_19 && witcher.HasBuff(EET_BattleTrance))
  2850. {
  2851. skillLevel = FloorF(witcher.GetStat(BCS_Focus));
  2852. witcher.RemoveAbilityMultiple(thePlayer.GetSkillAbilityName(S_Sword_5), skillLevel);
  2853. witcher.AddAbilityMultiple(thePlayer.GetSkillAbilityName(S_Perk_19), skillLevel);
  2854. }
  2855. else if(skill == S_Perk_20)
  2856. {
  2857. thePlayer.SkillReduceBombAmmoBonus();
  2858. }
  2859. else if(skill == S_Perk_22)
  2860. {
  2861. GetWitcherPlayer().UpdateEncumbrance();
  2862. guiMan = theGame.GetGuiManager();
  2863. if(guiMan)
  2864. {
  2865. commonMenu = theGame.GetGuiManager().GetCommonMenu();
  2866. if(commonMenu)
  2867. {
  2868. commonMenu.UpdateItemsCounter();
  2869. }
  2870. }
  2871. }
  2872.  
  2873. if(GetSkillPathType(skill) == ESP_Alchemy)
  2874. witcher.RecalcPotionsDurations();
  2875.  
  2876. //tutorial
  2877. if(ShouldProcessTutorial('TutorialCharDevEquipSkill'))
  2878. {
  2879. uiState = (W3TutorialManagerUIHandlerStateCharacterDevelopment)theGame.GetTutorialSystem().uiHandler.GetCurrentState();
  2880. if(uiState)
  2881. uiState.EquippedSkill();
  2882. }
  2883.  
  2884. //trial of grasses achievement
  2885. theGame.GetGamerProfile().CheckTrialOfGrasses();
  2886. }
  2887.  
  2888. private final function OnSkillUnequip(skill : ESkill)
  2889. {
  2890. var i, skillLevel : int;
  2891. var isPassive : bool;
  2892. var petard : W3Petard;
  2893. var ents : array<CGameplayEntity>;
  2894. var mutagens : array<CBaseGameplayEffect>;
  2895. var tox : W3Effect_Toxicity;
  2896. var names, abs : array<name>;
  2897. var skillName : name;
  2898. var battleTrance : W3Effect_BattleTrance;
  2899. var trophy : SItemUniqueId;
  2900. var horseManager : W3HorseManager;
  2901. var witcher : W3PlayerWitcher;
  2902. var weapon, armor : W3RepairObjectEnhancement;
  2903. var foodBuff : W3Effect_WellFed;
  2904. var commonMenu : CR4CommonMenu;
  2905. var guiMan : CR4GuiManager;
  2906. var hud : CR4ScriptedHud;
  2907.  
  2908. //always active
  2909. if(IsCoreSkill(skill))
  2910. return;
  2911.  
  2912. //cache skill ability
  2913. isPassive = theGame.GetDefinitionsManager().AbilityHasTag(skills[skill].abilityName, theGame.params.SKILL_GLOBAL_PASSIVE_TAG);
  2914.  
  2915. skillLevel = skills[skill].level;
  2916.  
  2917. for( i = 0; i < skillLevel; i += 1 )
  2918. {
  2919. if(isPassive)
  2920. owner.RemoveAbility(skills[skill].abilityName);
  2921. else
  2922. skillAbilities.Remove(skills[skill].abilityName);
  2923. }
  2924.  
  2925. //M.J. - adrenaline hack for sword skills
  2926. if(GetSkillPathType(skill) == ESP_Sword)
  2927. {
  2928. owner.RemoveAbilityMultiple('sword_adrenalinegain', skillLevel );
  2929. }
  2930.  
  2931. //some hack for magic skills
  2932. if(GetSkillPathType(skill) == ESP_Signs)
  2933. {
  2934. owner.RemoveAbilityMultiple('magic_staminaregen', GetSkillLevel(skill) );
  2935. }
  2936.  
  2937. //M.J. - potion duration hack for alchemy skills
  2938. if(GetSkillPathType(skill) == ESP_Alchemy)
  2939. {
  2940. owner.RemoveAbilityMultiple('alchemy_potionduration', GetSkillLevel(skill) );
  2941. }
  2942.  
  2943. //custom skill stuff
  2944. if(skill == S_Magic_s11) //yrden damaging
  2945. {
  2946. ((W3YrdenEntity) (GetWitcherPlayer().GetSignEntity(ST_Yrden))).SkillUnequipped(skill);
  2947. }
  2948. else if(skill == S_Magic_s07) //battle trance spell power bonus
  2949. {
  2950. owner.RemoveAbility( GetSkillAbilityName(S_Magic_s07) );
  2951. }
  2952. else if(skill == S_Alchemy_s04) //bonus random potion effect when drinking potion
  2953. {
  2954. owner.RemoveEffect(GetWitcherPlayer().GetSkillBonusPotionEffect());
  2955. }
  2956. /*
  2957. else if(skill == PROXIMITY_BOMBS) //proximity -> explode existing proximities, disable proxy on flying ones
  2958. {
  2959. FindGameplayEntitiesInSphere(ents, owner.GetWorldPosition(), theGame.params.MAX_THROW_RANGE + 0.5, 1000);
  2960. for(i=ents.Size()-1; i>=0; i-=1)
  2961. {
  2962. petard = (W3Petard)ents[i];
  2963. if(petard)
  2964. {
  2965. if(petard.IsStuck())
  2966. petard.ProcessEffect();
  2967. else if(petard.IsProximity())
  2968. petard.DisableProximity();
  2969. }
  2970. }
  2971. }*/
  2972. else if(skill == S_Alchemy_s13)
  2973. {
  2974. mutagens = GetWitcherPlayer().GetDrunkMutagens();
  2975.  
  2976. if(mutagens.Size() > 0)
  2977. {
  2978. charStats.RemoveAbilityMultiple( GetSkillAbilityName( S_Alchemy_s13 ), ( GetSkillLevel( skill ) * mutagens.Size() ));
  2979. }
  2980. }
  2981. else if(skill == S_Alchemy_s06)
  2982. {
  2983. hud = (CR4ScriptedHud)theGame.GetHud();
  2984. if ( hud )
  2985. {
  2986. hud.OnRelevantSkillChanged( skill, false );
  2987. }
  2988. }
  2989. else if(skill == S_Alchemy_s20)
  2990. {
  2991. owner.RemoveBuff(EET_IgnorePain);
  2992. }
  2993. else if(skill == S_Alchemy_s15 && owner.HasBuff(EET_Toxicity))
  2994. {
  2995. tox = (W3Effect_Toxicity)owner.GetBuff(EET_Toxicity);
  2996. tox.RecalcEffectValue();
  2997. }
  2998. else if(skill == S_Alchemy_s18) //toxicity pool upgrade per known recipe
  2999. {
  3000. names = GetWitcherPlayer().GetAlchemyRecipes();
  3001. skillName = SkillEnumToName(S_Alchemy_s18);
  3002. for(i=0; i<names.Size(); i+=1)
  3003. charStats.RemoveAbility(skillName);
  3004. }
  3005. else if(skill == S_Sword_s13) //slowmo for aiming
  3006. {
  3007. theGame.RemoveTimeScale( theGame.GetTimescaleSource(ETS_ThrowingAim) );
  3008. }
  3009. else if(skill == S_Alchemy_s08)
  3010. {
  3011. skillLevel = GetSkillLevel(S_Alchemy_s08);
  3012. for (i=0; i < skillLevel; i+=1)
  3013. thePlayer.SkillReduceBombAmmoBonus();
  3014. }
  3015. else if(skill == S_Perk_08)
  3016. {
  3017. //change level 3 items abilities from 3 to 2
  3018. thePlayer.ChangeAlchemyItemsAbilities(false);
  3019. }
  3020. else if(skill == S_Alchemy_s19)
  3021. {
  3022. MutagensSyngergyBonusUpdate( -1, 0 );
  3023. }
  3024. else if(skill == S_Perk_01)
  3025. {
  3026. SetPerk01Abilities(false, false);
  3027. }
  3028. else if(skill == S_Perk_05)
  3029. {
  3030. UpdatePerkArmorBonus(S_Perk_05, 0);
  3031. }
  3032. else if(skill == S_Perk_06)
  3033. {
  3034. UpdatePerkArmorBonus(S_Perk_06, 0);
  3035. }
  3036. else if(skill == S_Perk_07)
  3037. {
  3038. UpdatePerkArmorBonus(S_Perk_07, 0);
  3039. }
  3040. else if(skill == S_Perk_11)
  3041. {
  3042. battleTrance = (W3Effect_BattleTrance)owner.GetBuff(EET_BattleTrance);
  3043. if(battleTrance)
  3044. battleTrance.OnPerk11Unequipped();
  3045. }
  3046. else if( skill == S_Perk_15 )
  3047. {
  3048. foodBuff = (W3Effect_WellFed)owner.GetBuff( EET_WellFed );
  3049. if( foodBuff )
  3050. {
  3051. foodBuff.OnPerk15Unequipped();
  3052. }
  3053. }
  3054. else if(skill == S_Perk_19 && owner.HasBuff(EET_BattleTrance))
  3055. {
  3056. skillLevel = FloorF(owner.GetStat(BCS_Focus));
  3057. owner.RemoveAbilityMultiple(thePlayer.GetSkillAbilityName(S_Perk_19), skillLevel);
  3058. owner.AddAbilityMultiple(thePlayer.GetSkillAbilityName(S_Sword_5), skillLevel);
  3059. }
  3060. else if(skill == S_Perk_22)
  3061. {
  3062. GetWitcherPlayer().UpdateEncumbrance();
  3063. guiMan = theGame.GetGuiManager();
  3064. if(guiMan)
  3065. {
  3066. commonMenu = theGame.GetGuiManager().GetCommonMenu();
  3067. if(commonMenu)
  3068. {
  3069. commonMenu.UpdateItemsCounter();
  3070. }
  3071. }
  3072. }
  3073.  
  3074. if(GetSkillPathType(skill) == ESP_Alchemy)
  3075. GetWitcherPlayer().RecalcPotionsDurations();
  3076.  
  3077. // Update synegry bonus
  3078. if ( CanUseSkill(S_Alchemy_s19) )
  3079. {
  3080. MutagensSyngergyBonusUpdate( GetSkillGroupIdFromSkill( skill ), GetSkillLevel(S_Alchemy_s19) );
  3081. }
  3082. }
  3083.  
  3084. //goes through all armor pieces and updates perk bonus
  3085. public final function SetPerkArmorBonus(skill : ESkill, optional spawnPlayerEntity : W3PlayerWitcher )
  3086. {
  3087. var item : SItemUniqueId;
  3088. var armors : array<SItemUniqueId>;
  3089. var light, medium, heavy, i, cnt : int;
  3090. var armorType : EArmorType;
  3091. var witcher : W3PlayerWitcher;
  3092. var inventory : CInventoryComponent;
  3093.  
  3094. if(skill != S_Perk_05 && skill != S_Perk_06 && skill != S_Perk_07)
  3095. {
  3096. return;
  3097. }
  3098.  
  3099. if( spawnPlayerEntity )
  3100. {
  3101. witcher = spawnPlayerEntity;
  3102. }
  3103. else
  3104. {
  3105. witcher = GetWitcherPlayer();
  3106. }
  3107.  
  3108. armors.Resize(4);
  3109.  
  3110. if(witcher.GetItemEquippedOnSlot(EES_Armor, item))
  3111. armors[0] = item;
  3112.  
  3113. if(witcher.GetItemEquippedOnSlot(EES_Boots, item))
  3114. armors[1] = item;
  3115.  
  3116. if(witcher.GetItemEquippedOnSlot(EES_Pants, item))
  3117. armors[2] = item;
  3118.  
  3119. if(witcher.GetItemEquippedOnSlot(EES_Gloves, item))
  3120. armors[3] = item;
  3121.  
  3122. light = 0;
  3123. medium = 0;
  3124. heavy = 0;
  3125. inventory = witcher.GetInventory();
  3126. for(i=0; i<armors.Size(); i+=1)
  3127. {
  3128. armorType = inventory.GetArmorType(armors[i]);
  3129. if(armorType == EAT_Light)
  3130. light += 1;
  3131. else if(armorType == EAT_Medium)
  3132. medium += 1;
  3133. else if(armorType == EAT_Heavy)
  3134. heavy += 1;
  3135. }
  3136.  
  3137. if(skill == S_Perk_05)
  3138. cnt = light;
  3139. else if(skill == S_Perk_06)
  3140. cnt = medium;
  3141. else
  3142. cnt = heavy;
  3143.  
  3144. UpdatePerkArmorBonus(skill, cnt);
  3145. }
  3146.  
  3147. // adds/removes perk armor bonus
  3148. protected final function UpdatePerkArmorBonus(skill : ESkill, count : int)
  3149. {
  3150. var abilityName : name;
  3151. var currAbs : int;
  3152.  
  3153. abilityName = GetSkillAbilityName(skill);
  3154.  
  3155. if(count == 0)
  3156. {
  3157. charStats.RemoveAbilityAll( abilityName );
  3158. }
  3159. else
  3160. {
  3161. currAbs = charStats.GetAbilityCount( abilityName );
  3162.  
  3163. if(currAbs < count)
  3164. {
  3165. charStats.AddAbilityMultiple( abilityName, count - currAbs );
  3166. }
  3167. else if(currAbs > count)
  3168. {
  3169. charStats.RemoveAbilityMultiple( abilityName, currAbs - count );
  3170. }
  3171. }
  3172. }
  3173.  
  3174. //sets day/night perk01's abilities
  3175. public final function SetPerk01Abilities(enableDay : bool, enableNight : bool)
  3176. {
  3177. var abilityName : name;
  3178. var i : int;
  3179. var dm : CDefinitionsManagerAccessor;
  3180. var abs : array<name>;
  3181. var enable : bool;
  3182.  
  3183. abilityName = GetSkillAbilityName(S_Perk_01);
  3184. dm = theGame.GetDefinitionsManager();
  3185. dm.GetContainedAbilities(abilityName, abs);
  3186.  
  3187. for(i=0; i<abs.Size(); i+=1)
  3188. {
  3189. if(dm.AbilityHasTag(abs[i], 'Day'))
  3190. enable = enableDay;
  3191. else
  3192. enable = enableNight;
  3193.  
  3194. if(enable)
  3195. charStats.AddAbility(abs[i], false);
  3196. else
  3197. charStats.RemoveAbility(abs[i]);
  3198. }
  3199. }
  3200.  
  3201. //called when equipped skill changes level
  3202. private final function OnSkillEquippedLevelChange(skill : ESkill, prevLevel : int, currLevel : int)
  3203. {
  3204. var cnt, i : int;
  3205. var names : array<name>;
  3206. var skillAbilityName : name;
  3207. var mutagens : array<CBaseGameplayEffect>;
  3208. var recipe : SAlchemyRecipe;
  3209. var m_alchemyManager : W3AlchemyManager;
  3210. var ignorePain : W3Effect_IgnorePain;
  3211.  
  3212. //never changes levels
  3213. if(IsCoreSkill(skill))
  3214. return;
  3215.  
  3216. if(skill == S_Alchemy_s08)
  3217. {
  3218. if(currLevel < prevLevel)
  3219. thePlayer.SkillReduceBombAmmoBonus();
  3220. }
  3221. else if(skill == S_Alchemy_s18)
  3222. {
  3223. m_alchemyManager = new W3AlchemyManager in this;
  3224. m_alchemyManager.Init();
  3225. names = GetWitcherPlayer().GetAlchemyRecipes();
  3226. skillAbilityName = SkillEnumToName(S_Alchemy_s18);
  3227. cnt = 0;
  3228.  
  3229. //count how much we should have
  3230. for(i=0; i<names.Size(); i+=1)
  3231. {
  3232. m_alchemyManager.GetRecipe(names[i], recipe);
  3233. if ((recipe.cookedItemType != EACIT_Bolt) && (recipe.cookedItemType != EACIT_Undefined) && (recipe.level <= GetSkillLevel(S_Alchemy_s18)))
  3234. cnt += 1;
  3235. }
  3236.  
  3237. //add/remove abilities
  3238. cnt -= owner.GetAbilityCount(skillAbilityName);
  3239. if(cnt > 0)
  3240. charStats.AddAbilityMultiple(skillAbilityName, cnt);
  3241. else if(cnt < 0)
  3242. charStats.RemoveAbilityMultiple(skillAbilityName, -cnt);
  3243. }
  3244. else if(skill == S_Alchemy_s13)
  3245. {
  3246. mutagens = GetWitcherPlayer().GetDrunkMutagens();
  3247. skillAbilityName = GetSkillAbilityName(S_Alchemy_s13);
  3248.  
  3249. if(mutagens.Size() > 0)
  3250. charStats.AddAbilityMultiple(skillAbilityName, GetSkillLevel(skill));
  3251. else
  3252. charStats.RemoveAbilityMultiple(skillAbilityName, GetSkillLevel(skill));
  3253. }
  3254. else if(skill == S_Alchemy_s19)
  3255. {
  3256. //remove old, add new
  3257. if ( CanUseSkill(S_Alchemy_s19) )
  3258. {
  3259. MutagensSyngergyBonusUpdate( -1, currLevel );
  3260. }
  3261. }
  3262. else if(skill == S_Alchemy_s20)
  3263. {
  3264. if(owner.HasBuff(EET_IgnorePain))
  3265. {
  3266. ignorePain = (W3Effect_IgnorePain)owner.GetBuff(EET_IgnorePain);
  3267. ignorePain.OnSkillLevelChanged(currLevel - prevLevel);
  3268. }
  3269. }
  3270. else if(skill == S_Perk_08)
  3271. {
  3272. if(currLevel == 3)
  3273. thePlayer.ChangeAlchemyItemsAbilities(true);
  3274. else if(currLevel == 2 && prevLevel == 3)
  3275. thePlayer.ChangeAlchemyItemsAbilities(false);
  3276. }
  3277.  
  3278. //some hack for sword skills
  3279. if(GetSkillPathType(skill) == ESP_Sword)
  3280. {
  3281. if ( (currLevel - prevLevel) > 0)
  3282. owner.AddAbilityMultiple('sword_adrenalinegain', currLevel - prevLevel );
  3283. else if ( (currLevel - prevLevel) < 0)
  3284. owner.RemoveAbilityMultiple('sword_adrenalinegain', currLevel - prevLevel );
  3285. }
  3286.  
  3287. //some hack for magic skills
  3288. if(GetSkillPathType(skill) == ESP_Signs)
  3289. {
  3290. if ( (currLevel - prevLevel) > 0)
  3291. owner.AddAbilityMultiple('magic_staminaregen', currLevel - prevLevel );
  3292. else if ( (currLevel - prevLevel) < 0)
  3293. owner.RemoveAbilityMultiple('magic_staminaregen', currLevel - prevLevel );
  3294. }
  3295.  
  3296. //some hack for alchemy skills
  3297. if(GetSkillPathType(skill) == ESP_Alchemy)
  3298. {
  3299. if ( (currLevel - prevLevel) > 0)
  3300. owner.AddAbilityMultiple('alchemy_potionduration', currLevel - prevLevel );
  3301. else if ( (currLevel - prevLevel) < 0)
  3302. owner.RemoveAbilityMultiple('alchemy_potionduration', currLevel - prevLevel );
  3303. }
  3304.  
  3305. if(GetSkillPathType(skill) == ESP_Alchemy)
  3306. GetWitcherPlayer().RecalcPotionsDurations();
  3307. }
  3308.  
  3309. public final function CanUseSkill(skill : ESkill) : bool
  3310. {
  3311. var ind : int;
  3312.  
  3313. if(!IsSkillEquipped(skill))
  3314. return false;
  3315.  
  3316. if(skills[skill].level < 1)
  3317. return false;
  3318.  
  3319. if(skills[skill].remainingBlockedTime != 0)
  3320. return false;
  3321.  
  3322. if(theGame.GetDefinitionsManager().IsAbilityDefined(skills[skill].abilityName) && charStats.HasAbility(skills[skill].abilityName))
  3323. return !IsAbilityBlocked(skills[skill].abilityName);
  3324.  
  3325. return true;
  3326. }
  3327.  
  3328. public final function IsSkillEquipped(skill : ESkill) : bool
  3329. {
  3330. var i, idx : int;
  3331.  
  3332. //core skills always equipped
  3333. if(activeSkills.Contains(skill))
  3334. return true;
  3335. //PerksActive
  3336. if(IsCoreSkill(skill))
  3337. return true;
  3338.  
  3339. //skill slots
  3340. for(i=0; i<skillSlots.Size(); i+=1)
  3341. if(skillSlots[i].socketedSkill == skill)
  3342. return true;
  3343.  
  3344. //temp skills always equipped
  3345. if(tempSkills.Contains(skill))
  3346. return true;
  3347.  
  3348. return false;
  3349. }
  3350.  
  3351. //sets skill on given skill slot. Returns false if skillslot is locked
  3352. public final function GetSkillOnSlot(slotID : int, out skill : ESkill) : bool
  3353. {
  3354. var idx : int;
  3355.  
  3356. if(slotID > 0 && slotID <= totalSkillSlotsCount)
  3357. {
  3358. idx = GetSkillSlotIndex(slotID, true);
  3359. if(idx >= 0)
  3360. {
  3361. skill = skillSlots[idx].socketedSkill;
  3362. return true;
  3363. }
  3364. }
  3365.  
  3366. skill = S_SUndefined;
  3367. return false;
  3368. }
  3369.  
  3370. public final function GetSkillSlots() : array<SSkillSlot>
  3371. {
  3372. return skillSlots;
  3373. }
  3374.  
  3375. public final function GetSkillSlotsCount() : int
  3376. {
  3377. return totalSkillSlotsCount;
  3378. }
  3379.  
  3380. public final function IsSkillSlotUnlocked(slotIndex : int) : bool
  3381. {
  3382. if(slotIndex >= 0 && slotIndex < skillSlots.Size())
  3383. return skillSlots[slotIndex].unlocked;
  3384.  
  3385. return false;
  3386. }
  3387.  
  3388. //resets character dev
  3389. public final function ResetCharacterDev()
  3390. {
  3391. var i : int;
  3392. var skillType : ESkill;
  3393.  
  3394. //PerksActive
  3395. for(i=0; i<activeSkills.Size(); i+=1)
  3396. {
  3397. if(skills[activeSkills[i]].level != 0) OnSkillUnequip(activeSkills[i]);
  3398. }
  3399. //PerksActive
  3400.  
  3401. for(i=0; i<skills.Size(); i+=1)
  3402. {
  3403. skillType = skills[i].skillType;
  3404.  
  3405. if(IsCoreSkill(skillType))
  3406. continue;
  3407.  
  3408. if(IsSkillEquipped(skillType))
  3409. UnequipSkill(GetSkillSlotID(skillType));
  3410.  
  3411. skills[i].level = 0;
  3412. }
  3413.  
  3414. for(i=0; i<pathPointsSpent.Size(); i+=1)
  3415. {
  3416. pathPointsSpent[i] = 0;
  3417. }
  3418.  
  3419. owner.RemoveAbilityAll('sword_adrenalinegain');
  3420. owner.RemoveAbilityAll('magic_staminaregen');
  3421. owner.RemoveAbilityAll('alchemy_potionduration');
  3422. }
  3423.  
  3424. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3425. ////////////////////////////////////////////// @TUTORIAL ///////////////////////////////////////////////////////////////////////
  3426. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3427.  
  3428. /*
  3429. Stores (as returned value) skills equipped in three skill slots connected with first mutagen slot.
  3430. Then it unequips those skills,
  3431. */
  3432. public final function TutorialMutagensUnequipPlayerSkills() : array<STutorialSavedSkill>
  3433. {
  3434. var savedSkills : array<STutorialSavedSkill>; //array of skills that were initially in the slots, needed to restore them after tutorial is done
  3435. var i : int;
  3436. var slots : array<int>; //slot IDs of slots that are in the group connected to equipped mutagen slot
  3437. var equippedSkill : ESkill;
  3438. var savedSkill : STutorialSavedSkill;
  3439.  
  3440. //get three skill slots' indexes of group in which we have the mutagen
  3441. slots = TutorialGetConnectedSkillsSlotsIDs();
  3442.  
  3443. //save equipped skills and clear slots
  3444. for(i=0; i<slots.Size(); i+=1)
  3445. {
  3446. if(GetSkillOnSlot(slots[i], equippedSkill) && equippedSkill != S_SUndefined)
  3447. {
  3448. //save skill
  3449. savedSkill.skillType = equippedSkill;
  3450. savedSkill.skillSlotID = slots[i];
  3451. savedSkills.PushBack(savedSkill);
  3452.  
  3453. //clear slot
  3454. UnequipSkill(slots[i]);
  3455. }
  3456. }
  3457.  
  3458. //update UI
  3459. TutorialUpdateUI();
  3460.  
  3461. return savedSkills;
  3462. }
  3463.  
  3464. /*
  3465. 'learns' temporary skill if not known and equips it in first skill slot.
  3466. Such temporary skill has the same color as the color of equipped mutagen.
  3467. */
  3468. public final function TutorialMutagensEquipOneGoodSkill()
  3469. {
  3470. var slots : array<int>;
  3471.  
  3472. //get three skill slots' indexes of group in which we have the mutagen
  3473. slots = TutorialGetConnectedSkillsSlotsIDs();
  3474.  
  3475. //select temp skill
  3476. TutorialSelectAndAddTempSkill();
  3477.  
  3478. //equip temp skill to first slot
  3479. EquipSkill(temporaryTutorialSkills[0].skillType, ArrayFindMinInt(slots));
  3480.  
  3481. //update UI
  3482. TutorialUpdateUI();
  3483. }
  3484.  
  3485. //Adds one improper temp skill to second slot
  3486. public final function TutorialMutagensEquipOneGoodOneBadSkill()
  3487. {
  3488. var slots : array<int>;
  3489.  
  3490. //add temp skill
  3491. TutorialSelectAndAddTempSkill(true);
  3492.  
  3493. //equip to second slot
  3494. slots = TutorialGetConnectedSkillsSlotsIDs();
  3495. ArraySortInts(slots);
  3496. EquipSkill(temporaryTutorialSkills[1].skillType, slots[1] );
  3497.  
  3498. //refresh UI
  3499. TutorialUpdateUI();
  3500. }
  3501.  
  3502. //Removes improper skill from second slot and adds two proper ones to slot 2 & 3
  3503. public final function TutorialMutagensEquipThreeGoodSkills()
  3504. {
  3505. var slots : array<int>;
  3506.  
  3507. //we no longer need the temp wrong color skill - remove it
  3508. TutorialGetRidOfTempSkill(1);
  3509.  
  3510. //add two proper color temp skills
  3511. TutorialSelectAndAddTempSkill(false, 1);
  3512. TutorialSelectAndAddTempSkill(false, 2);
  3513.  
  3514. //equip to second & third slots
  3515. slots = TutorialGetConnectedSkillsSlotsIDs();
  3516. ArraySortInts(slots);
  3517. EquipSkill(temporaryTutorialSkills[1].skillType, slots[1]);
  3518. EquipSkill(temporaryTutorialSkills[2].skillType, slots[2]);
  3519.  
  3520. //refresh UI
  3521. TutorialUpdateUI();
  3522. }
  3523.  
  3524. //removes all temp skills of tutorial and restores previous skills
  3525. public final function TutorialMutagensCleanupTempSkills(savedEquippedSkills : array<STutorialSavedSkill>)
  3526. {
  3527. //remove 3 temp skills
  3528. TutorialGetRidOfTempSkill(2);
  3529. TutorialGetRidOfTempSkill(1);
  3530. TutorialGetRidOfTempSkill(0);
  3531.  
  3532. //restore skills you had previously equipped
  3533. EquipSkill(savedEquippedSkills[0].skillType, savedEquippedSkills[0].skillSlotID);
  3534. EquipSkill(savedEquippedSkills[1].skillType, savedEquippedSkills[1].skillSlotID);
  3535. EquipSkill(savedEquippedSkills[2].skillType, savedEquippedSkills[2].skillSlotID);
  3536.  
  3537. TutorialUpdateUI();
  3538. }
  3539.  
  3540. private final function TutorialGetRidOfTempSkill(tutTempArrIdx : int)
  3541. {
  3542. var tempSkill : ESkill;
  3543. var i, ind : int;
  3544.  
  3545. tempSkill = temporaryTutorialSkills[tutTempArrIdx].skillType;
  3546. if(temporaryTutorialSkills[tutTempArrIdx].wasLearned)
  3547. {
  3548. if(!skills[tempSkill].isCoreSkill)
  3549. pathPointsSpent[skills[tempSkill].skillPath] = pathPointsSpent[skills[tempSkill].skillPath] - 1;
  3550.  
  3551. skills[tempSkill].level = 0;
  3552. }
  3553.  
  3554. ind = GetSkillSlotID(tempSkill);
  3555. if(ind >= 0)
  3556. UnequipSkill(ind);
  3557.  
  3558. temporaryTutorialSkills.EraseFast(tutTempArrIdx);
  3559. tempSkills.Remove(tempSkill);
  3560. }
  3561.  
  3562. //Selects and 'learns' temp skill matching for mutagen on EES_SkillMutange1 slot.
  3563. //If 'of wrong' color is set, temp skill will have different color than the mutagen.
  3564. //If 'index' is set then it picks next in line skill. Eg. we have 3 skills prepared for chosing so index =1 will select the second in line.
  3565. private final function TutorialSelectAndAddTempSkill(optional ofWrongColor : bool, optional index : int)
  3566. {
  3567. var witcher : W3PlayerWitcher;
  3568. var mutagenColor : ESkillColor; //color of equipped mutagen
  3569. var tempSkill : ESkill;
  3570. var tutSkill : STutorialTemporarySkill;
  3571. var mutagenItemId : SItemUniqueId;
  3572.  
  3573. //get mutagen color
  3574. witcher = GetWitcherPlayer();
  3575. witcher.GetItemEquippedOnSlot(EES_SkillMutagen1, mutagenItemId);
  3576. mutagenColor = witcher.inv.GetSkillMutagenColor(mutagenItemId);
  3577.  
  3578. if(!ofWrongColor)
  3579. {
  3580. if(mutagenColor == SC_Blue)
  3581. {
  3582. if(index == 0) tempSkill = S_Magic_s01;
  3583. else if(index == 1) tempSkill = S_Magic_s02;
  3584. else if(index == 2) tempSkill = S_Magic_s03;
  3585. }
  3586. else if(mutagenColor == SC_Red)
  3587. {
  3588. if(index == 0) tempSkill = S_Sword_s01;
  3589. else if(index == 1) tempSkill = S_Sword_s02;
  3590. else if(index == 2) tempSkill = S_Sword_s03;
  3591. }
  3592. else if(mutagenColor == SC_Green)
  3593. {
  3594. if(index == 0) tempSkill = S_Alchemy_s01;
  3595. else if(index == 1) tempSkill = S_Alchemy_s02;
  3596. else if(index == 2) tempSkill = S_Alchemy_s03;
  3597. }
  3598. }
  3599. else
  3600. {
  3601. if(mutagenColor == SC_Green)
  3602. tempSkill = S_Magic_s01;
  3603. else
  3604. tempSkill = S_Alchemy_s01;
  3605. }
  3606.  
  3607. //add temp skill if not known
  3608. if(GetSkillLevel(tempSkill) <= 0)
  3609. {
  3610. tempSkills.PushBack(tempSkill);
  3611. AddSkill(tempSkill, true);
  3612. tutSkill.wasLearned = true;
  3613. }
  3614. else
  3615. {
  3616. tutSkill.wasLearned = false;
  3617. }
  3618.  
  3619. tutSkill.skillType = tempSkill;
  3620. temporaryTutorialSkills.PushBack(tutSkill);
  3621. }
  3622.  
  3623. //returns array of Slot IDs of those three slots that are connected to EES_SkillMutagen1 mutagen slot
  3624. private final function TutorialGetConnectedSkillsSlotsIDs() : array<int>
  3625. {
  3626. var i, connectedSkillsGroupID, processedSlots : int;
  3627. var slots : array<int>;
  3628.  
  3629. connectedSkillsGroupID = GetSkillGroupIdOfMutagenSlot(EES_SkillMutagen1);
  3630.  
  3631. for(i=0; i<skillSlots.Size(); i+=1)
  3632. {
  3633. if(skillSlots[i].groupID == connectedSkillsGroupID)
  3634. {
  3635. slots.PushBack(skillSlots[i].id);
  3636. processedSlots += 1;
  3637.  
  3638. if(processedSlots == 3)
  3639. break;
  3640. }
  3641. }
  3642.  
  3643. return slots;
  3644. }
  3645.  
  3646. private final function TutorialUpdateUI()
  3647. {
  3648. ( (CR4CharacterMenu) ((CR4MenuBase)theGame.GetGuiManager().GetRootMenu()).GetLastChild() ).UpdateData(false);
  3649. }
  3650.  
  3651. //DEBUG MUTATIONS
  3652. public function DEBUG_DevelopAndEquipMutation( mut : EPlayerMutationType )
  3653. {
  3654. var player : W3PlayerWitcher;
  3655. var tempInt : int;
  3656.  
  3657. player = GetWitcherPlayer();
  3658.  
  3659. tempInt = GetMutationIndex( mut );
  3660. mutations[ tempInt ].progress.overallProgress = 100;
  3661. mutations[ tempInt ].progress.blueUsed = mutations[ tempInt ].progress.blueRequired;
  3662. mutations[ tempInt ].progress.greenUsed = mutations[ tempInt ].progress.greenRequired;
  3663. mutations[ tempInt ].progress.redUsed = mutations[ tempInt ].progress.redRequired;
  3664. mutations[ tempInt ].progress.skillpointsUsed = mutations[ tempInt ].progress.skillpointsRequired;
  3665. OnMutationFullyResearched( mut );
  3666.  
  3667. DEBUG_SetEquippedMutation( mut );
  3668. }
  3669.  
  3670. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3671. ////////////////////////////////////////////// @MUTATIONS //////////////////////////////////////////////////////////////////////
  3672. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3673.  
  3674. public final function ResetMutationsDev()
  3675. {
  3676. var i : int;
  3677.  
  3678. //unequip bonus skills
  3679. for( i=0; i<mutationUnlockedSlotsIndexes.Size(); i+=1 )
  3680. {
  3681. UnequipSkill( mutationUnlockedSlotsIndexes[ i ] );
  3682. }
  3683.  
  3684. //unequip mutation
  3685. SetEquippedMutation( EPMT_None );
  3686.  
  3687. //reset research
  3688. for( i=0; i<mutations.Size(); i+=1 )
  3689. {
  3690. mutations[i].progress.redUsed = 0;
  3691. mutations[i].progress.blueUsed = 0;
  3692. mutations[i].progress.greenUsed = 0;
  3693. mutations[i].progress.skillpointsUsed = 0;
  3694. mutations[i].progress.overallProgress = -1; //uncached
  3695. }
  3696. }
  3697.  
  3698. public final function GetMutationsUsedSkillPoints() : int
  3699. {
  3700. var total, i : int;
  3701.  
  3702. total = 0;
  3703. for( i=0; i<mutations.Size(); i+=1 )
  3704. {
  3705. total += mutations[i].progress.skillpointsUsed;
  3706. }
  3707.  
  3708. return total;
  3709. }
  3710.  
  3711. //loads data from XML
  3712. private final function LoadMutationData()
  3713. {
  3714. var xmlMutations : array< SMutation >;
  3715. var i, j : int;
  3716. var foundInXML : bool;
  3717.  
  3718. LoadMutationDataFromXML( xmlMutations );
  3719.  
  3720. //go through exsting mutations
  3721. for( i=mutations.Size()-1; i>=0; i-=1 )
  3722. {
  3723. foundInXML = false;
  3724.  
  3725. //if existing mutation was read from XML, override it with XML data
  3726. for( j=xmlMutations.Size()-1; j>=0; j-=1 )
  3727. {
  3728. if( mutations[ i ].type == xmlMutations[ j ].type )
  3729. {
  3730. mutations[ i ].progress.redRequired = xmlMutations[ j ].progress.redRequired;
  3731. mutations[ i ].progress.blueRequired = xmlMutations[ j ].progress.blueRequired;
  3732. mutations[ i ].progress.greenRequired = xmlMutations[ j ].progress.greenRequired;
  3733. mutations[ i ].progress.skillpointsRequired = xmlMutations[ j ].progress.skillpointsRequired;
  3734. mutations[ i ].progress.overallProgress = -1;
  3735. mutations[ i ].localizationNameKey = xmlMutations[ j ].localizationNameKey;
  3736. mutations[ i ].localizationDescriptionKey = xmlMutations[ j ].localizationDescriptionKey;
  3737. mutations[ i ].iconPath = xmlMutations[ j ].iconPath;
  3738. mutations[ i ].soundbank = xmlMutations[ j ].soundbank;
  3739.  
  3740. mutations[ i ].colors.Clear();
  3741. mutations[ i ].requiredMutations.Clear();
  3742.  
  3743. mutations[ i ].requiredMutations = xmlMutations[ j ].requiredMutations;
  3744. mutations[ i ].colors = xmlMutations[ j ].colors;
  3745.  
  3746. xmlMutations.EraseFast( j );
  3747. foundInXML = true;
  3748. break;
  3749. }
  3750. }
  3751.  
  3752. //mutation was removed in XML - remove it ingame
  3753. if( !foundInXML )
  3754. {
  3755. //add used skillpoints
  3756. if( mutations[ i ].progress.skillpointsUsed > 0 )
  3757. {
  3758. GetWitcherPlayer().AddPoints( ESkillPoint, mutations[ i ].progress.skillpointsUsed, false );
  3759. }
  3760.  
  3761. mutations.EraseFast( i );
  3762. }
  3763. }
  3764.  
  3765. //mutations in XML but not ingame, add
  3766. for( i=0; i<xmlMutations.Size(); i+=1 )
  3767. {
  3768. mutations.PushBack( xmlMutations[ i ] );
  3769. }
  3770. }
  3771.  
  3772. private final function LoadMutationDataFromXML( out xmlMutations : array< SMutation > )
  3773. {
  3774. var dm : CDefinitionsManagerAccessor;
  3775. var main, subNode : SCustomNode;
  3776. var xmlMutation : SMutation;
  3777. var i, tmpInt, j : int;
  3778. var tmpName : name;
  3779. var tmpStr : string;
  3780. var skillColor : ESkillColor;
  3781.  
  3782. dm = theGame.GetDefinitionsManager();
  3783. main = dm.GetCustomDefinition( 'mutations' );
  3784.  
  3785. xmlMutation.progress.redUsed = 0;
  3786. xmlMutation.progress.blueUsed = 0;
  3787. xmlMutation.progress.greenUsed = 0;
  3788. xmlMutation.progress.skillpointsUsed = 0;
  3789. xmlMutation.progress.overallProgress = -1;
  3790.  
  3791. //read & fill current XML data
  3792. for( i=0; i<main.subNodes.Size(); i+=1 )
  3793. {
  3794. dm.GetCustomNodeAttributeValueName( main.subNodes[ i ], 'type_name', tmpName );
  3795. xmlMutation.type = MutationNameToType( tmpName );
  3796.  
  3797. dm.GetCustomNodeAttributeValueInt( main.subNodes[ i ], 'redMutagenPoints', tmpInt );
  3798. xmlMutation.progress.redRequired = tmpInt;
  3799.  
  3800. dm.GetCustomNodeAttributeValueInt( main.subNodes[ i ], 'blueMutagenPoints', tmpInt );
  3801. xmlMutation.progress.blueRequired = tmpInt;
  3802.  
  3803. dm.GetCustomNodeAttributeValueInt( main.subNodes[ i ], 'greenMutagenPoints', tmpInt );
  3804. xmlMutation.progress.greenRequired = tmpInt;
  3805.  
  3806. dm.GetCustomNodeAttributeValueInt( main.subNodes[ i ], 'skillPoints', tmpInt );
  3807. xmlMutation.progress.skillpointsRequired = tmpInt;
  3808.  
  3809. dm.GetCustomNodeAttributeValueName( main.subNodes[ i ], 'localizationNameKey_name', tmpName );
  3810. xmlMutation.localizationNameKey = tmpName;
  3811.  
  3812. dm.GetCustomNodeAttributeValueName( main.subNodes[ i ], 'localizationDescriptionKey_name', tmpName );
  3813. xmlMutation.localizationDescriptionKey = tmpName;
  3814.  
  3815. dm.GetCustomNodeAttributeValueName( main.subNodes[ i ], 'iconPath_name', tmpName );
  3816. xmlMutation.iconPath = tmpName;
  3817.  
  3818. dm.GetCustomNodeAttributeValueString( main.subNodes[ i ], 'soundbank', tmpStr );
  3819. xmlMutation.soundbank = tmpStr;
  3820.  
  3821. //colors
  3822. subNode = dm.GetCustomDefinitionSubNode( main.subNodes[ i ], 'colors' );
  3823. for( j=0; j<subNode.values.Size(); j+=1 )
  3824. {
  3825. skillColor = SkillColorStringToType( subNode.values[ j ] );
  3826. if( skillColor == SC_Blue || skillColor == SC_Red || skillColor == SC_Green )
  3827. {
  3828. xmlMutation.colors.PushBack( skillColor );
  3829. }
  3830. }
  3831.  
  3832. //required mutations
  3833. subNode = dm.GetCustomDefinitionSubNode( main.subNodes[ i ], 'required_mutations' );
  3834. for( j=0; j<subNode.values.Size(); j+=1 )
  3835. {
  3836. xmlMutation.requiredMutations.PushBack( MutationNameToType( subNode.values[ j ] ) );
  3837. }
  3838.  
  3839. xmlMutations.PushBack( xmlMutation );
  3840.  
  3841. xmlMutation.colors.Clear();
  3842. xmlMutation.requiredMutations.Clear();
  3843. }
  3844. }
  3845.  
  3846. public final function SetEquippedMutation( mutationType : EPlayerMutationType ) : bool
  3847. {
  3848. if( mutationType == EPMT_None && !( ( CR4Player ) owner ).IsInCombat() )
  3849. {
  3850. if( equippedMutation != EPMT_None )
  3851. {
  3852. OnMutationUnequippedPre( equippedMutation );
  3853. }
  3854. SSS_UnequipAllMutations( ); //zur13 modSSS
  3855. equippedMutation = EPMT_None;
  3856. MutationsDisable();
  3857.  
  3858. return true;
  3859. }
  3860. else if( CanEquipMutation( mutationType ) )
  3861. {
  3862. if( equippedMutation != EPMT_None )
  3863. {
  3864. OnMutationUnequippedPre( equippedMutation );
  3865. }
  3866. equippedMutation = EPMT_None; //zur13 modSSS
  3867. MutationsEnable();
  3868. SSS_EquipMutation( mutationType ); //zur13 modSSS
  3869. OnMutationEquippedPost( mutationType ); //zur13 modSSS
  3870. return true;
  3871. }
  3872.  
  3873. return false;
  3874. }
  3875.  
  3876. public final function DEBUG_SetEquippedMutation( mutationType : EPlayerMutationType )
  3877. {
  3878. if( mutationType == EPMT_None )
  3879. {
  3880. if( equippedMutation != EPMT_None )
  3881. {
  3882. OnMutationUnequippedPre( equippedMutation );
  3883. MutationsDisable();
  3884. }
  3885.  
  3886. equippedMutation = EPMT_None;
  3887. }
  3888. else
  3889. {
  3890. if( equippedMutation != EPMT_None )
  3891. {
  3892. OnMutationUnequippedPre( equippedMutation );
  3893. }
  3894.  
  3895. MutationsEnable();
  3896. equippedMutation = mutationType;
  3897. OnMutationEquippedPost( equippedMutation );
  3898. }
  3899. }
  3900.  
  3901. //called on unequipping mutation, before it is unequipped
  3902. private final function OnMutationUnequippedPre( mutationType : EPlayerMutationType )
  3903. {
  3904. var bank : string;
  3905. var i : int;
  3906. var buffs : array< CBaseGameplayEffect >;
  3907.  
  3908. //unload soundbank
  3909. bank = GetMutationSoundBank( mutationType );
  3910. if( bank != "" && theSound.SoundIsBankLoaded( bank ) )
  3911. {
  3912. theSound.SoundUnloadBank( bank );
  3913. }
  3914.  
  3915. if( mutationType == EPMT_Mutation5 )
  3916. {
  3917. owner.RemoveBuff( EET_Mutation5 );
  3918. }
  3919. else if( mutationType == EPMT_Mutation10 )
  3920. {
  3921. owner.RemoveBuff( EET_Mutation10 );
  3922. owner.StopEffect( 'mutation_10' );
  3923. }
  3924. else if( mutationType == EPMT_Mutation12 )
  3925. {
  3926. buffs = GetWitcherPlayer().GetDrunkMutagens( "Mutation12" );
  3927. for( i=buffs.Size()-1; i>=0; i-=1 )
  3928. {
  3929. owner.RemoveEffect( buffs[i] );
  3930. }
  3931. }
  3932.  
  3933. owner.RemoveBuff( EET_Mutation3 );
  3934.  
  3935. //hud helix
  3936. theGame.MutationHUDFeedback( MFT_PlayHide );
  3937. }
  3938.  
  3939. //called on equipping mutation, after it was equipped
  3940. private final function OnMutationEquippedPost( mutationType : EPlayerMutationType )
  3941. {
  3942. var tutEquipping : W3TutorialManagerUIHandlerStateMutationsEquipping;
  3943. var tutEquipped : W3TutorialManagerUIHandlerStateMutationsEquippedAfter;
  3944. var bank : string;
  3945.  
  3946. //load sound bank
  3947. bank = GetMutationSoundBank( mutationType );
  3948. if( bank != "" )
  3949. {
  3950. theSound.SoundLoadBank( bank, true );
  3951. }
  3952.  
  3953. UpdateMutationSkillSlots();
  3954.  
  3955. if( GetWitcherPlayer().IsMutationActive( EPMT_Mutation10 ) && GetStat( BCS_Toxicity ) != 0 )
  3956. {
  3957. owner.AddEffectDefault( EET_Mutation10, NULL, "Mutation 10" );
  3958. }
  3959.  
  3960. //tutorial about equipping mutation
  3961. if( ShouldProcessTutorial( 'TutorialMutationsEquippingOnlyOne' ) )
  3962. {
  3963. tutEquipping = ( W3TutorialManagerUIHandlerStateMutationsEquipping ) theGame.GetTutorialSystem().uiHandler.GetCurrentState();
  3964. if( tutEquipping )
  3965. {
  3966. tutEquipping.OnMutationEquippedPost();
  3967. }
  3968.  
  3969. tutEquipped = ( W3TutorialManagerUIHandlerStateMutationsEquippedAfter ) theGame.GetTutorialSystem().uiHandler.GetCurrentState();
  3970. if( tutEquipped )
  3971. {
  3972. tutEquipped.OnMutationEquippedPost();
  3973. }
  3974.  
  3975. GameplayFactsAdd( "tutorial_mutations_equipped_mutation" );
  3976. }
  3977. }
  3978.  
  3979. public final function GetMutationSoundBank( mut : EPlayerMutationType ) : string
  3980. {
  3981. var idx : int;
  3982.  
  3983. idx = GetMutationIndex( mut );
  3984. if( idx == -1 )
  3985. {
  3986. return "";
  3987. }
  3988.  
  3989. return mutations[idx].soundbank;
  3990. }
  3991.  
  3992. private final function MutationsEnable()
  3993. {
  3994. var witcher : W3PlayerWitcher;
  3995.  
  3996. witcher = GetWitcherPlayer();
  3997.  
  3998. //unequip mutagens
  3999. //witcher.UnequipItemFromSlot( EES_SkillMutagen1 );
  4000. //witcher.UnequipItemFromSlot( EES_SkillMutagen2 );
  4001. //witcher.UnequipItemFromSlot( EES_SkillMutagen3 );
  4002. //witcher.UnequipItemFromSlot( EES_SkillMutagen4 );
  4003.  
  4004. //enable special skill slots
  4005. UpdateMutationSkillSlots();
  4006. }
  4007.  
  4008. private final function MutationsDisable()
  4009. {
  4010. UpdateMutationSkillSlots();
  4011. }
  4012.  
  4013. public final function GetEquippedMutationType() : array< EPlayerMutationType > //zur13 modSSS
  4014. {
  4015. return equippedMutations; //zur13 modSSS
  4016. }
  4017.  
  4018. public final function CanEquipMutation( mutationType : EPlayerMutationType ) : bool
  4019. {
  4020. //master mutation is a passive so you can't equip it
  4021. if( mutationType == EPMT_MutationMaster )
  4022. {
  4023. return false;
  4024. }
  4025.  
  4026. if( !IsMutationResearched( mutationType ) )
  4027. {
  4028. return false;
  4029. }
  4030.  
  4031. if( ( ( CR4Player ) owner ).IsInCombat() )
  4032. {
  4033. return false;
  4034. }
  4035.  
  4036. return true;
  4037. }
  4038.  
  4039. public final function CanResearchMutation( mutationType : EPlayerMutationType ) : bool
  4040. {
  4041. var curMutation : SMutation;
  4042. var curRequiredMutations : array< EPlayerMutationType >;
  4043. var i, count : int;
  4044.  
  4045. if( owner.IsInCombat() )
  4046. {
  4047. return false;
  4048. }
  4049.  
  4050. curMutation = GetMutation( mutationType );
  4051. curRequiredMutations = curMutation.requiredMutations;
  4052. count = curRequiredMutations.Size();
  4053.  
  4054. for( i = 0; i < count; i += 1 )
  4055. {
  4056. if( !IsMutationResearched( curRequiredMutations[i] ) )
  4057. {
  4058. return false;
  4059. }
  4060. }
  4061.  
  4062. return true;
  4063. }
  4064.  
  4065. public final function GetMutationColors( mutationType : EPlayerMutationType ) : array< ESkillColor >
  4066. {
  4067. var idx : int;
  4068. var colors : array< ESkillColor >;
  4069.  
  4070. idx = GetMutationIndex( mutationType );
  4071. if( idx == -1 )
  4072. {
  4073. return colors;
  4074. }
  4075.  
  4076. if( mutations[idx].progress.redRequired > 0 )
  4077. {
  4078. colors.PushBack( SC_Red );
  4079. }
  4080. if( mutations[idx].progress.greenRequired > 0 )
  4081. {
  4082. colors.PushBack( SC_Green );
  4083. }
  4084. if( mutations[idx].progress.blueRequired > 0 )
  4085. {
  4086. colors.PushBack( SC_Blue );
  4087. }
  4088.  
  4089. return colors;
  4090. }
  4091.  
  4092. public final function IsMutationResearched( mutationType : EPlayerMutationType ) : bool
  4093. {
  4094. return GetMutationResearchProgress( mutationType ) >= 100;
  4095. }
  4096.  
  4097. //calculates overall progress of mutation 0-100 (%)
  4098. public final function GetMutationResearchProgress( mutationType : EPlayerMutationType ) : int
  4099. {
  4100. var mutation : SMutation;
  4101. var idx, researchedMutations, stage : int;
  4102. var progress, progressRequired : float;
  4103.  
  4104. idx = GetMutationIndex( mutationType );
  4105. if( idx == -1 )
  4106. {
  4107. return 0;
  4108. }
  4109.  
  4110. mutation = mutations[ idx ];
  4111.  
  4112. //fill progress data
  4113. if( mutation.type == EPMT_MutationMaster )
  4114. {
  4115. researchedMutations = GetResearchedMutationsCount();
  4116. stage = GetMasterMutationStage();
  4117.  
  4118. //set progress
  4119. progress = researchedMutations - GetMutationsRequiredForMasterStage( stage );
  4120. progressRequired = GetMutationsRequiredForMasterStage( stage + 1 ) - GetMutationsRequiredForMasterStage( stage );
  4121. }
  4122. else
  4123. {
  4124. //if cached return
  4125. if( mutation.progress.overallProgress >= 0 )
  4126. {
  4127. return mutation.progress.overallProgress;
  4128. }
  4129.  
  4130. progress = mutation.progress.redUsed + mutation.progress.blueUsed + mutation.progress.greenUsed + mutation.progress.skillpointsUsed;
  4131. progressRequired = mutation.progress.redRequired + mutation.progress.blueRequired + mutation.progress.greenRequired + mutation.progress.skillpointsRequired;
  4132. }
  4133.  
  4134. //calculate progress
  4135. progress = FloorF( ( 100 * progress ) / progressRequired );
  4136.  
  4137. //cache
  4138. mutations[ idx ].progress.overallProgress = ( int )progress;
  4139.  
  4140. return ( int )progress;
  4141. }
  4142.  
  4143. //Returns amount of mutations that need to be fully researched to reach given stage of master mutation.
  4144. public final function GetMutationsRequiredForMasterStage( stage : int ) : int
  4145. {
  4146. var dm : CDefinitionsManagerAccessor;
  4147. var min, max : SAbilityAttributeValue;
  4148. var attributeName : name;
  4149.  
  4150. switch( stage )
  4151. {
  4152. case 1:
  4153. attributeName = 'mutationsRequiredForSlot1';
  4154. break;
  4155. case 2:
  4156. attributeName = 'mutationsRequiredForSlot2';
  4157. break;
  4158. case 3:
  4159. attributeName = 'mutationsRequiredForSlot3';
  4160. break;
  4161. case 4:
  4162. attributeName = 'mutationsRequiredForSlot4';
  4163. break;
  4164. default:
  4165. return 0; //all done
  4166. }
  4167.  
  4168. dm = theGame.GetDefinitionsManager();
  4169. dm.GetAbilityAttributeValue('Mutation Master', attributeName, min, max);
  4170. return (int)min.valueAdditive;
  4171. }
  4172.  
  4173. public final function MutationSystemEnable( enable : bool )
  4174. {
  4175. isMutationSystemEnabled = enable;
  4176. }
  4177.  
  4178. public final function IsMutationSystemEnabled() : bool
  4179. {
  4180. return isMutationSystemEnabled;
  4181. }
  4182.  
  4183. public final function GetMasterMutationStage() : int
  4184. {
  4185. var idx, researchedMutations, i : int;
  4186.  
  4187. idx = GetMutationIndex( EPMT_MutationMaster );
  4188. if( idx == -1 )
  4189. {
  4190. return 0;
  4191. }
  4192.  
  4193. researchedMutations = GetResearchedMutationsCount();
  4194.  
  4195. for( i=4; i>0; i-= 1)
  4196. {
  4197. if(researchedMutations >= GetMutationsRequiredForMasterStage( i ) )
  4198. {
  4199. return i;
  4200. }
  4201. }
  4202.  
  4203. return 0;
  4204. }
  4205.  
  4206. public final function GetResearchedMutationsCount() : int
  4207. {
  4208. var researchedMutations, i : int;
  4209.  
  4210. researchedMutations = 0;
  4211. for( i=0; i<mutations.Size(); i+=1 )
  4212. {
  4213. if( mutations[ i ].type != EPMT_MutationMaster && GetMutationResearchProgress( mutations[ i ].type ) == 100 )
  4214. {
  4215. researchedMutations += 1;
  4216. }
  4217. }
  4218.  
  4219. return researchedMutations;
  4220. }
  4221.  
  4222. //gets index in mutations array for mutation of given type
  4223. private final function GetMutationIndex( mutationType : EPlayerMutationType ) : int
  4224. {
  4225. var i : int;
  4226.  
  4227. if( mutationType == EPMT_None )
  4228. {
  4229. return -1;
  4230. }
  4231.  
  4232. for( i=0; i<mutations.Size(); i+=1 )
  4233. {
  4234. if( mutations[ i ].type == mutationType )
  4235. return i;
  4236. }
  4237.  
  4238. return -1;
  4239. }
  4240.  
  4241. public final function GetMutation( mutationType : EPlayerMutationType ) : SMutation
  4242. {
  4243. var null : SMutation;
  4244. var idx : int;
  4245.  
  4246. idx = GetMutationIndex( mutationType );
  4247. if( idx != -1 )
  4248. {
  4249. return mutations[ idx ];
  4250. }
  4251.  
  4252. return null;
  4253. }
  4254.  
  4255. public final function GetMutations() : array< SMutation >
  4256. {
  4257. return mutations;
  4258. }
  4259.  
  4260. public final function MutationResearchWithSkillPoints( mutation : EPlayerMutationType, skillPoints : int ) : bool
  4261. {
  4262. var witcher : W3PlayerWitcher;
  4263. var availableSkillPoints, idx, progress : int;
  4264.  
  4265. //not witcher
  4266. witcher = GetWitcherPlayer();
  4267. if( owner != witcher )
  4268. {
  4269. return false;
  4270. }
  4271.  
  4272. //such mutation does not exist
  4273. idx = GetMutationIndex( mutation );
  4274. if( idx == -1 )
  4275. {
  4276. return false;
  4277. }
  4278.  
  4279. //mutation is not developped with skillpoints
  4280. if( mutations[ idx ].progress.skillpointsRequired == 0 )
  4281. {
  4282. return false;
  4283. }
  4284.  
  4285. //wrong amount passed
  4286. if( skillPoints <= 0 )
  4287. {
  4288. return false;
  4289. }
  4290.  
  4291. //not enough skill points
  4292. availableSkillPoints = witcher.levelManager.GetPointsFree( ESkillPoint );
  4293. if( availableSkillPoints < skillPoints )
  4294. {
  4295. return false;
  4296. }
  4297.  
  4298. //already maxed out
  4299. if( mutations[ idx ].progress.skillpointsRequired <= mutations[ idx ].progress.skillpointsUsed )
  4300. {
  4301. return false;
  4302. }
  4303.  
  4304. //trying to spend more skill points than required
  4305. if( mutations[ idx ].progress.skillpointsUsed + skillPoints > mutations[ idx ].progress.skillpointsRequired )
  4306. {
  4307. return false;
  4308. }
  4309.  
  4310. //research
  4311. witcher.levelManager.SpendPoints( ESkillPoint, skillPoints );
  4312. mutations[ idx ].progress.skillpointsUsed += skillPoints;
  4313. mutations[ idx ].progress.overallProgress = -1; //reset cache
  4314.  
  4315. //update current progress
  4316. progress = GetMutationResearchProgress( mutation );
  4317. if( progress == 100 )
  4318. {
  4319. OnMutationFullyResearched( mutation );
  4320. }
  4321.  
  4322. return true;
  4323. }
  4324.  
  4325. public final function MutationResearchWithItem( mutation : EPlayerMutationType, item : SItemUniqueId ) : bool
  4326. {
  4327. var witcher : W3PlayerWitcher;
  4328. var idx, redPoints, bluePoints, greenPoints, progress : int;
  4329.  
  4330. //not witcher
  4331. witcher = GetWitcherPlayer();
  4332. if( owner != witcher )
  4333. {
  4334. return false;
  4335. }
  4336.  
  4337. //such mutation does not exist
  4338. idx = GetMutationIndex( mutation );
  4339. if( idx == -1 )
  4340. {
  4341. return false;
  4342. }
  4343.  
  4344. //invalid item
  4345. if( !witcher.inv.IsIdValid( item ) )
  4346. {
  4347. return false;
  4348. }
  4349.  
  4350. //mutation is not developped with items
  4351. if( mutations[ idx ].progress.blueRequired + mutations[ idx ].progress.redRequired + mutations[ idx ].progress.greenRequired == 0 )
  4352. {
  4353. return false;
  4354. }
  4355.  
  4356. //get research points from item
  4357. redPoints = witcher.inv.GetMutationResearchPoints( SC_Red, item );
  4358. greenPoints = witcher.inv.GetMutationResearchPoints( SC_Green, item );
  4359. bluePoints = witcher.inv.GetMutationResearchPoints( SC_Blue, item );
  4360.  
  4361. //item has negative research points
  4362. if(redPoints < 0 || greenPoints < 0 || bluePoints < 0 )
  4363. {
  4364. return false;
  4365. }
  4366.  
  4367. //item does not have research points at all
  4368. if( redPoints + greenPoints + bluePoints == 0 )
  4369. {
  4370. return false;
  4371. }
  4372.  
  4373. //wrong type of points
  4374. if( ( redPoints > 0 && mutations[ idx ].progress.redRequired == 0 ) && ( bluePoints > 0 && mutations[ idx ].progress.blueRequired == 0 ) && ( greenPoints > 0 && mutations[ idx ].progress.greenRequired == 0 ) )
  4375. {
  4376. return false;
  4377. }
  4378.  
  4379. //already maxed out
  4380. if( ( redPoints > 0 && mutations[ idx ].progress.redRequired <= mutations[ idx ].progress.redUsed ) && ( bluePoints > 0 && mutations[ idx ].progress.blueRequired <= mutations[ idx ].progress.blueUsed ) && ( greenPoints > 0 && mutations[ idx ].progress.greenRequired <= mutations[ idx ].progress.greenUsed ) )
  4381. {
  4382. return false;
  4383. }
  4384.  
  4385. //research
  4386. witcher.inv.RemoveItem( item );
  4387. mutations[ idx ].progress.redUsed += redPoints;
  4388. mutations[ idx ].progress.greenUsed += greenPoints;
  4389. mutations[ idx ].progress.blueUsed += bluePoints;
  4390. mutations[ idx ].progress.overallProgress = -1; //reset cache
  4391.  
  4392. //invalidate current progress
  4393. progress = GetMutationResearchProgress( mutation );
  4394. if( progress == 100 )
  4395. {
  4396. OnMutationFullyResearched( mutation );
  4397. }
  4398.  
  4399. return true;
  4400. }
  4401.  
  4402. public final function GetMutationNameLocalizationKey( mutationType : EPlayerMutationType ) : name
  4403. {
  4404. var idx : int;
  4405.  
  4406. idx = GetMutationIndex( mutationType );
  4407. if( idx < 0 )
  4408. {
  4409. return '';
  4410. }
  4411.  
  4412. return mutations[ idx ].localizationNameKey;
  4413. }
  4414.  
  4415. public final function GetMutationDescriptionLocalizationKey( mutationType : EPlayerMutationType ) : name
  4416. {
  4417. var idx : int;
  4418.  
  4419. idx = GetMutationIndex( mutationType );
  4420. if( idx < 0 )
  4421. {
  4422. return '';
  4423. }
  4424.  
  4425. return mutations[ idx ].localizationDescriptionKey;
  4426. }
  4427.  
  4428.  
  4429. //Called when a mutation has been researched to full
  4430. private final function OnMutationFullyResearched( mutationType : EPlayerMutationType )
  4431. {
  4432. var idx, firstLockedSlotIdx, i : int;
  4433. var attributeName : name;
  4434. var min, max : SAbilityAttributeValue;
  4435. var tutEquip : W3TutorialManagerUIHandlerStateMutationsEquipping;
  4436.  
  4437. //get master mutation index
  4438. idx = GetMutationIndex( EPMT_MutationMaster );
  4439. if( idx < 0 )
  4440. {
  4441. return;
  4442. }
  4443.  
  4444. //update master mutation progress
  4445. GetMutationResearchProgress( EPMT_MutationMaster );
  4446.  
  4447. UpdateMutationSkillSlots();
  4448.  
  4449. //Achievement - School of the Mutant
  4450. theGame.GetGamerProfile().AddAchievement( EA_SchoolOfTheMutant );
  4451.  
  4452. //if first mutation and tutorials off - automatically equip
  4453. if( GetResearchedMutationsCount() == 1 && !theGame.GetTutorialSystem().AreMessagesEnabled() )
  4454. {
  4455. SetEquippedMutation( mutationType );
  4456. }
  4457.  
  4458. //tutorial about equipping mutation
  4459. if( ShouldProcessTutorial( 'TutorialMutationsEquipping' ) )
  4460. {
  4461. tutEquip = ( W3TutorialManagerUIHandlerStateMutationsEquipping ) theGame.GetTutorialSystem().uiHandler.GetCurrentState();
  4462. if( tutEquip )
  4463. {
  4464. tutEquip.OnMutationFullyResearched();
  4465. }
  4466. }
  4467. }
  4468.  
  4469. private final function UpdateMutationSkillSlots()
  4470. {
  4471. var i : int;
  4472. var skillType : ESkill;
  4473. var skillColor : ESkillColor;
  4474. var mutationColors : array< ESkillColor >;
  4475. var mutType : EPlayerMutationType;
  4476.  
  4477. UpdateMutationSkillSlotsLocks();
  4478.  
  4479. mutType = SSS_GetEquippedMutationType(); //zur13 modSSS
  4480. if( mutType != EPMT_None )
  4481. {
  4482. //check color of equipped skills and unequip if new mutation does not allow them
  4483. mutationColors = GetMutationColors( mutType );
  4484. for( i=0; i<mutationUnlockedSlotsIndexes.Size(); i+=1 )
  4485. {
  4486. //get skill type
  4487. skillType = skillSlots[ mutationUnlockedSlotsIndexes[ i ] ].socketedSkill;
  4488. if( skillType != S_SUndefined )
  4489. {
  4490. //check colors
  4491. skillColor = GetSkillColor( skillType );
  4492. if( !mutationColors.Contains( skillColor ) )
  4493. {
  4494. //sortX UnequipSkill( GetSkillSlotID( skillType ) );
  4495. }
  4496. }
  4497. }
  4498. }
  4499. else
  4500. {
  4501. //unequip all skills
  4502. for( i=0; i<mutationUnlockedSlotsIndexes.Size(); i+=1 )
  4503. {
  4504. skillType = skillSlots[ mutationUnlockedSlotsIndexes[ i ] ].socketedSkill;
  4505. UnequipSkill( GetSkillSlotID( skillType ) );
  4506. }
  4507. }
  4508. }
  4509.  
  4510. private final function UpdateMutationSkillSlotsLocks()
  4511. {
  4512. var i, researchedCount, masterStage, unlockedCount, idx : int;
  4513. var tutEquip : W3TutorialManagerUIHandlerStateMutationsUnlockedSkillSlot;
  4514.  
  4515. //if no mutation equipped all slots are locked
  4516. if( SSS_GetEquippedMutationType() == EPMT_None ) //zur13 modSSS
  4517. {
  4518. for( i=0; i<mutationUnlockedSlotsIndexes.Size(); i+=1 )
  4519. {
  4520. idx = GetSkillSlotIndex( mutationUnlockedSlotsIndexes[ i ], false );
  4521. skillSlots[ idx ].unlocked = false;
  4522. }
  4523. }
  4524. else
  4525. {
  4526. researchedCount = GetResearchedMutationsCount();
  4527. masterStage = GetMasterMutationStage();
  4528.  
  4529. for( i=0; i<mutationUnlockedSlotsIndexes.Size(); i+=1 )
  4530. {
  4531. if( masterStage >= i+1 && researchedCount >= GetMutationsRequiredForMasterStage( i+1 ) )
  4532. {
  4533. skillSlots[ GetSkillSlotIndex( mutationUnlockedSlotsIndexes[ i ], false ) ].unlocked = true;
  4534.  
  4535. if( ShouldProcessTutorial( 'TutorialMutationsMasterLevelUp' ) )
  4536. {
  4537. tutEquip = ( W3TutorialManagerUIHandlerStateMutationsUnlockedSkillSlot ) theGame.GetTutorialSystem().uiHandler.GetCurrentState();
  4538. if( tutEquip )
  4539. {
  4540. tutEquip.OnMutationSkillSlotUnlocked();
  4541. }
  4542. }
  4543. }
  4544. else
  4545. {
  4546. skillSlots[ GetSkillSlotIndex( mutationUnlockedSlotsIndexes[ i ], false ) ].unlocked = false;
  4547. }
  4548. }
  4549. }
  4550.  
  4551. if( ShouldProcessTutorial( 'TutorialMutationsAdditionalSkillSlot' ) )
  4552. {
  4553. unlockedCount = 0;
  4554. for( i=0; i<mutationUnlockedSlotsIndexes.Size(); i+=1 )
  4555. {
  4556. if( skillSlots[ mutationUnlockedSlotsIndexes[ i ] ].unlocked )
  4557. {
  4558. unlockedCount += 1;
  4559. }
  4560. }
  4561. GameplayFactsSet( "tutorial_mutations_unlocked_skill_slots", unlockedCount );
  4562. }
  4563. }
  4564. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4565. ////////////////////////////////////////////// @HAXXX //////////////////////////////////////////////////////////////////////////
  4566. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4567.  
  4568. //returns true if slot was unlocked in the process
  4569. final function Debug_HAX_UnlockSkillSlot(slotIndex : int) : bool
  4570. {
  4571. if(!IsSkillSlotUnlocked(slotIndex))
  4572. {
  4573. skillSlots[slotIndex].unlocked = true;
  4574. LogSkills("W3PlayerAbilityManager.Debug_HAX_UnlockSkillSlot: unlocking skill slot " + slotIndex + " for debug purposes");
  4575. return true;
  4576. }
  4577.  
  4578. return false;
  4579. }
  4580.  
  4581. final function DBG_SkillSlots()
  4582. {
  4583. var i : int;
  4584.  
  4585. for(i=0; i<skillSlots.Size(); i+=1)
  4586. {
  4587. LogChannel('DEBUG_SKILLS', i + ") ID=" + skillSlots[i].id + " | skill=" + skillSlots[i].socketedSkill + " | groupID=" + skillSlots[i].groupID + " | unlockedAt=" + skillSlots[i].unlockedOnLevel);
  4588. }
  4589.  
  4590. LogChannel('DEBUG_SKILLS',"");
  4591. }
  4592.  
  4593. public final function DEBUG_PrintMutationSkillSlotsLocks()
  4594. {
  4595. var i : int;
  4596.  
  4597. for( i=0; i<mutationUnlockedSlotsIndexes.Size(); i+=1 )
  4598. {
  4599. LogMutation( "Slot [" + mutationUnlockedSlotsIndexes[ i ] + "] = " + skillSlots[ mutationUnlockedSlotsIndexes[ i ] ].unlocked );
  4600. }
  4601. }
  4602.  
  4603. public final function MustEquipSkill(skill : ESkill) : bool
  4604. public function SSS_IsMutationSlotsInitRequired():bool
  4605. {
  4606. var targetSlot:SSkillSlot;
  4607. var mutSltIdx:int;
  4608. //return true if mutation slots init wasn't complete due to hidden slots already exist
  4609. if(mutationUnlockedSlotsIndexes.Size()>0)
  4610. {
  4611. mutSltIdx = mutationUnlockedSlotsIndexes[ 0 ];
  4612. if(mutSltIdx>-1){
  4613. targetSlot = skillSlots[ mutSltIdx ];
  4614. if(targetSlot.groupID==MUTATION_SKILL_GROUP_ID)
  4615. {
  4616. return false;
  4617. }
  4618. }
  4619. }
  4620. return true;
  4621. }
  4622.  
  4623. public function SSS_AddSkillSlot(slot : SSkillSlot)
  4624. {
  4625. totalSkillSlotsCount = Max(totalSkillSlotsCount, slot.id);
  4626. skillSlots.PushBack(slot);
  4627. }
  4628.  
  4629. if(!HasLearnedSkill(skill))
  4630. return false;
  4631. //skillSlots.Clear();
  4632. var curSize: int;
  4633. while(skillSlots.Size()>baseSkillSlotsCount)
  4634. {
  4635. skillSlots.PopBack();
  4636. }
  4637. //clear previous skill slots that prevent mutation slots from init
  4638. //if required
  4639. if(SSS_IsMutationSlotsInitRequired())
  4640. {
  4641. while(skillSlots.Size()>12)
  4642. {
  4643. skillSlots.PopBack();
  4644. }
  4645. }
  4646.  
  4647. totalSkillSlotsCount = skillSlots.Size();
  4648. }
  4649.  
  4650. public function SSS_InitSkillSlots()
  4651. {
  4652. var i: int;
  4653. InitSkillSlots(true);
  4654. //cache indexes of skill slots unlocked via mutation system
  4655. if( mutationUnlockedSlotsIndexes.Size() == 0 )
  4656. {
  4657. for( i=0; i<skillSlots.Size(); i+=1 )
  4658. {
  4659. if( skillSlots[ i ].groupID == MUTATION_SKILL_GROUP_ID )
  4660. {
  4661. mutationUnlockedSlotsIndexes.PushBack( i );
  4662. }
  4663. }
  4664. }
  4665. UpdateMutationSkillSlots();
  4666. }
  4667.  
  4668. public function SSS_CheckAndInitMutationsSkillSlots()
  4669. {
  4670. var i, tmpInt : int;
  4671. var slot : SSkillSlot;
  4672. var dm : CDefinitionsManagerAccessor;
  4673. var main : SCustomNode;
  4674. if(SSS_IsMutationSlotsInitRequired())
  4675. {
  4676. // failsafe way to add mutation skill slots
  4677. for(i=BSS_SkillSlot1; i<=BSS_SkillSlot4; i+=1)
  4678. {
  4679. slot.id = i;
  4680. slot.unlockedOnLevel = 999999;
  4681. slot.groupID = MUTATION_SKILL_GROUP_ID;
  4682.  
  4683. SSS_AddSkillSlot(slot);
  4684.  
  4685. slot.id = -1;
  4686. slot.unlockedOnLevel = 0;
  4687. slot.groupID = -1;
  4688. }
  4689. //cache indexes of skill slots unlocked via mutation system
  4690. mutationUnlockedSlotsIndexes.Clear();
  4691.  
  4692. for( i=0; i<skillSlots.Size(); i+=1 )
  4693. {
  4694. if( skillSlots[ i ].groupID == MUTATION_SKILL_GROUP_ID )
  4695. {
  4696. mutationUnlockedSlotsIndexes.PushBack( i );
  4697. return i;
  4698. }
  4699. }
  4700.  
  4701. UpdateMutationSkillSlots();
  4702. }
  4703. }
  4704.  
  4705. public function SSS_UnlockSkillSlots()
  4706. {
  4707. var i, playerLevel : int;
  4708. if( (W3PlayerWitcher)owner )
  4709. {
  4710. playerLevel = ((W3PlayerWitcher)owner).GetLevel();
  4711. for(i=0; i<skillSlots.Size(); i+=1)
  4712. {
  4713. if(skillSlots[i].id>=BSS_SkillSlot1 && skillSlots[i].id<=BSS_SkillSlot4) {
  4714. //Mutation slots
  4715. }
  4716. else
  4717. {
  4718. if(!unlockAllSkillSlots){
  4719. skillSlots[i].unlocked = ( playerLevel >= skillSlots[i].unlockedOnLevel);
  4720. }
  4721. else
  4722. {
  4723. skillSlots[i].unlocked = true;
  4724. }
  4725. }
  4726. }
  4727. }
  4728. UpdateMutationSkillSlots();
  4729. }
  4730.  
  4731. public function SSS_SetUnlockAllSkillSlots(newValue:bool)
  4732. {
  4733. unlockAllSkillSlots = newValue;
  4734. }
  4735. slot.unlocked = true;
  4736. skillSlots.PushBack(slot);
  4737.  
  4738. public function SSS_GetMutationUnlockedSlotsIndexes(): array< int >
  4739. {
  4740. return mutationUnlockedSlotsIndexes;
  4741. }
  4742.  
  4743. public function SSS_OnMutationUnequippedPre( mutationType : EPlayerMutationType )
  4744. {
  4745. OnMutationUnequippedPre( mutationType );
  4746. }
  4747.  
  4748. public function SSS_GetEquippedMutationType() : EPlayerMutationType
  4749. {
  4750. //return first equipped mutation
  4751. var equippedMutations : array< EPlayerMutationType >;
  4752. equippedMutations = GetEquippedMutationType();
  4753.  
  4754. if(equippedMutations.Size()>0)
  4755. {
  4756. return equippedMutations[0];
  4757. }
  4758. return EPMT_None;
  4759. }
  4760.  
  4761. function SSS_EquipMutation( mutationType : EPlayerMutationType )
  4762. {
  4763. equippedMutations.PushBack( mutationType );
  4764. }
  4765.  
  4766. function SSS_UnequipAllMutations( )
  4767. {
  4768. var i : int;
  4769. for( i=0; i<equippedMutations.Size(); i=i+1 )
  4770. {
  4771. SSS_OnMutationUnequippedPre( equippedMutations[i] );
  4772. }
  4773. equippedMutations.Clear();
  4774. }
  4775. }
  4776.  
  4777. exec function dbgskillslots()
  4778. {
  4779. thePlayer.DBG_SkillSlots();
  4780. }
  4781.  
  4782. exec function dbgmutslots()
  4783. {
  4784. ((W3PlayerAbilityManager)thePlayer.abilityManager).DEBUG_PrintMutationSkillSlotsLocks();
  4785. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement