· 9 years ago · Oct 27, 2016, 10:54 PM
1/***********************************************************************/
2/** Witcher Script file
3/***********************************************************************/
4/** Copyright © 2013-2014 CDProjektRed
5/** Author : Dexio ?
6/** Bartosz Bigaj
7/** Tomek Kozeraa
8/***********************************************************************/
9
10/*
11enum EInventoryEventType
12{
13 IET_Empty,
14 IET_ItemAdded, // quantity always positive -> number of added items
15 IET_ItemRemoved, // quantity always positive -> number of removed items
16 IET_ItemQuantityChanged, // quantity positive or negative -> number of added (P) or removed (N) items
17 IET_ItemTagChanged, // quantity not used - always equal to 0
18 IET_InventoryRebalanced, // quantity not used - always equal to 0, itemId == INVALID
19};
20*/
21
22class IInventoryScriptedListener
23{
24 event OnInventoryScriptedEvent( eventType : EInventoryEventType, itemId : SItemUniqueId, quantity : int, fromAssociatedInventory : bool ) {}
25}
26
27import struct SItemNameProperty
28{
29 import editable var itemName : name;
30};
31
32import struct SR4LootNameProperty
33{
34 import editable var lootName : name;
35};
36
37struct SItemExt
38{
39 editable var itemName : SItemNameProperty;
40 editable var quantity : int;
41 default quantity = 1;
42};
43
44struct SCardSourceData
45{
46 var cardName : name;
47 var source : string;
48 var originArea : string;
49 var originQuest : string;
50 var details : string;
51 var coords : string;
52};
53
54//used to pass data about item being added/removed from inventory
55import struct SItemChangedData
56{
57 import const var itemName : name; //name of changed item
58 import const var quantity : int; //total quantity of item (e.g. if it's stackable item that spanned to several ids this is the total count)
59 import const var informGui : bool; //should UI be informed that the change occured
60 import const var ids : array< SItemUniqueId >; //array of ids of added items (e.g. when we add 3 swords we'll get 3 different ids OR when we add stackable item we might get few ids if quantity > stack size)
61};
62
63import class CInventoryComponent extends CComponent
64{
65 editable var priceMult : float;
66 editable var priceRepairMult : float;
67 editable var priceRepair : float;
68 editable var fundsType : EInventoryFundsType;
69
70 private var recentlyAddedItems : array<SItemUniqueId>;
71 private var fundsMax : int;
72 private var daysToIncreaseFunds : int;
73
74 default priceMult = 1.0;
75 default priceRepairMult = 1.0;
76 default priceRepair = 10.0;
77 default fundsType = EInventoryFunds_Avg;
78 default daysToIncreaseFunds = 5;
79
80 // ---------------------------------------------------------------------------
81 // Funds Management
82 // ---------------------------------------------------------------------------
83 public function GetFundsType() : EInventoryFundsType
84 {
85 return fundsType;
86 }
87
88 public function GetDaysToIncreaseFunds() : int
89 {
90 return daysToIncreaseFunds;
91 }
92
93 public function GetFundsMax() : float
94 {
95 if ( EInventoryFunds_Broke == fundsType )
96 {
97 return 0;
98 }
99 else if ( EInventoryFunds_Avg == fundsType )
100 {
101 return 5000;
102 }
103 else if ( EInventoryFunds_Poor == fundsType )
104 {
105 return 2500;
106 }
107 else if ( EInventoryFunds_Rich == fundsType )
108 {
109 return 7500;
110 }
111 else if ( EInventoryFunds_RichQuickStart == fundsType )
112 {
113 return 15000;
114 }
115 return -1;
116 }
117
118 public function SetupFunds()
119 {
120 if ( EInventoryFunds_Broke == fundsType )
121 {
122 AddMoney( 0 );
123 }
124 else if ( EInventoryFunds_Poor == fundsType )
125 {
126 AddMoney( (int)( 200 * GetFundsModifier() ) );
127 }
128 else if ( EInventoryFunds_Avg == fundsType )
129 {
130 AddMoney( (int)( 500 * GetFundsModifier() ) );
131 }
132 else if ( EInventoryFunds_Rich == fundsType )
133 {
134 AddMoney( (int)( 1000 * GetFundsModifier() ) );
135 }
136 else if ( EInventoryFunds_RichQuickStart == fundsType )
137 {
138 AddMoney( (int)( 5000 * GetFundsModifier() ) );
139 }
140 }
141
142 public function IncreaseFunds()
143 {
144 if ( GetMoney() < GetFundsMax() )
145 {
146 if ( EInventoryFunds_Avg == fundsType )
147 {
148 AddMoney( (int)( 150 * GetFundsModifier()) );
149 }
150 else if ( EInventoryFunds_Poor == fundsType )
151 {
152 AddMoney( (int)( 100 * GetFundsModifier() ) );
153 }
154 else if ( EInventoryFunds_Rich == fundsType )
155 {
156 AddMoney( (int)( 1000 * GetFundsModifier() ) );
157 }
158 else if ( EInventoryFunds_RichQuickStart == fundsType )
159 {
160 AddMoney( 1000 + (int)( 2500 * GetFundsModifier() ) );
161 }
162 }
163 }
164
165 public function GetMoney() : int
166 {
167 return GetItemQuantityByName( 'Crowns' );
168 }
169
170 public function SetMoney( amount : int )
171 {
172 var currentMoney : int;
173
174 if ( amount >= 0 )
175 {
176 currentMoney = GetMoney();
177 RemoveMoney( currentMoney );
178
179 AddAnItem( 'Crowns', amount );
180 }
181 }
182
183 public function AddMoney( amount : int )
184 {
185 if ( amount > 0 )
186 {
187 AddAnItem( 'Crowns', amount );
188
189 if ( thePlayer == GetEntity() )
190 {
191 theTelemetry.LogWithValue( TE_HERO_CASH_CHANGED, amount );
192 }
193 }
194 }
195
196 public function RemoveMoney( amount : int )
197 {
198 if ( amount > 0 )
199 {
200 RemoveItemByName( 'Crowns', amount );
201
202 if ( thePlayer == GetEntity() )
203 {
204 theTelemetry.LogWithValue( TE_HERO_CASH_CHANGED, -amount );
205 }
206 }
207 }
208
209 // ---------------------------------------------------------------------------
210 // Items management
211 // ---------------------------------------------------------------------------
212
213 import final function GetItemAbilityAttributeValue( itemId : SItemUniqueId, attributeName : name, abilityName : name) : SAbilityAttributeValue;
214 //gets item currently equiped in specifed slot or SItemUniqueId::INVALID if none
215 import final function GetItemFromSlot( slotName : name ) : SItemUniqueId;
216
217 // Check if item index is valid.
218 import final function IsIdValid( itemId : SItemUniqueId ) : bool;
219
220 // Returns number of items in the inventory
221 import final function GetItemCount( optional useAssociatedInventory : bool /* = false */ ) : int;
222
223 // Returns all names of items stored in the inventory instance.
224 import final function GetItemsNames() : array< name >;
225
226 // Get all items in form of unique id array
227 import final function GetAllItems( out items : array< SItemUniqueId > );
228
229 //Returns id of first item item found that have given name
230 import public function GetItemId( itemName : name ) : SItemUniqueId;
231
232 //Returns ids of items that have given name
233 import public function GetItemsIds( itemName : name ) : array< SItemUniqueId >;
234
235 // Get all items with given tag in form of unique id array
236 import final function GetItemsByTag( tag : name ) : array< SItemUniqueId >;
237
238 // Get all items of given category in form of unique id array
239 import final function GetItemsByCategory( category : name ) : array< SItemUniqueId >;
240
241 // Get the names and quantities of ingredients of given schematic
242 import final function GetSchematicIngredients(itemName : SItemUniqueId, out quantity : array<int>, out names : array<name>); // #B crafting stuff, crafting doesn't work
243
244 // Get the type name of the craftsman for specific item
245 import final function GetSchematicRequiredCraftsmanType(craftName : SItemUniqueId) : name; // #B crafting stuff, crafting doesn't work
246
247 // Get the level name of the craftsman for specific item
248 import final function GetSchematicRequiredCraftsmanLevel(craftName : SItemUniqueId) : name; // #B crafting stuff, crafting doesn't work
249
250 // Get amount of stacked items
251 import final function GetNumOfStackedItems( itemUniqueId: SItemUniqueId ) : int;
252
253 import final function InitInvFromTemplate( resource : CEntityTemplate );
254 // ---------------------------------------------------------------------------
255 // Items localisation
256 // ---------------------------------------------------------------------------
257
258 // Get localized name of the item using CName
259 import final function GetItemLocalizedNameByName( itemName : CName ) : string;
260
261 // Get items localized desription using CName
262 import final function GetItemLocalizedDescriptionByName( itemName : CName ) : string;
263
264 // Get localized name of the item using UniqueID
265 import final function GetItemLocalizedNameByUniqueID( itemUniqueId : SItemUniqueId ) : string;
266
267 // Get items localized desripption using UniqueID
268 import final function GetItemLocalizedDescriptionByUniqueID( itemUniqueId : SItemUniqueId ) : string;
269
270 // Get item icon using UniqeID
271 import final function GetItemIconPathByUniqueID( itemUniqueId : SItemUniqueId ) : string;
272
273 // Get item icon using CName
274 import final function GetItemIconPathByName( itemName : CName ) : string;
275
276 import final function AddSlot( itemUniqueId : SItemUniqueId ) : bool;
277
278 import final function GetSlotItemsLimit( itemUniqueId : SItemUniqueId ) : int;
279
280 import private final function BalanceItemsWithPlayerLevel( playerLevel : int );
281
282 // **** modScalingArmors BEGIN
283 public function isItemScalable(item : SItemUniqueId) : bool
284 {
285 var itemCategory : name;
286 var itemQuality : int;
287
288 itemCategory = GetItemCategory(item);
289 itemQuality = RoundMath(CalculateAttributeValue( GetItemAttributeValue(item, 'quality' )));
290
291 return (itemCategory == 'armor' || itemCategory == 'gloves' || itemCategory == 'boots' || itemCategory == 'pants'
292 || ItemHasTag(item, 'PlayerSteelWeapon') || ItemHasTag(item, 'PlayerSilverWeapon'))
293 && !ItemHasTag(item, 'Aerondight') && itemQuality >= 4;
294 }
295 // ***** modScalingArmors END
296
297 public function ForceSpawnItemOnStart( itemId : SItemUniqueId ) : bool
298 {
299 return ItemHasTag(itemId, 'MutagenIngredient');
300 }
301
302 //gets total item armor including repair object bonuses and durability modifiers
303 public final function GetItemArmorTotal(item : SItemUniqueId, optional levelsToScale : int) : SAbilityAttributeValue
304 {
305 var armor, armorBonus : SAbilityAttributeValue;
306 var durMult : float;
307 // ***** modScalingArmors BEGIN
308 var i : int;
309
310 if( levelsToScale > 0) {
311 for (i = 0; i < levelsToScale; i += 1) {
312 if ( ItemHasTag( item, 'PlayerSteelWeapon' ) )
313 AddItemCraftedAbility(item, 'autogen_fixed_steel_dmg', true );
314 else if ( ItemHasTag( item, 'PlayerSilverWeapon' ) )
315 AddItemCraftedAbility(item, 'autogen_fixed_silver_dmg', true );
316 else if ( GetItemCategory( item ) == 'armor' )
317 AddItemCraftedAbility(item, 'autogen_fixed_armor_armor', true );
318 else if ( GetItemCategory( item ) == 'gloves' )
319 AddItemCraftedAbility(item, 'autogen_fixed_gloves_armor', true );
320 else if ( GetItemCategory( item ) == 'boots' || GetItemCategory( item ) == 'pants' )
321 AddItemCraftedAbility(item, 'autogen_fixed_pants_armor', true );
322 }
323 } else if( levelsToScale < 0 ) {
324 for (i = 0; i > levelsToScale; i -= 1) {
325 if ( ItemHasTag( item, 'PlayerSteelWeapon' ) )
326 RemoveItemCraftedAbility(item, 'autogen_fixed_steel_dmg' );
327 else if ( ItemHasTag( item, 'PlayerSilverWeapon' ) )
328 RemoveItemCraftedAbility(item, 'autogen_fixed_silver_dmg' );
329 else if ( GetItemCategory( item ) == 'armor' )
330 RemoveItemCraftedAbility(item, 'autogen_fixed_armor_armor' );
331 else if ( GetItemCategory( item ) == 'gloves' )
332 RemoveItemCraftedAbility(item, 'autogen_fixed_gloves_armor' );
333 else if ( GetItemCategory( item ) == 'boots' || GetItemCategory( item ) == 'pants' )
334 RemoveItemCraftedAbility(item, 'autogen_fixed_pants_armor' );
335 }
336 } else GetItemLevel(item);
337 // ***** modScalingArmors END
338
339 armor = GetItemAttributeValue(item, theGame.params.ARMOR_VALUE_NAME);
340 armorBonus = GetRepairObjectBonusValueForArmor(item);
341 durMult = theGame.params.GetDurabilityMultiplier( GetItemDurabilityRatio(item), false);
342
343 return armor * durMult + armorBonus;
344 }
345
346 public final function GetItemLevel(item : SItemUniqueId, optional scaled : bool) : int
347 {
348 var itemCategory : name;
349 var itemAttributes : array<SAbilityAttributeValue>;
350 var itemName : name;
351 var isWitcherGear : bool;
352 var isRelicGear : bool;
353 var level : int;
354 // ***** modScalingArmors BEGIN
355 var levelTarget, ilMin, maxLevel : int;
356 var isNGP : bool;
357 // ***** modScalingArmors END
358
359 itemCategory = GetItemCategory(item);
360 itemName = GetItemName(item);
361
362 isWitcherGear = false;
363 isRelicGear = false;
364 if ( RoundMath(CalculateAttributeValue( GetItemAttributeValue(item, 'quality' ) )) == 5 ) isWitcherGear = true;
365 if ( RoundMath(CalculateAttributeValue( GetItemAttributeValue(item, 'quality' ) )) == 4 ) isRelicGear = true;
366
367 switch(itemCategory)
368 {
369 case 'armor' :
370 case 'boots' :
371 case 'gloves' :
372 case 'pants' :
373 itemAttributes.PushBack( GetItemAttributeValue(item, 'armor') );
374 break;
375
376 case 'silversword' :
377 itemAttributes.PushBack( GetItemAttributeValue(item, 'SilverDamage') );
378 itemAttributes.PushBack( GetItemAttributeValue(item, 'BludgeoningDamage') );
379 itemAttributes.PushBack( GetItemAttributeValue(item, 'RendingDamage') );
380 itemAttributes.PushBack( GetItemAttributeValue(item, 'ElementalDamage') );
381 itemAttributes.PushBack( GetItemAttributeValue(item, 'FireDamage') );
382 itemAttributes.PushBack( GetItemAttributeValue(item, 'PiercingDamage') );
383 break;
384
385 case 'steelsword' :
386 itemAttributes.PushBack( GetItemAttributeValue(item, 'SlashingDamage') );
387 itemAttributes.PushBack( GetItemAttributeValue(item, 'BludgeoningDamage') );
388 itemAttributes.PushBack( GetItemAttributeValue(item, 'RendingDamage') );
389 itemAttributes.PushBack( GetItemAttributeValue(item, 'ElementalDamage') );
390 itemAttributes.PushBack( GetItemAttributeValue(item, 'FireDamage') );
391 itemAttributes.PushBack( GetItemAttributeValue(item, 'SilverDamage') );
392 itemAttributes.PushBack( GetItemAttributeValue(item, 'PiercingDamage') );
393 break;
394
395 case 'crossbow' :
396 itemAttributes.PushBack( GetItemAttributeValue(item, 'attack_power') );
397 break;
398
399 default :
400 break;
401 }
402
403 level = theGame.params.GetItemLevel(itemCategory, itemAttributes, itemName, true); // modScalingArmor
404
405 if ( isWitcherGear ) level = level - 2;
406 if ( isRelicGear ) level = level - 1;
407 if ( level < 1 ) level = 1;
408 if ( ItemHasTag(item, 'OlgierdSabre') ) level = level - 3;
409 if ( (isRelicGear || isWitcherGear) && ItemHasTag(item, 'EP1') ) level = level - 1;
410
411 // ***** modScalingArmors
412 maxLevel = GetWitcherPlayer().GetMaxLevel();
413 levelTarget = GetWitcherPlayer().GetLevel();
414 isNGP = FactsQuerySum("NewGamePlus") > 0;
415
416 if ( level < 1 ) level = 1; if ( level > maxLevel ) level = maxLevel;
417
418 if ( ItemHasTag( item, 'AutogenUseLevelRange') ) {
419 ilMin = RoundMath(CalculateAttributeValue( GetItemAttributeValue( item, 'item_level_min' ) ));
420 if ( isNGP ) ilMin += theGame.params.GetNewGamePlusLevel();
421 if ( levelTarget < ilMin ) levelTarget = ilMin;
422 if ( !scaled && isItemScalable(item) && (levelTarget > level || levelTarget < level && isNGP) )
423 {
424 GetItemArmorTotal(item, levelTarget - level);
425 return GetItemLevel(item, true);
426 }
427 // ***** modScalingArmors
428 return level;
429 }
430
431 public function GetItemLevelColorById( itemId : SItemUniqueId ) : string
432 {
433 var color : string;
434
435 if (GetItemLevel(itemId) <= thePlayer.GetLevel())
436 {
437 color = "<font color = '#A09588'>"; // gray
438 }
439 else
440 {
441 color = "<font color = '#9F1919'>"; // red
442 }
443
444 return color;
445 }
446
447 public function GetItemLevelColor( lvl_item : int ) : string
448 {
449 var color : string;
450
451 if ( lvl_item > thePlayer.GetLevel() )
452 {
453 color = "<font color = '#9F1919'>"; // red
454 } else
455 {
456 color = "<font color = '#A09588'>"; // gray
457 }
458
459 return color;
460 }
461
462 public final function AutoBalanaceItemsWithPlayerLevel()
463 {
464 var playerLevel : int;
465
466 playerLevel = thePlayer.GetLevel();
467
468 if( playerLevel < 0 )
469 {
470 playerLevel = 0;
471 }
472
473 BalanceItemsWithPlayerLevel( playerLevel );
474 }
475
476 public function GetItemsByName(itemName : name) : array<SItemUniqueId>
477 {
478 var ret : array<SItemUniqueId>;
479 var i : int;
480
481 if(!IsNameValid(itemName))
482 return ret;
483
484 GetAllItems(ret);
485
486 for(i=ret.Size()-1; i>=0; i-=1)
487 {
488 if(GetItemName(ret[i]) != itemName)
489 {
490 ret.EraseFast( i );
491 }
492 }
493
494 return ret;
495 }
496
497 public final function GetSingletonItems() : array<SItemUniqueId>
498 {
499 return GetItemsByTag(theGame.params.TAG_ITEM_SINGLETON);
500 }
501
502 //returns a total quantity of items that have given name
503 import final function GetItemQuantityByName( itemName : name, optional useAssociatedInventory : bool /* = false */, optional ignoreTags : array< name > ) : int;
504
505 //returns a total quantity of items that have given category
506 import final function GetItemQuantityByCategory( itemCategory : name, optional useAssociatedInventory : bool /* = false */, optional ignoreTags : array< name > ) : int;
507
508 //returns a total quantity of items that have given tag
509 import final function GetItemQuantityByTag( itemTag : name, optional useAssociatedInventory : bool /* = false */, optional ignoreTags : array< name > ) : int;
510
511 //Returns amount of all items in inventory. Be aware that this will also count NoShow and NoDrop items!
512 import final function GetAllItemsQuantity( optional useAssociatedInventory : bool /* = false */, optional ignoreTags : array< name > ) : int;
513
514 //if the flag is set then the inventory can have any amount of items with NoShow and/or NoDrop tags but only those
515 public function IsEmpty(optional bSkipNoDropNoShow : bool) : bool
516 {
517 var i : int;
518 var itemIds : array<SItemUniqueId>;
519
520 if(bSkipNoDropNoShow)
521 {
522 GetAllItems( itemIds );
523 for( i = itemIds.Size() - 1; i >= 0; i -= 1 )
524 {
525 if( !ItemHasTag( itemIds[ i ],theGame.params.TAG_DONT_SHOW ) && !ItemHasTag( itemIds[ i ], 'NoDrop' ) )
526 {
527 return false;
528 }
529 else if ( ItemHasTag( itemIds[ i ], 'Lootable') )
530 {
531 return false;
532 }
533 }
534
535 return true;
536 }
537
538 return GetItemCount() <= 0;
539 }
540
541 //Returns categories of all held items
542 public function GetAllHeldAndMountedItemsCategories( out heldItems : array<name>, optional out mountedItems : array<name> )
543 {
544 var allItems : array<SItemUniqueId>;
545 var i : int;
546
547 GetAllItems(allItems);
548 for(i=allItems.Size()-1; i >= 0; i-=1)
549 {
550 if ( IsItemHeld(allItems[i]) )
551 heldItems.PushBack(GetItemCategory(allItems[i]));
552 else if ( IsItemMounted(allItems[i]) )
553 mountedItems.PushBack(GetItemCategory(allItems[i]));
554 }
555 }
556
557 public function GetAllHeldItemsNames( out heldItems : array<name> )
558 {
559 var allItems : array<SItemUniqueId>;
560 var i : int;
561
562 GetAllItems(allItems);
563 for(i=allItems.Size()-1; i >= 0; i-=1)
564 {
565 if ( IsItemHeld(allItems[i]) )
566 heldItems.PushBack(GetItemName(allItems[i]));
567 }
568 }
569
570 public function HasMountedItemByTag(tag : name) : bool
571 {
572 var i : int;
573 var allItems : array<SItemUniqueId>;
574
575 if(!IsNameValid(tag))
576 return false;
577
578 allItems = GetItemsByTag(tag);
579 for(i=0; i<allItems.Size(); i+=1)
580 if(IsItemMounted(allItems[i]))
581 return true;
582
583 return false;
584 }
585
586 public function HasHeldOrMountedItemByTag(tag : name) : bool
587 {
588 var i : int;
589 var allItems : array<SItemUniqueId>;
590
591 if(!IsNameValid(tag))
592 return false;
593
594 allItems = GetItemsByTag(tag);
595 for(i=0; i<allItems.Size(); i+=1)
596 if( IsItemMounted(allItems[i]) || IsItemHeld(allItems[i]) )
597 return true;
598
599 return false;
600 }
601
602 // Get inventory item from item id
603 import final function GetItem( itemId : SItemUniqueId ) : SInventoryItem;
604
605 // Get item name
606 import final function GetItemName( itemId : SItemUniqueId ) : name;
607
608 // Get item category
609 import final function GetItemCategory( itemId : SItemUniqueId ) : name;
610
611 // Get item class
612 import final function GetItemClass( itemId : SItemUniqueId ) : EInventoryItemClass; // #B not used at all
613
614 // Get tags of given item, returns false if index is not valid
615 import final function GetItemTags( itemId : SItemUniqueId, out tags : array<name> ) : bool;
616
617 // Get name of the item that can be crafted from given one
618 import final function GetCraftedItemName( itemId : SItemUniqueId ) : name; // #B crafting stuff, check later
619
620 // Get item price
621 import final function TotalItemStats( invItem : SInventoryItem ) : float;
622
623 import final function GetItemPrice( itemId : SItemUniqueId ) : int;
624
625 // Get item price after item and vendor modifiers have been applied.
626 import final function GetItemPriceModified( itemId : SItemUniqueId, optional playerSellingItem : Bool ) : int;
627
628 // Get item price after item and vendor modifiers have been applied.
629 import final function GetInventoryItemPriceModified( invItem : SInventoryItem, optional playerSellingItem : Bool ) : int;
630
631 // Generates price per point of repair and total cost of repair for given item.
632 import final function GetItemPriceRepair( invItem : SInventoryItem, out costRepairPoint : int, out costRepairTotal : int );
633
634 // Returns cost of removing an upgrade from given item.
635 import final function GetItemPriceRemoveUpgrade( invItem : SInventoryItem ) : int;
636
637 // Returns cost of disassembling a given item.
638 import final function GetItemPriceDisassemble( invItem : SInventoryItem ) : int;
639
640 // Returns cost of adding a slot to a given item.
641 import final function GetItemPriceAddSlot( invItem : SInventoryItem ) : int;
642
643 // Returns cost of adding a slot to a given item.
644 import final function GetItemPriceCrafting( invItem : SInventoryItem ) : int;
645
646 // Returns cost of disassembling a given item.
647 import final function GetItemPriceEnchantItem( invItem : SInventoryItem ) : int;
648
649 // Returns cost of disassembling a given item.
650 import final function GetItemPriceRemoveEnchantment( invItem : SInventoryItem ) : int;
651
652 import final function GetFundsModifier() : float;
653
654 // Get item quantity by index
655 import final function GetItemQuantity( itemId : SItemUniqueId ) : int;
656
657 // Check if the item has given tag
658 import final function ItemHasTag( itemId : SItemUniqueId, tag : name ) : bool;
659
660 // Add tag to item - DOES NOT SAVE (it's a feature, not a bug)
661 import final function AddItemTag( itemId : SItemUniqueId, tag : name ) : bool;
662
663 // Remove tag from item
664 import final function RemoveItemTag( itemId : SItemUniqueId, tag : name ) : bool;
665
666 //Manages tag on item - adds it of removes it
667 public final function ManageItemsTag( items : array<SItemUniqueId>, tag : name, add : bool )
668 {
669 var i : int;
670
671 if( add )
672 {
673 for( i = 0 ; i < items.Size() ; i += 1 )
674 {
675 AddItemTag( items[ i ], tag );
676 }
677 }
678 else
679 {
680 for( i = 0 ; i < items.Size() ; i += 1 )
681 {
682 RemoveItemTag( items[ i ], tag );
683 }
684 }
685 }
686
687 // Get item for which we have given itemEntity spawned
688 import final function GetItemByItemEntity( itemEntity : CItemEntity ) : SItemUniqueId; // #B not used at all
689
690 //returns true if given item has given ability
691 public function ItemHasAbility(item : SItemUniqueId, abilityName : name) : bool
692 {
693 var abilities : array<name>;
694
695 GetItemAbilities(item, abilities);
696 return abilities.Contains(abilityName);
697 }
698
699 import final function GetItemAttributeValue( itemId : SItemUniqueId, attributeName : name, optional abilityTags : array< name >, optional withoutTags : bool ) : SAbilityAttributeValue;
700
701 // Get base attribute names from item.
702 import final function GetItemBaseAttributes( itemId : SItemUniqueId, out attributes : array<name> );
703
704 // Get all attribute names from item.
705 import final function GetItemAttributes( itemId : SItemUniqueId, out attributes : array<name> );
706
707 // Get abilities from item
708 import final function GetItemAbilities( itemId : SItemUniqueId, out abilities : array<name> );
709
710 // Get efects from abilities
711 import final function GetItemContainedAbilities( itemId : SItemUniqueId, out abilities : array<name> );
712
713 //returns abilities names of this item's ability which holds given attribute with specified value
714 public function GetItemAbilitiesWithAttribute(id : SItemUniqueId, attributeName : name, attributeVal : float) : array<name>
715 {
716 var i : int;
717 var abs, ret : array<name>;
718 var dm : CDefinitionsManagerAccessor;
719 var val : float;
720 var min, max : SAbilityAttributeValue;
721
722 GetItemAbilities(id, abs);
723 dm = theGame.GetDefinitionsManager();
724
725 for(i=0; i<abs.Size(); i+=1)
726 {
727 dm.GetAbilityAttributeValue(abs[i], attributeName, min, max);
728 val = CalculateAttributeValue(GetAttributeRandomizedValue(min, max));
729
730 if(val == attributeVal)
731 ret.PushBack(abs[i]);
732 }
733
734 return ret;
735 }
736 public function GetItemAbilitiesWithTag( itemId : SItemUniqueId, tag : name, out abilities : array<name> )
737 {
738 var i : int;
739 var dm : CDefinitionsManagerAccessor;
740 var allAbilities : array<name>;
741
742 dm = theGame.GetDefinitionsManager();
743 GetItemAbilities(itemId, allAbilities);
744
745 for(i=0; i<allAbilities.Size(); i+=1)
746 {
747 if(dm.AbilityHasTag(allAbilities[i], tag))
748 {
749 abilities.PushBack(allAbilities[i]);
750 }
751 }
752 }
753
754 // Transfer one item to other inventory ( holsters items if needed )
755 // This has to be overriden in scripts because of custom updating of player item data OnReceive
756 // Use GiveItemTo() instead
757 import private final function GiveItem( otherInventory : CInventoryComponent, itemId : SItemUniqueId, optional quantity : int ) : array<SItemUniqueId>;
758
759 public final function GiveMoneyTo(otherInventory : CInventoryComponent, optional quantity : int, optional informGUI : bool )
760 {
761 var moneyId : array<SItemUniqueId>;
762
763 moneyId = GetItemsByName('Crowns');
764 GiveItemTo(otherInventory, moneyId[0], quantity, false, true, informGUI);
765 }
766
767 public final function GiveItemTo( otherInventory : CInventoryComponent, itemId : SItemUniqueId, optional quantity : int, optional refreshNewFlag : bool, optional forceTransferNoDrops : bool, optional informGUI : bool ) : SItemUniqueId
768 {
769 var arr : array<SItemUniqueId>;
770 var itemName : name;
771 var i : int;
772 var uiData : SInventoryItemUIData;
773 var isQuestItem : bool;
774
775 //check quantity parameter
776 if(quantity == 0)
777 quantity = 1;
778
779 quantity = Clamp(quantity, 0, GetItemQuantity(itemId));
780 if(quantity == 0)
781 return GetInvalidUniqueId();
782
783 itemName = GetItemName(itemId);
784 //cannot pass items with NoDrop tag
785 if(!forceTransferNoDrops && ( ItemHasTag(itemId, 'NoDrop') && !ItemHasTag(itemId, 'Lootable') ))
786 {
787 LogItems("Cannot transfer item <<" + itemName + ">> as it has the NoDrop tag set!!!");
788 return GetInvalidUniqueId();
789 }
790
791 //there can be only one singleton item at a time of the same type
792 if(IsItemSingletonItem(itemId))
793 {
794 //player already has singleton - get id
795 if(otherInventory == thePlayer.inv && otherInventory.GetItemQuantityByName(itemName) > 0)
796 {
797 LogAssert(false, "CInventoryComponent.GiveItemTo: cannot add singleton item as player already has this item!");
798 return GetInvalidUniqueId();
799 }
800 //player does not have singleton - add one item and get id
801 else
802 {
803 arr = GiveItem(otherInventory, itemId, quantity);
804 }
805 }
806 else
807 {
808 //transfer non-singleton items
809 arr = GiveItem(otherInventory, itemId, quantity);
810 }
811
812 //custom code if player is given an item
813 if(otherInventory == thePlayer.inv)
814 {
815 isQuestItem = this.IsItemQuest( itemId );
816 theTelemetry.LogWithLabelAndValue(TE_INV_ITEM_PICKED, itemName, quantity);
817
818 if ( !theGame.AreSavesLocked() && ( isQuestItem || this.GetItemQuality( itemId ) >= 4 ) )
819 {
820 theGame.RequestAutoSave( "item gained", false );
821 }
822 }
823
824 if (refreshNewFlag)
825 {
826 for (i = 0; i < arr.Size(); i += 1)
827 {
828 uiData = otherInventory.GetInventoryItemUIData( arr[i] );
829 uiData.isNew = true;
830 otherInventory.SetInventoryItemUIData( arr[i], uiData );
831 }
832 }
833
834 return arr[0];
835 }
836
837 public final function GiveAllItemsTo(otherInventory : CInventoryComponent, optional forceTransferNoDrops : bool, optional informGUI : bool)
838 {
839 var items : array<SItemUniqueId>;
840
841 GetAllItems(items);
842 GiveItemsTo(otherInventory, items, forceTransferNoDrops, informGUI);
843 }
844
845 public final function GiveItemsTo(otherInventory : CInventoryComponent, items : array<SItemUniqueId>, optional forceTransferNoDrops : bool, optional informGUI : bool) : array<SItemUniqueId>
846 {
847 var i : int;
848 var ret : array<SItemUniqueId>;
849
850 for( i = 0; i < items.Size(); i += 1 )
851 {
852 ret.PushBack(GiveItemTo(otherInventory, items[i], GetItemQuantity(items[i]), true, forceTransferNoDrops, informGUI));
853 }
854
855 return ret;
856 }
857
858 // If there is any item with the same name in inventory
859 import final function HasItem( item : name ) : bool;
860
861 // If there is specified item in inventory
862 //TK: won't it be enough to check if ID is valid?
863 final function HasItemById(id : SItemUniqueId) : bool
864 {
865 var arr : array<SItemUniqueId>;
866
867 GetAllItems(arr);
868 return arr.Contains(id);
869 }
870
871 public function HasItemByTag(tag : name) : bool
872 {
873 var quantity : int;
874
875 quantity = GetItemQuantityByTag( tag );
876 return quantity > 0;
877 }
878
879 public function HasItemByCategory(category : name) : bool
880 {
881 var quantity : int;
882
883 quantity = GetItemQuantityByCategory( category );
884 return quantity > 0;
885 }
886
887 //returns true if has bolts with infinite ammo
888 public function HasInfiniteBolts() : bool
889 {
890 var ids : array<SItemUniqueId>;
891 var i : int;
892
893 ids = GetItemsByTag(theGame.params.TAG_INFINITE_AMMO);
894 for(i=0; i<ids.Size(); i+=1)
895 {
896 if(IsItemBolt(ids[i]))
897 {
898 return true;
899 }
900 }
901
902 return false;
903 }
904
905 //returns true if has bolts with infinite ammo
906 public function HasGroundBolts() : bool
907 {
908 var ids : array<SItemUniqueId>;
909 var i : int;
910
911 ids = GetItemsByTag(theGame.params.TAG_GROUND_AMMO);
912 for(i=0; i<ids.Size(); i+=1)
913 {
914 if(IsItemBolt(ids[i]))
915 {
916 return true;
917 }
918 }
919
920 return false;
921 }
922
923 //returns true if has bolts with underwater ammo
924 public function HasUnderwaterBolts() : bool
925 {
926 var ids : array<SItemUniqueId>;
927 var i : int;
928
929 ids = GetItemsByTag(theGame.params.TAG_UNDERWATER_AMMO);
930 for(i=0; i<ids.Size(); i+=1)
931 {
932 if(IsItemBolt(ids[i]))
933 {
934 return true;
935 }
936 }
937
938 return false;
939 }
940
941 // Add specified item to inventory
942 // due to performance we should call AddSingleItem when only 1 item is added to avoid passing dynamic arrays from code
943 import private final function AddMultiItem( item : name, optional quantity : int, optional informGui : bool /* = true */, optional markAsNew : bool /* = false */, optional lootable : bool /* =true */ ) : array<SItemUniqueId>;
944 import private final function AddSingleItem( item : name, optional informGui : bool /* = true */, optional markAsNew : bool /* = false */, optional lootable : bool /* =true */ ) : SItemUniqueId;
945
946 /*
947 Returns array of item ids of given items (more than 1 if quantity is big enough to split items into few stacks.
948 If item is SingleInstanceItem then nothing is added, instead id of the item already in inventory is returned.
949 */
950 public final function AddAnItem(item : name, optional quantity : int, optional dontInformGui : bool, optional dontMarkAsNew : bool, optional showAsRewardInUIHax : bool) : array<SItemUniqueId>
951 {
952 var arr : array<SItemUniqueId>;
953 var i : int;
954 var isReadableItem : bool;
955
956 //there can be only one singleton item at a time of the same type
957 if( theGame.GetDefinitionsManager().IsItemSingletonItem(item) && GetEntity() == thePlayer)
958 {
959 if(GetItemQuantityByName(item) > 0)
960 {
961 arr = GetItemsIds(item);
962 }
963 else
964 {
965 arr.PushBack(AddSingleItem(item, !dontInformGui, !dontMarkAsNew));
966 }
967
968 quantity = 1;
969 }
970 else
971 {
972 if(quantity < 2 ) // #B quantity equals one, or quantity wasn't set, both means that is only one item to add
973 {
974 arr.PushBack(AddSingleItem(item, !dontInformGui, !dontMarkAsNew));
975 }
976 else
977 {
978 arr = AddMultiItem(item, quantity, !dontInformGui, !dontMarkAsNew);
979 }
980 }
981
982 //only do checks/show UI once - all items are the same
983 if(this == thePlayer.GetInventory())
984 {
985 if(ItemHasTag(arr[0],'ReadableItem'))
986 UpdateInitialReadState(arr[0]);
987
988 //Gwint card are not displayed in inventory, looting them needs to show visible reward notification for minigames and containers - quest post 1.0 hax
989 if(showAsRewardInUIHax || ItemHasTag(arr[0],'GwintCard'))
990 thePlayer.DisplayItemRewardNotification(GetItemName(arr[0]), quantity );
991 }
992
993 return arr;
994 }
995
996 // Remove item with specified index from inventory
997 import final function RemoveItem( itemId : SItemUniqueId, optional quantity : int ) : bool;
998
999 //internal function to remove requested quantity of items
1000 private final function InternalRemoveItems(ids : array<SItemUniqueId>, quantity : int)
1001 {
1002 var i, currQuantityToTake : int;
1003
1004 //for each item stack
1005 for(i=0; i<ids.Size(); i+=1 )
1006 {
1007 //collect the quantity of items in current stack, clamp it to remaining required quantity
1008 currQuantityToTake = Min(quantity, GetItemQuantity(ids[i]) );
1009
1010 //If taken item is a gwint card remove it from collection as well
1011 if( GetEntity() == thePlayer )
1012 {
1013 GetWitcherPlayer().RemoveGwentCard( GetItemName(ids[i]) , currQuantityToTake);
1014 }
1015
1016 //remove items
1017 RemoveItem(ids[i], currQuantityToTake);
1018
1019 //update remaining required quantity to take
1020 quantity -= currQuantityToTake;
1021
1022 //if took enough then quit
1023 if ( quantity == 0 )
1024 {
1025 return;
1026 }
1027
1028 //if took too much then call Houston...
1029 LogAssert(quantity>0, "CInventoryComponent.InternalRemoveItems(" + GetItemName(ids[i]) + "): somehow took too many items! Should be " + (-quantity) + " less... Investigate!");
1030 }
1031 }
1032
1033 // if quantity <0 then removes all items from inventory
1034 // if quantity == 0 then removes only 1 item
1035 public function RemoveItemByName(itemName : name, optional quantity : int) : bool
1036 {
1037 var totalItemCount : int;
1038 var ids : array<SItemUniqueId>;
1039
1040 //does not have that many items
1041 totalItemCount = GetItemQuantityByName(itemName);
1042 if(totalItemCount < quantity || quantity == 0)
1043 {
1044 return false;
1045 }
1046
1047 if(quantity == 0)
1048 {
1049 quantity = 1;
1050 }
1051 else if(quantity < 0)
1052 {
1053 quantity = totalItemCount;
1054 }
1055
1056 ids = GetItemsIds(itemName);
1057
1058 if(GetEntity() == thePlayer && thePlayer.GetSelectedItemId() == ids[0] )
1059 {
1060 thePlayer.ClearSelectedItemId();
1061 }
1062
1063 InternalRemoveItems(ids, quantity);
1064
1065 return true;
1066 }
1067
1068 // if quantity <0 then removes all items from inventory
1069 // if quantity == 0 then removes only 1 item
1070 public function RemoveItemByCategory(itemCategory : name, optional quantity : int) : bool
1071 {
1072 var totalItemCount : int;
1073 var ids : array<SItemUniqueId>;
1074 var selectedItemId : SItemUniqueId;
1075 var i : int;
1076
1077 //does not have that many items
1078 totalItemCount = GetItemQuantityByCategory(itemCategory);
1079 if(totalItemCount < quantity)
1080 {
1081 return false;
1082 }
1083
1084 if(quantity == 0)
1085 {
1086 quantity = 1;
1087 }
1088 else if(quantity < 0)
1089 {
1090 quantity = totalItemCount;
1091 }
1092
1093 ids = GetItemsByCategory(itemCategory);
1094
1095 if(GetEntity() == thePlayer)
1096 {
1097 selectedItemId = thePlayer.GetSelectedItemId();
1098 for(i=0; i<ids.Size(); i+=1)
1099 {
1100 if(selectedItemId == ids[i] )
1101 {
1102 thePlayer.ClearSelectedItemId();
1103 break;
1104 }
1105 }
1106 }
1107
1108 InternalRemoveItems(ids, quantity);
1109
1110 return true;
1111 }
1112
1113 // if quantity <0 then removes all items from inventory
1114 // if quantity == 0 then removes only 1 item
1115 public function RemoveItemByTag(itemTag : name, optional quantity : int) : bool
1116 {
1117 var totalItemCount : int;
1118 var ids : array<SItemUniqueId>;
1119 var i : int;
1120 var selectedItemId : SItemUniqueId;
1121
1122 //does not have that many items
1123 totalItemCount = GetItemQuantityByTag(itemTag);
1124 if(totalItemCount < quantity)
1125 {
1126 return false;
1127 }
1128
1129 if(quantity == 0)
1130 {
1131 quantity = 1;
1132 }
1133 else if(quantity < 0)
1134 {
1135 quantity = totalItemCount;
1136 }
1137
1138 ids = GetItemsByTag(itemTag);
1139
1140 if(GetEntity() == thePlayer)
1141 {
1142 selectedItemId = thePlayer.GetSelectedItemId();
1143 for(i=0; i<ids.Size(); i+=1)
1144 {
1145 if(selectedItemId == ids[i] )
1146 {
1147 thePlayer.ClearSelectedItemId();
1148 break;
1149 }
1150 }
1151 }
1152
1153 InternalRemoveItems(ids, quantity);
1154
1155 return true;
1156 }
1157
1158 // Removes all items from inventory
1159 import final function RemoveAllItems();
1160
1161 // USE WITH EXTREME CAUTION / ASK MARCIN GOLLENT
1162 import final function GetItemEntityUnsafe( itemId : SItemUniqueId ) : CItemEntity;
1163
1164 // Spawn deployment item entity
1165 import final function GetDeploymentItemEntity( itemId : SItemUniqueId, optional position : Vector, optional rotation : EulerAngles, optional allocateIdTag : bool ) : CEntity;
1166
1167 // Add specified item to inventory
1168 import final function MountItem( itemId : SItemUniqueId, optional toHand : bool, optional force : bool ) : bool;
1169
1170 // Add specified item to inventory
1171 import final function UnmountItem( itemId : SItemUniqueId, optional destroyEntity : bool ) : bool;
1172
1173 // Check if specified item is mounted to equip bone BUT if it is held in hand it will return false
1174 // use IsItemEquipped instead to get around this
1175 import final function IsItemMounted( itemId : SItemUniqueId ) : bool;
1176
1177 // Check if specified item is held in hand - only a silver, steel sword or secondary weapon!
1178 // If item is held then it is not mounted!!!!!!!!!!
1179 import final function IsItemHeld( itemId : SItemUniqueId ) : bool;
1180
1181 // Drop item
1182 import final function DropItem( itemId : SItemUniqueId, optional removeFromInv /*=false*/ : bool );
1183
1184 // Returns the name of a hold slot defined for the item
1185 import final function GetItemHoldSlot( itemId : SItemUniqueId ) : name;
1186
1187 // Play effect on item
1188 import final function PlayItemEffect( itemId : SItemUniqueId, effectName : name );
1189 import final function StopItemEffect( itemId : SItemUniqueId, effectName : name );
1190
1191 // Throw away given item to a spawned container, returns true if succeded
1192 import final function ThrowAwayItem( itemId : SItemUniqueId, optional quantity : int ) : bool;
1193
1194 // Throw away all items, returns entity created
1195 import final function ThrowAwayAllItems() : CEntity; // #B not used at all
1196
1197 // Throw away items, excluding those with any of given tags, returns entity created
1198 import final function ThrowAwayItemsFiltered( excludedTags : array< name > ) : CEntity;
1199
1200 // Throw away lootable items, returns entity created
1201 import final function ThrowAwayLootableItems( optional skipNoDropNoShow : bool ) : CEntity;
1202
1203 // Get arrays of names and counts
1204 import final function GetItemRecyclingParts( itemId : SItemUniqueId ) : array<SItemParts>;
1205
1206 import final function GetItemWeight( id : SItemUniqueId ) : float;
1207/* {
1208 var weight : float;
1209
1210 if( !IsIdValid( id ) )
1211 return 0;
1212
1213 dm = theGame.GetDefinitionsManager();
1214
1215 weight = -1;
1216 weight = dm.GetItemWeight( id );
1217
1218 if ( weight == -1 )
1219 {
1220 return CalculateAttributeValue( GetItemAttributeValue( id, 'weight' ) );
1221 }
1222
1223 return weight;
1224 }*/
1225
1226 public final function HasQuestItem() : bool
1227 {
1228 var allItems : array< SItemUniqueId >;
1229 var i : int;
1230
1231 allItems = GetItemsByTag('Quest');
1232 for ( i=0; i<allItems.Size(); i+=1 )
1233 {
1234 if(!ItemHasTag(allItems[i], theGame.params.TAG_DONT_SHOW))
1235 {
1236 return true;
1237 }
1238 }
1239
1240 return false;
1241 }
1242
1243 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1244 ////////////////////////////////////// @DURABILITY //////////////////////////////////////////////////////////////////////////////////
1245 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1246
1247 // Durability, -1 if has none or not set
1248 import final function HasItemDurability( itemId : SItemUniqueId ) : bool;
1249 import final function GetItemDurability( itemId : SItemUniqueId ) : float;
1250 import private final function SetItemDurability( itemId : SItemUniqueId, durability : float );
1251 import final function GetItemInitialDurability( itemId : SItemUniqueId ) : float;
1252 import final function GetItemMaxDurability( itemId : SItemUniqueId ) : float;
1253 import final function GetItemGridSize( itemId : SItemUniqueId ) : int;
1254
1255
1256 import final function NotifyItemLooted( item : SItemUniqueId );
1257 import final function ResetContainerData();
1258
1259 public function SetItemDurabilityScript( itemId : SItemUniqueId, durability : float )
1260 {
1261 SetItemDurability( itemId, GetItemMaxDurability(itemId));
1262 }
1263
1264 //returns false if item durability could not be reduced (no durability at all or already at 0)
1265 public function ReduceItemDurability(itemId : SItemUniqueId, optional forced : bool) : bool
1266 {
1267 SetItemDurabilityScript( itemId, GetItemMaxDurability(itemId));
1268 //get global stats
1269 // Reduce durability
1270 return true;
1271 }
1272
1273 public function GetItemDurabilityRatio(itemId : SItemUniqueId) : float
1274 {
1275 if ( !IsIdValid( itemId ) || !HasItemDurability( itemId ) )
1276 return -1;
1277
1278 return GetItemDurability(itemId) / GetItemMaxDurability(itemId);
1279 }
1280
1281 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1282 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1283 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1284
1285 //gets item resistance value taking durability into consideration
1286 public function GetItemResistStatWithDurabilityModifiers(itemId : SItemUniqueId, stat : ECharacterDefenseStats, out points : SAbilityAttributeValue, out percents : SAbilityAttributeValue)
1287 {
1288 var mult : float;
1289 var null : SAbilityAttributeValue;
1290
1291 points = null;
1292 percents = null;
1293 if(!IsItemAnyArmor(itemId))
1294 return;
1295
1296 mult = theGame.params.GetDurabilityMultiplier(GetItemDurabilityRatio(itemId), false);
1297
1298 points = GetItemAttributeValue(itemId, ResistStatEnumToName(stat, true));
1299 percents = GetItemAttributeValue(itemId, ResistStatEnumToName(stat, false));
1300
1301 points = points * mult;
1302 percents = percents * mult;
1303 }
1304
1305 //returns list of resistance types that this item gives
1306 public function GetItemResistanceTypes(id : SItemUniqueId) : array<ECharacterDefenseStats>
1307 {
1308 var ret : array<ECharacterDefenseStats>;
1309 var i : int;
1310 var stat : ECharacterDefenseStats;
1311 var atts : array<name>;
1312 var tmpBool : bool;
1313
1314 if(!IsIdValid(id))
1315 return ret;
1316
1317 GetItemAttributes(id, atts);
1318 for(i=0; i<atts.Size(); i+=1)
1319 {
1320 stat = ResistStatNameToEnum(atts[i], tmpBool);
1321 if(stat != CDS_None && !ret.Contains(stat))
1322 ret.PushBack(stat);
1323 }
1324
1325 return ret;
1326 }
1327
1328 import final function GetItemModifierFloat( itemId : SItemUniqueId, modName : name, optional defValue : float ) : float;
1329 import final function SetItemModifierFloat( itemId : SItemUniqueId, modName : name, val : float);
1330 import final function GetItemModifierInt ( itemId : SItemUniqueId, modName : name, optional defValue : int ) : int;
1331 import final function SetItemModifierInt ( itemId : SItemUniqueId, modName : name, val : int );
1332
1333 // Adds quest_bonus tag to component tag list.
1334 import final function ActivateQuestBonus();
1335
1336 // The Set name ( or empty if none exists )
1337 import final function GetItemSetName( itemId : SItemUniqueId ) : name;
1338
1339 // Adds an ability to the item (for example - during crafting an item)
1340 import final function AddItemCraftedAbility( itemId : SItemUniqueId, abilityName : name, optional allowDuplicate : bool );
1341
1342 // Removes a crafted ability from the item
1343 import final function RemoveItemCraftedAbility( itemId : SItemUniqueId, abilityName : name );
1344
1345 //adds item ability
1346 import final function AddItemBaseAbility(item : SItemUniqueId, abilityName : name);
1347
1348 //removes item ability
1349 import final function RemoveItemBaseAbility(item : SItemUniqueId, abilityName : name);
1350
1351 // Destroy item
1352 import final function DespawnItem( itemId : SItemUniqueId ); // #B not used at all
1353
1354 // ---------------------------------------------------------------------------
1355 // Weapons
1356 // ---------------------------------------------------------------------------
1357
1358 // Get the inventory item ui data
1359 import final function GetInventoryItemUIData( item : SItemUniqueId ) : SInventoryItemUIData;
1360
1361 // Set the inventory item ui data
1362 import final function SetInventoryItemUIData( item : SItemUniqueId, data : SInventoryItemUIData );
1363
1364 import final function SortInventoryUIData(); // #B need to check C++ how it works, curently not used
1365
1366 // ---------------------------------------------------------------------------
1367 // Debug
1368 // ---------------------------------------------------------------------------
1369
1370 // Print contents of inventory
1371 import final function PrintInfo();
1372
1373 // ---------------------------------------------------------------------------
1374 // Loot
1375 // ---------------------------------------------------------------------------
1376
1377 // Enable generating loot
1378 import final function EnableLoot( enable : bool );
1379
1380 // Test loot cache against loot definition. Add items if their respawn time elapsed
1381 import final function UpdateLoot();
1382
1383 // Add items from specified loot definition
1384 import final function AddItemsFromLootDefinition( lootDefinitionName : name );
1385
1386 // Check if loot contains items that need to be respawned
1387 import final function IsLootRenewable() : bool;
1388
1389 // Check if loot will be renewed now (renew time expired)
1390 import final function IsReadyToRenew() : bool;
1391
1392 // ---------------------------------------------------------------------------
1393 // Initialization
1394 // ---------------------------------------------------------------------------
1395
1396 /**
1397 #B Called by player for tracking books
1398 */
1399 function Created()
1400 {
1401 LoadBooksDefinitions();
1402 }
1403
1404 function ClearGwintCards()
1405 {
1406 var attr : SAbilityAttributeValue;
1407 var allItems : array<SItemUniqueId>;
1408 var card : array<SItemUniqueId>;
1409 var iHave, shopHave, cardLimit, delta : int;
1410 var curItem : SItemUniqueId;
1411 var i : int;
1412
1413 allItems = GetItemsByCategory('gwint');
1414 for(i=allItems.Size()-1; i >= 0; i-=1)
1415 {
1416 curItem = allItems[i];
1417
1418 attr = GetItemAttributeValue( curItem, 'max_count');
1419 card = thePlayer.GetInventory().GetItemsByName( GetItemName( curItem ) );
1420 iHave = thePlayer.GetInventory().GetItemQuantity( card[0] );
1421 cardLimit = RoundF(attr.valueBase);
1422 shopHave = GetItemQuantity( curItem );
1423
1424 if (iHave > 0 && shopHave > 0)
1425 {
1426 delta = shopHave - (cardLimit - iHave);
1427
1428 if ( delta > 0 )
1429 {
1430 RemoveItem( curItem, delta );
1431 }
1432 }
1433 }
1434 }
1435
1436 function ClearTHmaps()
1437 {
1438 var attr : SAbilityAttributeValue;
1439 var allItems : array<SItemUniqueId>;
1440 var map : array<SItemUniqueId>;
1441 var i : int;
1442 var thCompleted : bool;
1443 var iHave, shopHave : int;
1444
1445 allItems = GetItemsByTag('ThMap');
1446 for(i=allItems.Size()-1; i >= 0; i-=1)
1447 {
1448 attr = GetItemAttributeValue( allItems[i], 'max_count');
1449 map = thePlayer.GetInventory().GetItemsByName( GetItemName( allItems[i] ) );
1450 thCompleted = FactsDoesExist(GetItemName(allItems[i]));
1451 iHave = thePlayer.GetInventory().GetItemQuantity( map[0] );
1452 shopHave = RoundF(attr.valueBase);
1453
1454 if ( iHave >= shopHave || thCompleted )
1455 {
1456 RemoveItem( allItems[i], GetItemQuantity( allItems[i] ) );
1457 }
1458 }
1459 }
1460
1461 //removes known recipe items (to be used inside shop inventory)
1462 public final function ClearKnownRecipes()
1463 {
1464 var witcher : W3PlayerWitcher;
1465 var recipes, craftRecipes : array<name>;
1466 var i : int;
1467 var itemName : name;
1468 var allItems : array<SItemUniqueId>;
1469
1470 witcher = GetWitcherPlayer();
1471 if(!witcher)
1472 return; //only witchers have recipes
1473
1474 //get recipes
1475 recipes = witcher.GetAlchemyRecipes();
1476 craftRecipes = witcher.GetCraftingSchematicsNames();
1477 ArrayOfNamesAppend(recipes, craftRecipes);
1478
1479 //get items
1480 GetAllItems(allItems);
1481
1482 //filter
1483 for(i=allItems.Size()-1; i>=0; i-=1)
1484 {
1485 itemName = GetItemName(allItems[i]);
1486 if(recipes.Contains(itemName))
1487 RemoveItem(allItems[i], GetItemQuantity(allItems[i]));
1488 }
1489 }
1490
1491 // ---------------------------------------------------------------------------
1492 // Books
1493 // ---------------------------------------------------------------------------
1494
1495 function LoadBooksDefinitions() : void // #B
1496 {
1497 var readableArray : array<SItemUniqueId>;
1498 var i : int;
1499
1500 readableArray = GetItemsByTag('ReadableItem');
1501
1502 for( i = 0; i < readableArray.Size(); i += 1 )
1503 {
1504 if( IsBookRead(readableArray[i]))
1505 {
1506 continue;
1507 }
1508 UpdateInitialReadState(readableArray[i]);
1509 }
1510 }
1511
1512 function UpdateInitialReadState( item : SItemUniqueId ) // #B
1513 {
1514 var abilitiesArray : array<name>;
1515 var i : int;
1516 GetItemAbilities(item,abilitiesArray);
1517
1518 for( i = 0; i < abilitiesArray.Size(); i += 1 )
1519 {
1520 if( abilitiesArray[i] == 'WasRead' )
1521 {
1522 ReadBook(item);
1523 break;
1524 }
1525 }
1526 }
1527
1528 function IsBookRead( item : SItemUniqueId ) : bool // #B
1529 {
1530 var bookName : name;
1531 var bResult : bool;
1532
1533 bookName = GetItemName( item );
1534
1535 bResult = IsBookReadByName( bookName ); //#B by name because it can be few different instances of one book
1536 return bResult;
1537 }
1538
1539 function IsBookReadByName( bookName : name ) : bool // #B
1540 {
1541 var bookFactName : string;
1542
1543 bookFactName = GetBookReadFactName( bookName );
1544 if( FactsDoesExist(bookFactName) )
1545 {
1546 return FactsQuerySum( bookFactName );
1547 }
1548
1549 return false;
1550 }
1551
1552 function ReadBook( item : SItemUniqueId, optional noNotification : bool ) //#B
1553 {
1554 //var mapManager : W3Common
1555 var bookName : name;
1556 var abilitiesArray : array<name>;
1557 var i : int;
1558 var commonMapManager : CCommonMapManager = theGame.GetCommonMapManager();
1559
1560 bookName = GetItemName( item );
1561
1562 if ( !IsBookRead ( item ) && ItemHasTag ( item, 'FastTravel' ))
1563 {
1564 GetItemAbilities(item, abilitiesArray);
1565
1566 for ( i = 0; i < abilitiesArray.Size(); i+=1 )
1567 {
1568 commonMapManager.SetEntityMapPinDiscoveredScript(true, abilitiesArray[i], true );
1569 }
1570 }
1571 ReadBookByNameId( bookName, item, false, noNotification );
1572
1573 //RemoveItem(item);
1574
1575 // Add perk associated with the book (M.J.)
1576 if(ItemHasTag(item, 'PerkBook'))
1577 {
1578 //TODO
1579 }
1580 }
1581
1582 public function GetBookText(item : SItemUniqueId) : string // #B
1583 {
1584 if ( GetItemName( item ) != 'Gwent Almanac' )
1585 {
1586 return ReplaceTagsToIcons(GetLocStringByKeyExt(GetItemLocalizedNameByUniqueID(item)+"_text"));
1587 }
1588 else
1589 {
1590 return GetGwentAlmanacContents();
1591 }
1592 }
1593
1594 public function GetBookTextByName( bookName : name ) : string
1595 {
1596 if( bookName != 'Gwent Almanac' )
1597 {
1598 return ReplaceTagsToIcons( GetLocStringByKeyExt( GetItemLocalizedNameByName( bookName ) + "_text" ) );
1599 }
1600 else
1601 {
1602 return GetGwentAlmanacContents();
1603 }
1604 }
1605
1606 function ReadSchematicsAndRecipes( item : SItemUniqueId )
1607 {
1608 var itemCategory : name;
1609 var itemName : name;
1610 var player : W3PlayerWitcher;
1611
1612 ReadBook( item );
1613
1614 player = GetWitcherPlayer();
1615 if ( !player )
1616 {
1617 return;
1618 }
1619
1620 itemName = GetItemName( item );
1621 itemCategory = GetItemCategory( item );
1622 if ( itemCategory == 'alchemy_recipe' )
1623 {
1624 if ( player.CanLearnAlchemyRecipe( itemName ) )
1625 {
1626 player.AddAlchemyRecipe( itemName );
1627 player.GetInventory().AddItemTag(item, 'NoShow');
1628 //theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt("panel_hud_alchemyschematic_update_new_entry") );
1629 }
1630 }
1631 else if ( itemCategory == 'crafting_schematic' )
1632 {
1633 player.AddCraftingSchematic( itemName );
1634 player.GetInventory().AddItemTag(item, 'NoShow');
1635 //theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt("panel_hud_craftingschematic_update_new_entry") );
1636 }
1637 }
1638
1639 function ReadBookByName( bookName : name , unread : bool, optional noNotification : bool ) // #B
1640 {
1641 var defMgr : CDefinitionsManagerAccessor;
1642 var bookFactName : string;
1643
1644 if( IsBookReadByName( bookName ) != unread )
1645 {
1646 return;
1647 }
1648
1649 bookFactName = "BookReadState_"+bookName;
1650 bookFactName = StrReplace(bookFactName," ","_");
1651
1652 if( unread )
1653 {
1654 FactsSubstract( bookFactName, 1 );
1655 }
1656 else
1657 {
1658 FactsAdd( bookFactName, 1 );
1659
1660 //reading achievement
1661 defMgr = theGame.GetDefinitionsManager();
1662 if(!IsAlchemyRecipe(bookName) && !IsCraftingSchematic(bookName) && !defMgr.ItemHasTag( bookName, 'Painting' ) )
1663 {
1664 theGame.GetGamerProfile().IncStat(ES_ReadBooks);
1665
1666 if( !noNotification )
1667 {
1668 theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "notification_book_moved" ), 0, false );
1669 }
1670 }
1671
1672 // Add bestiary entry from the book
1673 if ( AddBestiaryFromBook(bookName) )
1674 return;
1675
1676
1677 /*
1678 else if ( AddRecipePotionFromBook(bookName) )
1679 return;
1680 else if ( AddRecipeOilFromBook(bookName) )
1681 return;
1682 else if ( AddRecipePetardFromBook(bookName) )
1683 return;
1684 else if ( AddRecipeBoltFromBook(bookName) )
1685 return;
1686 else if ( AddRecipeSteelSwordFromBook(bookName) )
1687 return;
1688 else if ( AddRecipeSilverSwordFromBook(bookName) )
1689 return;
1690 else if ( AddRecipeRangedFromBook(bookName) )
1691 return;
1692 else if ( AddRecipeArmorFromBook(bookName) )
1693 return;
1694 else if ( AddRecipeBootsFromBook(bookName) )
1695 return;
1696 else if ( AddRecipePantsFromBook(bookName) )
1697 return;
1698 else if ( AddRecipeGlovesFromBook(bookName) )
1699 return;
1700 else if ( AddRecipeWitcherArmorsFromBook(bookName) )
1701 return;
1702 else if ( AddRecipeComponentFromBook(bookName) )
1703 return;
1704 else if ( AddRecipeUpgradeFromBook(bookName) )
1705 return;
1706 */
1707 }
1708 }
1709
1710 function ReadBookByNameId( bookName : name, itemId:SItemUniqueId, unread : bool, optional noNotification : bool ) // #B
1711 {
1712 var bookFactName : string;
1713
1714 if( IsBookReadByName( bookName ) != unread )
1715 {
1716 return;
1717 }
1718
1719 bookFactName = "BookReadState_"+bookName;
1720 bookFactName = StrReplace(bookFactName," ","_");
1721
1722 if( unread )
1723 {
1724 FactsSubstract( bookFactName, 1 );
1725 }
1726 else
1727 {
1728 FactsAdd( bookFactName, 1 );
1729
1730 //reading achievement
1731 if( !IsAlchemyRecipe( bookName ) && !IsCraftingSchematic( bookName ) )
1732 {
1733 theGame.GetGamerProfile().IncStat(ES_ReadBooks);
1734
1735 if( !noNotification )
1736 {
1737 //theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "notification_book_moved" ), 0, false );
1738 GetWitcherPlayer().AddReadBook( bookName );
1739 }
1740 }
1741
1742 // Add bestiary entry from the book
1743 if ( AddBestiaryFromBook(bookName) )
1744 return;
1745 else
1746 ReadSchematicsAndRecipes( itemId );
1747 }
1748 }
1749
1750
1751 private function AddBestiaryFromBook( bookName : name ) : bool
1752 {
1753 var i, j, r, len : int;
1754 var manager : CWitcherJournalManager;
1755 var resource : array<CJournalResource>;
1756 var entryBase : CJournalBase;
1757 var childGroups : array<CJournalBase>;
1758 var childEntries : array<CJournalBase>;
1759 var descriptionGroup : CJournalCreatureDescriptionGroup;
1760 var descriptionEntry : CJournalCreatureDescriptionEntry;
1761
1762 manager = theGame.GetJournalManager();
1763
1764 switch ( bookName )
1765 {
1766 case 'Beasts vol 1':
1767 resource.PushBack( (CJournalResource)LoadResource( "BestiaryWolf" ) );
1768 resource.PushBack( (CJournalResource)LoadResource( "BestiaryDog" ) );
1769 break;
1770 case 'Beasts vol 2':
1771 resource.PushBack( (CJournalResource)LoadResource( "BestiaryBear" ) );
1772 break;
1773 case 'Cursed Monsters vol 1':
1774 resource.PushBack( (CJournalResource)LoadResource( "BestiaryWerewolf" ) );
1775 resource.PushBack( (CJournalResource)LoadResource( "BestiaryLycanthrope" ) );
1776 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 24');
1777 break;
1778 case 'Cursed Monsters vol 2':
1779 resource.PushBack( (CJournalResource)LoadResource( "BestiaryWerebear" ) );
1780 resource.PushBack( (CJournalResource)LoadResource( "BestiaryMiscreant" ) );
1781 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 11');
1782 break;
1783 case 'Draconides vol 1':
1784 resource.PushBack( (CJournalResource)LoadResource( "BestiaryCockatrice" ) );
1785 resource.PushBack( (CJournalResource)LoadResource( "BestiaryBasilisk" ) );
1786 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 3');
1787 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 23');
1788 break;
1789 case 'Draconides vol 2':
1790 resource.PushBack( (CJournalResource)LoadResource( "BestiaryWyvern" ) );
1791 resource.PushBack( (CJournalResource)LoadResource( "BestiaryForktail" ) );
1792 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 10');
1793 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 17');
1794 break;
1795 case 'Hybrid Monsters vol 1':
1796 resource.PushBack( (CJournalResource)LoadResource( "BestiaryHarpy" ) );
1797 resource.PushBack( (CJournalResource)LoadResource( "BestiaryErynia" ) );
1798 resource.PushBack( (CJournalResource)LoadResource( "BestiarySiren" ) );
1799 resource.PushBack( (CJournalResource)LoadResource( "BestiarySuccubus" ) );
1800 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 14');
1801 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 21');
1802 break;
1803 case 'Hybrid Monsters vol 2':
1804 resource.PushBack( (CJournalResource)LoadResource( "BestiaryGriffin" ) );
1805 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 4');
1806 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 27');
1807 break;
1808 case 'Insectoids vol 1':
1809 resource.PushBack( (CJournalResource)LoadResource( "BestiaryEndriagaWorker" ) );
1810 resource.PushBack( (CJournalResource)LoadResource( "BestiaryEndriagaTruten" ) );
1811 resource.PushBack( (CJournalResource)LoadResource( "BestiaryEndriaga" ) );
1812 break;
1813 case 'Insectoids vol 2':
1814 resource.PushBack( (CJournalResource)LoadResource( "BestiaryCrabSpider" ) );
1815 resource.PushBack( (CJournalResource)LoadResource( "BestiaryArmoredArachas" ) );
1816 resource.PushBack( (CJournalResource)LoadResource( "BestiaryPoisonousArachas" ) );
1817 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 2');
1818 break;
1819 case 'Magical Monsters vol 1':
1820 resource.PushBack( (CJournalResource)LoadResource( "BestiaryGolem" ) );
1821 break;
1822 case 'Magical Monsters vol 2':
1823 resource.PushBack( (CJournalResource)LoadResource( "BestiaryElemental" ) );
1824 resource.PushBack( (CJournalResource)LoadResource( "BestiaryIceGolem" ) );
1825 resource.PushBack( (CJournalResource)LoadResource( "BestiaryFireElemental" ) );
1826 resource.PushBack( (CJournalResource)LoadResource( "BestiaryWhMinion" ) );
1827 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 20');
1828 break;
1829 case 'Necrophage vol 1':
1830 resource.PushBack( (CJournalResource)LoadResource( "BestiaryGhoul" ) );
1831 resource.PushBack( (CJournalResource)LoadResource( "BestiaryAlghoul" ) );
1832 resource.PushBack( (CJournalResource)LoadResource( "BestiaryGreaterRotFiend" ) );
1833 resource.PushBack( (CJournalResource)LoadResource( "BestiaryDrowner" ) );
1834 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 15');
1835 break;
1836 case 'Necrophage vol 2':
1837 resource.PushBack( (CJournalResource)LoadResource( "BestiaryGraveHag" ) );
1838 resource.PushBack( (CJournalResource)LoadResource( "BestiaryWaterHag" ) );
1839 resource.PushBack( (CJournalResource)LoadResource( "BestiaryFogling" ) );
1840 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 5');
1841 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 9');
1842 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 18');
1843 break;
1844 case 'Relict Monsters vol 1':
1845 resource.PushBack( (CJournalResource)LoadResource( "BestiaryBies" ) );
1846 resource.PushBack( (CJournalResource)LoadResource( "BestiaryCzart" ) );
1847 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 8');
1848 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 16');
1849 break;
1850 case 'Relict Monsters vol 2':
1851 resource.PushBack( (CJournalResource)LoadResource( "BestiaryLeshy" ) );
1852 resource.PushBack( (CJournalResource)LoadResource( "BestiarySilvan" ) );
1853 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 22');
1854 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 26');
1855 break;
1856 case 'Specters vol 1':
1857 resource.PushBack( (CJournalResource)LoadResource( "BestiaryMoonwright" ) );
1858 resource.PushBack( (CJournalResource)LoadResource( "BestiaryNoonwright" ) );
1859 resource.PushBack( (CJournalResource)LoadResource( "BestiaryPesta" ) );
1860 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 6');
1861 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 13');
1862 break;
1863 case 'Specters vol 2':
1864 resource.PushBack( (CJournalResource)LoadResource( "BestiaryWraith" ) );
1865 resource.PushBack( (CJournalResource)LoadResource( "BestiaryHim" ) );
1866 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 19');
1867 break;
1868 case 'Ogres vol 1':
1869 resource.PushBack( (CJournalResource)LoadResource( "BestiaryNekker" ) );
1870 resource.PushBack( (CJournalResource)LoadResource( "BestiaryIceTroll" ) );
1871 resource.PushBack( (CJournalResource)LoadResource( "BestiaryCaveTroll" ) );
1872 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 12');
1873 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 25');
1874 break;
1875 case 'Ogres vol 2':
1876 resource.PushBack( (CJournalResource)LoadResource( "BestiaryCyclop" ) );
1877 resource.PushBack( (CJournalResource)LoadResource( "BestiaryIceGiant" ) );
1878 break;
1879 case 'Vampires vol 1':
1880 resource.PushBack( (CJournalResource)LoadResource( "BestiaryEkkima" ) );
1881 resource.PushBack( (CJournalResource)LoadResource( "BestiaryHigherVampire" ) );
1882 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 7');
1883 break;
1884 case 'Vampires vol 2':
1885 resource.PushBack( (CJournalResource)LoadResource( "BestiaryKatakan" ) );
1886 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Mutagen 1');
1887 break;
1888 // EP2 books
1889 case 'bestiary_sharley_book':
1890 resource.PushBack( (CJournalResource)LoadResource( "BestiarySharley" ) );
1891 break;
1892 case 'bestiary_barghest_book':
1893 resource.PushBack( (CJournalResource)LoadResource( "BestiaryBarghest" ) );
1894 break;
1895 case 'bestiary_garkain_book':
1896 resource.PushBack( (CJournalResource)LoadResource( "BestiaryGarkain" ) );
1897 break;
1898 case 'bestiary_alp_book':
1899 resource.PushBack( (CJournalResource)LoadResource( "BestiaryAlp" ) );
1900 break;
1901 case 'bestiary_bruxa_book':
1902 resource.PushBack( (CJournalResource)LoadResource( "BestiaryBruxa" ) );
1903 break;
1904 case 'bestiary_spriggan_book':
1905 resource.PushBack( (CJournalResource)LoadResource( "BestiarySpriggan" ) );
1906 break;
1907 case 'bestiary_fleder_book':
1908 resource.PushBack( (CJournalResource)LoadResource( "BestiaryFleder" ) );
1909 break;
1910 case 'bestiary_wight_book':
1911 resource.PushBack( (CJournalResource)LoadResource( "BestiaryWicht" ) );
1912 break;
1913 case 'bestiary_dracolizard_book':
1914 resource.PushBack( (CJournalResource)LoadResource( "BestiaryDracolizard" ) );
1915 break;
1916 case 'bestiary_panther_book':
1917 resource.PushBack( (CJournalResource)LoadResource( "BestiaryPanther" ) );
1918 break;
1919 case 'bestiary_kikimore_book':
1920 resource.PushBack( (CJournalResource)LoadResource( "BestiaryKikimoraWarrior" ) );
1921 resource.PushBack( (CJournalResource)LoadResource( "BestiaryKikimoraWorker" ) );
1922 break;
1923 case 'bestiary_scolopendromorph_book':
1924 case 'mq7023_fluff_book_scolopendromorphs':
1925 resource.PushBack( (CJournalResource)LoadResource( "BestiaryScolopendromorph" ) );
1926 break;
1927 case 'bestiary_archespore_book':
1928 resource.PushBack( (CJournalResource)LoadResource( "BestiaryArchespore" ) );
1929 break;
1930 case 'bestiary_protofleder_book':
1931 resource.PushBack( (CJournalResource)LoadResource( "BestiaryProtofleder" ) );
1932 break;
1933 default:
1934 return false;
1935 }
1936
1937 // alternatively instead of full path an alias used in LoadResource function i.e.
1938 //resource = (CJournalResource)LoadResource( "JournalBasilisk" );
1939
1940 len = resource.Size();
1941 if( len > 0)
1942 {
1943 //inventory panel UI notification about new bestiary entry
1944 theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "panel_hud_journal_entry_bestiary_new" ), 0, true );
1945 theSound.SoundEvent("gui_journal_track_quest"); // theSound.SoundEvent("gui_ingame_new_journal");
1946 }
1947
1948 for (r=0; r < len; r += 1 )
1949 {
1950 if ( !resource[ r ] )
1951 {
1952 // missing resource
1953 continue;
1954 }
1955 entryBase = resource[r].GetEntry();
1956 if ( entryBase )
1957 {
1958 manager.ActivateEntry( entryBase, JS_Active );
1959 manager.SetEntryHasAdvancedInfo( entryBase, true );
1960
1961 // additionally activate all description entries from description group
1962 manager.GetAllChildren( entryBase, childGroups );
1963 for ( i = 0; i < childGroups.Size(); i += 1 )
1964 {
1965 descriptionGroup = ( CJournalCreatureDescriptionGroup )childGroups[ i ];
1966 if ( descriptionGroup )
1967 {
1968 manager.GetAllChildren( descriptionGroup, childEntries );
1969 for ( j = 0; j < childEntries.Size(); j += 1 )
1970 {
1971 descriptionEntry = ( CJournalCreatureDescriptionEntry )childEntries[ j ];
1972 if ( descriptionEntry )
1973 {
1974 manager.ActivateEntry( descriptionEntry, JS_Active );
1975 }
1976 }
1977 break;
1978 }
1979 }
1980 }
1981 }
1982
1983 if ( resource.Size() > 0 )
1984 return true;
1985 else
1986 return false;
1987 }
1988
1989 /*
1990 private function AddRecipePotionFromBook( bookName : name ) : bool
1991 {
1992 switch ( bookName )
1993 {
1994 case 'Recipe for Black Blood 1':
1995 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Black Blood 1');
1996 return true;
1997 case 'Recipe for Black Blood 2':
1998 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Black Blood 2');
1999 return true;
2000 case 'Recipe for Black Blood 3':
2001 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Black Blood 3');
2002 return true;
2003
2004 case 'Recipe for Blizzard 1':
2005 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Blizzard 1');
2006 return true;
2007 case 'Recipe for Blizzard 2':
2008 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Blizzard 2');
2009 return true;
2010 case 'Recipe for Blizzard 3':
2011 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Blizzard 3');
2012 return true;
2013
2014 case 'Recipe for Cat 1':
2015 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Cat 1');
2016 return true;
2017 case 'Recipe for Cat 2':
2018 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Cat 2');
2019 return true;
2020 case 'Recipe for Cat 3':
2021 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Cat 3');
2022 return true;
2023
2024 case 'Recipe for Full Moon 1':
2025 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Full Moon 1');
2026 return true;
2027 case 'Recipe for Full Moon 2':
2028 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Full Moon 2');
2029 return true;
2030 case 'Recipe for Full Moon 3':
2031 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Full Moon 3');
2032 return true;
2033
2034 case 'Recipe for Golden Oriole 1':
2035 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Golden Oriole 1');
2036 return true;
2037 case 'Recipe for Golden Oriole 2':
2038 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Golden Oriole 2');
2039 return true;
2040 case 'Recipe for Golden Oriole 3':
2041 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Golden Oriole 3');
2042 return true;
2043
2044 case 'Recipe for Killer Whale 1':
2045 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Killer Whale 1');
2046 return true;
2047 case 'Recipe for Killer Whale 2':
2048 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Killer Whale 2');
2049 return true;
2050 case 'Recipe for Killer Whale 3':
2051 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Killer Whale 3');
2052 return true;
2053
2054 case 'Recipe for Maribor Forest 1':
2055 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Maribor Forest 1');
2056 return true;
2057 case 'Recipe for Maribor Forest 2':
2058 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Maribor Forest 2');
2059 return true;
2060 case 'Recipe for Maribor Forest 3':
2061 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Maribor Forest 3');
2062 return true;
2063
2064 case 'Recipe for Petris Philtre 1':
2065 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Petris Philtre 1');
2066 return true;
2067 case 'Recipe for Petris Philtre 2':
2068 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Petris Philtre 2');
2069 return true;
2070 case 'Recipe for Petris Philtre 3':
2071 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Petris Philtre 3');
2072 return true;
2073
2074 case 'Recipe for Swallow 1':
2075 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Swallow 1');
2076 return true;
2077 case 'Recipe for Swallow 2':
2078 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Swallow 2');
2079 return true;
2080 case 'Recipe for Swallow 3':
2081 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Swallow 3');
2082 return true;
2083
2084 case 'Recipe for Tawny Owl 1':
2085 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Tawny Owl 1');
2086 return true;
2087 case 'Recipe for Tawny Owl 2':
2088 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Tawny Owl 2');
2089 return true;
2090 case 'Recipe for Tawny Owl 3':
2091 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Tawny Owl 3');
2092 return true;
2093
2094 case 'Recipe for Thunderbolt 1':
2095 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Thunderbolt 1');
2096 return true;
2097 case 'Recipe for Thunderbolt 2':
2098 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Thunderbolt 2');
2099 return true;
2100 case 'Recipe for Thunderbolt 3':
2101 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Thunderbolt 3');
2102 return true;
2103
2104 case 'Recipe for White Honey 1':
2105 GetWitcherPlayer().AddAlchemyRecipe('Recipe for White Honey 1');
2106 return true;
2107 case 'Recipe for White Honey 2':
2108 GetWitcherPlayer().AddAlchemyRecipe('Recipe for White Honey 2');
2109 return true;
2110 case 'Recipe for White Honey 3':
2111 GetWitcherPlayer().AddAlchemyRecipe('Recipe for White Honey 3');
2112 return true;
2113
2114 case 'Recipe for White Raffard Decoction 1':
2115 GetWitcherPlayer().AddAlchemyRecipe('Recipe for White Raffards Decoction 1');
2116 return true;
2117 case 'Recipe for White Raffard Decoction 2':
2118 GetWitcherPlayer().AddAlchemyRecipe('Recipe for White Raffards Decoction 2');
2119 return true;
2120 case 'Recipe for White Raffard Decoction 3':
2121 GetWitcherPlayer().AddAlchemyRecipe('Recipe for White Raffards Decoction 3');
2122 return true;
2123
2124 case 'Recipe for Drowner Pheromone Potion 1':
2125 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Drowner Pheromone Potion 1');
2126 return true;
2127
2128 default:
2129 return false;
2130 }
2131 }
2132
2133 private function AddRecipeOilFromBook( bookName : name ) : bool
2134 {
2135 switch ( bookName )
2136 {
2137 case 'Recipe for Beast Oil 1':
2138 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Beast Oil 1');
2139 return true;
2140 case 'Recipe for Beast Oil 2':
2141 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Beast Oil 2');
2142 return true;
2143 case 'Recipe for Beast Oil 3':
2144 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Beast Oil 3');
2145 return true;
2146
2147 case 'Recipe for Cursed Oil 1':
2148 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Cursed Oil 1');
2149 return true;
2150 case 'Recipe for Cursed Oil 2':
2151 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Cursed Oil 2');
2152 return true;
2153 case 'Recipe for Cursed Oil 3':
2154 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Cursed Oil 3');
2155 return true;
2156
2157 case 'Recipe for Hanged Man Venom 1':
2158 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Hanged Man Venom 1');
2159 return true;
2160 case 'Recipe for Hanged Man Venom 2':
2161 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Hanged Man Venom 2');
2162 return true;
2163 case 'Recipe for Hanged Man Venom 3':
2164 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Hanged Man Venom 3');
2165 return true;
2166
2167 case 'Recipe for Hybrid Oil 1':
2168 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Hybrid Oil 1');
2169 return true;
2170 case 'Recipe for Hybrid Oil 2':
2171 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Hybrid Oil 2');
2172 return true;
2173 case 'Recipe for Hybrid Oil 3':
2174 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Hybrid Oil 3');
2175 return true;
2176
2177 case 'Recipe for Insectoid Oil 1':
2178 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Insectoid Oil 1');
2179 return true;
2180 case 'Recipe for Insectoid Oil 2':
2181 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Insectoid Oil 2');
2182 return true;
2183 case 'Recipe for Insectoid Oil 3':
2184 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Insectoid Oil 3');
2185 return true;
2186
2187 case 'Recipe for Magicals Oil 1':
2188 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Magicals Oil 1');
2189 return true;
2190 case 'Recipe for Magicals Oil 2':
2191 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Magicals Oil 2');
2192 return true;
2193 case 'Recipe for Magicals Oil 3':
2194 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Magicals Oil 3');
2195 return true;
2196
2197 case 'Recipe for Necrophage Oil 1':
2198 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Necrophage Oil 1');
2199 return true;
2200 case 'Recipe for Necrophage Oil 2':
2201 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Necrophage Oil 2');
2202 return true;
2203 case 'Recipe for Necrophage Oil 3':
2204 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Necrophage Oil 3');
2205 return true;
2206
2207 case 'Recipe for Specter Oil 1':
2208 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Specter Oil 1');
2209 return true;
2210 case 'Recipe for Specter Oil 2':
2211 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Specter Oil 2');
2212 return true;
2213 case 'Recipe for Specter Oil 3':
2214 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Specter Oil 3');
2215 return true;
2216
2217 case 'Recipe for Vampire Oil 1':
2218 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Vampire Oil 2');
2219 return true;
2220 case 'Recipe for Vampire Oil 2':
2221 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Vampire Oil 2');
2222 return true;
2223 case 'Recipe for Vampire Oil 3':
2224 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Vampire Oil 3');
2225 return true;
2226
2227 case 'Recipe for Draconide Oil 1':
2228 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Draconide Oil 1');
2229 return true;
2230 case 'Recipe for Draconide Oil 2':
2231 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Draconide Oil 2');
2232 return true;
2233 case 'Recipe for Draconide Oil 3':
2234 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Draconide Oil 3');
2235 return true;
2236
2237 case 'Recipe for Ogre Oil 1':
2238 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Ogre Oil 1');
2239 return true;
2240 case 'Recipe for Ogre Oil 2':
2241 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Ogre Oil 2');
2242 return true;
2243 case 'Recipe for Ogre Oil 3':
2244 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Ogre Oil 3');
2245 return true;
2246
2247 case 'Recipe for Relic Oil 1':
2248 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Relic Oil 1');
2249 return true;
2250 case 'Recipe for Relic Oil 2':
2251 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Relic Oil 2');
2252 return true;
2253 case 'Recipe for Relic Oil 3':
2254 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Relic Oil 3');
2255 return true;
2256
2257 default:
2258 return false;
2259 }
2260 }
2261
2262 private function AddRecipePetardFromBook( bookName : name ) : bool
2263 {
2264 switch ( bookName )
2265 {
2266 case 'Recipe for Dancing Star 1':
2267 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Dancing Star 1');
2268 return true;
2269 case 'Recipe for Dancing Star 2':
2270 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Dancing Star 2');
2271 return true;
2272 case 'Recipe for Dancing Star 3':
2273 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Dancing Star 3');
2274 return true;
2275
2276 case 'Recipe for Devils Puffball 1':
2277 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Devils Puffball 1');
2278 return true;
2279 case 'Recipe for Devils Puffball 2':
2280 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Devils Puffball 2');
2281 return true;
2282 case 'Recipe for Devils Puffball 3':
2283 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Devils Puffball 3');
2284 return true;
2285
2286 case 'Recipe for Dwimeritium Bomb 1':
2287 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Dwimeritium Bomb 1');
2288 return true;
2289 case 'Recipe for Dwimeritium Bomb 2':
2290 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Dwimeritium Bomb 2');
2291 return true;
2292 case 'Recipe for Dwimeritium Bomb 3':
2293 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Dwimeritium Bomb 3');
2294 return true;
2295
2296 case 'Recipe for Dragons Dream 1':
2297 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Dragons Dream 1');
2298 return true;
2299 case 'Recipe for Dragons Dream 2':
2300 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Dragons Dream 2');
2301 return true;
2302 case 'Recipe for Dragons Dream 3':
2303 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Dragons Dream 3');
2304 return true;
2305
2306 case 'Recipe for Grapeshot 1':
2307 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Grapeshot 1');
2308 return true;
2309 case 'Recipe for Grapeshot 2':
2310 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Grapeshot 2');
2311 return true;
2312 case 'Recipe for Grapeshot 3':
2313 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Grapeshot 3');
2314 return true;
2315
2316 case 'Recipe for Samum 1':
2317 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Samum 1');
2318 return true;
2319 case 'Recipe for Samum 2':
2320 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Samum 2');
2321 return true;
2322 case 'Recipe for Samum 3':
2323 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Samum 3');
2324 return true;
2325
2326 case 'Recipe for Silver Dust Bomb 1':
2327 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Silver Dust Bomb 1');
2328 return true;
2329 case 'Recipe for Silver Dust Bomb 2':
2330 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Silver Dust Bomb 2');
2331 return true;
2332 case 'Recipe for Silver Dust Bomb 3':
2333 GetWitcherPlayer().AddAlchemyRecipe('Recipe for Silver Dust Bomb 3');
2334 return true;
2335
2336 case 'Recipe for White Frost 1':
2337 GetWitcherPlayer().AddAlchemyRecipe('Recipe for White Frost 1');
2338 return true;
2339 case 'Recipe for White Frost 2':
2340 GetWitcherPlayer().AddAlchemyRecipe('Recipe for White Frost 2');
2341 return true;
2342 case 'Recipe for White Frost 3':
2343 GetWitcherPlayer().AddAlchemyRecipe('Recipe for White Frost 3');
2344 return true;
2345
2346 default:
2347 return false;
2348 }
2349 }
2350
2351 private function AddRecipeBoltFromBook( bookName : name ) : bool
2352 {
2353 switch ( bookName )
2354 {
2355 case 'Bodkin Bolt schematic':
2356 GetWitcherPlayer().AddCraftingSchematic('Bodkin Bolt schematic');
2357 return true;
2358 case 'Blunt Bolt schematic':
2359 GetWitcherPlayer().AddCraftingSchematic('Blunt Bolt schematic');
2360 return true;
2361 case 'Broadhead Bolt schematic':
2362 GetWitcherPlayer().AddCraftingSchematic('Broadhead Bolt schematic');
2363 return true;
2364 case 'Target Point Bolt schematic':
2365 GetWitcherPlayer().AddCraftingSchematic('Target Point Bolt schematic');
2366 return true;
2367 case 'Split Bolt schematic':
2368 GetWitcherPlayer().AddCraftingSchematic('Split Bolt schematic');
2369 return true;
2370 case 'Explosive Bolt schematic':
2371 GetWitcherPlayer().AddCraftingSchematic('Explosive Bolt schematic');
2372 return true;
2373 case 'Bait Bolt schematic':
2374 GetWitcherPlayer().AddCraftingSchematic('Bait Bolt schematic');
2375 return true;
2376 case 'Tracking Bolt schematic':
2377 GetWitcherPlayer().AddCraftingSchematic('Tracking Bolt schematic');
2378 return true;
2379
2380 default:
2381 return false;
2382 }
2383 }
2384
2385 private function AddRecipeSteelSwordFromBook( bookName : name ) : bool
2386 {
2387 switch ( bookName )
2388 {
2389 case 'Short sword 1 schematic':
2390 GetWitcherPlayer().AddCraftingSchematic('Short sword 1 schematic');
2391 return true;
2392 case 'Short sword 2 schematic':
2393 GetWitcherPlayer().AddCraftingSchematic('Short sword 2 schematic');
2394 return true;
2395 case 'No Mans Land sword 1 schematic':
2396 GetWitcherPlayer().AddCraftingSchematic('No Mans Land sword 1 schematic');
2397 return true;
2398 case 'No Mans Land sword 2 schematic':
2399 GetWitcherPlayer().AddCraftingSchematic('No Mans Land sword 2 schematic');
2400 return true;
2401 case 'Skellige sword 1 schematic':
2402 GetWitcherPlayer().AddCraftingSchematic('Skellige sword 1 schematic');
2403 return true;
2404 case 'Lynx School steel sword schematic':
2405 GetWitcherPlayer().AddCraftingSchematic('Lynx School steel sword schematic');
2406 return true;
2407 case 'Nilfgaardian sword 1 schematic':
2408 GetWitcherPlayer().AddCraftingSchematic('Nilfgaardian sword 1 schematic');
2409 return true;
2410 case 'Novigraadan sword 1 schematic':
2411 GetWitcherPlayer().AddCraftingSchematic('Novigraadan sword 1 schematic');
2412 return true;
2413 case 'No Mans Land sword 3 schematic':
2414 GetWitcherPlayer().AddCraftingSchematic('No Mans Land sword 3 schematic');
2415 return true;
2416 case 'Skellige sword 2 schematic':
2417 GetWitcherPlayer().AddCraftingSchematic('Skellige sword 2 schematic');
2418 return true;
2419 case 'Gryphon School steel sword schematic':
2420 GetWitcherPlayer().AddCraftingSchematic('Gryphon School steel sword schematic');
2421 return true;
2422 case 'No Mans Land sword 4 schematic':
2423 GetWitcherPlayer().AddCraftingSchematic('No Mans Land sword 4 schematic');
2424 return true;
2425 case 'Scoiatael sword 2 schematic':
2426 GetWitcherPlayer().AddCraftingSchematic('Scoiatael sword 2 schematic');
2427 return true;
2428 case 'Novigraadan sword 4 schematic':
2429 GetWitcherPlayer().AddCraftingSchematic('Novigraadan sword 4 schematic');
2430 return true;
2431 case 'Nilfgaardian sword 4 schematic':
2432 GetWitcherPlayer().AddCraftingSchematic('Nilfgaardian sword 4 schematic');
2433 return true;
2434 case 'Scoiatael sword 3 schematic':
2435 GetWitcherPlayer().AddCraftingSchematic('Scoiatael sword 3 schematic');
2436 return true;
2437 case 'Inquisitor sword 1 schematic':
2438 GetWitcherPlayer().AddCraftingSchematic('Inquisitor sword 1 schematic');
2439 return true;
2440 case 'Bear School steel sword schematic':
2441 GetWitcherPlayer().AddCraftingSchematic('Bear School steel sword schematic');
2442 return true;
2443 case 'Wolf School steel sword schematic':
2444 GetWitcherPlayer().AddCraftingSchematic('Wolf School steel sword schematic');
2445 return true;
2446 case 'Inquisitor sword 2 schematic':
2447 GetWitcherPlayer().AddCraftingSchematic('Inquisitor sword 2 schematic');
2448 return true;
2449 case 'Dwarven sword 1 schematic':
2450 GetWitcherPlayer().AddCraftingSchematic('Dwarven sword 1 schematic');
2451 return true;
2452 case 'Dwarven sword 2 schematic':
2453 GetWitcherPlayer().AddCraftingSchematic('Dwarven sword 2 schematic');
2454 return true;
2455 case 'Gnomish sword 1 schematic':
2456 GetWitcherPlayer().AddCraftingSchematic('Gnomish sword 1 schematic');
2457 return true;
2458 case 'Gnomish sword 2 schematic':
2459 GetWitcherPlayer().AddCraftingSchematic('Gnomish sword 2 schematic');
2460 return true;
2461 case 'Viper Steel sword schematic':
2462 GetWitcherPlayer().AddCraftingSchematic('Viper Steel sword schematic');
2463 return true;
2464
2465 // Relic steel swords
2466 case 'Arbitrator schematic':
2467 GetWitcherPlayer().AddCraftingSchematic('Arbitrator schematic');
2468 return true;
2469 case 'Beannshie schematic':
2470 GetWitcherPlayer().AddCraftingSchematic('Beannshie schematic');
2471 return true;
2472 case 'Blackunicorn schematic':
2473 GetWitcherPlayer().AddCraftingSchematic('Blackunicorn schematic');
2474 return true;
2475 case 'Longclaw schematic':
2476 GetWitcherPlayer().AddCraftingSchematic('Longclaw schematic');
2477 return true;
2478
2479 default:
2480 return false;
2481 }
2482 }
2483
2484 private function AddRecipeSilverSwordFromBook( bookName : name ) : bool
2485 {
2486 switch ( bookName )
2487 {
2488 case 'Viper Silver sword schematic':
2489 GetWitcherPlayer().AddCraftingSchematic('Viper Silver sword schematic');
2490 return true;
2491 case 'Silver sword 1 schematic':
2492 GetWitcherPlayer().AddCraftingSchematic('Silver sword 1 schematic');
2493 return true;
2494 case 'Silver sword 2 schematic':
2495 GetWitcherPlayer().AddCraftingSchematic('Silver sword 2 schematic');
2496 return true;
2497 case 'Lynx School silver sword schematic':
2498 GetWitcherPlayer().AddCraftingSchematic('Lynx School silver sword schematic');
2499 return true;
2500 case 'Silver sword 3 schematic':
2501 GetWitcherPlayer().AddCraftingSchematic('Silver sword 3 schematic');
2502 return true;
2503 case 'Gryphon School silver sword schematic':
2504 GetWitcherPlayer().AddCraftingSchematic('Gryphon School silver sword schematic');
2505 return true;
2506 case 'Silver sword 4 schematic':
2507 GetWitcherPlayer().AddCraftingSchematic('Silver sword 4 schematic');
2508 return true;
2509 case 'Silver sword 6 schematic':
2510 GetWitcherPlayer().AddCraftingSchematic('Silver sword 6 schematic');
2511 return true;
2512 case 'Silver sword 7 schematic':
2513 GetWitcherPlayer().AddCraftingSchematic('Silver sword 7 schematic');
2514 return true;
2515 case 'Elven silver sword 1 schematic':
2516 GetWitcherPlayer().AddCraftingSchematic('Elven silver sword 1 schematic');
2517 return true;
2518 case 'Bear School silver sword schematic':
2519 GetWitcherPlayer().AddCraftingSchematic('Bear School silver sword schematic');
2520 return true;
2521 case 'Elven silver sword 2 schematic':
2522 GetWitcherPlayer().AddCraftingSchematic('Elven silver sword 2 schematic');
2523 return true;
2524 case 'Wolf School silver sword schematic':
2525 GetWitcherPlayer().AddCraftingSchematic('Wolf School silver sword schematic');
2526 return true;
2527 case 'Dwarven silver sword 1 schematic':
2528 GetWitcherPlayer().AddCraftingSchematic('Dwarven silver sword 1 schematic');
2529 return true;
2530 case 'Dwarven silver sword 2 schematic':
2531 GetWitcherPlayer().AddCraftingSchematic('Dwarven silver sword 2 schematic');
2532 return true;
2533 case 'Gnomish silver sword 1 schematic':
2534 GetWitcherPlayer().AddCraftingSchematic('Gnomish silver sword 1 schematic');
2535 return true;
2536 case 'Gnomish silver sword 2 schematic':
2537 GetWitcherPlayer().AddCraftingSchematic('Gnomish silver sword 2 schematic');
2538 return true;
2539
2540 // Relic silver swords
2541 case 'Harpy schematic':
2542 GetWitcherPlayer().AddCraftingSchematic('Harpy schematic');
2543 return true;
2544 case 'Negotiator schematic':
2545 GetWitcherPlayer().AddCraftingSchematic('Negotiator schematic');
2546 return true;
2547 case 'Weeper schematic':
2548 GetWitcherPlayer().AddCraftingSchematic('Weeper schematic');
2549 return true;
2550
2551 default:
2552 return false;
2553 }
2554 }
2555
2556 private function AddRecipeRangedFromBook( bookName : name ) : bool
2557 {
2558 switch ( bookName )
2559 {
2560 case 'Bear School Crossbow schematic':
2561 GetWitcherPlayer().AddCraftingSchematic('Bear School Crossbow schematic');
2562 return true;
2563 case 'Lynx School Crossbow schematic':
2564 GetWitcherPlayer().AddCraftingSchematic('Lynx School Crossbow schematic');
2565 return true;
2566
2567 default:
2568 return false;
2569 }
2570 }
2571
2572 private function AddRecipeArmorFromBook( bookName : name ) : bool
2573 {
2574 switch ( bookName )
2575 {
2576 case 'Light Armor 1 schematic':
2577 GetWitcherPlayer().AddCraftingSchematic('Light Armor 1 schematic');
2578 return true;
2579 case 'Light Armor 2 schematic':
2580 GetWitcherPlayer().AddCraftingSchematic('Light Armor 2 schematic');
2581 return true;
2582 case 'Light Armor 3 schematic':
2583 GetWitcherPlayer().AddCraftingSchematic('Light Armor 3 schematic');
2584 return true;
2585 case 'Light Armor 4 schematic':
2586 GetWitcherPlayer().AddCraftingSchematic('Light Armor 4 schematic');
2587 return true;
2588 case 'Light Armor 5 schematic':
2589 GetWitcherPlayer().AddCraftingSchematic('Light Armor 5 schematic');
2590 return true;
2591 case 'Light Armor 6 schematic':
2592 GetWitcherPlayer().AddCraftingSchematic('Light Armor 6 schematic');
2593 return true;
2594 case 'Light Armor 7 schematic':
2595 GetWitcherPlayer().AddCraftingSchematic('Light Armor 7 schematic');
2596 return true;
2597 case 'Light Armor 8 schematic':
2598 GetWitcherPlayer().AddCraftingSchematic('Light Armor 8 schematic');
2599 return true;
2600 case 'Medium Armor 1 schematic':
2601 GetWitcherPlayer().AddCraftingSchematic('Medium Armor 1 schematic');
2602 return true;
2603 case 'Medium Armor 2 schematic':
2604 GetWitcherPlayer().AddCraftingSchematic('Medium Armor 2 schematic');
2605 return true;
2606 case 'Medium Armor 3 schematic':
2607 GetWitcherPlayer().AddCraftingSchematic('Medium Armor 3 schematic');
2608 return true;
2609 case 'Medium Armor 4 schematic':
2610 GetWitcherPlayer().AddCraftingSchematic('Medium Armor 4 schematic');
2611 return true;
2612 case 'Heavy Armor 1 schematic':
2613 GetWitcherPlayer().AddCraftingSchematic('Heavy Armor 1 schematic');
2614 return true;
2615 case 'Heavy Armor 2 schematic':
2616 GetWitcherPlayer().AddCraftingSchematic('Heavy Armor 2 schematic');
2617 return true;
2618 case 'Heavy Armor 3 schematic':
2619 GetWitcherPlayer().AddCraftingSchematic('Heavy Armor 3 schematic');
2620 return true;
2621 case 'Heavy Armor 4 schematic':
2622 GetWitcherPlayer().AddCraftingSchematic('Heavy Armor 4 schematic');
2623 return true;
2624
2625 default:
2626 return false;
2627 }
2628 }
2629
2630 private function AddRecipeBootsFromBook( bookName : name ) : bool
2631 {
2632 switch ( bookName )
2633 {
2634 case 'Boots 1 schematic':
2635 GetWitcherPlayer().AddCraftingSchematic('Boots 1 schematic');
2636 return true;
2637 case 'Boots 2 schematic':
2638 GetWitcherPlayer().AddCraftingSchematic('Boots 2 schematic');
2639 return true;
2640 case 'Boots 3 schematic':
2641 GetWitcherPlayer().AddCraftingSchematic('Boots 3 schematic');
2642 return true;
2643 case 'Boots 4 schematic':
2644 GetWitcherPlayer().AddCraftingSchematic('Boots 4 schematic');
2645 return true;
2646 case 'Heavy Boots 1 schematic':
2647 GetWitcherPlayer().AddCraftingSchematic('Heavy Boots 1 schematic');
2648 return true;
2649 case 'Heavy Boots 2 schematic':
2650 GetWitcherPlayer().AddCraftingSchematic('Heavy Boots 2 schematic');
2651 return true;
2652 case 'Heavy Boots 3 schematic':
2653 GetWitcherPlayer().AddCraftingSchematic('Heavy Boots 3 schematic');
2654 return true;
2655 case 'Heavy Boots 4 schematic':
2656 GetWitcherPlayer().AddCraftingSchematic('Heavy Boots 4 schematic');
2657 return true;
2658
2659 default:
2660 return false;
2661 }
2662 }
2663
2664 private function AddRecipePantsFromBook( bookName : name ) : bool
2665 {
2666 switch ( bookName )
2667 {
2668 case 'Pants 1 schematic':
2669 GetWitcherPlayer().AddCraftingSchematic('Pants 1 schematic');
2670 return true;
2671 case 'Pants 2 schematic':
2672 GetWitcherPlayer().AddCraftingSchematic('Pants 2 schematic');
2673 return true;
2674 case 'Pants 3 schematic':
2675 GetWitcherPlayer().AddCraftingSchematic('Pants 3 schematic');
2676 return true;
2677 case 'Pants 4 schematic':
2678 GetWitcherPlayer().AddCraftingSchematic('Pants 4 schematic');
2679 return true;
2680 case 'Heavy Pants 1 schematic':
2681 GetWitcherPlayer().AddCraftingSchematic('Heavy Pants 1 schematic');
2682 return true;
2683 case 'Heavy Pants 2 schematic':
2684 GetWitcherPlayer().AddCraftingSchematic('Heavy Pants 2 schematic');
2685 return true;
2686 case 'Heavy Pants 3 schematic':
2687 GetWitcherPlayer().AddCraftingSchematic('Heavy Pants 3 schematic');
2688 return true;
2689 case 'Heavy Pants 4 schematic':
2690 GetWitcherPlayer().AddCraftingSchematic('Heavy Pants 4 schematic');
2691 return true;
2692
2693 default:
2694 return false;
2695 }
2696 }
2697
2698 private function AddRecipeGlovesFromBook(bookName : name ) : bool
2699 {
2700 switch ( bookName )
2701 {
2702 case 'Gloves 1 schematic':
2703 GetWitcherPlayer().AddCraftingSchematic('Gloves 1 schematic');
2704 return true;
2705 case 'Gloves 2 schematic':
2706 GetWitcherPlayer().AddCraftingSchematic('Gloves 2 schematic');
2707 return true;
2708 case 'Gloves 3 schematic':
2709 GetWitcherPlayer().AddCraftingSchematic('Gloves 3 schematic');
2710 return true;
2711 case 'Gloves 4 schematic':
2712 GetWitcherPlayer().AddCraftingSchematic('Gloves 4 schematic');
2713 return true;
2714 case 'Heavy Gloves 1 schematic':
2715 GetWitcherPlayer().AddCraftingSchematic('Heavy Gloves1 schematic');
2716 return true;
2717 case 'Heavy Gloves 2 schematic':
2718 GetWitcherPlayer().AddCraftingSchematic('Heavy Gloves 2 schematic');
2719 return true;
2720 case 'Heavy Gloves 3 schematic':
2721 GetWitcherPlayer().AddCraftingSchematic('Heavy Gloves 3 schematic');
2722 return true;
2723 case 'Heavy Gloves 4 schematic':
2724 GetWitcherPlayer().AddCraftingSchematic('Heavy Gloves 4 schematic');
2725 return true;
2726
2727 default:
2728 return false;
2729 }
2730 }
2731
2732 private function AddRecipeWitcherArmorsFromBook(bookName : name ) : bool
2733 {
2734 switch ( bookName )
2735 {
2736 case 'Lynx Armor schematic':
2737 GetWitcherPlayer().AddCraftingSchematic('Lynx Armor schematic');
2738 return true;
2739 case 'Lynx Boots schematic':
2740 GetWitcherPlayer().AddCraftingSchematic('Lynx Boots schematic');
2741 return true;
2742 case 'Lynx Gloves schematic':
2743 GetWitcherPlayer().AddCraftingSchematic('Lynx Gloves schematic');
2744 return true;
2745 case 'Lynx Pants schematic':
2746 GetWitcherPlayer().AddCraftingSchematic('Lynx Pants schematic');
2747 return true;
2748 case 'Gryphon Armor schematic':
2749 GetWitcherPlayer().AddCraftingSchematic('Gryphon Armor schematic');
2750 return true;
2751 case 'Gryphon Boots schematic':
2752 GetWitcherPlayer().AddCraftingSchematic('Gryphon Boots schematic');
2753 return true;
2754 case 'Gryphon Gloves schematic':
2755 GetWitcherPlayer().AddCraftingSchematic('Gryphon Gloves schematic');
2756 return true;
2757 case 'Gryphon Pants schematic':
2758 GetWitcherPlayer().AddCraftingSchematic('Gryphon Pants schematic');
2759 return true;
2760 case 'Bear Armor schematic':
2761 GetWitcherPlayer().AddCraftingSchematic('Bear Armor schematic');
2762 return true;
2763 case 'Bear Boots schematic':
2764 GetWitcherPlayer().AddCraftingSchematic('Bear Boots schematic');
2765 return true;
2766 case 'Bear Gloves schematic':
2767 GetWitcherPlayer().AddCraftingSchematic('Bear Gloves schematic');
2768 return true;
2769 case 'Bear Pants schematic':
2770 GetWitcherPlayer().AddCraftingSchematic('Bear Pants schematic');
2771 return true;
2772 case 'Wolf Armor schematic':
2773 GetWitcherPlayer().AddCraftingSchematic('Wolf Armor schematic');
2774 return true;
2775 case 'Wolf Boots schematic':
2776 GetWitcherPlayer().AddCraftingSchematic('Wolf Boots schematic');
2777 return true;
2778 case 'Wolf Gloves schematic':
2779 GetWitcherPlayer().AddCraftingSchematic('Wolf Gloves schematic');
2780 return true;
2781 case 'Wolf Pants schematic':
2782 GetWitcherPlayer().AddCraftingSchematic('Wolf Pants schematic');
2783 return true;
2784
2785 default:
2786 return false;
2787 }
2788 }
2789
2790 private function AddRecipeComponentFromBook(bookName : name ) : bool
2791 {
2792 switch ( bookName )
2793 {
2794 case 'Steel ingot schematic':
2795 GetWitcherPlayer().AddCraftingSchematic('Steel ingot schematic');
2796 return true;
2797 case 'Dark Iron ingot schematic':
2798 GetWitcherPlayer().AddCraftingSchematic('Dark Iron ingot schematic');
2799 return true;
2800 case 'Meteorite ingot schematic':
2801 GetWitcherPlayer().AddCraftingSchematic('Meteorite ingot schematic');
2802 return true;
2803 case 'Dwimeryte ingot schematic':
2804 GetWitcherPlayer().AddCraftingSchematic('Dwimeryte ingot schematic');
2805 return true;
2806 case 'Silver ingot schematic 1':
2807 GetWitcherPlayer().AddCraftingSchematic('Silver ingot schematic 1');
2808 return true;
2809 case 'Silver ingot schematic 2':
2810 GetWitcherPlayer().AddCraftingSchematic('Silver ingot schematic 2');
2811 return true;
2812 case 'Silver ingot schematic 3':
2813 GetWitcherPlayer().AddCraftingSchematic('Silver ingot schematic 3');
2814 return true;
2815 case 'Hardened leather schematic 1':
2816 GetWitcherPlayer().AddCraftingSchematic('Hardened leather schematic 1');
2817 return true;
2818 case 'Hardened leather schematic 2':
2819 GetWitcherPlayer().AddCraftingSchematic('Hardened leather schematic 2');
2820 return true;
2821 case 'Hardened leather schematic 3':
2822 GetWitcherPlayer().AddCraftingSchematic('Hardened leather schematic 3');
2823 return true;
2824 case 'Hardened leather schematic 4':
2825 GetWitcherPlayer().AddCraftingSchematic('Hardened leather schematic 4');
2826 return true;
2827 case 'Hardened timber schematic 1':
2828 GetWitcherPlayer().AddCraftingSchematic('Hardened timber schematic 1');
2829 return true;
2830 case 'Draconide leather schematic 1':
2831 GetWitcherPlayer().AddCraftingSchematic('Draconide leather schematic 1');
2832 return true;
2833 case 'Draconide leather schematic 2':
2834 GetWitcherPlayer().AddCraftingSchematic('Draconide leather schematic 2');
2835 return true;
2836 case 'Draconide leather schematic 3':
2837 GetWitcherPlayer().AddCraftingSchematic('Draconide leather schematic 3');
2838 return true;
2839 case 'Draconide leather schematic 4':
2840 GetWitcherPlayer().AddCraftingSchematic('Draconide leather schematic 4');
2841 return true;
2842 case 'Leather schematic 1':
2843 GetWitcherPlayer().AddCraftingSchematic('Leather schematic 1');
2844 return true;
2845 case 'Leather schematic 2':
2846 GetWitcherPlayer().AddCraftingSchematic('Leather schematic 2');
2847 return true;
2848 case 'Leather schematic 3':
2849 GetWitcherPlayer().AddCraftingSchematic('Leather schematic 3');
2850 return true;
2851 case 'Leather schematic 4':
2852 GetWitcherPlayer().AddCraftingSchematic('Leather schematic 4');
2853 return true;
2854 case 'Leather schematic 5':
2855 GetWitcherPlayer().AddCraftingSchematic('Leather schematic 5');
2856 return true;
2857 case 'Leather schematic 6':
2858 GetWitcherPlayer().AddCraftingSchematic('Leather schematic 6');
2859 return true;
2860 case 'Leather schematic 7':
2861 GetWitcherPlayer().AddCraftingSchematic('Leather schematic 7');
2862 return true;
2863 case 'Leather schematic 8':
2864 GetWitcherPlayer().AddCraftingSchematic('Leather schematic 8');
2865 return true;
2866 case 'Leather straps schematic':
2867 GetWitcherPlayer().AddCraftingSchematic('Leather straps schematic');
2868 return true;
2869 case 'Steel plates schematic':
2870 GetWitcherPlayer().AddCraftingSchematic('Steel plates schematic');
2871 return true;
2872
2873 default:
2874 return false;
2875 }
2876 }
2877
2878 private function AddRecipeUpgradeFromBook(bookName : name ) : bool
2879 {
2880 switch ( bookName )
2881 {
2882 case 'Starting Armor Upgrade schematic 1':
2883 GetWitcherPlayer().AddCraftingSchematic('Starting Armor Upgrade schematic 1');
2884 return true;
2885
2886 case 'Witcher Bear Jacket Upgrade schematic 1':
2887 GetWitcherPlayer().AddCraftingSchematic('Witcher Bear Jacket Upgrade schematic 1');
2888 return true;
2889 case 'Witcher Bear Jacket Upgrade schematic 2':
2890 GetWitcherPlayer().AddCraftingSchematic('Witcher Bear Jacket Upgrade schematic 2');
2891 return true;
2892 case 'Witcher Bear Jacket Upgrade schematic 3':
2893 GetWitcherPlayer().AddCraftingSchematic('Witcher Bear Jacket Upgrade schematic 3');
2894 return true;
2895 case 'Witcher Bear Boots Upgrade schematic 1':
2896 GetWitcherPlayer().AddCraftingSchematic('Witcher Bear Boots Upgrade schematic 1');
2897 return true;
2898 case 'Witcher Bear Pants Upgrade schematic 1':
2899 GetWitcherPlayer().AddCraftingSchematic('Witcher Bear Pants Upgrade schematic 1');
2900 return true;
2901 case 'Witcher Bear Gloves Upgrade schematic 1':
2902 GetWitcherPlayer().AddCraftingSchematic('Witcher Bear Gloves Upgrade schematic 1');
2903 return true;
2904 case 'Bear School steel sword Upgrade schematic 1':
2905 GetWitcherPlayer().AddCraftingSchematic('Bear School steel sword Upgrade schematic 1');
2906 return true;
2907 case 'Bear School steel sword Upgrade schematic 2':
2908 GetWitcherPlayer().AddCraftingSchematic('Bear School steel sword Upgrade schematic 2');
2909 return true;
2910 case 'Bear School steel sword Upgrade schematic 3':
2911 GetWitcherPlayer().AddCraftingSchematic('Bear School steel sword Upgrade schematic 3');
2912 return true;
2913 case 'Bear School silver sword Upgrade schematic 1':
2914 GetWitcherPlayer().AddCraftingSchematic('Bear School silver sword Upgrade schematic 1');
2915 return true;
2916 case 'Bear School silver sword Upgrade schematic 2':
2917 GetWitcherPlayer().AddCraftingSchematic('Bear School silver sword Upgrade schematic 2');
2918 return true;
2919 case 'Bear School silver sword Upgrade schematic 3':
2920 GetWitcherPlayer().AddCraftingSchematic('Bear School silver sword Upgrade schematic 3');
2921 return true;
2922
2923 case 'Witcher Gryphon Jacket Upgrade schematic 1':
2924 GetWitcherPlayer().AddCraftingSchematic('Witcher Gryphon Jacket Upgrade schematic 1');
2925 return true;
2926 case 'Witcher Gryphon Jacket Upgrade schematic 2':
2927 GetWitcherPlayer().AddCraftingSchematic('Witcher Gryphon Jacket Upgrade schematic 2');
2928 return true;
2929 case 'Witcher Gryphon Jacket Upgrade schematic 3':
2930 GetWitcherPlayer().AddCraftingSchematic('Witcher Gryphon Jacket Upgrade schematic 3');
2931 return true;
2932 case 'Witcher Gryphon Boots Upgrade schematic 1':
2933 GetWitcherPlayer().AddCraftingSchematic('Witcher Gryphon Boots Upgrade schematic 1');
2934 return true;
2935 case 'Witcher Gryphon Pants Upgrade schematic 1':
2936 GetWitcherPlayer().AddCraftingSchematic('Witcher Gryphon Pants Upgrade schematic 1');
2937 return true;
2938 case 'Witcher Gryphon Gloves Upgrade schematic 1':
2939 GetWitcherPlayer().AddCraftingSchematic('Witcher Gryphon Gloves Upgrade schematic 1');
2940 return true;
2941 case 'Gryphon School steel sword Upgrade schematic 1':
2942 GetWitcherPlayer().AddCraftingSchematic('Gryphon School steel sword Upgrade schematic 1');
2943 return true;
2944 case 'Gryphon School steel sword Upgrade schematic 2':
2945 GetWitcherPlayer().AddCraftingSchematic('Gryphon School steel sword Upgrade schematic 2');
2946 return true;
2947 case 'Gryphon School steel sword Upgrade schematic 3':
2948 GetWitcherPlayer().AddCraftingSchematic('Gryphon School steel sword Upgrade schematic 3');
2949 return true;
2950 case 'Gryphon School silver sword Upgrade schematic 1':
2951 GetWitcherPlayer().AddCraftingSchematic('Gryphon School silver sword Upgrade schematic 1');
2952 return true;
2953 case 'Gryphon School silver sword Upgrade schematic 2':
2954 GetWitcherPlayer().AddCraftingSchematic('Gryphon School silver sword Upgrade schematic 2');
2955 return true;
2956 case 'Gryphon School silver sword Upgrade schematic 3':
2957 GetWitcherPlayer().AddCraftingSchematic('Gryphon School silver sword Upgrade schematic 3');
2958 return true;
2959
2960 case 'Witcher Wolf Jacket Upgrade schematic 1':
2961 GetWitcherPlayer().AddCraftingSchematic('Witcher Wolf Jacket Upgrade schematic 1');
2962 return true;
2963 case 'Witcher Wolf Jacket Upgrade schematic 2':
2964 GetWitcherPlayer().AddCraftingSchematic('Witcher Wolf Jacket Upgrade schematic 2');
2965 return true;
2966 case 'Witcher Wolf Jacket Upgrade schematic 3':
2967 GetWitcherPlayer().AddCraftingSchematic('Witcher Wolf Jacket Upgrade schematic 3');
2968 return true;
2969 case 'Witcher Wolf Boots Upgrade schematic 1':
2970 GetWitcherPlayer().AddCraftingSchematic('Witcher Wolf Boots Upgrade schematic 1');
2971 return true;
2972 case 'Witcher Wolf Pants Upgrade schematic 1':
2973 GetWitcherPlayer().AddCraftingSchematic('Witcher Wolf Pants Upgrade schematic 1');
2974 return true;
2975 case 'Witcher Wolf Gloves Upgrade schematic 1':
2976 GetWitcherPlayer().AddCraftingSchematic('Witcher Wolf Gloves Upgrade schematic 1');
2977 return true;
2978 case 'Wolf School steel sword Upgrade schematic 1':
2979 GetWitcherPlayer().AddCraftingSchematic('Wolf School steel sword Upgrade schematic 1');
2980 return true;
2981 case 'Wolf School steel sword Upgrade schematic 2':
2982 GetWitcherPlayer().AddCraftingSchematic('Wolf School steel sword Upgrade schematic 2');
2983 return true;
2984 case 'Wolf School steel sword Upgrade schematic 3':
2985 GetWitcherPlayer().AddCraftingSchematic('Wolf School steel sword Upgrade schematic 3');
2986 return true;
2987 case 'Wolf School silver sword Upgrade schematic 1':
2988 GetWitcherPlayer().AddCraftingSchematic('Wolf School silver sword Upgrade schematic 1');
2989 return true;
2990 case 'Wolf School silver sword Upgrade schematic 2':
2991 GetWitcherPlayer().AddCraftingSchematic('Wolf School silver sword Upgrade schematic 2');
2992 return true;
2993 case 'Wolf School silver sword Upgrade schematic 3':
2994 GetWitcherPlayer().AddCraftingSchematic('Wolf School silver sword Upgrade schematic 3');
2995 return true;
2996
2997 case 'Witcher Lynx Jacket Upgrade schematic 1':
2998 GetWitcherPlayer().AddCraftingSchematic('Witcher Lynx Jacket Upgrade schematic 1');
2999 return true;
3000 case 'Witcher Lynx Jacket Upgrade schematic 2':
3001 GetWitcherPlayer().AddCraftingSchematic('Witcher Lynx Jacket Upgrade schematic 2');
3002 return true;
3003 case 'Witcher Lynx Jacket Upgrade schematic 3':
3004 GetWitcherPlayer().AddCraftingSchematic('Witcher Lynx Jacket Upgrade schematic 3');
3005 return true;
3006 case 'Witcher Lynx Boots Upgrade schematic 1':
3007 GetWitcherPlayer().AddCraftingSchematic('Witcher Lynx Boots Upgrade schematic 1');
3008 return true;
3009 case 'Witcher Lynx Pants Upgrade schematic 1':
3010 GetWitcherPlayer().AddCraftingSchematic('Witcher Lynx Pants Upgrade schematic 1');
3011 return true;
3012 case 'Witcher Lynx Gloves Upgrade schematic 1':
3013 GetWitcherPlayer().AddCraftingSchematic('Witcher Lynx Gloves Upgrade schematic 1');
3014 return true;
3015 case 'Lynx School steel sword Upgrade schematic 1':
3016 GetWitcherPlayer().AddCraftingSchematic('Lynx School steel sword Upgrade schematic 1');
3017 return true;
3018 case 'Lynx School steel sword Upgrade schematic 2':
3019 GetWitcherPlayer().AddCraftingSchematic('Lynx School steel sword Upgrade schematic 2');
3020 return true;
3021 case 'Lynx School steel sword Upgrade schematic 3':
3022 GetWitcherPlayer().AddCraftingSchematic('Lynx School steel sword Upgrade schematic 3');
3023 return true;
3024 case 'Lynx School silver sword Upgrade schematic 1':
3025 GetWitcherPlayer().AddCraftingSchematic('Lynx School silver sword Upgrade schematic 1');
3026 return true;
3027 case 'Lynx School silver sword Upgrade schematic 2':
3028 GetWitcherPlayer().AddCraftingSchematic('Lynx School silver sword Upgrade schematic 2');
3029 return true;
3030 case 'Lynx School silver sword Upgrade schematic 3':
3031 GetWitcherPlayer().AddCraftingSchematic('Lynx School silver sword Upgrade schematic 3');
3032 return true;
3033
3034 default:
3035 return false;
3036 }
3037 }
3038 */
3039
3040 // ---------------------------------------------------------------------------
3041 // #Books End
3042 // ---------------------------------------------------------------------------
3043
3044 //gets weapon damage types from XML definition
3045 function GetWeaponDTNames( id : SItemUniqueId, out dmgNames : array< name > ) : int
3046 {
3047 var attrs : array< name >;
3048 var i, size : int;
3049
3050 dmgNames.Clear();
3051
3052 if( IsIdValid(id) )
3053 {
3054 GetItemAttributes( id, attrs );
3055 size = attrs.Size();
3056
3057 for( i = 0; i < size; i += 1 )
3058 if( IsDamageTypeNameValid(attrs[i]) )
3059 dmgNames.PushBack( attrs[i] );
3060
3061 if(dmgNames.Size() == 0)
3062 LogAssert(false, "CInventoryComponent.GetWeaponDTNames: weapon <<" + GetItemName(id) + ">> has no damage types defined!");
3063 }
3064 return dmgNames.Size();
3065 }
3066
3067 public function GetWeapons() : array<SItemUniqueId>
3068 {
3069 var ids, ids2 : array<SItemUniqueId>;
3070
3071 ids = GetItemsByCategory('monster_weapon');
3072 ids2 = GetItemsByTag('Weapon');
3073 ArrayOfIdsAppend(ids, ids2);
3074
3075 return ids;
3076 }
3077
3078 public function GetHeldWeapons() : array<SItemUniqueId>
3079 {
3080 var i : int;
3081 var w : array<SItemUniqueId>;
3082
3083 w = GetWeapons();
3084
3085 for(i=w.Size()-1; i>=0; i-=1)
3086 {
3087 if(!IsItemHeld(w[i]))
3088 {
3089 w.EraseFast( i );
3090 }
3091 }
3092
3093 return w;
3094 }
3095
3096 public function GetCurrentlyHeldSword() : SItemUniqueId
3097 {
3098 var i : int;
3099 var w : array<SItemUniqueId>;
3100
3101 w = GetHeldWeapons();
3102
3103 for( i = 0 ; i < w.Size() ; i+=1 )
3104 {
3105 if( IsItemSteelSwordUsableByPlayer( w[i] ) || IsItemSilverSwordUsableByPlayer( w[i] ) )
3106 {
3107 return w[i];
3108 }
3109 }
3110
3111 return GetInvalidUniqueId();
3112 }
3113
3114 public function GetCurrentlyHeldSwordEntity( out ent : CItemEntity ) : bool
3115 {
3116 var id : SItemUniqueId;
3117
3118 id = GetCurrentlyHeldSword();
3119
3120 if( IsIdValid( id ) )
3121 {
3122 ent = GetItemEntityUnsafe( id );
3123
3124 if( ent )
3125 {
3126 return true;
3127 }
3128 else
3129 {
3130 return false;
3131 }
3132 }
3133 return false;
3134 }
3135
3136 public function GetHeldWeaponsWithCategory( category : name, out items : array<SItemUniqueId> )
3137 {
3138 var i : int;
3139
3140 items = GetItemsByCategory( category );
3141
3142 for ( i = items.Size()-1; i >= 0; i -= 1)
3143 {
3144 if ( !IsItemHeld( items[i] ) )
3145 {
3146 items.EraseFast( i );
3147 }
3148 }
3149 }
3150
3151 public function GetPotionItemBuffData(id : SItemUniqueId, out type : EEffectType, out customAbilityName : name) : bool
3152 {
3153 var size, i : int;
3154 var arr : array<name>;
3155
3156 if(IsIdValid(id))
3157 {
3158 GetItemContainedAbilities( id, arr );
3159 size = arr.Size();
3160
3161 for( i = 0; i < size; i += 1 )
3162 {
3163 if( IsEffectNameValid(arr[i]) )
3164 {
3165 EffectNameToType(arr[i], type, customAbilityName);
3166 return true;
3167 }
3168 }
3169 }
3170
3171 return false;
3172 }
3173
3174 /**
3175 Breaks item into recyclable parts and gives them to hero.
3176 */
3177 public function RecycleItem( id : SItemUniqueId, level : ECraftsmanLevel ) : array<SItemUniqueId>
3178 {
3179 var itemsAdded : array<SItemUniqueId>;
3180 var currentAdded : array<SItemUniqueId>;
3181
3182 var parts : array<SItemParts>;
3183 var i : int;
3184
3185 parts = GetItemRecyclingParts( id );
3186
3187 for ( i = 0; i < parts.Size(); i += 1 )
3188 {
3189 if ( ECL_Grand_Master == level || ECL_Arch_Master == level )
3190 {
3191 currentAdded = AddAnItem( parts[i].itemName, parts[i].quantity );
3192 }
3193 else if ( ECL_Master == level && parts[i].quantity > 1 )
3194 {
3195 currentAdded = AddAnItem( parts[i].itemName, RandRange( parts[i].quantity, 1 ) );
3196 }
3197 else
3198 {
3199 currentAdded = AddAnItem( parts[i].itemName, 1 );
3200 }
3201 itemsAdded.PushBack(currentAdded[0]);
3202 }
3203
3204 RemoveItem(id);
3205
3206 return itemsAdded;
3207 }
3208
3209 //////////////////////////////////////////////////////////////////////////////////////////
3210 // Potions
3211 //////////////////////////////////////////////////////////////////////////////////////////
3212
3213 /**
3214 Gets buff names that the given item will give. Checks if item defines attribute with a name the same as some buff name.
3215 Returns buffs size.
3216 */
3217 public function GetItemBuffs( id : SItemUniqueId, out buffs : array<SEffectInfo>) : int
3218 {
3219 var attrs, abs, absFast : array< name >;
3220 var i, k : int;
3221 var type : EEffectType;
3222 var abilityName : name;
3223 var buff : SEffectInfo;
3224 var dm : CDefinitionsManagerAccessor;
3225
3226 buffs.Clear();
3227
3228 if( !IsIdValid(id) )
3229 return 0;
3230
3231 //Potential fast exit. Get amount of all abilities included
3232 GetItemContainedAbilities(id, absFast);
3233 if(absFast.Size() == 0)
3234 return 0;
3235
3236 GetItemAbilities(id, abs);
3237 dm = theGame.GetDefinitionsManager();
3238 for(k=0; k<abs.Size(); k+=1)
3239 {
3240 dm.GetContainedAbilities(abs[k], attrs);
3241 buff.applyChance = CalculateAttributeValue(GetItemAbilityAttributeValue(id, 'buff_apply_chance', abs[k])) * ArrayOfNamesCount(abs, abs[k]);
3242
3243 for( i = 0; i < attrs.Size(); i += 1 )
3244 {
3245 if( IsEffectNameValid(attrs[i]) )
3246 {
3247 EffectNameToType(attrs[i], type, abilityName);
3248
3249 buff.effectType = type;
3250 buff.effectAbilityName = abilityName;
3251
3252 buffs.PushBack(buff);
3253
3254 //when we found some buff we remove 1 item from all included abilities array - if it's empty we can quit
3255 if(absFast.Size() == 1)
3256 return buffs.Size();
3257 else
3258 absFast.EraseFast(0);
3259 }
3260 }
3261 }
3262
3263 return buffs.Size();
3264 }
3265
3266 /*
3267 Drops intem from the inventory to the ground. Item is placed in a bag.
3268 If there is a bag nearby, the items are added to that bag
3269 */
3270 public function DropItemInBag( item : SItemUniqueId, quantity : int ) // #B probably not in use
3271 {
3272 var entities : array<CGameplayEntity>;
3273 var i : int;
3274 var owner : CActor;
3275 var bag : W3ActorRemains;
3276 var template : CEntityTemplate;
3277 var bagtags : array <name>;
3278 var bagPosition : Vector;
3279 var tracedPosition, tracedNormal : Vector;
3280
3281 if(ItemHasTag(item, 'NoDrop')) // #B shouldn't be also NoShow here ?
3282 return; //fast abort
3283
3284 owner = (CActor)GetEntity();
3285 FindGameplayEntitiesInRange(entities, owner, 0.5, 100);
3286
3287 for(i=0; i<entities.Size(); i+=1)
3288 {
3289 bag = (W3ActorRemains)entities[i];
3290
3291 if(bag)
3292 break;
3293 }
3294
3295 //create bag entity if none found near
3296 if(!bag)
3297 {
3298 template = (CEntityTemplate)LoadResource("lootbag");
3299 bagtags.PushBack('lootbag');
3300
3301 // Do raycast down from player position to check if he's in the air
3302 bagPosition = owner.GetWorldPosition();
3303 if ( theGame.GetWorld().StaticTrace( bagPosition, bagPosition + Vector( 0.0f, 0.0f, -10.0f, 0.0f ), tracedPosition, tracedNormal ) )
3304 {
3305 bagPosition = tracedPosition;
3306 }
3307 bag = (W3ActorRemains)theGame.CreateEntity(template, bagPosition, owner.GetWorldRotation(), true, false, false, PM_Persist,bagtags);
3308 }
3309
3310 //give item
3311 GiveItemTo(bag.GetInventory(), item, quantity, false);
3312
3313 //if item was not given for some reason then delete empty bag
3314 if(bag.GetInventory().IsEmpty())
3315 {
3316 delete bag;
3317 return;
3318 }
3319 //if item added successfully
3320 bag.LootDropped(); //this will also reset the timer if we add items to an already created container
3321 theTelemetry.LogWithLabelAndValue(TE_INV_ITEM_DROPPED, GetItemName(item), quantity);
3322
3323 // if dropped underwater, play curve animation of "floating"
3324 if( thePlayer.IsSwimming() )
3325 {
3326 bag.PlayPropertyAnimation( 'float', 0 );
3327 }
3328 }
3329
3330 /////////////////////////////////////////////
3331 // @REPAIR OBJECTS
3332 /////////////////////////////////////////////
3333
3334 //returns true if some bonus was added
3335 public final function AddRepairObjectItemBonuses(buffArmor : bool, buffSwords : bool, ammoArmor : int, ammoWeapon : int) : bool
3336 {
3337 var upgradedSomething, isArmor : bool;
3338 var i, ammo, currAmmo : int;
3339 var items, items2 : array<SItemUniqueId>;
3340
3341 //get items to upgrade
3342 if(buffArmor)
3343 {
3344 items = GetItemsByTag(theGame.params.TAG_ARMOR);
3345 }
3346 if(buffSwords)
3347 {
3348 items2 = GetItemsByTag(theGame.params.TAG_PLAYER_STEELSWORD);
3349 ArrayOfIdsAppend(items, items2);
3350 items2.Clear();
3351 items2 = GetItemsByTag(theGame.params.TAG_PLAYER_SILVERSWORD);
3352 ArrayOfIdsAppend(items, items2);
3353 }
3354
3355 upgradedSomething = false;
3356
3357 for(i=0; i<items.Size(); i+=1)
3358 {
3359 //check if item is armor
3360 if(IsItemAnyArmor(items[i]))
3361 {
3362 isArmor = true;
3363 ammo = ammoArmor;
3364 }
3365 else
3366 {
3367 isArmor = false;
3368 ammo = ammoWeapon;
3369 }
3370
3371 //get current ammo
3372 currAmmo = GetItemModifierInt(items[i], 'repairObjectBonusAmmo', 0);
3373
3374 //if ammo is greater than current
3375 if(ammo > currAmmo)
3376 {
3377 SetItemModifierInt(items[i], 'repairObjectBonusAmmo', ammo);
3378 upgradedSomething = true;
3379
3380 //if had no ammo - add ability
3381 if(currAmmo == 0)
3382 {
3383 if(isArmor)
3384 AddItemCraftedAbility(items[i], theGame.params.REPAIR_OBJECT_BONUS_ARMOR_ABILITY, false);
3385 else
3386 AddItemCraftedAbility(items[i], theGame.params.REPAIR_OBJECT_BONUS_WEAPON_ABILITY, false);
3387 }
3388 }
3389 }
3390
3391 return upgradedSomething;
3392 }
3393
3394 public final function ReduceItemRepairObjectBonusCharge(item : SItemUniqueId)
3395 {
3396 var currAmmo : int;
3397
3398 currAmmo = GetItemModifierInt(item, 'repairObjectBonusAmmo', 0);
3399
3400 if(currAmmo > 0)
3401 {
3402 SetItemModifierInt(item, 'repairObjectBonusAmmo', currAmmo - 1);
3403
3404 if(currAmmo == 1)
3405 {
3406 if(IsItemAnyArmor(item))
3407 RemoveItemCraftedAbility(item, theGame.params.REPAIR_OBJECT_BONUS_ARMOR_ABILITY);
3408 else
3409 RemoveItemCraftedAbility(item, theGame.params.REPAIR_OBJECT_BONUS_WEAPON_ABILITY);
3410 }
3411 }
3412 }
3413
3414 //gets value of 'armor' attribute bonus for given item from 'repair objects'
3415 public final function GetRepairObjectBonusValueForArmor(armor : SItemUniqueId) : SAbilityAttributeValue
3416 {
3417 var retVal, bonusValue, baseArmor : SAbilityAttributeValue;
3418
3419 if(GetItemModifierInt(armor, 'repairObjectBonusAmmo', 0) > 0)
3420 {
3421 bonusValue = GetItemAttributeValue(armor, theGame.params.REPAIR_OBJECT_BONUS);
3422 baseArmor = GetItemAttributeValue(armor, theGame.params.ARMOR_VALUE_NAME);
3423
3424 baseArmor.valueMultiplicative += 1; //added from character ability later on I guess?
3425 retVal.valueAdditive = bonusValue.valueAdditive + CalculateAttributeValue(baseArmor) * bonusValue.valueMultiplicative;
3426 }
3427
3428 return retVal;
3429 }
3430
3431 /////////////////////////////////////////////
3432 // @OILS
3433 /////////////////////////////////////////////
3434
3435 /**
3436 Checks if item can be upgraded with oil
3437 */
3438 public function CanItemHaveOil(id : SItemUniqueId) : bool
3439 {
3440 return IsItemSteelSwordUsableByPlayer(id) || IsItemSilverSwordUsableByPlayer(id);
3441 }
3442
3443 public final function RemoveAllOilsFromItem( id : SItemUniqueId )
3444 {
3445 var i : int;
3446 var oils : array< W3Effect_Oil >;
3447 var actor : CActor;
3448
3449 actor = ( CActor ) GetEntity();
3450 oils = GetOilsAppliedOnItem( id );
3451 for( i = oils.Size() - 1; i >= 0; i -= 1 )
3452 {
3453 actor.RemoveEffect( oils[ i ] );
3454 }
3455 }
3456
3457 public final function GetActiveOilsAppliedOnItemCount( id : SItemUniqueId ) : int
3458 {
3459 var oils : array< W3Effect_Oil >;
3460 var i, count : int;
3461
3462 count = 0;
3463 oils = GetOilsAppliedOnItem( id );
3464 for( i=0; i<oils.Size(); i+=1 )
3465 {
3466 if( oils[ i ].GetAmmoCurrentCount() > 0 )
3467 {
3468 count += 1;
3469 }
3470 }
3471 return count;
3472 }
3473
3474 public final function RemoveOldestOilFromItem( id : SItemUniqueId )
3475 {
3476 var buffToRemove : W3Effect_Oil;
3477 var actor : CActor;
3478
3479 actor = ( CActor ) GetEntity();
3480 if(! actor )
3481 return;
3482
3483 buffToRemove = GetOldestOilAppliedOnItem(id, false);
3484
3485 if(buffToRemove)
3486 {
3487 actor.RemoveEffect( buffToRemove );
3488 }
3489 }
3490
3491 public final function GetOilsAppliedOnItem( id : SItemUniqueId ) : array< W3Effect_Oil >
3492 {
3493 var i : int;
3494 var oils : array< CBaseGameplayEffect >;
3495 var buff : W3Effect_Oil;
3496 var ret : array < W3Effect_Oil >;
3497 var actor : CActor;
3498
3499 actor = ( CActor ) GetEntity();
3500 if(! actor )
3501 return ret;
3502
3503 oils = actor.GetBuffs( EET_Oil );
3504 for( i = oils.Size() - 1; i >= 0; i -= 1 )
3505 {
3506 buff = ( W3Effect_Oil ) oils[ i ];
3507 if(buff && buff.GetSwordItemId() == id )
3508 {
3509 ret.PushBack( buff );
3510 }
3511 }
3512
3513 return ret;
3514 }
3515
3516 public final function GetNewestOilAppliedOnItem( id : SItemUniqueId, onlyShowable : bool ) : W3Effect_Oil
3517 {
3518 return GetOilAppliedOnItemInternal( id, onlyShowable, true );
3519 }
3520
3521 public final function GetOldestOilAppliedOnItem( id : SItemUniqueId, onlyShowable : bool ) : W3Effect_Oil
3522 {
3523 return GetOilAppliedOnItemInternal( id, onlyShowable, false );
3524 }
3525
3526 private final function GetOilAppliedOnItemInternal( id : SItemUniqueId, onlyShowable : bool, newest : bool ) : W3Effect_Oil
3527 {
3528 var oils : array< W3Effect_Oil >;
3529 var i, lastIndex : int;
3530
3531 oils = GetOilsAppliedOnItem( id );
3532 lastIndex = -1;
3533
3534 for( i=0; i<oils.Size(); i+=1 )
3535 {
3536 if( onlyShowable && !oils[i].GetShowOnHUD() )
3537 {
3538 continue;
3539 }
3540
3541 if( lastIndex == -1 )
3542 {
3543 lastIndex = i;
3544 }
3545 else if( newest && oils[i].GetQueueTimer() < oils[lastIndex].GetQueueTimer() )
3546 {
3547 lastIndex = i;
3548 }
3549 else if( !newest && oils[i].GetQueueTimer() > oils[lastIndex].GetQueueTimer() )
3550 {
3551 lastIndex = i;
3552 }
3553 }
3554
3555 if( lastIndex == -1 )
3556 {
3557 return NULL;
3558 }
3559
3560 return oils[lastIndex];
3561 }
3562
3563 public final function ItemHasAnyActiveOilApplied( id : SItemUniqueId ) : bool
3564 {
3565 return GetActiveOilsAppliedOnItemCount( id );
3566 }
3567
3568 public final function ItemHasActiveOilApplied( id : SItemUniqueId, monsterCategory : EMonsterCategory ) : bool
3569 {
3570 var i : int;
3571 var oils : array< W3Effect_Oil >;
3572
3573 oils = GetOilsAppliedOnItem( id );
3574 for( i=0; i<oils.Size(); i+=1 )
3575 {
3576 if( oils[ i ].GetMonsterCategory() == monsterCategory && oils[ i ].GetAmmoCurrentCount() > 0 )
3577 {
3578 return true;
3579 }
3580 }
3581
3582 return false;
3583 }
3584
3585 /////////////////////////////////////////////
3586 // TOOLTIPS
3587 /////////////////////////////////////////////
3588
3589 public final function GetParamsForRunewordTooltip(runewordName : name, out i : array<int>, out f : array<float>, out s : array<string>)
3590 {
3591 var min, max : SAbilityAttributeValue;
3592 var val : float;
3593 var attackRangeBase, attackRangeExt : CAIAttackRange;
3594
3595 i.Clear();
3596 f.Clear();
3597 s.Clear();
3598
3599 switch(runewordName)
3600 {
3601 case 'Glyphword 5':
3602 theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 5 _Stats', 'glyphword5_chance', min, max);
3603 i.PushBack( RoundMath( CalculateAttributeValue(min) * 100) );
3604 break;
3605 case 'Glyphword 6' :
3606 theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 6 _Stats', 'glyphword6_stamina_drain_perc', min, max);
3607 i.PushBack( RoundMath( CalculateAttributeValue(min) * 100) );
3608 break;
3609 case 'Glyphword 12' :
3610 theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 12 _Stats', 'glyphword12_range', min, max);
3611 val = CalculateAttributeValue(min);
3612 s.PushBack( NoTrailZeros(val) );
3613
3614 theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 12 _Stats', 'glyphword12_chance', min, max);
3615 i.PushBack( RoundMath( min.valueAdditive * 100) );
3616 break;
3617 case 'Glyphword 17' :
3618 theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 17 _Stats', 'quen_apply_chance', min, max);
3619 val = CalculateAttributeValue(min);
3620 i.PushBack( RoundMath(val * 100) );
3621 break;
3622 case 'Glyphword 14' :
3623 case 'Glyphword 18' :
3624 theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 18 _Stats', 'increas_duration', min, max);
3625 val = CalculateAttributeValue(min);
3626 s.PushBack( NoTrailZeros(val) );
3627 break;
3628
3629 case 'Runeword 2' :
3630 attackRangeBase = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'specialattacklight');
3631 attackRangeExt = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'runeword2_light');
3632 s.PushBack( NoTrailZeros(attackRangeExt.rangeMax - attackRangeBase.rangeMax) );
3633
3634 attackRangeBase = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'slash_long');
3635 attackRangeExt = theGame.GetAttackRangeForEntity(GetWitcherPlayer(), 'runeword2_heavy');
3636 s.PushBack( NoTrailZeros(attackRangeExt.rangeMax - attackRangeBase.rangeMax) );
3637
3638 break;
3639 case 'Runeword 4' :
3640 theGame.GetDefinitionsManager().GetAbilityAttributeValue('Runeword 4 _Stats', 'max_bonus', min, max);
3641 i.PushBack( RoundMath(max.valueMultiplicative * 100) ); //hardcoded
3642 break;
3643 case 'Runeword 6' :
3644 theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 6 _Stats', 'runeword6_duration_bonus', min, max );
3645 i.PushBack( RoundMath(min.valueMultiplicative * 100) );
3646 break;
3647 case 'Runeword 7' :
3648 theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 7 _Stats', 'stamina', min, max );
3649 i.PushBack( RoundMath(min.valueMultiplicative * 100) );
3650 break;
3651 case 'Runeword 10' :
3652 theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 10 _Stats', 'stamina', min, max );
3653 i.PushBack( RoundMath(min.valueMultiplicative * 100) ); //hardcoded
3654 break;
3655 case 'Runeword 11' :
3656 theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 11 _Stats', 'duration', min, max );
3657 s.PushBack( NoTrailZeros(min.valueAdditive) );
3658 break;
3659 case 'Runeword 12' :
3660 theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'Runeword 12 _Stats', 'focus', min, max );
3661 f.PushBack(min.valueAdditive);
3662 f.PushBack(max.valueAdditive);
3663 break;
3664 default:
3665 break;
3666 }
3667 }
3668
3669 public final function GetPotionAttributesForTooltip(potionId : SItemUniqueId, out tips : array<SAttributeTooltip>):void
3670 {
3671 var i, j, settingsSize : int;
3672 var buffType : EEffectType;
3673 var abilityName : name;
3674 var abs, attrs : array<name>;
3675 var val : SAbilityAttributeValue;
3676 var newAttr : SAttributeTooltip;
3677 var attributeString : string;
3678
3679 //if not a potion then quit
3680 if(!IsItemPotion(potionId))
3681 return;
3682
3683 //get potion buff attributes
3684 GetItemContainedAbilities(potionId, abs);
3685 for(i=0; i<abs.Size(); i+=1)
3686 {
3687 EffectNameToType(abs[i], buffType, abilityName);
3688
3689 //not a buff ability
3690 if(buffType == EET_Undefined)
3691 continue;
3692
3693 //otherwise get list of attributes
3694 theGame.GetDefinitionsManager().GetAbilityAttributes(abs[i], attrs);
3695 break;
3696 }
3697
3698 //custom attribute filtering
3699 attrs.Remove('duration');
3700 attrs.Remove('level');
3701
3702 if(buffType == EET_Cat)
3703 {
3704 //internal
3705 attrs.Remove('highlightObjectsRange');
3706 }
3707 else if(buffType == EET_GoldenOriole)
3708 {
3709 //in tooltip
3710 attrs.Remove('poison_resistance_perc');
3711 }
3712 else if(buffType == EET_MariborForest)
3713 {
3714 //in tooltip
3715 attrs.Remove('focus_on_drink');
3716 }
3717 else if(buffType == EET_KillerWhale)
3718 {
3719 //internal
3720 attrs.Remove('swimmingStamina');
3721 attrs.Remove('vision_strength');
3722 }
3723 else if(buffType == EET_Thunderbolt)
3724 {
3725 //in tooltip
3726 attrs.Remove('critical_hit_chance');
3727 }
3728 else if(buffType == EET_WhiteRaffardDecoction)
3729 {
3730 val = GetItemAttributeValue(potionId, 'level');
3731 if(val.valueAdditive == 3)
3732 attrs.Insert(0, 'duration');
3733 }
3734 else if(buffType == EET_Mutagen20)
3735 {
3736 attrs.Remove('burning_DoT_damage_resistance_perc');
3737 attrs.Remove('poison_DoT_damage_resistance_perc');
3738 attrs.Remove('bleeding_DoT_damage_resistance_perc');
3739 }
3740 else if(buffType == EET_Mutagen27)
3741 {
3742 attrs.Remove('mutagen27_max_stack');
3743 }
3744 else if(buffType == EET_Mutagen18)
3745 {
3746 attrs.Remove('mutagen18_max_stack');
3747 }
3748 else if(buffType == EET_Mutagen19)
3749 {
3750 attrs.Remove('max_hp_perc_trigger');
3751 }
3752 else if(buffType == EET_Mutagen21)
3753 {
3754 attrs.Remove('healingRatio');
3755 }
3756 else if(buffType == EET_Mutagen22)
3757 {
3758 attrs.Remove('mutagen22_max_stack');
3759 }
3760 else if(buffType == EET_Mutagen02)
3761 {
3762 attrs.Remove('resistGainRate');
3763 }
3764 else if(buffType == EET_Mutagen04)
3765 {
3766 attrs.Remove('staminaCostPerc');
3767 attrs.Remove('healthReductionPerc');
3768 }
3769 else if(buffType == EET_Mutagen08)
3770 {
3771 attrs.Remove('resistGainRate');
3772 }
3773 else if(buffType == EET_Mutagen10)
3774 {
3775 attrs.Remove('mutagen10_max_stack');
3776 }
3777 else if(buffType == EET_Mutagen14)
3778 {
3779 attrs.Remove('mutagen14_max_stack');
3780 }
3781
3782 //fill attribute names and values
3783 for(j=0; j<attrs.Size(); j+=1)
3784 {
3785 val = GetItemAbilityAttributeValue(potionId, attrs[j], abs[i]);
3786
3787 newAttr.originName = attrs[j];
3788 newAttr.attributeName = GetAttributeNameLocStr(attrs[j], false);
3789
3790 if(buffType == EET_MariborForest && attrs[j] == 'focus_gain')
3791 {
3792 newAttr.value = val.valueAdditive;
3793 newAttr.percentageValue = false;
3794 }
3795 else if(val.valueMultiplicative != 0)
3796 {
3797 if(buffType == EET_Mutagen26)
3798 {
3799 //uses same attribute twice with mult and add
3800 newAttr.value = val.valueAdditive;
3801 newAttr.percentageValue = false;
3802 tips.PushBack(newAttr);
3803
3804 newAttr.value = val.valueMultiplicative;
3805 newAttr.percentageValue = true;
3806
3807 attrs.Erase(1);
3808 }
3809 else if(buffType == EET_Mutagen07)
3810 {
3811 //has mult == 1 and uses base
3812 attrs.Erase(1);
3813 newAttr.value = val.valueBase;
3814 newAttr.percentageValue = true;
3815 }
3816 else
3817 {
3818 newAttr.value = val.valueMultiplicative;
3819 newAttr.percentageValue = true;
3820 }
3821 }
3822 else if(val.valueAdditive != 0)
3823 {
3824 if(buffType == EET_Thunderbolt)
3825 {
3826 newAttr.value = val.valueAdditive * 100;
3827 newAttr.percentageValue = true;
3828 }
3829 else if(buffType == EET_Blizzard)
3830 {
3831 newAttr.value = 1 - val.valueAdditive;
3832 newAttr.percentageValue = true;
3833 }
3834 else if(buffType == EET_Mutagen01 || buffType == EET_Mutagen15 || buffType == EET_Mutagen28 || buffType == EET_Mutagen27)
3835 {
3836 newAttr.value = val.valueAdditive;
3837 newAttr.percentageValue = true;
3838 }
3839 else
3840 {
3841 newAttr.value = val.valueAdditive;
3842 newAttr.percentageValue = false;
3843 }
3844 }
3845 else if(buffType == EET_GoldenOriole)
3846 {
3847 newAttr.value = val.valueBase;
3848 newAttr.percentageValue = true;
3849 }
3850 else
3851 {
3852 newAttr.value = val.valueBase;
3853 newAttr.percentageValue = false;
3854 }
3855
3856 tips.PushBack(newAttr);
3857 }
3858 }
3859
3860 /**
3861 ACHTUNG!
3862
3863 This cannot be done by taking two ids of items because the id is unique ONLY in THIS inventory.
3864 So if you have items from two different inventories (like shop, container) the id of the item from
3865 the other inventory cannot be used in this inventory (it will point to NULL or some other random item).
3866
3867 id - item id of the item in this inventory
3868 invOther - inventory component of the other item
3869 idOther - item id of the other item
3870 */
3871 public function GetItemRelativeTooltipType(id :SItemUniqueId, invOther : CInventoryComponent, idOther : SItemUniqueId) : ECompareType
3872 {
3873
3874 if( (GetItemCategory(id) == invOther.GetItemCategory(idOther)) ||
3875 ItemHasTag(id, 'PlayerSteelWeapon') && invOther.ItemHasTag(idOther, 'PlayerSteelWeapon') ||
3876 ItemHasTag(id, 'PlayerSilverWeapon') && invOther.ItemHasTag(idOther, 'PlayerSilverWeapon') ||
3877 ItemHasTag(id, 'PlayerSecondaryWeapon') && invOther.ItemHasTag(idOther, 'PlayerSecondaryWeapon')
3878 )
3879 {
3880 return ECT_Compare;
3881 }
3882 return ECT_Incomparable;
3883 }
3884
3885 /**
3886 Formats a float value to show in the tooltip. The value is decimal with 2 points after the dot always. // #B deprecated
3887 */
3888 private function FormatFloatForTooltip(fValue : float) : string
3889 {
3890 var valueInt, valueDec : int;
3891 var strValue : string;
3892
3893 if(fValue < 0)
3894 {
3895 valueInt = CeilF(fValue);
3896 valueDec = RoundMath((fValue - valueInt)*(-100));
3897 }
3898 else
3899 {
3900 valueInt = FloorF(fValue);
3901 valueDec = RoundMath((fValue - valueInt)*(100));
3902 }
3903 strValue = valueInt+".";
3904 if(valueDec < 10)
3905 strValue += "0"+valueDec;
3906 else
3907 strValue += ""+valueDec;
3908
3909 return strValue;
3910 }
3911
3912 public function SetPriceMultiplier( mult : float )
3913 {
3914 priceMult = mult;
3915 }
3916
3917 // Price modified by area and item category
3918 public function GetMerchantPriceModifier( shopNPC : CNewNPC, item : SItemUniqueId ) : float
3919 {
3920 var areaPriceMult : float;
3921 var itemPriceMult : float;
3922 var importPriceMult : float;
3923 var finalPriceMult : float;
3924 var tag : name;
3925 var zoneName : EZoneName;
3926
3927 zoneName = theGame.GetCurrentZone();
3928
3929 switch ( zoneName )
3930 {
3931 case ZN_NML_CrowPerch : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('crow_perch_price_mult'));
3932 case ZN_NML_SpitfireBluff : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('spitfire_bluff_price_mult'));
3933 case ZN_NML_TheMire : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('the_mire_price_mult'));
3934 case ZN_NML_Mudplough : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('mudplough_price_mult'));
3935 case ZN_NML_Grayrocks : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('grayrocks_price_mult'));
3936 case ZN_NML_TheDescent : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('the_descent_price_mult'));
3937 case ZN_NML_CrookbackBog : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('crookback_bog_price_mult'));
3938 case ZN_NML_BaldMountain : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('bald_mountain_price_mult'));
3939 case ZN_NML_Novigrad : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('novigrad_price_mult'));
3940 case ZN_NML_Homestead : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('homestead_price_mult'));
3941 case ZN_NML_Gustfields : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('gustfields_price_mult'));
3942 case ZN_NML_Oxenfurt : areaPriceMult = CalculateAttributeValue(thePlayer.GetAttributeValue('oxenfurt_price_mult'));
3943 case ZN_Undefined : areaPriceMult = 1;
3944 }
3945
3946 if (ItemHasTag(item,'weapon')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('weapon_price_mult')); }
3947 else if (ItemHasTag(item,'armor')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('armor_price_mult')); }
3948 else if (ItemHasTag(item,'crafting')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('crafting_price_mult')); }
3949 else if (ItemHasTag(item,'alchemy')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('alchemy_price_mult')); }
3950 else if (ItemHasTag(item,'alcohol')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('alcohol_price_mult')); }
3951 else if (ItemHasTag(item,'food')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('food_price_mult')); }
3952 else if (ItemHasTag(item,'fish')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('fish_price_mult')); }
3953 else if (ItemHasTag(item,'books')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('books_price_mult')); }
3954 else if (ItemHasTag(item,'valuables')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('valuables_price_mult')); }
3955 else if (ItemHasTag(item,'junk')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('junk_price_mult')); }
3956 else if (ItemHasTag(item,'orens')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('orens_price_mult')); }
3957 else if (ItemHasTag(item,'florens')) { itemPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('florens_price_mult')); }
3958 else { itemPriceMult = 1; }
3959
3960 if (ItemHasTag(item,'novigrad')) { importPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('novigrad_price_mult')); }
3961 else if (ItemHasTag(item,'nilfgard')) { importPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('nilfgard_price_mult')); }
3962 else if (ItemHasTag(item,'nomansland')) { importPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('nomansland_price_mult')); }
3963 else if (ItemHasTag(item,'skellige')) { importPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('skellige_price_mult')); }
3964 else if (ItemHasTag(item,'nonhuman')) { importPriceMult = CalculateAttributeValue(shopNPC.GetAttributeValue('nonhuman_price_mult')); }
3965 else { importPriceMult = 1; }
3966
3967 finalPriceMult = areaPriceMult*itemPriceMult*importPriceMult*priceMult;
3968 return finalPriceMult;
3969 }
3970
3971 public function SetRepairPriceMultiplier( mult : float ) // #B
3972 {
3973 priceRepairMult = mult;
3974 }
3975
3976 // Price modified by area and item category
3977 public function GetRepairPriceModifier( repairNPC : CNewNPC ) : float // #B should be taken from NPC invComp
3978 {
3979 return priceRepairMult;
3980 }
3981
3982 public function GetRepairPrice( item : SItemUniqueId ) : float // #B
3983 {
3984 var currDiff : float;
3985 currDiff = GetItemMaxDurability(item) - GetItemDurability(item);
3986
3987 return priceRepair * currDiff;
3988 }
3989
3990 //fills item tooltip data
3991 public function GetTooltipData(itemId : SItemUniqueId, out localizedName : string, out localizedDescription : string, out price : int, out localizedCategory : string,
3992 out itemStats : array<SAttributeTooltip>, out localizedFluff : string)
3993 {
3994 if( !IsIdValid(itemId) )
3995 {
3996 return;
3997 }
3998 localizedName = GetItemLocalizedNameByUniqueID(itemId);
3999 localizedDescription = GetItemLocalizedDescriptionByUniqueID(itemId);
4000 localizedFluff = "IMPLEMENT ME - fluff text";
4001 price = GetItemPriceModified( itemId, false );
4002 localizedCategory = GetItemCategoryLocalisedString(GetItemCategory(itemId));
4003 GetItemStats(itemId, itemStats);
4004 }
4005
4006 // get only item's base and crafted stats
4007 public function GetItemBaseStats(itemId : SItemUniqueId, out itemStats : array<SAttributeTooltip>)
4008 {
4009 var attributes : array<name>;
4010
4011 var dm : CDefinitionsManagerAccessor;
4012 var oilAbilities, oilAttributes : array<name>;
4013 var weights : array<float>;
4014 var i, j : int;
4015 var tmpI, tmpJ : int;
4016
4017 var idx : int;
4018 var oilStatsCount : int;
4019 var oilName : name;
4020 var oilStats : array<SAttributeTooltip>;
4021 var oilStatFirst : SAttributeTooltip;
4022 var oils : array< W3Effect_Oil >;
4023
4024 GetItemBaseAttributes(itemId, attributes);
4025
4026 // #Y hack to remove oil bufs from this list
4027 oils = GetOilsAppliedOnItem( itemId );
4028 dm = theGame.GetDefinitionsManager();
4029 for( i=0; i<oils.Size(); i+=1 )
4030 {
4031 oilName = oils[ i ].GetOilItemName();
4032
4033 oilAbilities.Clear();
4034 weights.Clear();
4035 dm.GetItemAbilitiesWithWeights(oilName, GetEntity() == thePlayer, oilAbilities, weights, tmpI, tmpJ);
4036
4037 oilAttributes.Clear();
4038 oilAttributes = dm.GetAbilitiesAttributes(oilAbilities);
4039
4040 oilStatsCount = oilAttributes.Size();
4041 for (idx = 0; idx < oilStatsCount; idx+=1)
4042 {
4043 attributes.Remove(oilAttributes[idx]);
4044 }
4045 }
4046
4047 GetItemTooltipAttributes(itemId, attributes, itemStats);
4048 }
4049
4050 //filling attributes/statsfluff
4051 public function GetItemStats(itemId : SItemUniqueId, out itemStats : array<SAttributeTooltip>)
4052 {
4053 var attributes : array<name>;
4054
4055 GetItemAttributes(itemId, attributes);
4056 GetItemTooltipAttributes(itemId, attributes, itemStats);
4057 }
4058
4059 private function GetItemTooltipAttributes(itemId : SItemUniqueId, attributes : array<name>, out itemStats : array<SAttributeTooltip>):void
4060 {
4061 var itemCategory:name;
4062 var i, j, settingsSize : int;
4063 var attributeString : string;
4064 var attributeColor : string;
4065 var attributeName : name;
4066 var isPercentageValue : string;
4067 var primaryStatLabel : string;
4068 var statLabel : string;
4069
4070 var stat : SAttributeTooltip;
4071 var attributeVal : SAbilityAttributeValue;
4072
4073 settingsSize = theGame.tooltipSettings.GetNumRows();
4074 itemStats.Clear();
4075 itemCategory = GetItemCategory(itemId);
4076 for(i=0; i<settingsSize; i+=1)
4077 {
4078 //get next in order attribute name
4079 attributeString = theGame.tooltipSettings.GetValueAt(0,i);
4080 if(StrLen(attributeString) <= 0)
4081 continue; //just an empty line in file
4082
4083 attributeName = '';
4084
4085 //check if this item has this attribute
4086 for(j=0; j<attributes.Size(); j+=1)
4087 {
4088 if(NameToString(attributes[j]) == attributeString)
4089 {
4090 attributeName = attributes[j];
4091 break;
4092 }
4093 }
4094 if(!IsNameValid(attributeName))
4095 continue;
4096
4097 // hardcode: we don't show damage for swords
4098 if(itemCategory == 'silversword' && attributeName == 'SlashingDamage') continue;
4099 if(itemCategory == 'steelsword' && attributeName == 'SilverDamage') continue;
4100
4101 //get the color of the attribute string (for the tooltip panel)
4102 attributeColor = theGame.tooltipSettings.GetValueAt(1,i);
4103
4104 isPercentageValue = theGame.tooltipSettings.GetValueAt(2,i);
4105
4106 //if yes then get the values and add them to stats array
4107 attributeVal = GetItemAttributeValue(itemId, attributeName);
4108 stat.attributeColor = attributeColor;
4109 stat.percentageValue = isPercentageValue;
4110 stat.primaryStat = IsPrimaryStatById(itemId, attributeName, primaryStatLabel);
4111 stat.value = 0;
4112 stat.originName = attributeName;
4113 if(attributeVal.valueBase != 0)
4114 {
4115 statLabel = GetAttributeNameLocStr(attributeName, false);
4116 stat.value = attributeVal.valueBase;
4117 }
4118 if(attributeVal.valueMultiplicative != 0)
4119 {
4120 // #J setting percentage Value to true is smarter here and the localized version of the _mult strings doesn't exist and is overkill from what I can tell
4121 // So changing true to false
4122 statLabel = GetAttributeNameLocStr(attributeName, false);
4123 stat.value = attributeVal.valueMultiplicative;
4124 stat.percentageValue = true;
4125 }
4126 if(attributeVal.valueAdditive != 0)
4127 {
4128 statLabel = GetAttributeNameLocStr(attributeName, false);
4129 stat.value = attributeVal.valueAdditive;
4130 }
4131 if (stat.value != 0)
4132 {
4133 stat.attributeName = statLabel;
4134 //stat.attributeName = primaryStatLabel;
4135 itemStats.PushBack(stat);
4136 }
4137 }
4138 }
4139
4140 //filling attributes/statsfluff for crafting recipe
4141 public function GetItemStatsFromName(itemName : name, out itemStats : array<SAttributeTooltip>)
4142 {
4143 var itemCategory : name;
4144 var i, j, settingsSize : int;
4145 var attributeString : string;
4146 var attributeColor : string;
4147 var attributeName : name;
4148 var isPercentageValue : string;
4149 var attributes, itemAbilities, tmpArray : array<name>;
4150 var weights : array<float>;
4151 var stat : SAttributeTooltip;
4152 var attributeVal, min, max : SAbilityAttributeValue;
4153 var dm : CDefinitionsManagerAccessor;
4154 var primaryStatLabel : string;
4155 var statLabel : string;
4156
4157 settingsSize = theGame.tooltipSettings.GetNumRows();
4158 dm = theGame.GetDefinitionsManager();
4159 dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, weights, i, j);
4160 attributes = dm.GetAbilitiesAttributes(itemAbilities);
4161
4162 itemStats.Clear();
4163 itemCategory = dm.GetItemCategory(itemName);
4164 for(i=0; i<settingsSize; i+=1)
4165 {
4166 //get next in order attribute name
4167 attributeString = theGame.tooltipSettings.GetValueAt(0,i);
4168 if(StrLen(attributeString) <= 0)
4169 continue; //just an empty line in file
4170
4171 attributeName = '';
4172
4173 //check if this item has this attribute
4174 for(j=0; j<attributes.Size(); j+=1)
4175 {
4176 if(NameToString(attributes[j]) == attributeString)
4177 {
4178 attributeName = attributes[j];
4179 break;
4180 }
4181 }
4182 if(!IsNameValid(attributeName))
4183 continue;
4184
4185 // hardcode: we don't show damage for swords
4186 if(itemCategory == 'silversword' && attributeName == 'SlashingDamage') continue;
4187 if(itemCategory == 'steelsword' && attributeName == 'SilverDamage') continue;
4188
4189 //get the color of the attribute string (for the tooltip panel)
4190 attributeColor = theGame.tooltipSettings.GetValueAt(1,i);
4191
4192 isPercentageValue = theGame.tooltipSettings.GetValueAt(2,i);
4193
4194 //if yes then get the values and add them to stats array
4195 dm.GetAbilitiesAttributeValue(itemAbilities, attributeName, min, max);
4196 attributeVal = GetAttributeRandomizedValue(min, max);
4197 //attributeVal = GetItemAttributeValue(itemId, attributeName);
4198 stat.attributeColor = attributeColor;
4199 stat.percentageValue = isPercentageValue;
4200
4201 stat.primaryStat = IsPrimaryStat(itemCategory, attributeName, primaryStatLabel);
4202
4203 stat.value = 0;
4204 stat.originName = attributeName;
4205
4206 if(attributeVal.valueBase != 0)
4207 {
4208 stat.value = attributeVal.valueBase;
4209 }
4210 if(attributeVal.valueMultiplicative != 0)
4211 {
4212 stat.value = attributeVal.valueMultiplicative;
4213 stat.percentageValue = true;
4214 }
4215 if(attributeVal.valueAdditive != 0)
4216 {
4217 statLabel = GetAttributeNameLocStr(attributeName, false);
4218 stat.value = attributeVal.valueBase + attributeVal.valueAdditive;
4219 }
4220
4221 if (attributeName == 'toxicity_offset')
4222 {
4223 statLabel = GetAttributeNameLocStr('toxicity', false);
4224 stat.percentageValue = false;
4225 }
4226 else
4227 {
4228 statLabel = GetAttributeNameLocStr(attributeName, false);
4229 }
4230
4231 if (stat.value != 0)
4232 {
4233 stat.attributeName = statLabel;
4234 //stat.attributeName = primaryStatLabel;
4235 itemStats.PushBack(stat);
4236 }
4237
4238 //itemStats.PushBack(stat);
4239 }
4240 }
4241
4242 public function IsThereItemOnSlot(slot : EEquipmentSlots) : bool
4243 {
4244 var player : W3PlayerWitcher;
4245
4246 player = ((W3PlayerWitcher)GetEntity());
4247 if(player)
4248 {
4249 return player.IsAnyItemEquippedOnSlot(slot);
4250 }
4251 else
4252 {
4253 return false;
4254 }
4255 }
4256
4257 public function GetItemEquippedOnSlot(slot : EEquipmentSlots, out item : SItemUniqueId) : bool
4258 {
4259 var player : W3PlayerWitcher;
4260
4261 player = ((W3PlayerWitcher)GetEntity());
4262 if(player)
4263 {
4264 return player.GetItemEquippedOnSlot(slot, item);
4265 }
4266 else
4267 {
4268 return false;
4269 }
4270 }
4271
4272 public function IsItemExcluded ( itemID : SItemUniqueId, excludedItems : array < SItemNameProperty > ) : bool
4273 {
4274 var i : int;
4275 var currItemName : name;
4276
4277 currItemName = GetItemName( itemID );
4278
4279 for ( i = 0; i < excludedItems.Size(); i+=1 )
4280 {
4281 if ( currItemName == excludedItems[i].itemName )
4282 {
4283 return true;
4284 }
4285 }
4286 return false;
4287 }
4288
4289 // #Y TODO: Check it
4290 public function GetItemPrimaryStat(itemId : SItemUniqueId, out attributeLabel : string, out attributeVal : float ) : void
4291 {
4292 var attributeName : name;
4293 var attributeValue:SAbilityAttributeValue;
4294
4295 GetItemPrimaryStatImplById(itemId, attributeLabel, attributeVal, attributeName);
4296
4297 attributeValue = GetItemAttributeValue(itemId, attributeName);
4298
4299 if(attributeValue.valueBase != 0)
4300 {
4301 attributeVal = attributeValue.valueBase;
4302 }
4303 if(attributeValue.valueMultiplicative != 0)
4304 {
4305 attributeVal = attributeValue.valueMultiplicative;
4306 }
4307 if(attributeValue.valueAdditive != 0)
4308 {
4309 attributeVal = attributeValue.valueAdditive;
4310 }
4311 }
4312
4313 public function GetItemStatByName(itemName : name, statName : name, out resultValue : float) : void
4314 {
4315 var dm : CDefinitionsManagerAccessor;
4316 var attributes, itemAbilities : array<name>;
4317 var min, max, attributeValue : SAbilityAttributeValue;
4318 var tmpInt : int;
4319 var tmpArray : array<float>;
4320
4321 dm = theGame.GetDefinitionsManager();
4322 dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, tmpArray, tmpInt, tmpInt);
4323 attributes = dm.GetAbilitiesAttributes(itemAbilities);
4324
4325 dm.GetAbilitiesAttributeValue(itemAbilities, statName, min, max);
4326 attributeValue = GetAttributeRandomizedValue(min, max);
4327
4328 if(attributeValue.valueBase != 0)
4329 {
4330 resultValue = attributeValue.valueBase;
4331 }
4332 if(attributeValue.valueMultiplicative != 0)
4333 {
4334 resultValue = attributeValue.valueMultiplicative;
4335 }
4336 if(attributeValue.valueAdditive != 0)
4337 {
4338 resultValue = attributeValue.valueAdditive;
4339 }
4340 }
4341
4342 public function GetItemPrimaryStatFromName(itemName : name, out attributeLabel : string, out attributeVal : float, out primAttrName : name) : void
4343 {
4344 var dm : CDefinitionsManagerAccessor;
4345 var attributeName : name;
4346 var attributes, itemAbilities : array<name>;
4347 var attributeValue, min, max : SAbilityAttributeValue;
4348
4349 var tmpInt : int;
4350 var tmpArray : array<float>;
4351
4352 dm = theGame.GetDefinitionsManager();
4353
4354 GetItemPrimaryStatImpl(dm.GetItemCategory(itemName), attributeLabel, attributeVal, attributeName);
4355 dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, tmpArray, tmpInt, tmpInt);
4356 attributes = dm.GetAbilitiesAttributes(itemAbilities);
4357 for (tmpInt = 0; tmpInt < attributes.Size(); tmpInt += 1)
4358 if (attributes[tmpInt] == attributeName)
4359 {
4360 dm.GetAbilitiesAttributeValue(itemAbilities, attributeName, min, max);
4361 attributeValue = GetAttributeRandomizedValue(min, max);
4362 primAttrName = attributeName;
4363 break;
4364 }
4365
4366 if(attributeValue.valueBase != 0)
4367 {
4368 attributeVal = attributeValue.valueBase;
4369 }
4370 if(attributeValue.valueMultiplicative != 0)
4371 {
4372 attributeVal = attributeValue.valueMultiplicative;
4373 }
4374 if(attributeValue.valueAdditive != 0)
4375 {
4376 attributeVal = attributeValue.valueAdditive;
4377 }
4378
4379 }
4380
4381 public function IsPrimaryStatById(itemId : SItemUniqueId, attributeName : name, out attributeLabel : string) : bool
4382 {
4383 var attrValue : float;
4384 var attrName : name;
4385
4386 GetItemPrimaryStatImplById(itemId, attributeLabel, attrValue, attrName);
4387 return attrName == attributeName;
4388 }
4389
4390 private function GetItemPrimaryStatImplById(itemId : SItemUniqueId, out attributeLabel : string, out attributeVal : float, out attributeName : name ) : void
4391 {
4392 var itemOnSlot : SItemUniqueId;
4393 var categoryName : name;
4394 var abList : array<name>;
4395
4396 attributeName = '';
4397 attributeLabel = "";
4398 categoryName = GetItemCategory(itemId);
4399
4400 // #Y Maybe we can just select max stat? TODO: Discuss with Kanik
4401 if (categoryName == 'bolt' || categoryName == 'petard')
4402 {
4403 GetItemAttributes(itemId, abList);
4404 if (abList.Contains('FireDamage'))
4405 {
4406 attributeName = 'FireDamage';
4407 }
4408 else if (abList.Contains('PiercingDamage'))
4409 {
4410 attributeName = 'PiercingDamage';
4411 }
4412 else if (abList.Contains('PiercingDamage'))
4413 {
4414 attributeName = 'PiercingDamage';
4415 }
4416 else if (abList.Contains('PoisonDamage'))
4417 {
4418 attributeName = 'PoisonDamage';
4419 }
4420 else if (abList.Contains('BludgeoningDamage'))
4421 {
4422 attributeName = 'BludgeoningDamage';
4423 }
4424 else
4425 {
4426 attributeName = 'PhysicalDamage';
4427 }
4428 attributeLabel = GetAttributeNameLocStr(attributeName, false);
4429 }
4430 else if (categoryName == 'secondary')
4431 {
4432 GetItemAttributes(itemId, abList);
4433 if (abList.Contains('BludgeoningDamage'))
4434 {
4435 attributeName = 'BludgeoningDamage';
4436 }
4437 else
4438 {
4439 attributeName = 'PhysicalDamage';
4440 }
4441 attributeLabel = GetAttributeNameLocStr(attributeName, false);
4442 }
4443 else if (categoryName == 'steelsword')
4444 {
4445 GetItemAttributes(itemId, abList);
4446 if (abList.Contains('SlashingDamage'))
4447 {
4448 attributeName = 'SlashingDamage';
4449 attributeLabel = GetLocStringByKeyExt("panel_inventory_tooltip_damage");
4450 }
4451 else if (abList.Contains('BludgeoningDamage'))
4452 {
4453 attributeName = 'BludgeoningDamage';
4454 }
4455 else if (abList.Contains('PiercingDamage'))
4456 {
4457 attributeName = 'PiercingDamage';
4458 }
4459 else
4460 {
4461 attributeName = 'PhysicalDamage';
4462 }
4463 if (attributeLabel == "")
4464 {
4465 attributeLabel = GetAttributeNameLocStr(attributeName, false);
4466 }
4467 }
4468 else
4469 {
4470 GetItemPrimaryStatImpl(categoryName, attributeLabel, attributeVal, attributeName);
4471 }
4472 }
4473
4474 public function IsPrimaryStat(categoryName : name, attributeName : name, out attributeLabel : string) : bool
4475 {
4476 var attrValue : float;
4477 var attrName : name;
4478
4479 GetItemPrimaryStatImpl(categoryName, attributeLabel, attrValue, attrName);
4480 return attrName == attributeName;
4481 }
4482
4483 private function GetItemPrimaryStatImpl(categoryName : name, out attributeLabel : string, out attributeVal : float, out attributeName : name ) : void
4484 {
4485 attributeName = '';
4486 attributeLabel = "";
4487 switch (categoryName)
4488 {
4489 case 'steelsword':
4490 attributeName = 'SlashingDamage';
4491 attributeLabel = GetLocStringByKeyExt("panel_inventory_tooltip_damage");
4492 break;
4493 case 'silversword':
4494 attributeName = 'SilverDamage';
4495 attributeLabel = GetLocStringByKeyExt("panel_inventory_tooltip_damage");
4496 break;
4497 case 'armor':
4498 case 'gloves':
4499 case 'gloves':
4500 case 'boots':
4501 case 'pants':
4502 attributeName = 'armor';
4503 break;
4504 case 'potion':
4505 case 'oil':
4506 //attributeName = 'duration';
4507 break;
4508 case 'bolt':
4509 case 'petard':
4510 attributeName = 'PhysicalDamage';
4511 break;
4512 case 'crossbow':
4513 default:
4514 attributeLabel = "";
4515 attributeVal = 0;
4516 return;
4517 break;
4518 }
4519
4520 if (attributeLabel == "")
4521 {
4522 attributeLabel = GetAttributeNameLocStr(attributeName, false);
4523 }
4524 }
4525
4526 public function CanBeCompared(itemId : SItemUniqueId) : bool
4527 {
4528 var wplayer : W3PlayerWitcher;
4529 var itemSlot : EEquipmentSlots;
4530 var equipedItem : SItemUniqueId;
4531 var horseManager : W3HorseManager;
4532
4533 var isArmorOrWeapon : bool;
4534
4535 if (IsItemHorseItem(itemId))
4536 {
4537 horseManager = GetWitcherPlayer().GetHorseManager();
4538
4539 if (!horseManager)
4540 {
4541 return false;
4542 }
4543
4544 if (horseManager.IsItemEquipped(itemId))
4545 {
4546 return false;
4547 }
4548
4549 itemSlot = GetHorseSlotForItem(itemId);
4550 equipedItem = horseManager.GetItemInSlot(itemSlot);
4551 if (!horseManager.GetInventoryComponent().IsIdValid(equipedItem))
4552 {
4553 return false;
4554 }
4555 }
4556 else
4557 {
4558 isArmorOrWeapon = IsItemAnyArmor(itemId) || IsItemWeapon(itemId);
4559 if (!isArmorOrWeapon)
4560 {
4561 return false;
4562 }
4563
4564 wplayer = GetWitcherPlayer();
4565 if (wplayer.IsItemEquipped(itemId))
4566 {
4567 return false;
4568 }
4569
4570 itemSlot = GetSlotForItemId(itemId);
4571 wplayer.GetItemEquippedOnSlot(itemSlot, equipedItem);
4572 if (!wplayer.inv.IsIdValid(equipedItem))
4573 {
4574 return false;
4575 }
4576 }
4577
4578 return true;
4579 }
4580
4581 public function GetHorseSlotForItem(id : SItemUniqueId) : EEquipmentSlots
4582 {
4583 var tags : array<name>;
4584
4585 GetItemTags(id, tags);
4586
4587 if(tags.Contains('Saddle')) return EES_HorseSaddle;
4588 else if(tags.Contains('HorseBag')) return EES_HorseBag;
4589 else if(tags.Contains('Trophy')) return EES_HorseTrophy;
4590 else if(tags.Contains('Blinders')) return EES_HorseBlinders;
4591 else return EES_InvalidSlot;
4592 }
4593
4594 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4595 //////////////////////// @SINGLETON ITEMS ////////////////////////////////////////////////////////////////////////////////////////////////
4596 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4597
4598 public final function SingletonItemRefillAmmo( id : SItemUniqueId, optional alchemyTableUsed : bool )
4599 {
4600 var l_bed : W3WitcherBed;
4601 var refilledByBed : bool;
4602
4603 refilledByBed = false;
4604
4605 //Alchemy Table increases all the potions by 1
4606 if( FactsQuerySum( "PlayerInsideOuterWitcherHouse" ) >= 1 && FactsQuerySum( "AlchemyTableExists" ) >= 1 && !IsItemMutagenPotion( id ) )
4607 {
4608 l_bed = (W3WitcherBed)theGame.GetEntityByTag( 'witcherBed' );
4609
4610 if( l_bed.GetWasUsed() || alchemyTableUsed )
4611 {
4612 SetItemModifierInt( id, 'ammo_current', SingletonItemGetMaxAmmo(id) + theGame.params.QUANTITY_INCREASED_BY_ALCHEMY_TABLE ) ;
4613 refilledByBed = true;
4614 if( !l_bed.GetWereItemsRefilled() )
4615 {
4616 l_bed.SetWereItemsRefilled( true );
4617 }
4618 }
4619 }
4620
4621 //regular refill
4622 if( !refilledByBed && SingletonItemGetAmmo( id ) < SingletonItemGetMaxAmmo( id ) )
4623 {
4624 SetItemModifierInt(id, 'ammo_current', SingletonItemGetMaxAmmo(id));
4625 }
4626
4627 theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged );
4628 }
4629
4630 public function SingletonItemSetAmmo(id : SItemUniqueId, quantity : int)
4631 {
4632 var amount : int;
4633
4634 if(ItemHasTag(id, theGame.params.TAG_INFINITE_AMMO))
4635 {
4636 amount = -1;
4637 }
4638 else
4639 {
4640 amount = Clamp(quantity, 0, SingletonItemGetMaxAmmo(id));
4641 }
4642
4643 SetItemModifierInt(id, 'ammo_current', amount);
4644 theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged );
4645 }
4646
4647 public function SingletonItemAddAmmo(id : SItemUniqueId, quantity : int)
4648 {
4649 var ammo : int;
4650
4651 if(quantity <= 0)
4652 return;
4653
4654 ammo = GetItemModifierInt(id, 'ammo_current');
4655
4656 if(ammo == -1)
4657 return; //infinite, cannot add
4658
4659 ammo = Clamp(ammo + quantity, 0, SingletonItemGetMaxAmmo(id));
4660 SetItemModifierInt(id, 'ammo_current', ammo);
4661 theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged );
4662 }
4663
4664 public function SingletonItemsRefillAmmo( optional alchemyTableUsed : bool ) : bool
4665 {
4666 var i : int;
4667 var singletonItems : array<SItemUniqueId>;
4668 var alco : SItemUniqueId;
4669 var arrStr : array<string>;
4670 var witcher : W3PlayerWitcher;
4671 var itemLabel : string;
4672
4673 witcher = GetWitcherPlayer();
4674 if(GetEntity() == witcher && HasNotFilledSingletonItem( alchemyTableUsed ) )
4675 {
4676 alco = witcher.GetAlcoholForAlchemicalItemsRefill();
4677
4678 if(!IsIdValid(alco))
4679 {
4680 //doesn't have alcohol that can be used to refill
4681 theGame.GetGuiManager().ShowNotification(GetLocStringByKeyExt("message_common_alchemy_items_cannot_refill"));
4682 theSound.SoundEvent("gui_global_denied");
4683
4684 return false;
4685 }
4686 else
4687 {
4688 //has alco to refill
4689 arrStr.PushBack(GetItemName(alco));
4690 itemLabel = GetLocStringByKeyExt(GetItemLocalizedNameByUniqueID(alco));
4691 theGame.GetGuiManager().ShowNotification( itemLabel + " - " + GetLocStringByKeyExtWithParams("message_common_alchemy_items_refilled", , , arrStr));
4692 theSound.SoundEvent("gui_alchemy_brew");
4693
4694 if(!ItemHasTag(alco, theGame.params.TAG_INFINITE_USE))
4695 RemoveItem(alco);
4696 }
4697 }
4698
4699 singletonItems = GetSingletonItems();
4700 for(i=0; i<singletonItems.Size(); i+=1)
4701 {
4702 SingletonItemRefillAmmo( singletonItems[i], alchemyTableUsed );
4703 }
4704
4705 return true;
4706 }
4707
4708 public function SingletonItemsRefillAmmoNoAlco(optional dontUpdateUI : bool)
4709 {
4710 var i : int;
4711 var singletonItems : array<SItemUniqueId>;
4712 var alco : SItemUniqueId;
4713 var arrStr : array<string>;
4714 var witcher : W3PlayerWitcher;
4715 var itemLabel : string;
4716
4717 witcher = GetWitcherPlayer();
4718 if(!dontUpdateUI && GetEntity() == witcher && HasNotFilledSingletonItem())
4719 {
4720 //has alco to refill
4721 arrStr.PushBack(GetItemName(alco));
4722 itemLabel = GetLocStringByKeyExt(GetItemLocalizedNameByUniqueID(alco));
4723 theGame.GetGuiManager().ShowNotification( itemLabel + " - " + GetLocStringByKeyExtWithParams("message_common_alchemy_items_refilled", , , arrStr));
4724 theSound.SoundEvent("gui_alchemy_brew");
4725 }
4726
4727 singletonItems = GetSingletonItems();
4728 for(i=0; i<singletonItems.Size(); i+=1)
4729 {
4730 SingletonItemRefillAmmo(singletonItems[i]);
4731 }
4732 }
4733
4734 //returns true if has at least one singleton item that does not have full ammo
4735 private final function HasNotFilledSingletonItem( optional alchemyTableUsed : bool ) : bool
4736 {
4737 var i : int;
4738 var singletonItems : array<SItemUniqueId>;
4739 var hasLab : bool;
4740 var l_bed : W3WitcherBed;
4741
4742 //Alchemy Table increases all the potions by 1
4743 hasLab = false;
4744 if( FactsQuerySum( "PlayerInsideOuterWitcherHouse" ) >= 1 && FactsQuerySum( "AlchemyTableExists" ) >= 1 )
4745 {
4746 l_bed = (W3WitcherBed)theGame.GetEntityByTag( 'witcherBed' );
4747 if( l_bed.GetWasUsed() || alchemyTableUsed )
4748 {
4749 hasLab = true;
4750 }
4751 }
4752
4753 singletonItems = GetSingletonItems();
4754 for(i=0; i<singletonItems.Size(); i+=1)
4755 {
4756 if( hasLab && !IsItemMutagenPotion( singletonItems[i] ) )
4757 {
4758 if(SingletonItemGetAmmo(singletonItems[i]) <= SingletonItemGetMaxAmmo(singletonItems[i]))
4759 {
4760 return true;
4761 }
4762 }
4763 else if(SingletonItemGetAmmo(singletonItems[i]) < SingletonItemGetMaxAmmo(singletonItems[i]))
4764 {
4765 return true;
4766 }
4767 }
4768
4769 return false;
4770 }
4771
4772 public function SingletonItemRemoveAmmo(itemID : SItemUniqueId, optional quantity : int)
4773 {
4774 var ammo : int;
4775
4776 if(!IsItemSingletonItem(itemID) || ItemHasTag(itemID, theGame.params.TAG_INFINITE_AMMO))
4777 return;
4778
4779 if(quantity <= 0)
4780 quantity = 1;
4781
4782 ammo = GetItemModifierInt(itemID, 'ammo_current');
4783 ammo = Max(0, ammo - quantity);
4784 SetItemModifierInt(itemID, 'ammo_current', ammo);
4785
4786 //count alchemy usage but only after nightmare
4787 if(ammo == 0 && ShouldProcessTutorial('TutorialAlchemyRefill') && FactsQuerySum("q001_nightmare_ended") > 0)
4788 {
4789 FactsAdd('tut_alch_refill', 1);
4790 }
4791 theGame.GetGlobalEventsManager().OnScriptedEvent( SEC_OnAmmoChanged );
4792 }
4793
4794 public function SingletonItemGetAmmo(itemID : SItemUniqueId) : int
4795 {
4796 if(!IsItemSingletonItem(itemID))
4797 return 0;
4798
4799 return GetItemModifierInt(itemID, 'ammo_current');
4800 }
4801
4802 public function SingletonItemGetMaxAmmo(itemID : SItemUniqueId) : int
4803 {
4804 var ammo, i : int;
4805 var perk20Bonus, min, max : SAbilityAttributeValue;
4806 var atts : array<name>;
4807 var canUseSkill : bool;
4808
4809 ammo = RoundMath(CalculateAttributeValue(GetItemAttributeValue(itemID, 'ammo')));
4810
4811 if( !ItemHasTag( itemID, 'NoAdditionalAmmo' ) )
4812 {
4813 if(GetEntity() == GetWitcherPlayer() && ammo > 0)
4814 {
4815 if(IsItemBomb(itemID) && thePlayer.CanUseSkill(S_Alchemy_s08) )
4816 {
4817 ammo += thePlayer.GetSkillLevel(S_Alchemy_s08);
4818 }
4819 //mutagen 3
4820 if(thePlayer.HasBuff(EET_Mutagen03) && (IsItemBomb(itemID) || (!IsItemMutagenPotion(itemID) && IsItemPotion(itemID))) )
4821 {
4822 ammo += 1;
4823 }
4824
4825 if( GetWitcherPlayer().IsSetBonusActive( EISB_RedWolf_2 ) && !IsItemMutagenPotion(itemID) )
4826 {
4827 theGame.GetDefinitionsManager().GetAbilityAttributeValue( GetSetBonusAbility( EISB_RedWolf_2 ), 'amount', min, max);
4828 ammo += (int)min.valueAdditive;
4829 }
4830
4831 //Perk 20 - decreases amount of bombs in stack, but increases their damage
4832 if( IsItemBomb( itemID ) && thePlayer.CanUseSkill( S_Perk_20 ) && GetItemName( itemID ) != 'Snow Ball' )
4833 {
4834 GetItemAttributes( itemID, atts );
4835 canUseSkill = thePlayer.CanUseSkill( S_Alchemy_s10 );
4836 perk20Bonus = GetWitcherPlayer().GetSkillAttributeValue( S_Perk_20, 'stack_multiplier', false, false );
4837
4838 for( i=0 ; i<atts.Size() ; i+=1 )
4839 {
4840 if( canUseSkill || IsDamageTypeNameValid( atts[i] ) )
4841 {
4842 ammo = RoundMath( ammo * perk20Bonus.valueMultiplicative );
4843 break;
4844 }
4845 }
4846 }
4847 }
4848 }
4849
4850 return ammo;
4851 }
4852
4853 public function ManageSingletonItemsBonus()
4854 {
4855 var l_items : array<SItemUniqueId>;
4856 var l_i : int;
4857 var l_haveBombOrPot : bool;
4858
4859 l_items = GetSingletonItems();
4860
4861 for( l_i = 0 ; l_i < l_items.Size() ; l_i += 1 )
4862 {
4863 if( IsItemPotion( l_items[ l_i ] ) || IsItemBomb( l_items[ l_i ] ) )
4864 {
4865 l_haveBombOrPot = true;
4866 if( SingletonItemGetMaxAmmo( l_items[ l_i ] ) >= SingletonItemGetAmmo( l_items[ l_i ] ) )
4867 {
4868 if( SingletonItemsRefillAmmo( true ) )
4869 {
4870 theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_applied" ),, true );
4871 }
4872
4873 return;
4874 }
4875 }
4876 }
4877
4878 if( !l_haveBombOrPot )
4879 {
4880 theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_no_items" ),, true );
4881 return;
4882 }
4883
4884 theGame.GetGuiManager().ShowNotification( GetLocStringByKeyExt( "message_common_alchemy_table_buff_already_on" ),, true );
4885 }
4886
4887 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4888 //////////////////////// @SLOTS //////////////////////////////////////////////////////////////////////////////////////////////////////////
4889 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4890
4891 public final function IsItemSteelSwordUsableByPlayer(item : SItemUniqueId) : bool
4892 {
4893 return ItemHasTag(item, theGame.params.TAG_PLAYER_STEELSWORD) && !ItemHasTag(item, 'SecondaryWeapon');
4894 }
4895
4896 public final function IsItemSilverSwordUsableByPlayer(item : SItemUniqueId) : bool
4897 {
4898 return ItemHasTag(item, theGame.params.TAG_PLAYER_SILVERSWORD) && !ItemHasTag(item, 'SecondaryWeapon');
4899 }
4900
4901 public final function IsItemFists(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'fist';}
4902 public final function IsItemWeapon(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Weapon') || ItemHasTag(item, 'WeaponTab');}
4903 public final function IsItemCrossbow(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'crossbow';}
4904 public final function IsItemChestArmor(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'armor';}
4905 public final function IsItemBody(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Body');}
4906 public final function IsRecipeOrSchematic( item : SItemUniqueId ) : bool {return GetItemCategory(item) == 'alchemy_recipe' || GetItemCategory(item) == 'crafting_schematic'; }
4907 public final function IsItemBoots(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'boots';}
4908 public final function IsItemGloves(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'gloves';}
4909 public final function IsItemPants(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'trousers' || GetItemCategory(item) == 'pants';}
4910 public final function IsItemTrophy(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'trophy';}
4911 public final function IsItemMask(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'mask';}
4912 public final function IsItemBomb(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'petard';}
4913 public final function IsItemBolt(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'bolt';}
4914 public final function IsItemUpgrade(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'upgrade';}
4915 public final function IsItemTool(item : SItemUniqueId) : bool {return GetItemCategory(item) == 'tool';}
4916 public final function IsItemPotion(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Potion');}
4917 public final function IsItemOil(item : SItemUniqueId) : bool {return ItemHasTag(item, 'SilverOil') || ItemHasTag(item, 'SteelOil');}
4918 public final function IsItemAnyArmor(item : SItemUniqueId) : bool {return ItemHasTag(item, theGame.params.TAG_ARMOR);}
4919 public final function IsItemUpgradeable(item : SItemUniqueId) : bool {return ItemHasTag(item, theGame.params.TAG_ITEM_UPGRADEABLE);}
4920 public final function IsItemIngredient(item : SItemUniqueId) : bool {return ItemHasTag(item, 'AlchemyIngredient') || ItemHasTag(item, 'CraftingIngredient');}
4921 public final function IsItemDismantleKit(item : SItemUniqueId) : bool {return ItemHasTag(item, 'DismantleKit');}
4922 public final function IsItemHorseBag(item : SItemUniqueId) : bool {return ItemHasTag(item, 'HorseBag');}
4923 public final function IsItemReadable(item : SItemUniqueId) : bool {return ItemHasTag(item, 'ReadableItem');}
4924 public final function IsItemAlchemyItem(item : SItemUniqueId) : bool {return IsItemOil(item) || IsItemPotion(item) || IsItemBomb(item); /*|| ItemHasTag(item, 'QuickSlot');*/ } // #B
4925 public final function IsItemSingletonItem(item : SItemUniqueId) : bool {return ItemHasTag(item, theGame.params.TAG_ITEM_SINGLETON);}
4926 public final function IsItemQuest(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Quest');}
4927 public final function IsItemFood(item : SItemUniqueId) : bool {return ItemHasTag(item, 'Edibles') || ItemHasTag(item, 'Drinks');}
4928 public final function IsItemSecondaryWeapon(item : SItemUniqueId) : bool {return ItemHasTag(item, 'SecondaryWeapon');}
4929 public final function IsItemHorseItem(item: SItemUniqueId) : bool {return ItemHasTag(item, 'Saddle') || ItemHasTag(item, 'HorseBag') || ItemHasTag(item, 'Trophy') || ItemHasTag(item, 'Blinders'); }
4930 public final function IsItemSaddle(item: SItemUniqueId) : bool {return ItemHasTag(item, 'Saddle');}
4931 public final function IsItemBlinders(item: SItemUniqueId) : bool {return ItemHasTag(item, 'Blinders');}
4932 public final function IsItemDye( item : SItemUniqueId ) : bool { return ItemHasTag( item, 'mod_dye' ); }
4933 public final function IsItemUsable( item : SItemUniqueId ) : bool { return GetItemCategory( item ) == 'usable'; }
4934 public final function IsItemJunk( item : SItemUniqueId ) : bool { return ItemHasTag( item,'junk' ) || GetItemCategory( item ) == 'junk' ; }
4935 public final function IsItemAlchemyIngredient(item : SItemUniqueId) : bool { return ItemHasTag( item, 'AlchemyIngredient' ); }
4936 public final function IsItemCraftingIngredient(item : SItemUniqueId) : bool { return ItemHasTag( item, 'CraftingIngredient' ); }
4937 public final function IsItemArmorReapairKit(item : SItemUniqueId) : bool { return ItemHasTag( item, 'ArmorReapairKit' ); }
4938 public final function IsItemWeaponReapairKit(item : SItemUniqueId) : bool { return ItemHasTag( item, 'WeaponReapairKit' ); }
4939 public final function IsQuickSlotItem( item : SItemUniqueId ) : bool { return ItemHasTag( item, 'QuickSlot' ); }
4940
4941 public final function IsItemNew( item : SItemUniqueId ) : bool
4942 {
4943 var uiData : SInventoryItemUIData;
4944
4945 uiData = GetInventoryItemUIData( item );
4946 return uiData.isNew;
4947 }
4948
4949 public final function IsItemMutagenPotion(item : SItemUniqueId) : bool
4950 {
4951 return IsItemPotion(item) && ItemHasTag(item, 'Mutagen');
4952 }
4953
4954 public final function CanItemBeColored( item : SItemUniqueId) : bool
4955 {
4956 if ( RoundMath( CalculateAttributeValue( GetItemAttributeValue( item, 'quality' ) ) ) == 5 )
4957 {
4958 return true;
4959 }
4960 return false;
4961 }
4962
4963 public final function IsItemSetItem(item : SItemUniqueId) : bool
4964 {
4965 return
4966 ItemHasTag(item, theGame.params.ITEM_SET_TAG_BEAR) ||
4967 ItemHasTag(item, theGame.params.ITEM_SET_TAG_GRYPHON) ||
4968 ItemHasTag(item, theGame.params.ITEM_SET_TAG_LYNX) ||
4969 ItemHasTag(item, theGame.params.ITEM_SET_TAG_WOLF) ||
4970 ItemHasTag(item, theGame.params.ITEM_SET_TAG_RED_WOLF) ||
4971 ItemHasTag( item, theGame.params.ITEM_SET_TAG_VAMPIRE ) ||
4972 ItemHasTag(item, theGame.params.ITEM_SET_TAG_VIPER);
4973 }
4974
4975 public function GetArmorType(item : SItemUniqueId) : EArmorType
4976 {
4977 var isItemEquipped : bool;
4978
4979 isItemEquipped = GetWitcherPlayer().IsItemEquipped(item);
4980
4981 //GlyphWord bonuses
4982 if( thePlayer.HasAbility('Glyphword 2 _Stats', true) && isItemEquipped )
4983 {return EAT_Light;}
4984 if( thePlayer.HasAbility('Glyphword 3 _Stats', true) && isItemEquipped )
4985 {return EAT_Medium;}
4986 if( thePlayer.HasAbility('Glyphword 4 _Stats', true) && isItemEquipped )
4987 {return EAT_Heavy;}
4988
4989 if(ItemHasTag(item, 'LightArmor'))
4990 return EAT_Light;
4991 else if(ItemHasTag(item, 'MediumArmor'))
4992 return EAT_Medium;
4993 else if(ItemHasTag(item, 'HeavyArmor'))
4994 return EAT_Heavy;
4995
4996 return EAT_Undefined;
4997 }
4998
4999 public final function GetAlchemyCraftableItems() : array<SItemUniqueId>
5000 {
5001 var items : array<SItemUniqueId>;
5002 var i : int;
5003
5004 GetAllItems(items);
5005
5006 for(i=items.Size()-1; i>=0; i-=1)
5007 {
5008 if(!IsItemPotion(items[i]) && !IsItemBomb(items[i]) && !IsItemOil(items[i]))
5009 items.EraseFast(i);
5010 }
5011
5012 return items;
5013 }
5014
5015 public function IsItemEncumbranceItem(item : SItemUniqueId) : bool
5016 {
5017 if(ItemHasTag(item, theGame.params.TAG_ENCUMBRANCE_ITEM_FORCE_YES))
5018 return true;
5019
5020 if(ItemHasTag(item, theGame.params.TAG_ENCUMBRANCE_ITEM_FORCE_NO))
5021 return false;
5022
5023 //#J added in IsItemAlchemyItem and IsItemIngredient to make it consisten with tooltip. Need to varify which is correct but this way makes most sense
5024 if (// IsItemQuest(item)
5025 IsRecipeOrSchematic( item )
5026 || IsItemBody( item )
5027 // || IsItemBolt(item)
5028 // || IsItemAlchemyItem(item)
5029 // || IsItemIngredient(item)
5030 // || IsItemTool(item)
5031 // || GetItemCategory(item) == 'misc'
5032 // || GetItemCategory(item) == 'usable'
5033 // || GetItemCategory(item) == 'book'
5034 // || GetItemCategory(item) == 'key'
5035 // || GetItemCategory(item) == 'trophy'
5036 // || GetItemCategory(item) == 'mask'
5037 // || GetItemCategory(item) == 'junk'
5038 // || GetItemCategory(item) == 'horse_bag'
5039 )
5040 return false;
5041
5042 return true;
5043 }
5044
5045 public function GetItemEncumbrance(item : SItemUniqueId) : float
5046 {
5047 var itemCategory : name;
5048 if ( IsItemEncumbranceItem( item ) )
5049 {
5050 itemCategory = GetItemCategory( item );
5051 if ( itemCategory == 'quest' || itemCategory == 'key' )
5052 {
5053 return 0.01 * GetItemQuantity( item );
5054 }
5055 else if ( itemCategory == 'usable' || itemCategory == 'upgrade' || itemCategory == 'junk' )
5056 {
5057 return 0.01 + GetItemWeight( item ) * GetItemQuantity( item ) * 0.2;
5058 }
5059 else if ( IsItemAlchemyItem( item ) || IsItemIngredient( item ) || IsItemFood( item ) || IsItemReadable( item ) )
5060 {
5061 return 0.0;
5062 }
5063 else
5064 {
5065 return 0.01 + GetItemWeight( item ) * GetItemQuantity( item ) * 0.5;
5066 }
5067 }
5068 return 0;
5069 }
5070
5071 public function GetFilterTypeByItem( item : SItemUniqueId ) : EInventoryFilterType
5072 {
5073 var filterType : EInventoryFilterType;
5074
5075 if( ItemHasTag( item, 'Quest' ) )
5076 {
5077 return IFT_QuestItems;
5078 }
5079 else if( IsItemIngredient( item ) )
5080 {
5081 return IFT_Ingredients;
5082 }
5083 else if( IsItemAlchemyItem(item) )
5084 {
5085 return IFT_AlchemyItems;
5086 }
5087 else if( IsItemAnyArmor(item) )
5088 {
5089 return IFT_Armors;
5090 }
5091 else if( IsItemWeapon( item ) )
5092 {
5093 return IFT_Weapons;
5094 }
5095 else
5096 {
5097 return IFT_Default;
5098 }
5099 }
5100
5101 //returns true if given item is an item that is placed in quickslots
5102 public function IsItemQuickslotItem(item : SItemUniqueId) : bool
5103 {
5104 return IsSlotQuickslot( GetSlotForItemId(item) );
5105 }
5106
5107 public function GetCrossbowAmmo(id : SItemUniqueId) : int
5108 {
5109 if(!IsItemCrossbow(id))
5110 return -1;
5111
5112 return (int)CalculateAttributeValue(GetItemAttributeValue(id, 'ammo'));
5113 }
5114
5115 //Returns appropriate slot for given item. If it's a slot that exists in multiple numbers (e.g. quickslot) tries to find first free one. If there is no free one
5116 //then returns the default slot for this group.
5117 public function GetSlotForItemId(item : SItemUniqueId) : EEquipmentSlots
5118 {
5119 var tags : array<name>;
5120 var player : W3PlayerWitcher;
5121 var slot : EEquipmentSlots;
5122
5123 player = ((W3PlayerWitcher)GetEntity());
5124
5125 GetItemTags(item, tags);
5126 slot = GetSlotForItem( GetItemCategory(item), tags, player );
5127
5128 if(!player)
5129 return slot;
5130
5131 if(IsMultipleSlot(slot))
5132 {
5133 if(slot == EES_Petard1 && player.IsAnyItemEquippedOnSlot(slot))
5134 {
5135 if(!player.IsAnyItemEquippedOnSlot(EES_Petard2))
5136 slot = EES_Petard2;
5137 }
5138 else if(slot == EES_Quickslot1 && player.IsAnyItemEquippedOnSlot(slot))
5139 {
5140 if(!player.IsAnyItemEquippedOnSlot(EES_Quickslot2))
5141 slot = EES_Quickslot2;
5142 }
5143 else if(slot == EES_Potion1 && player.IsAnyItemEquippedOnSlot(EES_Potion1))
5144 {
5145 if(!player.IsAnyItemEquippedOnSlot(EES_Potion2))
5146 {
5147 slot = EES_Potion2;
5148 }
5149 else
5150 {
5151 if(!player.IsAnyItemEquippedOnSlot(EES_Potion3))
5152 {
5153 slot = EES_Potion3;
5154 }
5155 else
5156 {
5157 if(!player.IsAnyItemEquippedOnSlot(EES_Potion4))
5158 {
5159 slot = EES_Potion4;
5160 }
5161 }
5162 }
5163 }
5164 else if(slot == EES_PotionMutagen1 && player.IsAnyItemEquippedOnSlot(slot))
5165 {
5166 if(!player.IsAnyItemEquippedOnSlot(EES_PotionMutagen2))
5167 {
5168 slot = EES_PotionMutagen2;
5169 }
5170 else
5171 {
5172 if(!player.IsAnyItemEquippedOnSlot(EES_PotionMutagen3))
5173 {
5174 slot = EES_PotionMutagen3;
5175 }
5176 else
5177 {
5178 if(!player.IsAnyItemEquippedOnSlot(EES_PotionMutagen4))
5179 {
5180 slot = EES_PotionMutagen4;
5181 }
5182 }
5183 }
5184 }
5185 else if(slot == EES_SkillMutagen1 && player.IsAnyItemEquippedOnSlot(slot))
5186 {
5187 if(!player.IsAnyItemEquippedOnSlot(EES_SkillMutagen2))
5188 {
5189 slot = EES_SkillMutagen2;
5190 }
5191 else
5192 {
5193 if(!player.IsAnyItemEquippedOnSlot(EES_SkillMutagen3))
5194 {
5195 slot = EES_SkillMutagen3;
5196 }
5197 else
5198 {
5199 if(!player.IsAnyItemEquippedOnSlot(EES_SkillMutagen4))
5200 {
5201 slot = EES_SkillMutagen4;
5202 }
5203 }
5204 }
5205 }
5206 }
5207
5208 return slot;
5209 }
5210
5211
5212
5213 public function GetAllWeapons() : array<SItemUniqueId>
5214 {
5215 return GetItemsByTag('Weapon');
5216 }
5217
5218 /*
5219 Quest function to get specific items - do not use outisde of quest function!
5220
5221 Gets items of given types, except the ones that cannot be dropped.
5222 */
5223 public function GetSpecifiedPlayerItemsQuest(steelSword, silverSword, armor, boots, gloves, pants, trophy, mask, bombs, crossbow, secondaryWeapon, equippedOnly : bool) : array<SItemUniqueId>
5224 {
5225 var items, allItems : array<SItemUniqueId>;
5226 var i : int;
5227
5228 GetAllItems(allItems);
5229
5230 for(i=0; i<allItems.Size(); i+=1)
5231 {
5232 if(
5233 (steelSword && IsItemSteelSwordUsableByPlayer(allItems[i])) ||
5234 (silverSword && IsItemSilverSwordUsableByPlayer(allItems[i])) ||
5235 (armor && IsItemChestArmor(allItems[i])) ||
5236 (boots && IsItemBoots(allItems[i])) ||
5237 (gloves && IsItemGloves(allItems[i])) ||
5238 (pants && IsItemPants(allItems[i])) ||
5239 (trophy && IsItemTrophy(allItems[i])) ||
5240 (mask && IsItemMask(allItems[i])) ||
5241 (bombs && IsItemBomb(allItems[i])) ||
5242 (crossbow && (IsItemCrossbow(allItems[i]) || IsItemBolt(allItems[i]))) ||
5243 (secondaryWeapon && IsItemSecondaryWeapon(allItems[i]))
5244 )
5245 {
5246 if(!equippedOnly || (equippedOnly && ((W3PlayerWitcher)GetEntity()) && GetWitcherPlayer().IsItemEquipped(allItems[i])) )
5247 {
5248 if(!ItemHasTag(allItems[i], 'NoDrop'))
5249 items.PushBack(allItems[i]);
5250 }
5251 }
5252 }
5253
5254 return items;
5255 }
5256 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5257
5258 //Called BEFORE the item is removed from inventory
5259 event OnItemRemoved( itemId : SItemUniqueId, quantity : int )
5260 {
5261 var ent : CGameplayEntity;
5262 var crossbows : array<SItemUniqueId>;
5263 var witcher : W3PlayerWitcher;
5264 var refill : W3RefillableContainer;
5265
5266 witcher = GetWitcherPlayer();
5267 //if player
5268 if(GetEntity() == witcher)
5269 {
5270 //update encumbrance
5271 //if(IsItemEncumbranceItem(itemId)) // #B there is no sense in calling it here, "Called BEFORE the item is removed from inventory"
5272 // GetWitcherPlayer().UpdateEncumbrance();
5273
5274 //remove infinite bolts if player has no crossbow
5275 if(IsItemCrossbow(itemId) && HasInfiniteBolts())
5276 {
5277 crossbows = GetItemsByCategory('crossbow');
5278 crossbows.Remove(itemId);
5279
5280 if(crossbows.Size() == 0)
5281 {
5282 RemoveItemByName('Bodkin Bolt', GetItemQuantityByName('Bodkin Bolt'));
5283 RemoveItemByName('Harpoon Bolt', GetItemQuantityByName('Harpoon Bolt'));
5284 }
5285 }
5286 else if(IsItemBolt(itemId) && witcher.IsItemEquipped(itemId) && witcher.inv.GetItemQuantity(itemId) == quantity)
5287 {
5288 //losing all equipped bolts
5289 witcher.UnequipItem(itemId);
5290 }
5291
5292 //removing equipped crossbow
5293 if(IsItemCrossbow(itemId) && witcher.IsItemEquipped(itemId) && witcher.rangedWeapon)
5294 {
5295 witcher.rangedWeapon.ClearDeployedEntity(true);
5296 witcher.rangedWeapon = NULL;
5297 }
5298 if( GetItemCategory(itemId) == 'usable' )
5299 {
5300 if(witcher.IsHoldingItemInLHand() && itemId == witcher.currentlyEquipedItemL )
5301 {
5302 witcher.HideUsableItem(true);
5303 }
5304 }
5305
5306 //failsafe for removing equipped item without proper checks
5307 if(witcher.IsItemEquipped(itemId) && quantity >= witcher.inv.GetItemQuantity(itemId))
5308 witcher.UnequipItem(itemId);
5309 }
5310
5311 //if removing currently held weapon (or mounted - Ciri has issues with her Held weapons not being considered held!)
5312 if(GetEntity() == thePlayer && IsItemWeapon(itemId) && (IsItemHeld(itemId) || IsItemMounted(itemId) ))
5313 {
5314 thePlayer.OnHolsteredItem(GetItemCategory(itemId),'r_weapon');
5315 }
5316
5317 //callback to the entity
5318 ent = (CGameplayEntity)GetEntity();
5319 if(ent)
5320 ent.OnItemTaken( itemId, quantity );
5321
5322 //refillable container
5323 if(IsLootRenewable())
5324 {
5325 refill = (W3RefillableContainer)GetEntity();
5326 if(refill)
5327 refill.AddTimer('Refill', 20, true);
5328 }
5329 }
5330
5331 //FIXME URGENT - what if player is not spawned yet?
5332 function GenerateItemLevel( item : SItemUniqueId, rewardItem : bool )
5333 {
5334 var stat : SAbilityAttributeValue;
5335 var playerLevel : int;
5336 var lvl, i : int;
5337 var quality : int;
5338 var ilMin, ilMax : int;
5339
5340 playerLevel = GetWitcherPlayer().GetLevel();
5341
5342 lvl = playerLevel - 1;
5343
5344 // W3MOD - MAS - Merchants should offer items beyond the player's level.
5345 if ( ( W3MerchantNPC )GetEntity() )
5346 {
5347 lvl = RoundF( playerLevel + RandRangeF( 2, 0 ) );
5348 AddItemTag( item, 'AutogenUseLevelRange' );
5349 }
5350 else if ( rewardItem )
5351 {
5352 lvl = RoundF( playerLevel + RandRangeF( 1, 0 ) );
5353 }
5354 else if ( ItemHasTag( item, 'AutogenUseLevelRange') )
5355 {
5356 quality = RoundMath( CalculateAttributeValue( GetItemAttributeValue( item, 'quality' ) ) );
5357 ilMin = RoundMath(CalculateAttributeValue( GetItemAttributeValue( item, 'item_level_min' ) ));
5358 ilMax = RoundMath(CalculateAttributeValue( GetItemAttributeValue( item, 'item_level_max' ) ));
5359
5360 lvl += 1; //as it is for some reason decreased in on of the futher funtions ...
5361 if ( !ItemHasTag( item, 'AutogenForceLevel') )
5362 lvl += RoundMath(RandRangeF( 1, -1 ));
5363
5364 if ( FactsQuerySum("NewGamePlus") > 0 )
5365 {
5366 if ( lvl < ilMin + theGame.params.GetNewGamePlusLevel() ) lvl = ilMin + theGame.params.GetNewGamePlusLevel();
5367 if ( lvl > ilMax + theGame.params.GetNewGamePlusLevel() ) lvl = ilMax + theGame.params.GetNewGamePlusLevel();
5368 }
5369 else
5370 {
5371 if ( lvl < ilMin ) lvl = ilMin;
5372 if ( lvl > ilMax ) lvl = ilMax;
5373 }
5374
5375 if ( quality == 5 ) lvl += 2;
5376 if ( quality == 4 ) lvl += 1;
5377 if ( (quality == 5 || quality == 4) && ItemHasTag(item, 'EP1') ) lvl += 1;
5378 }
5379 else if ( !ItemHasTag( item, 'AutogenForceLevel') )
5380 {
5381 quality = RoundMath( CalculateAttributeValue( GetItemAttributeValue( item, 'quality' ) ) );
5382
5383 if ( quality == 5 )
5384 {
5385 lvl = RoundF( playerLevel + RandRangeF( 2, 0 ) );
5386 }
5387 else if ( quality == 4 )
5388 {
5389 lvl = RoundF( playerLevel + RandRangeF( 1, -2 ) );
5390 }
5391 else if ( quality == 3 )
5392 {
5393 lvl = RoundF( playerLevel + RandRangeF( -1, -3 ) );
5394
5395 if ( RandF() > 0.9 )
5396 {
5397 lvl = playerLevel;
5398 }
5399 }
5400 else if ( quality == 2 )
5401 {
5402 lvl = RoundF( playerLevel + RandRangeF( -2, -5 ) );
5403
5404 if ( RandF() > 0.95 )
5405 {
5406 lvl = playerLevel;
5407 }
5408 }
5409 else
5410 {
5411 lvl = RoundF( playerLevel + RandRangeF( -2, -8 ) );
5412
5413 if ( RandF() == 0 )
5414 {
5415 lvl = playerLevel;
5416 }
5417 }
5418 }
5419
5420 if (FactsQuerySum("StandAloneEP1") > 0)
5421 lvl = GetWitcherPlayer().GetLevel() - 1;
5422
5423
5424 if ( FactsQuerySum("NewGamePlus") > 0 && !ItemHasTag( item, 'AutogenUseLevelRange') )
5425 {
5426 if ( quality == 5 ) lvl += 2;
5427 if ( quality == 4 ) lvl += 1;
5428 }
5429
5430 if ( lvl < 1 ) lvl = 1;
5431 if ( lvl > GetWitcherPlayer().GetMaxLevel() ) lvl = GetWitcherPlayer().GetMaxLevel();
5432
5433 if ( ItemHasTag( item, 'PlayerSteelWeapon' ) && !( ItemHasAbility( item, 'autogen_steel_base' ) || ItemHasAbility( item, 'autogen_fixed_steel_base' ) ) ) // STEEL SWORD
5434 {
5435 if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_steel_base') )
5436 return;
5437
5438 if ( ItemHasTag(item, 'AutogenUseLevelRange') )
5439 AddItemCraftedAbility(item, 'autogen_fixed_steel_base' );
5440 else
5441 AddItemCraftedAbility(item, 'autogen_steel_base' );
5442
5443 for( i=0; i<lvl; i+=1 )
5444 {
5445 if (FactsQuerySum("StandAloneEP1") > 0)
5446 {
5447 AddItemCraftedAbility(item, 'autogen_fixed_steel_dmg', true );
5448 continue;
5449 }
5450
5451 if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag(item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 )
5452 AddItemCraftedAbility(item, 'autogen_fixed_steel_dmg', true );
5453 else
5454 AddItemCraftedAbility(item, 'autogen_steel_dmg', true );
5455 }
5456 }
5457 else if ( ItemHasTag( item, 'PlayerSilverWeapon' ) && !( ItemHasAbility( item, 'autogen_silver_base' ) || ItemHasAbility( item, 'autogen_fixed_silver_base' ) ) ) // SILVER SWORD
5458 {
5459 if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_silver_base') )
5460 return;
5461
5462 if ( ItemHasTag(item, 'AutogenUseLevelRange') )
5463 AddItemCraftedAbility(item, 'autogen_fixed_silver_base' );
5464 else
5465 AddItemCraftedAbility(item, 'autogen_silver_base' );
5466
5467 for( i=0; i<lvl; i+=1 )
5468 {
5469 if (FactsQuerySum("StandAloneEP1") > 0)
5470 {
5471 AddItemCraftedAbility(item, 'autogen_fixed_silver_dmg', true );
5472 continue;
5473 }
5474
5475 if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag(item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 )
5476 AddItemCraftedAbility(item, 'autogen_fixed_silver_dmg', true );
5477 else
5478 AddItemCraftedAbility(item, 'autogen_silver_dmg', true );
5479 }
5480 }
5481 else if ( GetItemCategory( item ) == 'armor' && !( ItemHasAbility( item, 'autogen_armor_base' ) || ItemHasAbility( item, 'autogen_fixed_armor_base' ) ) ) // Armor
5482 {
5483 if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_armor_base') )
5484 return;
5485
5486 if ( ItemHasTag(item, 'AutogenUseLevelRange') )
5487 AddItemCraftedAbility(item, 'autogen_fixed_armor_base' );
5488 else
5489 AddItemCraftedAbility(item, 'autogen_armor_base' );
5490
5491 for( i=0; i<lvl; i+=1 )
5492 {
5493 if (FactsQuerySum("StandAloneEP1") > 0)
5494 {
5495 AddItemCraftedAbility(item, 'autogen_fixed_armor_armor', true );
5496 continue;
5497 }
5498
5499 if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag( item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 )
5500 AddItemCraftedAbility(item, 'autogen_fixed_armor_armor', true );
5501 else
5502 AddItemCraftedAbility(item, 'autogen_armor_armor', true );
5503 }
5504 }
5505 else if ( ( GetItemCategory( item ) == 'boots' || GetItemCategory( item ) == 'pants' ) && !( ItemHasAbility( item, 'autogen_pants_base' ) || ItemHasAbility( item, 'autogen_fixed_pants_base' ) ) ) // Pants and boots
5506 {
5507 if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_pants_base') )
5508 return;
5509
5510 if ( ItemHasTag(item, 'AutogenUseLevelRange') )
5511 AddItemCraftedAbility(item, 'autogen_fixed_pants_base' );
5512 else
5513 AddItemCraftedAbility(item, 'autogen_pants_base' );
5514
5515 for( i=0; i<lvl; i+=1 )
5516 {
5517 if (FactsQuerySum("StandAloneEP1") > 0)
5518 {
5519 AddItemCraftedAbility(item, 'autogen_fixed_pants_armor', true );
5520 continue;
5521 }
5522
5523 if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag( item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 )
5524 AddItemCraftedAbility(item, 'autogen_fixed_pants_armor', true );
5525 else
5526 AddItemCraftedAbility(item, 'autogen_pants_armor', true );
5527 }
5528 }
5529 else if ( GetItemCategory( item ) == 'gloves' && !( ItemHasAbility( item, 'autogen_gloves_base' ) || ItemHasAbility( item, 'autogen_fixed_gloves_base' ) ) ) // Gloves
5530 {
5531 if ( ItemHasTag(item, 'AutogenUseLevelRange') && ItemHasAbility(item, 'autogen_fixed_gloves_base') )
5532 return;
5533
5534 if ( ItemHasTag(item, 'AutogenUseLevelRange') )
5535 AddItemCraftedAbility(item, 'autogen_fixed_gloves_base' );
5536 else
5537 AddItemCraftedAbility(item, 'autogen_gloves_base' );
5538
5539 for( i=0; i<lvl; i+=1 )
5540 {
5541 if (FactsQuerySum("StandAloneEP1") > 0)
5542 {
5543 AddItemCraftedAbility(item, 'autogen_fixed_gloves_armor', true );
5544 continue;
5545 }
5546
5547 if ( ItemHasTag( item, 'AutogenForceLevel') || ItemHasTag(item, 'AutogenUseLevelRange') || FactsQuerySum("NewGamePlus") > 0 )
5548 AddItemCraftedAbility(item, 'autogen_fixed_gloves_armor', true );
5549 else
5550 AddItemCraftedAbility(item, 'autogen_gloves_armor', true );
5551 }
5552 }
5553 }
5554
5555 //Called AFTER the item was added to inventory
5556 event OnItemAdded(data : SItemChangedData)
5557 {
5558 var i, j : int;
5559 var ent : CGameplayEntity;
5560 var allCardsNames, foundCardsNames : array<name>;
5561 var allStringNamesOfCards : array<string>;
5562 var foundCardsStringNames : array<string>;
5563 var gwintCards : array<SItemUniqueId>;
5564 var itemName : name;
5565 var witcher : W3PlayerWitcher;
5566 var itemCategory : name;
5567 var dm : CDefinitionsManagerAccessor;
5568 var locKey : string;
5569 var leaderCardsHack : array<name>;
5570
5571 var hud : CR4ScriptedHud;
5572 var journalUpdateModule : CR4HudModuleJournalUpdate;
5573 var itemId : SItemUniqueId;
5574
5575 var isItemShematic : bool;
5576
5577 var ngp : bool;
5578
5579 ent = (CGameplayEntity)GetEntity();
5580
5581 itemId = data.ids[0];
5582
5583 //inform GUI
5584 if( data.informGui )
5585 {
5586 recentlyAddedItems.PushBack( itemId );
5587 if( ItemHasTag( itemId, 'FocusObject' ) )
5588 {
5589 GetWitcherPlayer().GetMedallion().Activate( true, 3.0);
5590 }
5591 }
5592
5593 //if item should be auto balanced - do it
5594 if ( ItemHasTag(itemId, 'Autogen') )
5595 {
5596 GenerateItemLevel( itemId, false );
5597 }
5598
5599 witcher = GetWitcherPlayer();
5600
5601 //Items with quality and stats change
5602 if(ent == witcher || ((W3MerchantNPC)ent) )
5603 {
5604 ngp = FactsQuerySum("NewGamePlus") > 0;
5605 for(i=0; i<data.ids.Size(); i+=1)
5606 {
5607 //Process items that do not have stats changed already
5608 if ( GetItemModifierInt(data.ids[i], 'ItemQualityModified') <= 0 )
5609 AddRandomEnhancementToItem(data.ids[i]);
5610 //Safeguard against unwanted level decrease for DLC items
5611 if ( ngp )
5612 SetItemModifierInt(data.ids[i], 'DoNotAdjustNGPDLC', 1);
5613
5614 itemName = GetItemName(data.ids[i]);
5615 // For NG+ items need to increase in level to match NG+
5616 if ( ngp && GetItemModifierInt(data.ids[i], 'NGPItemAdjusted') <= 0 && !ItemHasTag(data.ids[i], 'Autogen') )
5617 {
5618 IncreaseNGPItemlevel(data.ids[i]);
5619 }
5620
5621 }
5622 }
5623 if(ent == witcher)
5624 {
5625 for(i=0; i<data.ids.Size(); i+=1)
5626 {
5627 //if gwint card then progress achievement
5628 if( ItemHasTag( itemId, theGame.params.GWINT_CARD_ACHIEVEMENT_TAG ) || !FactsDoesExist( "fix_for_gwent_achievement_bug_121588" ) )
5629 {
5630 //Achievement hack for leaders as they use unique localisation key in XML
5631 leaderCardsHack.PushBack('gwint_card_emhyr_gold');
5632 leaderCardsHack.PushBack('gwint_card_emhyr_silver');
5633 leaderCardsHack.PushBack('gwint_card_emhyr_bronze');
5634 leaderCardsHack.PushBack('gwint_card_foltest_gold');
5635 leaderCardsHack.PushBack('gwint_card_foltest_silver');
5636 leaderCardsHack.PushBack('gwint_card_foltest_bronze');
5637 leaderCardsHack.PushBack('gwint_card_francesca_gold');
5638 leaderCardsHack.PushBack('gwint_card_francesca_silver');
5639 leaderCardsHack.PushBack('gwint_card_francesca_bronze');
5640 leaderCardsHack.PushBack('gwint_card_eredin_gold');
5641 leaderCardsHack.PushBack('gwint_card_eredin_silver');
5642 leaderCardsHack.PushBack('gwint_card_eredin_bronze');
5643
5644 dm = theGame.GetDefinitionsManager();
5645 //get max count from XML
5646 allCardsNames = theGame.GetDefinitionsManager().GetItemsWithTag(theGame.params.GWINT_CARD_ACHIEVEMENT_TAG);
5647
5648 //get all cards in inventory
5649 gwintCards = GetItemsByTag(theGame.params.GWINT_CARD_ACHIEVEMENT_TAG);
5650
5651 //Achievement hack for leaders as they use unique localisation key in XML
5652 allStringNamesOfCards.PushBack('gwint_name_emhyr');
5653 allStringNamesOfCards.PushBack('gwint_name_emhyr');
5654 allStringNamesOfCards.PushBack('gwint_name_emhyr');
5655 allStringNamesOfCards.PushBack('gwint_name_foltest');
5656 allStringNamesOfCards.PushBack('gwint_name_foltest');
5657 allStringNamesOfCards.PushBack('gwint_name_foltest');
5658 allStringNamesOfCards.PushBack('gwint_name_francesca');
5659 allStringNamesOfCards.PushBack('gwint_name_francesca');
5660 allStringNamesOfCards.PushBack('gwint_name_francesca');
5661 allStringNamesOfCards.PushBack('gwint_name_eredin');
5662 allStringNamesOfCards.PushBack('gwint_name_eredin');
5663 allStringNamesOfCards.PushBack('gwint_name_eredin');
5664
5665 //Count only UNIQUE cards (with the same localisation key name)
5666 for(j=0; j<allCardsNames.Size(); j+=1)
5667 {
5668 itemName = allCardsNames[j];
5669 locKey = dm.GetItemLocalisationKeyName(allCardsNames[j]);
5670 if (!allStringNamesOfCards.Contains(locKey))
5671 {
5672 allStringNamesOfCards.PushBack(locKey);
5673 }
5674 }
5675
5676 //If minimum amount needed for achievement (120 unique cards) - Count only UNIQUE cards (with the same localisation key name)
5677 if(gwintCards.Size() >= allStringNamesOfCards.Size())
5678 {
5679 foundCardsNames.Clear();
5680 for(j=0; j<gwintCards.Size(); j+=1)
5681 {
5682 itemName = GetItemName(gwintCards[j]);
5683 locKey = dm.GetItemLocalisationKeyName(itemName);
5684 // Hack for Leader Cards as they have the same loc key name
5685 if(!foundCardsStringNames.Contains(locKey) || leaderCardsHack.Contains(itemName))
5686 {
5687 foundCardsStringNames.PushBack(locKey);
5688 }
5689 }
5690
5691 if(foundCardsStringNames.Size() >= allStringNamesOfCards.Size())
5692 {
5693 theGame.GetGamerProfile().AddAchievement(EA_GwintCollector);
5694 FactsAdd("gwint_all_cards_collected", 1, -1);
5695 }
5696 }
5697
5698 if(!FactsDoesExist("fix_for_gwent_achievement_bug_121588"))
5699 FactsAdd("fix_for_gwent_achievement_bug_121588", 1, -1);
5700 }
5701
5702 itemCategory = GetItemCategory( itemId );
5703 isItemShematic = itemCategory == 'alchemy_recipe' || itemCategory == 'crafting_schematic';
5704
5705 if( isItemShematic )
5706 {
5707 ReadSchematicsAndRecipes( itemId );
5708 }
5709
5710 //gwent cards
5711 if( ItemHasTag( data.ids[i], 'GwintCard'))
5712 {
5713 witcher.AddGwentCard(GetItemName(data.ids[i]), data.quantity);
5714 }
5715
5716 // book
5717
5718 if( !isItemShematic && ( this.ItemHasTag( itemId, 'ReadableItem' ) || this.ItemHasTag( itemId, 'Painting' ) ) && !this.ItemHasTag( itemId, 'NoNotification' ) )
5719 {
5720 hud = (CR4ScriptedHud)theGame.GetHud();
5721 if( hud )
5722 {
5723 journalUpdateModule = (CR4HudModuleJournalUpdate)hud.GetHudModule( "JournalUpdateModule" );
5724 if( journalUpdateModule )
5725 {
5726 journalUpdateModule.AddQuestBookInfo( itemId );
5727 }
5728 }
5729 }
5730 }
5731 }
5732
5733 //singleton item ammo initialize
5734 if( IsItemSingletonItem( itemId ) )
5735 {
5736 for(i=0; i<data.ids.Size(); i+=1)
5737 {
5738 if(!GetItemModifierInt(data.ids[i], 'is_initialized', 0))
5739 {
5740 SingletonItemRefillAmmo(data.ids[i]);
5741 SetItemModifierInt(data.ids[i], 'is_initialized', 1);
5742 }
5743 }
5744 }
5745
5746 // ***** modScalingArmors
5747 if( isItemScalable(itemId) )
5748 thePlayer.GetInventory().GetItemLevel(itemId); // Makes sure the item level is set when you start playing
5749 // ***** modScalingArmors
5750 if(ent)
5751 ent.OnItemGiven(data);
5752 }
5753
5754 public function AddRandomEnhancementToItem(item : SItemUniqueId)
5755 {
5756 var itemCategory : name;
5757 var itemQuality : int;
5758 var ability : name;
5759 var ent : CGameplayEntity;
5760 //var dm : CDefinitionsManagerAccessor;
5761
5762 //dm = theGame.GetDefinitionsManager();
5763
5764 if( ItemHasTag(item, 'DoNotEnhance') )
5765 {
5766 SetItemModifierInt(item, 'ItemQualityModified', 1);
5767 return;
5768 }
5769
5770 itemCategory = GetItemCategory(item);
5771 itemQuality = RoundMath(CalculateAttributeValue(GetItemAttributeValue(item, 'quality' )));
5772
5773 if ( itemCategory == 'armor' )
5774 {
5775 switch ( itemQuality )
5776 {
5777 case 2 :
5778 ability = 'quality_masterwork_armor';
5779 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkArmorAbility(), true);
5780 break;
5781 case 3 :
5782 ability = 'quality_magical_armor';
5783 if ( ItemHasTag(item, 'EP1') )
5784 {
5785 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true);
5786 break;
5787 }
5788 // first ability
5789 if ( RandF() > 0.5 )
5790 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true);
5791 else
5792 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkArmorAbility(), true);
5793 //second ability
5794 if ( RandF() > 0.5 )
5795 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true);
5796 else
5797 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkArmorAbility(), true);
5798 break;
5799 default : break;
5800 }
5801 }
5802 else if ( itemCategory == 'gloves' )
5803 {
5804 switch ( itemQuality )
5805 {
5806 case 2 :
5807 ability = 'quality_masterwork_gloves';
5808 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkGlovesAbility(), true);
5809 break;
5810 case 3 :
5811 ability = 'quality_magical_gloves';
5812 if ( ItemHasTag(item, 'EP1') )
5813 {
5814 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true);
5815 break;
5816 }
5817 // first ability
5818 if ( RandF() > 0.5 )
5819 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalGlovesAbility(), true);
5820 else
5821 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkGlovesAbility(), true);
5822 //second ability
5823 if ( RandF() > 0.5 )
5824 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalGlovesAbility(), true);
5825 else
5826 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkGlovesAbility(), true);
5827 break;
5828 default : break;
5829 }
5830 }
5831 else if ( itemCategory == 'pants' )
5832 {
5833 switch ( itemQuality )
5834 {
5835 case 2 :
5836 ability = 'quality_masterwork_pants';
5837 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkPantsAbility(), true);
5838 break;
5839 case 3 :
5840 ability = 'quality_magical_pants';
5841 if ( ItemHasTag(item, 'EP1') )
5842 {
5843 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true);
5844 break;
5845 }
5846 // first ability
5847 if ( RandF() > 0.5 )
5848 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalPantsAbility(), true);
5849 else
5850 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkPantsAbility(), true);
5851 //second ability
5852 if ( RandF() > 0.5 )
5853 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalPantsAbility(), true);
5854 else
5855 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkPantsAbility(), true);
5856 break;
5857 default : break;
5858 }
5859 }
5860 else if ( itemCategory == 'boots' )
5861 {
5862 switch ( itemQuality )
5863 {
5864 case 2 :
5865 ability = 'quality_masterwork_boots';
5866 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkBootsAbility(), true);
5867 break;
5868 case 3 :
5869 ability = 'quality_magical_boots';
5870 if ( ItemHasTag(item, 'EP1') )
5871 {
5872 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true);
5873 break;
5874 }
5875 // first ability
5876 if ( RandF() > 0.5 )
5877 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalBootsAbility(), true);
5878 else
5879 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkBootsAbility(), true);
5880 //second ability
5881 if ( RandF() > 0.5 )
5882 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalBootsAbility(), true);
5883 else
5884 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkBootsAbility(), true);
5885 break;
5886 default : break;
5887 }
5888 }
5889 else if ( itemCategory == 'steelsword' )
5890 {
5891 switch ( itemQuality )
5892 {
5893 case 2 :
5894 ability = 'quality_masterwork_steelsword';
5895 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true);
5896 break;
5897 case 3 :
5898 ability = 'quality_magical_steelsword';
5899 if ( ItemHasTag(item, 'EP1') )
5900 {
5901 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true);
5902 break;
5903 }
5904 // first ability
5905 if ( RandF() > 0.5 )
5906 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true);
5907 else
5908 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true);
5909 //second ability
5910 if ( RandF() > 0.5 )
5911 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true);
5912 else
5913 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true);
5914 break;
5915 default : break;
5916 }
5917 }
5918 else if ( itemCategory == 'silversword' )
5919 {
5920 switch ( itemQuality )
5921 {
5922 case 2 :
5923 ability = 'quality_masterwork_silversword';
5924 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true);
5925 break;
5926 case 3 :
5927 ability = 'quality_magical_silversword';
5928 if ( ItemHasTag(item, 'EP1') )
5929 {
5930 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalArmorAbility(), true);
5931 break;
5932 }
5933 // first ability
5934 if ( RandF() > 0.5 )
5935 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true);
5936 else
5937 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true);
5938 //second ability
5939 if ( RandF() > 0.5 )
5940 AddItemCraftedAbility(item, theGame.params.GetRandomMagicalWeaponAbility(), true);
5941 else
5942 AddItemCraftedAbility(item, theGame.params.GetRandomMasterworkWeaponAbility(), true);
5943 break;
5944
5945 default : break;
5946 }
5947 }
5948
5949 if(IsNameValid(ability))
5950 {
5951 AddItemCraftedAbility(item, ability, false);
5952 SetItemModifierInt(item, 'ItemQualityModified', 1);
5953 }
5954 }
5955
5956 public function IncreaseNGPItemlevel(item : SItemUniqueId)
5957 {
5958 var i, diff : int;
5959
5960 diff = theGame.params.NewGamePlusLevelDifference();
5961
5962 if (diff > 0)
5963 {
5964 if ( ItemHasTag( item, 'PlayerSteelWeapon' ) ) // STEEL SWORD
5965 {
5966 for( i=0; i<diff; i+=1 )
5967 {
5968 AddItemCraftedAbility(item, 'autogen_fixed_steel_dmg', true );
5969 }
5970 }
5971 else if ( ItemHasTag( item, 'PlayerSilverWeapon' ) ) // SILVER SWORD
5972 {
5973 for( i=0; i<diff; i+=1 )
5974 {
5975 AddItemCraftedAbility(item, 'autogen_fixed_silver_dmg', true );
5976 }
5977 }
5978 else if ( IsItemChestArmor(item) ) // Armor
5979 {
5980 for( i=0; i<diff; i+=1 )
5981 {
5982 AddItemCraftedAbility(item, 'autogen_fixed_armor_armor', true );
5983 }
5984 }
5985 else if ( IsItemBoots(item) || IsItemPants(item) ) // Pants and boots
5986 {
5987 for( i=0; i<diff; i+=1 )
5988 {
5989 AddItemCraftedAbility(item, 'autogen_fixed_pants_armor', true );
5990 }
5991 }
5992 else if ( IsItemGloves(item) ) // Gloves
5993 {
5994 for( i=0; i<diff; i+=1 )
5995 {
5996 AddItemCraftedAbility(item, 'autogen_fixed_gloves_armor', true );
5997 }
5998 }
5999 }
6000
6001 SetItemModifierInt(item, 'NGPItemAdjusted', 1);
6002 }
6003
6004 public function GetItemQuality( itemId : SItemUniqueId ) : int
6005 {
6006 var itemQuality : float;
6007 var itemQualityAtribute : SAbilityAttributeValue;
6008 var excludedTags : array<name>;
6009 var tempItemQualityAtribute : SAbilityAttributeValue;
6010
6011 //get attribute but exclude attribute value of applied oil!!
6012 excludedTags.PushBack(theGame.params.OIL_ABILITY_TAG);
6013 itemQualityAtribute = GetItemAttributeValue( itemId, 'quality', excludedTags, true );
6014
6015 itemQuality = itemQualityAtribute.valueAdditive;
6016 if( itemQuality == 0 )
6017 {
6018 itemQuality = 1;
6019 }
6020 return RoundMath(itemQuality);
6021 }
6022
6023 public function GetItemQualityFromName( itemName : name, out min : int, out max : int)
6024 {
6025 var dm : CDefinitionsManagerAccessor;
6026 var attributeName : name;
6027 var attributes, itemAbilities : array<name>;
6028 var attributeMin, attributeMax : SAbilityAttributeValue;
6029
6030 var tmpInt : int;
6031 var tmpArray : array<float>;
6032
6033 dm = theGame.GetDefinitionsManager();
6034
6035 dm.GetItemAbilitiesWithWeights(itemName, GetEntity() == thePlayer, itemAbilities, tmpArray, tmpInt, tmpInt);
6036 attributes = dm.GetAbilitiesAttributes(itemAbilities);
6037 for (tmpInt = 0; tmpInt < attributes.Size(); tmpInt += 1)
6038 {
6039 if (attributes[tmpInt] == 'quality')
6040 {
6041 dm.GetAbilitiesAttributeValue(itemAbilities, 'quality', attributeMin, attributeMax);
6042 min = RoundMath(CalculateAttributeValue(attributeMin));
6043 max = RoundMath(CalculateAttributeValue(attributeMax));
6044 break;
6045 }
6046 }
6047 }
6048
6049 public function GetRecentlyAddedItems() : array<SItemUniqueId> //#B
6050 {
6051 return recentlyAddedItems;
6052 }
6053
6054 public function GetRecentlyAddedItemsListSize() : int //#B
6055 {
6056 return recentlyAddedItems.Size();
6057 }
6058
6059 public function RemoveItemFromRecentlyAddedList( itemId : SItemUniqueId ) : bool //#B
6060 {
6061 var i : int;
6062
6063 for( i = 0; i < recentlyAddedItems.Size(); i += 1 )
6064 {
6065 if( recentlyAddedItems[i] == itemId )
6066 {
6067 recentlyAddedItems.EraseFast( i );
6068 return true;
6069 }
6070 }
6071
6072 return false;
6073 }
6074
6075 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6076 // callbacks
6077
6078 import final function NotifyScriptedListeners( notify : bool );
6079
6080 var listeners : array< IInventoryScriptedListener >;
6081
6082 function AddListener( listener : IInventoryScriptedListener )
6083 {
6084 if ( listeners.FindFirst( listener ) == -1 )
6085 {
6086 listeners.PushBack( listener );
6087 if ( listeners.Size() == 1 )
6088 {
6089 NotifyScriptedListeners( true );
6090 }
6091 }
6092 }
6093
6094 function RemoveListener( listener : IInventoryScriptedListener )
6095 {
6096 if ( listeners.Remove( listener ) )
6097 {
6098 if ( listeners.Size() == 0 )
6099 {
6100 NotifyScriptedListeners( false );
6101 }
6102 }
6103 }
6104
6105 event OnInventoryScriptedEvent( eventType : EInventoryEventType, itemId : SItemUniqueId, quantity : int, fromAssociatedInventory : bool )
6106 {
6107 var i, size : int;
6108
6109 size = listeners.Size();
6110 for (i=size-1; i>=0; i-=1 ) //it seems listeners erase themselves so array iterator gets corrupted
6111 {
6112 listeners[i].OnInventoryScriptedEvent( eventType, itemId, quantity, fromAssociatedInventory );
6113 }
6114
6115 //update encumbrance
6116 if(GetEntity() == GetWitcherPlayer() && (eventType == IET_ItemRemoved || eventType == IET_ItemQuantityChanged) )
6117 GetWitcherPlayer().UpdateEncumbrance();
6118 }
6119
6120 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6121 //////////////////////////////////// @MUTAGENS /////////////////////////////////////////////////////////////////
6122 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6123 public final function GetMutationResearchPoints( color : ESkillColor, item : SItemUniqueId ) : int
6124 {
6125 var val : SAbilityAttributeValue;
6126 var colorAttribute : name;
6127
6128 //wrong input
6129 if( color == SC_None || color == SC_Yellow || !IsIdValid( item ) )
6130 {
6131 return 0;
6132 }
6133
6134 //get attribute name
6135 switch( color )
6136 {
6137 case SC_Red:
6138 colorAttribute = 'mutation_research_points_red';
6139 break;
6140 case SC_Blue:
6141 colorAttribute = 'mutation_research_points_blue';
6142 break;
6143 case SC_Green:
6144 colorAttribute = 'mutation_research_points_green';
6145 break;
6146 }
6147
6148 //get value
6149 val = GetItemAttributeValue( item, colorAttribute );
6150
6151 return ( int )val.valueAdditive;
6152 }
6153
6154 public function GetSkillMutagenColor(item : SItemUniqueId) : ESkillColor
6155 {
6156 var abs : array<name>;
6157
6158 //not a mutagen ingredient
6159 if(!ItemHasTag(item, 'MutagenIngredient'))
6160 return SC_None;
6161
6162 GetItemAbilities(item, abs);
6163
6164 if(abs.Contains('mutagen_color_green')) return SC_Green;
6165 if(abs.Contains('mutagen_color_blue')) return SC_Blue;
6166 if(abs.Contains('mutagen_color_red')) return SC_Red;
6167 if(abs.Contains('lesser_mutagen_color_green')) return SC_Green;
6168 if(abs.Contains('lesser_mutagen_color_blue')) return SC_Blue;
6169 if(abs.Contains('lesser_mutagen_color_red')) return SC_Red;
6170 if(abs.Contains('greater_mutagen_color_green')) return SC_Green;
6171 if(abs.Contains('greater_mutagen_color_blue')) return SC_Blue;
6172 if(abs.Contains('greater_mutagen_color_red')) return SC_Red;
6173
6174 return SC_None;
6175 }
6176
6177 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6178 //////////////////////////////////// @Enhancements /////////////////////////////////////////////////////////////
6179 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6180
6181 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6182 //
6183 // FUNCTIONS YOU ALWAYS WANTED TO KNOW, BUT NOBODY TOLD YOU ABOUT THEM - ITEM SOCKETS
6184 //
6185 import final function GetItemEnhancementSlotsCount( itemId : SItemUniqueId ) : int;
6186 import final function GetItemEnhancementItems( itemId : SItemUniqueId, out names : array< name > );
6187 import final function GetItemEnhancementCount( itemId : SItemUniqueId ) : int;
6188 import final function GetItemColor( itemId : SItemUniqueId ) : name;
6189 import final function IsItemColored( itemId : SItemUniqueId ) : bool;
6190 import final function SetPreviewColor( itemId : SItemUniqueId, colorId : int );
6191 import final function ClearPreviewColor( itemId : SItemUniqueId ) : bool;
6192 import final function ColorItem( itemId : SItemUniqueId, dyeId : SItemUniqueId );
6193 import final function ClearItemColor( itemId : SItemUniqueId ) : bool;
6194 import final function EnchantItem( enhancedItemId : SItemUniqueId, enchantmentName : name, enchantmentStat : name ) : bool;
6195 import final function GetEnchantment( enhancedItemId : SItemUniqueId ) : name;
6196 import final function IsItemEnchanted( enhancedItemId : SItemUniqueId ) : bool;
6197 import final function UnenchantItem( enhancedItemId : SItemUniqueId ) : bool;
6198 import private function EnhanceItem( enhancedItemId : SItemUniqueId, extensionItemId : SItemUniqueId ) : bool;
6199 import private function RemoveItemEnhancementByIndex( enhancedItemId : SItemUniqueId, slotIndex : int ) : bool;
6200 import private function RemoveItemEnhancementByName( enhancedItemId : SItemUniqueId, extensionItemName : name ) : bool;
6201 import final function PreviewItemAttributeAfterUpgrade( baseItemId : SItemUniqueId, upgradeItemId : SItemUniqueId, attributeName : name, optional baseInventory : CInventoryComponent, optional upgradeInventory : CInventoryComponent ) : SAbilityAttributeValue;
6202 import final function HasEnhancementItemTag( enhancedItemId : SItemUniqueId, slotIndex : int, tag : name ) : bool;
6203
6204
6205 function NotifyEnhancedItem( enhancedItemId : SItemUniqueId )
6206 {
6207 var weapons : array<SItemUniqueId>;
6208 var sword : CWitcherSword;
6209 var i : int;
6210
6211 sword = (CWitcherSword) GetItemEntityUnsafe( enhancedItemId );
6212 sword.UpdateEnhancements( this );
6213 }
6214
6215 function EnhanceItemScript( enhancedItemId : SItemUniqueId, extensionItemId : SItemUniqueId ) : bool
6216 {
6217 var i : int;
6218 var enhancements : array<name>;
6219 var runeword : Runeword;
6220
6221 if ( EnhanceItem( enhancedItemId, extensionItemId ) )
6222 {
6223 NotifyEnhancedItem( enhancedItemId );
6224 // Check runeword
6225 GetItemEnhancementItems( enhancedItemId, enhancements );
6226 if ( theGame.runewordMgr.GetRuneword( enhancements, runeword ) )
6227 {
6228 for ( i = 0; i < runeword.abilities.Size(); i+=1 )
6229 {
6230 AddItemBaseAbility( enhancedItemId, runeword.abilities[i] );
6231 }
6232 }
6233 return true;
6234 }
6235 return false;
6236 }
6237
6238 function RemoveItemEnhancementByIndexScript( enhancedItemId : SItemUniqueId, slotIndex : int ) : bool
6239 {
6240 var i : int;
6241 var enhancements : array<name>;
6242 var runeword : Runeword;
6243 var hasRuneword : bool;
6244 var names : array< name >;
6245
6246 GetItemEnhancementItems( enhancedItemId, enhancements );
6247 hasRuneword = theGame.runewordMgr.GetRuneword( enhancements, runeword );
6248
6249 GetItemEnhancementItems( enhancedItemId, names );
6250
6251 if ( RemoveItemEnhancementByIndex( enhancedItemId, slotIndex ) )
6252 {
6253 NotifyEnhancedItem( enhancedItemId );
6254
6255 //Readd rune to inventory
6256 //AddAnItem( names[slotIndex], 1, true, true );
6257 if ( hasRuneword )
6258 {
6259 //Remove runeword
6260 for ( i = 0; i < runeword.abilities.Size(); i+=1 )
6261 {
6262 RemoveItemBaseAbility( enhancedItemId, runeword.abilities[i] );
6263 }
6264 }
6265 return true;
6266 }
6267 return false;
6268 }
6269
6270
6271 function RemoveItemEnhancementByNameScript( enhancedItemId : SItemUniqueId, extensionItemName : name ) : bool
6272 {
6273 var i : int;
6274 var enhancements : array<name>;
6275 var runeword : Runeword;
6276 var hasRuneword : bool;
6277
6278 GetItemEnhancementItems( enhancedItemId, enhancements );
6279 hasRuneword = theGame.runewordMgr.GetRuneword( enhancements, runeword );
6280
6281 //check runeword
6282 if ( RemoveItemEnhancementByName( enhancedItemId, extensionItemName ) )
6283 {
6284 NotifyEnhancedItem( enhancedItemId );
6285
6286 //Readd rune to inventory
6287 AddAnItem( extensionItemName, 1, true, true );
6288 if ( hasRuneword )
6289 {
6290 //Remove runeword
6291 for ( i = 0; i < runeword.abilities.Size(); i+=1 )
6292 {
6293 RemoveItemBaseAbility( enhancedItemId, runeword.abilities[i] );
6294 }
6295 }
6296 return true;
6297 }
6298 return false;
6299 }
6300
6301 function RemoveAllItemEnhancements( enhancedItemId : SItemUniqueId )
6302 {
6303 var count, i : int;
6304
6305 count = GetItemEnhancementCount( enhancedItemId );
6306 for ( i = count - 1; i >= 0; i-=1 )
6307 {
6308 RemoveItemEnhancementByIndexScript( enhancedItemId, i );
6309 }
6310 }
6311
6312 function GetHeldAndMountedItems( out items : array< SItemUniqueId > )
6313 {
6314 var allItems : array< SItemUniqueId >;
6315 var i : int;
6316 var itemName : name;
6317
6318 GetAllItems( allItems );
6319
6320 items.Clear();
6321 for( i = 0; i < allItems.Size(); i += 1 )
6322 {
6323 if ( IsItemHeld( allItems[ i ] ) || IsItemMounted( allItems[ i ] ) )
6324 {
6325 items.PushBack( allItems[ i ] );
6326 }
6327 }
6328 }
6329
6330 //Check if this inventory components have any valid items for an armor stand, moved here since it's also used in UI popup
6331 public function GetHasValidDecorationItems( items : array<SItemUniqueId>, decoration : W3HouseDecorationBase ) : bool
6332 {
6333 var i, size : int;
6334
6335 size = items.Size();
6336
6337 //No valid items were found in the inventory
6338 if(size == 0 )
6339 {
6340 LogChannel( 'houseDecorations', "No items with valid tag were found!" );
6341 return false;
6342 }
6343
6344 //Filter out all items that are not valid but have the tag
6345 for( i=0; i < size; i+= 1 )
6346 {
6347 //Exclude equipped items
6348 if( GetWitcherPlayer().IsItemEquipped( items[i] ) )
6349 {
6350 LogChannel( 'houseDecorations', "Found item is equipped, erasing..." );
6351 continue;
6352 }
6353
6354 //If items m_acceptQuestItems is false exclude all quest items
6355 if( IsItemQuest( items[i] ) && decoration.GetAcceptQuestItems() == false )
6356 {
6357 LogChannel( 'houseDecorations', "Found item is quest item, and quest items are not accepted, erasing..." );
6358 continue;
6359 }
6360
6361 //If the item has a forbiden tag
6362 if( decoration.GetItemHasForbiddenTag( items[i] ) )
6363 {
6364 LogChannel( 'houseDecorations', "Found item has a forbidden tag, erasing..." );
6365 continue;
6366 }
6367
6368 LogChannel( 'houseDecorations', "Item checks out: "+ GetItemName( items[i] ) );
6369 return true;
6370 }
6371 LogChannel( 'houseDecorations', "No valid items were found!" );
6372
6373 return false;
6374 }
6375
6376 //Checks all defined cards against player's collected cards and Gwent Collector Achievement condition, returns missing cards
6377 function GetMissingCards() : array< name >
6378 {
6379 var defMgr : CDefinitionsManagerAccessor = theGame.GetDefinitionsManager();
6380 var allCardNames : array< name > = defMgr.GetItemsWithTag(theGame.params.GWINT_CARD_ACHIEVEMENT_TAG);
6381 var playersCards : array< SItemUniqueId > = GetItemsByTag(theGame.params.GWINT_CARD_ACHIEVEMENT_TAG);
6382 var playersCardLocs : array< string >;
6383 var missingCardLocs : array< string >;
6384 var missingCards : array< name >;
6385 var i, j : int;
6386 var found : bool;
6387
6388 //divide all cards between found and not found, based on item names (not localization keys)
6389 for ( i = 0; i < allCardNames.Size(); i+=1 )
6390 {
6391 found = false;
6392
6393 for ( j = 0; j < playersCards.Size(); j+=1 )
6394 {
6395 if ( allCardNames[i] == GetItemName( playersCards[j] ) )
6396 {
6397 found = true;
6398 playersCardLocs.PushBack( defMgr.GetItemLocalisationKeyName ( allCardNames[i] ) );
6399 break;
6400 }
6401 }
6402
6403 if ( !found )
6404 {
6405 missingCardLocs.PushBack( defMgr.GetItemLocalisationKeyName( allCardNames[i] ) );
6406 missingCards.PushBack( allCardNames[i] );
6407 }
6408 }
6409
6410 if( missingCardLocs.Size() < 2 )
6411 {
6412 return missingCards;
6413 }
6414
6415 //remove from missingCards the ones the player's got, based on localization keys so non-achievement cards are also removed
6416 for ( i = missingCardLocs.Size()-1 ; i >= 0 ; i-=1 )
6417 {
6418 for ( j = 0 ; j < playersCardLocs.Size() ; j+=1 )
6419 {
6420 if ( missingCardLocs[i] == playersCardLocs[j]
6421 && missingCardLocs[i] != "gwint_name_emhyr" && missingCardLocs[i] != "gwint_name_foltest"
6422 && missingCardLocs[i] != "gwint_name_francesca" && missingCardLocs[i] != "gwint_name_eredin" )
6423 {
6424 missingCardLocs.EraseFast( i );
6425 missingCards.EraseFast( i );
6426 break;
6427 }
6428 }
6429 }
6430
6431 return missingCards;
6432 }
6433
6434 public function FindCardSources( missingCards : array< name > ) : array< SCardSourceData >
6435 {
6436 var sourceCSV : C2dArray;
6437 var sourceTable : array< SCardSourceData >;
6438 var sourceRemaining : array< SCardSourceData >;
6439 var sourceCount, i, j : int;
6440
6441 if ( theGame.IsFinalBuild() )
6442 {
6443 sourceCSV = LoadCSV("gameplay\globals\card_sources.csv");
6444 }
6445 else
6446 {
6447 sourceCSV = LoadCSV("qa\card_sources.csv");
6448 }
6449
6450 sourceCount = sourceCSV.GetNumRows();
6451 sourceTable.Resize(sourceCount);
6452
6453 for ( i = 0 ; i < sourceCount ; i+=1 )
6454 {
6455 sourceTable[i].cardName = sourceCSV.GetValueAsName("CardName",i);
6456 sourceTable[i].source = sourceCSV.GetValue("Source",i);
6457 sourceTable[i].originArea = sourceCSV.GetValue("OriginArea",i);
6458 sourceTable[i].originQuest = sourceCSV.GetValue("OriginQuest",i);
6459 sourceTable[i].details = sourceCSV.GetValue("Details",i);
6460 sourceTable[i].coords = sourceCSV.GetValue("Coords",i);
6461 }
6462
6463 for ( i = 0 ; i < missingCards.Size() ; i+=1 )
6464 {
6465 for ( j = 0 ; j < sourceCount ; j+=1 )
6466 {
6467 if ( sourceTable[j].cardName == missingCards[i] )
6468 {
6469 sourceRemaining.PushBack( sourceTable[j] );
6470 }
6471 }
6472 }
6473
6474 return sourceRemaining;
6475 }
6476
6477 public function GetGwentAlmanacContents() : string
6478 {
6479 var sourcesRemaining : array< SCardSourceData >;
6480 var missingCards : array< string >;
6481 var almanacContents : string;
6482 var i : int;
6483 var NML, Novigrad, Skellige, Prologue, Vizima, KaerMorhen, Random : int;
6484
6485 sourcesRemaining = FindCardSources( GetMissingCards() );
6486
6487 for ( i = 0 ; i < sourcesRemaining.Size() ; i+=1 )
6488 {
6489 switch ( sourcesRemaining[i].originArea )
6490 {
6491 case "NML":
6492 NML += 1;
6493 break;
6494 case "Novigrad":
6495 Novigrad += 1;
6496 break;
6497 case "Skellige":
6498 Skellige += 1;
6499 break;
6500 case "Prologue":
6501 Prologue += 1;
6502 break;
6503 case "Vizima":
6504 Vizima += 1;
6505 break;
6506 case "KaerMorhen":
6507 KaerMorhen += 1;
6508 break;
6509 case "Random":
6510 Random += 1;
6511 break;
6512 default:
6513 break;
6514 }
6515 }
6516
6517 if ( NML + Novigrad + Skellige + Prologue + Vizima + KaerMorhen + Random == 0 )
6518 {
6519 almanacContents = GetLocStringByKeyExt( "gwent_almanac_text" ) + "<br>";
6520 almanacContents += GetLocStringByKeyExt( "gwent_almanac_completed_text" );
6521 }
6522 else
6523 {
6524 almanacContents = GetLocStringByKeyExt( "gwent_almanac_text" ) + "<br>";
6525 if ( NML > 0 )
6526 {
6527 almanacContents += GetLocStringByKeyExt( "location_name_velen" ) + ": " + NML + "<br>";
6528 }
6529 if ( Novigrad > 0 )
6530 {
6531 almanacContents += GetLocStringByKeyExt( "map_location_novigrad" ) + ": " + Novigrad + "<br>";
6532 }
6533 if ( Skellige > 0 )
6534 {
6535 almanacContents += GetLocStringByKeyExt( "map_location_skellige" ) + ": " + Skellige + "<br>";
6536 }
6537 if ( Prologue > 0 )
6538 {
6539 almanacContents += GetLocStringByKeyExt( "map_location_prolog_village" ) + ": " + Prologue + "<br>";
6540 }
6541 if ( Vizima > 0 )
6542 {
6543 almanacContents += GetLocStringByKeyExt( "map_location_wyzima_castle" ) + ": " + Vizima + "<br>";
6544 }
6545 if ( KaerMorhen > 0 )
6546 {
6547 almanacContents += GetLocStringByKeyExt( "map_location_kaer_morhen" ) + ": " + KaerMorhen + "<br>";
6548 }
6549 almanacContents += GetLocStringByKeyExt( "gwent_source_random" ) + ": " + Random;
6550 }
6551
6552 return almanacContents;
6553 }
6554}
6555
6556exec function findMissingCards( optional card : name )
6557{
6558 var inv : CInventoryComponent = thePlayer.GetInventory();
6559 var sourcesRemaining : array< SCardSourceData >;
6560 var missingCards : array< name >;
6561 var i : int;
6562 var sourceLogString : string;
6563
6564 if ( card != '' )
6565 {
6566 missingCards.PushBack( card );
6567 }
6568 else
6569 {
6570 missingCards = inv.GetMissingCards();
6571 }
6572
6573 sourcesRemaining = inv.FindCardSources( missingCards );
6574
6575 for ( i = 0 ; i < sourcesRemaining.Size() ; i+=1 )
6576 {
6577 sourceLogString = sourcesRemaining[i].cardName + " is a " + sourcesRemaining[i].source ;
6578 if ( sourcesRemaining[i].originArea == "Random" )
6579 {
6580 sourceLogString += " card from a random merchant.";
6581 }
6582 else
6583 {
6584 sourceLogString += " item in " + sourcesRemaining[i].originArea + " from ";
6585
6586 if ( sourcesRemaining[i].originQuest != "" )
6587 {
6588 sourceLogString += sourcesRemaining[i].originQuest + " , ";
6589 }
6590
6591 sourceLogString += sourcesRemaining[i].details;
6592 }
6593 Log( sourceLogString );
6594
6595 if ( sourcesRemaining[i].coords != "" )
6596 {
6597 Log( sourcesRemaining[i].coords );
6598 }
6599 }
6600}
6601
6602exec function slotTest()
6603{
6604 var inv : CInventoryComponent = thePlayer.inv;
6605 var weaponItemId : SItemUniqueId;
6606 var upgradeItemId : SItemUniqueId;
6607 var i : int;
6608
6609 LogChannel('SlotTest', "----------------------------------------------------------------");
6610
6611 // add upgrades
6612 inv.AddAnItem( 'Perun rune', 1);
6613 inv.AddAnItem( 'Svarog rune', 1);
6614
6615
6616 for ( i = 0; i < 2; i += 1 )
6617 {
6618 // get 'Long Steel Sword'
6619 if ( !GetItem( inv, 'steelsword', weaponItemId ) ||
6620 !GetItem( inv, 'upgrade', upgradeItemId ) )
6621 {
6622 return;
6623 }
6624
6625 // print
6626 PrintItem( inv, weaponItemId );
6627
6628 // enhance
6629 if ( inv.EnhanceItemScript( weaponItemId, upgradeItemId ) )
6630 {
6631 LogChannel('SlotTest', "Enhanced item");
6632 }
6633 else
6634 {
6635 LogChannel('SlotTest', "Failed to enhance item!");
6636 }
6637 }
6638
6639 // get item again
6640 if ( !GetItem( inv, 'steelsword', weaponItemId ) )
6641 {
6642 return;
6643 }
6644
6645 // print
6646 PrintItem( inv, weaponItemId );
6647
6648 // remove enhancement by name
6649 if ( inv.RemoveItemEnhancementByNameScript( weaponItemId, 'Svarog rune' ) )
6650 {
6651 LogChannel('SlotTest', "Removed enhancement");
6652 }
6653 else
6654 {
6655 LogChannel('SlotTest', "Failed to remove enhancement!");
6656 }
6657
6658 // get item again
6659 if ( !GetItem( inv, 'steelsword', weaponItemId ) )
6660 {
6661 return;
6662 }
6663
6664 // print
6665 PrintItem( inv, weaponItemId );
6666
6667 // remove enhancement by index
6668 if ( inv.RemoveItemEnhancementByIndexScript( weaponItemId, 0 ) )
6669 {
6670 LogChannel('SlotTest', "Removed enhancement");
6671 }
6672 else
6673 {
6674 LogChannel('SlotTest', "Failed to remove enhancement!");
6675 }
6676
6677 // get item again
6678 if ( !GetItem( inv, 'steelsword', weaponItemId ) )
6679 {
6680 return;
6681 }
6682
6683 // print
6684 PrintItem( inv, weaponItemId );
6685}
6686
6687function GetItem( inv : CInventoryComponent, category : name, out itemId : SItemUniqueId ) : bool
6688{
6689 var itemIds : array< SItemUniqueId >;
6690
6691 itemIds = inv.GetItemsByCategory( category );
6692 if ( itemIds.Size() > 0 )
6693 {
6694 itemId = itemIds[ 0 ];
6695 return true;
6696 }
6697 LogChannel( 'SlotTest', "Failed to get item with GetItemsByCategory( '" + category + "' )" );
6698 return false;
6699}
6700
6701function PrintItem( inv : CInventoryComponent, weaponItemId : SItemUniqueId )
6702{
6703 var names : array< name >;
6704 var tags : array< name >;
6705 var i : int;
6706 var line : string;
6707 var attribute : SAbilityAttributeValue;
6708
6709 LogChannel('SlotTest', "Slots: " + inv.GetItemEnhancementCount( weaponItemId ) + "/" + inv.GetItemEnhancementSlotsCount( weaponItemId ) );
6710 inv.GetItemEnhancementItems( weaponItemId, names );
6711 if ( names.Size() > 0 )
6712 {
6713 for ( i = 0; i < names.Size(); i += 1 )
6714 {
6715 if ( i == 0 )
6716 {
6717 line += "[";
6718 }
6719 line += names[ i ];
6720 if ( i < names.Size() - 1 )
6721 {
6722 line += ", ";
6723 }
6724 if ( i == names.Size() - 1 )
6725 {
6726 line += "]";
6727 }
6728 }
6729 }
6730 else
6731 {
6732 line += "[]";
6733 }
6734 LogChannel('SlotTest', "Upgrade item names " + line );
6735
6736 tags.PushBack('Upgrade');
6737
6738 attribute = inv.GetItemAttributeValue( weaponItemId, 'PhysicalDamage' );
6739 LogChannel('SlotTest', "Attribute '" + 'PhysicalDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive );
6740 attribute = inv.GetItemAttributeValue( weaponItemId, 'SilverDamage' );
6741 LogChannel('SlotTest', "Attribute '" + 'SilverDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive );
6742
6743 attribute = inv.GetItemAttributeValue( weaponItemId, 'PhysicalDamage', tags, true );
6744 LogChannel('SlotTest', "Attribute '" + 'PhysicalDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive );
6745 attribute = inv.GetItemAttributeValue( weaponItemId, 'SilverDamage', tags, true );
6746 LogChannel('SlotTest', "Attribute '" + 'SilverDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive );
6747
6748 attribute = inv.GetItemAttributeValue( weaponItemId, 'PhysicalDamage', tags );
6749 LogChannel('SlotTest', "Attribute '" + 'PhysicalDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive );
6750 attribute = inv.GetItemAttributeValue( weaponItemId, 'SilverDamage', tags );
6751 LogChannel('SlotTest', "Attribute '" + 'SilverDamage' + "' " + attribute.valueBase + " " + attribute.valueMultiplicative + " " + attribute.valueAdditive );
6752
6753}
6754
6755function PlayItemEquipSound( itemCategory : name ) : void // #B
6756{
6757 switch( itemCategory )
6758 {
6759 case 'steelsword' :
6760 theSound.SoundEvent("gui_inventory_steelsword_attach");
6761 return;
6762 case 'silversword' :
6763 theSound.SoundEvent("gui_inventory_silversword_attach");
6764 return;
6765 case 'secondary' :
6766 theSound.SoundEvent("gui_inventory_weapon_attach");
6767 return;
6768 case 'armor' :
6769 theSound.SoundEvent("gui_inventory_armor_attach");
6770 return;
6771 case 'pants' :
6772 theSound.SoundEvent("gui_inventory_pants_attach");
6773 return;
6774 case 'boots' :
6775 theSound.SoundEvent("gui_inventory_boots_attach");
6776 return;
6777 case 'gloves' :
6778 theSound.SoundEvent("gui_inventory_gauntlet_attach");
6779 return;
6780 case 'potion' :
6781 theSound.SoundEvent("gui_inventory_potion_attach");
6782 return;
6783 case 'petard' :
6784 theSound.SoundEvent("gui_inventory_bombs_attach");
6785 return;
6786 case 'ranged' :
6787 theSound.SoundEvent("gui_inventory_ranged_attach");
6788 return;
6789 case 'herb' :
6790 theSound.SoundEvent("gui_pick_up_herbs");
6791 return;
6792 case 'trophy' :
6793 case 'horse_bag' :
6794 theSound.SoundEvent("gui_inventory_horse_bage_attach");
6795 return;
6796 case 'horse_blinder' :
6797 theSound.SoundEvent("gui_inventory_horse_blinder_attach");
6798 return;
6799 case 'horse_saddle' :
6800 theSound.SoundEvent("gui_inventory_horse_saddle_attach");
6801 return;
6802 default :
6803 theSound.SoundEvent("gui_inventory_other_attach");
6804 return;
6805 }
6806}
6807
6808function PlayItemUnequipSound( itemCategory : name ) : void // #B
6809{
6810 switch( itemCategory )
6811 {
6812 case 'steelsword' :
6813 theSound.SoundEvent("gui_inventory_steelsword_back");
6814 return;
6815 case 'silversword' :
6816 theSound.SoundEvent("gui_inventory_silversword_back");
6817 return;
6818 case 'secondary' :
6819 theSound.SoundEvent("gui_inventory_weapon_back");
6820 return;
6821 case 'armor' :
6822 theSound.SoundEvent("gui_inventory_armor_back");
6823 return;
6824 case 'pants' :
6825 theSound.SoundEvent("gui_inventory_pants_back");
6826 return;
6827 case 'boots' :
6828 theSound.SoundEvent("gui_inventory_boots_back");
6829 return;
6830 case 'gloves' :
6831 theSound.SoundEvent("gui_inventory_gauntlet_back");
6832 return;
6833 case 'petard' :
6834 theSound.SoundEvent("gui_inventory_bombs_back");
6835 return;
6836 case 'potion' :
6837 theSound.SoundEvent("gui_inventory_potion_back");
6838 return;
6839 case 'ranged' :
6840 theSound.SoundEvent("gui_inventory_ranged_back");
6841 return;
6842 case 'trophy' :
6843 case 'horse_bag' :
6844 theSound.SoundEvent("gui_inventory_horse_bage_back");
6845 return;
6846 case 'horse_blinder' :
6847 theSound.SoundEvent("gui_inventory_horse_blinder_back");
6848 return;
6849 case 'horse_saddle' :
6850 theSound.SoundEvent("gui_inventory_horse_saddle_back");
6851 return;
6852 default :
6853 theSound.SoundEvent("gui_inventory_other_back");
6854 return;
6855 }
6856}
6857
6858function PlayItemConsumeSound( item : SItemUniqueId ) : void
6859{
6860 if( thePlayer.GetInventory().ItemHasTag( item, 'Drinks' ) || thePlayer.GetInventory().ItemHasTag( item, 'Alcohol' ) )
6861 {
6862 theSound.SoundEvent('gui_inventory_drink');
6863 }
6864 else
6865 {
6866 theSound.SoundEvent('gui_inventory_eat');
6867 }
6868}