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