• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[GUI Friendly] Item Fusion Shop

Item Fusion Shop is a System to register item merging to get another, in most cases better, item. That item merging is often used in AoS (moba) maps.
The Item merging is not done automatically when an unit pickups all mats. No the user has to order the merging inside Item Fusion shop, which looks and feels like visiting a warcraft 3 shop. If an item has many upgrades the shop gets a page conrol allowing to change the currently shown 9 upgrade options.
Upgrade options display the requiered mats and the gold to instantly buy it.
(in 1.6 and below that was done by using stock amount of the item).
(Int 2.0.2 the gold cost are added as suffix to the headline of the upgrade option)​


V2.0.2a Requiers warcraft 3 1.29+ (cause of dynamic Abilities)
V1.6 can be used with warcraft 3 versions having hashtables.


Features

How to install

How to Use

System

ChangeLog


Uses the default Warcraft 3 UI.
Each Player has its own dynamic shop.
Shows upgrades of items.
Or even upgrades of upgrades, when wanted.​
Fuses items only on user order.
Shop supports considing a Bagpack.
Bagpack accessability is frequently rechecked during shoping.​
Uses Rects to define Shoping Zones, each ShopZone can exclude a playergroup from using it.
Autogenerates Requiered Mat lists for registered Fusions.
Given Item Stats are on default taken from the field description of the fusion result.

  • Make sure you set the Option "File - preferences - Create Unknown Variables".
  • Copy The Ability "IFS - Select Hero".
  • > "ItemFusionShop - Show Upgrades"
  • > "ItemFusionShop - Page Next"
  • > "ItemFusionShop - Page Previous"
  • > All of the "ItemFusionShop - Button" 1 to 9
  • Copy The "ItemFusionShop" Unit.
  • Copy the Folder "Item Fusion Shop"
  • Check out the Configer below Triggers, to complet missing links and fill the database.
  • To let units open the Item fusion shop checkout the Demo Map only folder.
    • If you get an error, you might need to make sure that the mapheader contains an valid function.

After item fusion was successfuly installed in your map, you have to save gold costs of items beeings used as mats. And you have to register all builtways you wana have.

Gold Costs are saved as integer on:
inside: udg_IFShop_Table
MainKey: itemType
SecKey: 0
There is also a GUI Wrapper trigger doing the gold saving, checkout the demo map if you wana use it.
Each Builtway is one upgrade option.

Recommented generation is function IFShopAddFusion.

JASS:
function IFShopAddFusion takes integer fusion, integer mat0, integer mat1, integer mat2, integer mat3, integer mat4, integer mat5, integer mat6 returns boolean
There is also a GUI wrapper Trigger in the demo map.

Important: Do start saving your item data after you executed Item fusion shop once (which is on default done inside the demo maps Init General), the first execution of Item fusion shop will create shops, hashtable and Events.

Now you also need to setup ways to open the shop. Then players can use it in the game.

after item fusion shop was executed the first time it morphs its action from initializing to open shop. Based on the current Event from which you execute Item Fusion shop it will call function IFShopShow with different values.

  • Effect of Ability: Triggering Unit is used as shopper, upgrades are shown of the current spellTarget - item, if there is none all upgrades of all items in the units inventories are shown.
  • Gain item: The unit gaining the item is the shopper and upgrades of the gained items are shown.
  • Enter Region: The unit entering is the shopper and all registered upgrades are shown.
Before executing Item fusion Shop to open the shop you can set IFShop_Shopper_Bagpack[0] to define the bagpack of the shopping.

If you are using jass you could also use this function to open Item fusion shop for an unit/player.
JASS:
function IFShopShow takes integer playerIndex, unit shopper, unit bagpack, integer itemType returns nothing
//       GUI playerIndex; 1 = red
//       this will show the shop the owner of shopper
//       itemType = 0, will add all Ugrades of all items in the inventories of shopper and bagpack
//       itemType = -1 all Plans are added to the shop.


JASS:
//Item Fusion Shop 2.0.2
//By Tasyen
//============

//Item fusion shop is a Recipe System showing possible upgrades of an item inside the Warcraft basic user interface.
//The system calculates the needed gold cost and regards items already obtained by the hero and its bagpack, if wanted.
//This way the player gets control over the fusions he want to do and it feels like visiting a shop in basic Warcraft 3.

//============
//   API Fusion Creation
//============
//    function IFShopAddFusion takes integer fusion, integer mat0, integer mat1, integer mat2, integer mat3, integer mat4, integer mat5, integer mat6 returns boolean
//       Creates a Fusion with Mat 0 to 6 returns.
//       You need to set all mats, with a ItemTypeId or 0 for not needed.
//       Auto generates a Requier String List

//   function IFShopAddMat takes integer mat, integer plan returns nothing
//       Adds a Material component to the plan
//       expects ItemTypeId
//       after beeing done with AddMats one can "call IFShopUpdateReqStrings(plan)" to generate a requier list.

//   function IFShopAddMatEx takes integer mat returns nothing
//       Wraper function for IFShopAddMat for the Last register Plan

//   function IFShopCreate takes integer fusion returns boolean
//       Creates a Fusion without material

//   function IFShopSetItemStringList takes integer itemType, string text returns nothing
//       Write only the content
//       On default one does not need to call that one.
//       Requier Lists are autogenerated and Gives List are using the Object Field Description of the fusion result.

//============
//   API Show Shop
//============
//   function IFShopIsInShopZone takes unit u returns boolean
//       Checks if the unit is inside an BuyZone which his owner can use.
//        This should be used before calling IFShopShow, but is not requiered.

//   function IFShopShow takes integer playerIndex, unit shopper, unit bagpack, integer itemType returns nothing
//       this will show the shop the owner of shopper
//       itemType = 0, will add all Ugrades of all items in the inventories of shopper and bagpack
//       itemType = -1 all Plans are added to the shop.
//============
// API   for getting fusions (not needed on default usage)
//============
//   function IFShopCalcCost takes integer playerIndex, unit shopper, unit bagpack returns nothing
//       calcs the goldcosts regarding owned items from the two units.
//       into udg_IFShop_Shop_Avaible_Fuse_Costs
//       you should fill the list with IFShopGetPossibleFusions before using this.

//   function IFShopResetPossibleFusion takes integer playerIndex returns nothing
//       Resets the listvariables at playerIndex.

//   function IFShopGetPossibleFusions takes integer itemType, integer playerIndex returns nothing
//       Loads all upgrades of the itemType into udg_IFShop_Shop_Avaible_Fuse_plans, udg_IFShop_Shop_Avaible_Fusions
//       MPI based access udg_IFShop_Shop_Avaible_Fuse_First,udg_IFShop_Shop_Avaible_Fuse_Last
//       udg_IFShop_ShowMaxUpgrades enables to show itemtypes upgrade's upgrade...,

//   function IFShopGetAllFusions takes integer playerIndex, integer start returns nothing
//       Loads all Plans registered for that player, starting from Plan start.
//============

// The intervale in which the System rechecks Bagpack useability
// Every x seconds useability of Bagpack is rechecked.
// Lower numbers are more accurate but more costly.
constant function IFShopTimerIntervale takes nothing returns real
   return 0.4
endfunction

//how many items can a shop contain?
//keep max player amount * this smaller than 32k (JASS_MAX_ARRAY_SIZE)
//this system uses GUI PlayerIds therefore the 0 IFShopPlayerShopSize block is not used.
constant function IFShopPlayerShopSize takes nothing returns integer
   return 500
endfunction

//this are the number of Items each page contains
//setting this to something higher than 9 is not working (2 pagecontrol +1 target control) (Wc3 V1.28.5)
//Each PageEntry needs 1 Ability beeing its button.
constant function IFShopPageSize takes nothing returns integer
   return 9
endfunction

//Strings used by this system, one could change them to change results a bit.
function IFShopInitStrings takes nothing returns nothing
   set udg_IFShop_Strings[0] = "\n\n|cffffA000Requiers|r:" //Requiers Word
   set udg_IFShop_Strings[1] = "\n  "       //Prefix for each Mat in the Requiers List beeing autogenerated
  set udg_IFShop_Strings[2] = "|cffffA000Gives|r:\n"   //Start of the builtInfo part, builtInfo uses item description of the fusion result.
   set udg_IFShop_Strings[3] = "\n\n|cffffA000Replaces|r:" //If a fusion needs only one Mat, this is used instead of Requiers.
   set udg_IFShop_Strings[4] = " - " //Prefix GoldCost Number
   set udg_IFShop_Strings[5] = " "+GetLocalizedString("GOLD") //Sufix GoldCost Number
   set udg_IFShop_Strings[6] = "x " //2x Axe, written after the number

   set udg_IFShop_Strings[7] = "|cffffff00Singpleplayer Info|r: " //Duplicat - Warning Prefix
   set udg_IFShop_Strings[8] = " amount of builtways: " //Duplicat - Warning Sufix
  set udg_IFShop_Strings[9] = "|cffff0000Error|r:|nIFShopPlayerShopSize limit was exceeded." //Warning IFShopPlayerShopSize exceeded

endfunction

//============
//System constants
//============
//hashtable saved:
//============
//   Normal items (itemCode 'I000'):
//============
//   +side   = beeing material in plan
//   0          = Goldvalue
//   -side    = built ways
//   0 = Granted Powers List as Text
//============
//   Item Handle
//============
//   0 = true -> Is already used in current calculation

//============
//   plans
//============
//   0    = -1 easy identyfier
//   0   = Requiered Item List as Text
//   1    = result
//   2    = Mat amount
//   3+    = Mats
//============

//The OrderId of select ShopTarget.
constant function IFShopSelectShopTarget takes nothing returns integer
   return 852566
endfunction

constant function IFShopAbiltiyIdSellItems takes nothing returns integer
   return 'Asid'
endfunction

constant function IFShopTableResult takes nothing returns integer
   return 1
endfunction

constant function IFShopTablePlan takes nothing returns integer
   return 0
endfunction

constant function IFShopTableMatAmount takes nothing returns integer
   return 2
endfunction

constant function IFShopTableMatStart takes nothing returns integer
   return 3
endfunction

//Is this buildway already registered?
function IFShopIsBuiltWay takes integer itemType, integer plan returns boolean
   local integer index = 0
   local integer ancestor
   //find next free ancestor spot
   loop
       set index = index -1
       set ancestor = LoadInteger(udg_IFShop_Table,itemType,index)
       exitwhen ancestor == 0
       if ancestor == plan then
           return true
       endif
   endloop
   return false
endfunction

//Returns the already existing amount of builtways for an item
function IFShopGetBuiltWayCount takes integer itemType returns integer
   local integer index = 0
   //find next free ancestor spot
   loop
       set index = index -1
       exitwhen not HaveSavedInteger(udg_IFShop_Table,itemType,index)
   endloop
   return - (index + 1)
endfunction

//Remember that this item can be built by this plan.
//Builtways are saved at the -Side.
function IFShopAddBuiltWay takes integer itemType, integer plan returns nothing
   local integer index = 0
   if plan == 0 then
       return
   endif
   //find next free ancestor spot
   loop
       set index = index -1
       exitwhen not HaveSavedInteger(udg_IFShop_Table,itemType,index)
   endloop
   call SaveInteger(udg_IFShop_Table, itemType, index, plan)
endfunction

//Remebers that this item is used in plan as material
//Beeing Material is at the +Side.
function IFShopMatIsUsedInPlan takes integer itemType, integer plan returns nothing
   local integer index = 0
   if plan == 0 then
       return
   endif
   //find next free ancestor spot
   loop
       set index = index +1
       //Already know this mat can be used in this plan?
       if LoadInteger(udg_IFShop_Table,itemType,index) == plan then
           return
       endif
       exitwhen not HaveSavedInteger(udg_IFShop_Table,itemType,index)
   endloop
   call SaveInteger(udg_IFShop_Table, itemType, index, plan)
endfunction

//Updates the Requier string List also merges same mats as one strong with 2x Blade
//On Default everytime you use IFShopAddFusion
function IFShopUpdateReqStrings takes integer plan returns nothing
   local integer Loop_A = 0
   local integer matCount = LoadInteger(udg_IFShop_Table, plan, IFShopTableMatAmount())
   local integer array matTypes       //the types found
   local integer array matTypesAmount //Amount of items of type[index] found
   local integer matTypesCount = 0       //size of matTypes & matTypesAmount
   local string text = ""
   local integer itemType
   local boolean isNew
   loop
       exitwhen matCount == -1
       set itemType = LoadInteger(udg_IFShop_Table, plan, IFShopTableMatStart()+matCount)
       set Loop_A = matTypesCount
       set isNew = true
       loop
           exitwhen Loop_A == 0
           if matTypes[Loop_A] == itemType then
               set isNew = false
               set matTypesAmount[Loop_A] = matTypesAmount[Loop_A] + 1
               exitwhen true
           endif

           set Loop_A = Loop_A -1
       endloop
       if isNew then
           set matTypesCount = matTypesCount + 1
           set matTypesAmount[matTypesCount] = 1
           set matTypes[matTypesCount] = itemType
       endif
       set matCount = matCount - 1
   endloop

   loop
       exitwhen matTypesCount == 0
       if matTypesAmount[matTypesCount] > 1 then
         set text = text + udg_IFShop_Strings[1]+ I2S(matTypesAmount[matTypesCount]) + udg_IFShop_Strings[6] +GetObjectName(matTypes[matTypesCount])
       else
           set text = text + udg_IFShop_Strings[1]+GetObjectName(matTypes[matTypesCount])
       endif
       set matTypesCount = matTypesCount - 1
   endloop
   call SaveStr(udg_IFShop_Table, plan, 0, text)
endfunction

function IFShopSetItemStringList takes integer itemType, string text returns nothing
   call SaveStr(udg_IFShop_Table, itemType, 0, text)
endfunction


//The most important API action
//It creates an new way to built an Fusion.
//taking up to 7 mats as argument ( this is not the max limit)
//function IFShopAddFusion takes integer fusion, integer plan, integer mat0, integer mat1, integer mat2, integer mat3, integer mat4, integer mat5, integer mat6 returns boolean
function IFShopAddFusion takes integer fusion, integer mat0, integer mat1, integer mat2, integer mat3, integer mat4, integer mat5, integer mat6 returns boolean
   local integer amount = -1
   local integer plan
   local item i
   set udg_IFShop_Item_List_Fusions_Last = udg_IFShop_Item_List_Fusions_Last + 1
   set plan = udg_IFShop_Item_List_Fusions_Last

   if not HaveSavedString (udg_IFShop_Table, fusion, 0) then
       set i = CreateItem(fusion,0,0)
       call SaveStr(udg_IFShop_Table, fusion, 0, BlzGetItemDescription(i))
       call RemoveItem(i)
       set i = null
   endif

   //PrintOut multiple Builtways in Single player, might be an possible error.
   if bj_isSinglePlayer then
       if IFShopGetBuiltWayCount(fusion) != 0 then
         call DisplayTimedTextToPlayer( GetLocalPlayer(),0,0, 30, udg_IFShop_Strings[7]+GetObjectName(fusion) + udg_IFShop_Strings[8] +I2S(IFShopGetBuiltWayCount(fusion)+1) )
       endif
   endif
   call IFShopAddBuiltWay(fusion, plan)

   //Save Fusion and plan
   call SaveInteger( udg_IFShop_Table, plan, IFShopTableResult(), fusion)
   call SaveInteger( udg_IFShop_Table, plan, IFShopTablePlan(), -1 )


   //Check for Mats and save them at nearest slot
   if( mat0 != 0) then
       set amount = amount + 1
       call SaveInteger(udg_IFShop_Table, plan, IFShopTableMatStart()+amount,  mat0)
       call IFShopMatIsUsedInPlan(mat0, plan)
   endif
   if( mat1 != 0) then
       set amount = amount + 1
       call SaveInteger(udg_IFShop_Table, plan, IFShopTableMatStart()+amount,  mat1)
       call IFShopMatIsUsedInPlan(mat1, plan)
   endif
   if( mat2 != 0) then
       set amount = amount + 1
       call SaveInteger(udg_IFShop_Table, plan, IFShopTableMatStart()+amount,  mat2)
       call IFShopMatIsUsedInPlan(mat2, plan)
   endif
   if( mat3 != 0) then
       set amount = amount + 1
       call SaveInteger(udg_IFShop_Table, plan, IFShopTableMatStart()+amount,  mat3)
       call IFShopMatIsUsedInPlan(mat3, plan)
   endif
   if( mat4 != 0) then
       set amount = amount + 1
       call SaveInteger(udg_IFShop_Table, plan, IFShopTableMatStart()+amount,  mat4)
       call IFShopMatIsUsedInPlan(mat4, plan)
   endif
   if( mat5 != 0) then
       set amount = amount + 1
       call SaveInteger(udg_IFShop_Table, plan, IFShopTableMatStart()+amount,  mat5)
       call IFShopMatIsUsedInPlan(mat5, plan)
   endif
   if( mat6 != 0) then
       set amount = amount + 1
       call SaveInteger(udg_IFShop_Table, plan, IFShopTableMatStart()+amount,  mat6)
       call IFShopMatIsUsedInPlan(mat6, plan)
   endif

   call SaveInteger( udg_IFShop_Table, plan, IFShopTableMatAmount(), amount)

   call IFShopUpdateReqStrings(plan)
   return true
endfunction

//Adds material to plan.
function IFShopAddMat takes integer mat, integer plan returns nothing
   local integer amount
   //Ignore calls with no ItemType
   if(   mat != 0 and plan != 0) then
       set amount = LoadInteger(udg_IFShop_Table, plan, IFShopTableMatAmount())+1
       call SaveInteger( udg_IFShop_Table, plan, IFShopTableMatAmount(), amount)
       call SaveInteger(udg_IFShop_Table, plan, IFShopTableMatStart()+amount,  mat)
       call IFShopMatIsUsedInPlan(mat, plan)
   endif
endfunction

//Add an material to the last created plan
function IFShopAddMatEx takes integer mat returns nothing
   call IFShopAddMat(mat, udg_IFShop_Item_List_Fusions_Last)
endfunction

//Creates an fusion without mats.
function IFShopCreate takes integer fusion returns boolean

   //PrintOut multiple Builtways in Single player, might be an possible error.
   if bj_isSinglePlayer then
       if IFShopGetBuiltWayCount(fusion) != 0 then
         call DisplayTimedTextToPlayer( GetLocalPlayer(),0,0, 30, udg_IFShop_Strings[7]+GetObjectName(fusion) + udg_IFShop_Strings[8] +I2S(IFShopGetBuiltWayCount(fusion)+1) )
       endif
   endif
   //Inc Pool Size
   set udg_IFShop_Item_List_Fusions_Last = udg_IFShop_Item_List_Fusions_Last + 1
   call IFShopAddBuiltWay(fusion, udg_IFShop_Item_List_Fusions_Last)
   //Save ItemTypes and mat amount
   call SaveInteger( udg_IFShop_Table, udg_IFShop_Item_List_Fusions_Last, IFShopTableResult(), fusion)
   call SaveInteger( udg_IFShop_Table, udg_IFShop_Item_List_Fusions_Last, IFShopTableMatAmount(), -1)
   call SaveStr( udg_IFShop_Table, udg_IFShop_Item_List_Fusions_Last, 0, "")
   return true
endfunction

//Updates the shop for this Player.
//Uses GUI Indexing Red = 1 blue = 2
function IFShopUpdate takes integer playerIndex returns nothing
   local integer Loop_A
   local integer Loop_A_End
   local integer itemType
   local integer counter = 0
   local player p = Player(playerIndex - 1)
   local string text
   //Clear Shop
   set Loop_A = IFShopPageSize()
   loop
       exitwhen Loop_A <= 0
       //call SetPlayerAbilityAvailable(p, udg_IFShop_Page_Skill_Button[Loop_A], false)
       call UnitRemoveAbility(udg_IFShop_Shop[playerIndex],udg_IFShop_Page_Skill_Button[Loop_A])
       set Loop_A = Loop_A - 1
   endloop


   call UnitRemoveAbility( udg_IFShop_Shop[playerIndex] , IFShopAbiltiyIdSellItems()  )
   call UnitAddAbility(  udg_IFShop_Shop[playerIndex] , IFShopAbiltiyIdSellItems() )

   //Is Multipaging needed?
   if( udg_IFShop_Page_Max[playerIndex] > 0) then
       //Get Current-Page ItemTypes
     set   Loop_A = ( udg_IFShop_Shop_Avaible_Fuse_First[playerIndex] + ( IFShopPageSize() * udg_IFShop_Page_Current[playerIndex] ) )
       set Loop_A_End = Loop_A + (IFShopPageSize()-1)
       if  Loop_A_End > udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] then
           set Loop_A_End = udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex]
       endif
       //Add Page Controll
       call UnitAddAbility(  udg_IFShop_Shop[playerIndex] ,udg_IFShop_Page_Skill_Next )
       call UnitAddAbility(  udg_IFShop_Shop[playerIndex] ,udg_IFShop_Page_Skill_Previous )
   else
       //Remove Page Controll
       call UnitRemoveAbility( udg_IFShop_Shop[playerIndex], udg_IFShop_Page_Skill_Next )
        call UnitRemoveAbility( udg_IFShop_Shop[playerIndex], udg_IFShop_Page_Skill_Previous )
       //Get ItemTypes
       set Loop_A = udg_IFShop_Shop_Avaible_Fuse_First[playerIndex]
       set Loop_A_End = udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex]
   endif
   set counter = 1
   loop
       exitwhen Loop_A > Loop_A_End
       set itemType = udg_IFShop_Shop_Avaible_Fusions[Loop_A]

       if GetLocalPlayer() == p then
           if LoadInteger(udg_IFShop_Table, udg_IFShop_Shop_Avaible_Fuse_plans[Loop_A], IFShopTableMatAmount()) == 0 then
               if HaveSavedString(udg_IFShop_Table, itemType, 0) then //Has Gained Effect String List?
                 set text = udg_IFShop_Strings[2]+ LoadStr(udg_IFShop_Table, itemType, 0) + udg_IFShop_Strings[3] + LoadStr(udg_IFShop_Table, udg_IFShop_Shop_Avaible_Fuse_plans[Loop_A], 0)
               else
                 set text = BlzGetAbilityExtendedTooltip(itemType,1) + udg_IFShop_Strings[3] + LoadStr(udg_IFShop_Table, udg_IFShop_Shop_Avaible_Fuse_plans[Loop_A], 0)
               endif
           else
               if HaveSavedString(udg_IFShop_Table, itemType, 0) then
                 set text = udg_IFShop_Strings[2]+ LoadStr(udg_IFShop_Table, itemType, 0) + udg_IFShop_Strings[0] + LoadStr(udg_IFShop_Table, udg_IFShop_Shop_Avaible_Fuse_plans[Loop_A], 0)
               else
                 set text = BlzGetAbilityExtendedTooltip(itemType,1) + udg_IFShop_Strings[0] + LoadStr(udg_IFShop_Table, udg_IFShop_Shop_Avaible_Fuse_plans[Loop_A], 0)
               endif
           endif
        
           call BlzSetAbilityExtendedTooltip(udg_IFShop_Page_Skill_Button[counter], text,1)
           if udg_IFShop_Shop_Avaible_Fuse_Costs[Loop_A] > 0 then
             call BlzSetAbilityTooltip(udg_IFShop_Page_Skill_Button[counter],    BlzGetAbilityTooltip(itemType,1) + udg_IFShop_Strings[4]+I2S(udg_IFShop_Shop_Avaible_Fuse_Costs[Loop_A]) + udg_IFShop_Strings[5],1)
           else
               call BlzSetAbilityTooltip(udg_IFShop_Page_Skill_Button[counter],    BlzGetAbilityTooltip(itemType,1) ,1)
           endif
           call BlzSetAbilityIcon(udg_IFShop_Page_Skill_Button[counter], BlzGetAbilityIcon(itemType))

       endif
       //call SetPlayerAbilityAvailable(p, udg_IFShop_Page_Skill_Button[counter], true)
       call UnitAddAbility(udg_IFShop_Shop[playerIndex],udg_IFShop_Page_Skill_Button[counter])
       set counter = counter + 1
       set Loop_A = Loop_A + 1
   endloop

   set p = null
endfunction

//When one deselects the shop hide it.
function IFShopHide takes nothing returns nothing
   local integer playerIndex = GetPlayerId( GetOwningPlayer(GetTriggerUnit()) ) + 1
   //Clear and Hide Shop
   call UnitRemoveAbility( udg_IFShop_Shop[playerIndex] , IFShopAbiltiyIdSellItems()  )
   call ShowUnit(GetTriggerUnit(),false)
   set udg_IFShop_Is_Shopping[playerIndex] = false
   set udg_IFShop_Shopper_Count = udg_IFShop_Shopper_Count - 1
   //If none is shopping disable Backpack loop checking.
   if(udg_IFShop_Shopper_Count == 0) then
       call PauseTimer( udg_IFShop_Bagpack_Timer )
   endif
endfunction

function IFShopPageControl takes integer spell, integer playerIndex returns nothing
   if( spell == udg_IFShop_Page_Skill_Next ) then
       set udg_IFShop_Page_Current[playerIndex] = ( udg_IFShop_Page_Current[playerIndex] + 1 )
       //Return to Page 0?
       if ( udg_IFShop_Page_Current[playerIndex] > udg_IFShop_Page_Max[playerIndex]) then
           set udg_IFShop_Page_Current[playerIndex] = 0
       endif
   else
       //Previous Page.
       set udg_IFShop_Page_Current[playerIndex] = ( udg_IFShop_Page_Current[playerIndex] - 1 )
       //Return to max Max?
       if ( udg_IFShop_Page_Current[playerIndex] < 0) then
           set udg_IFShop_Page_Current[playerIndex] = udg_IFShop_Page_Max[playerIndex]
       endif
   endif
   call IFShopUpdate(playerIndex)
endfunction

//Checks if the unit is inside an BuyZone whiche his owner can use.
// This should be used before calling IFShopShow
function IFShopIsInShopZone takes unit u returns boolean
   local real x = GetUnitX(u)
   local real y = GetUnitY(u)
   local integer Loop_A=0
   //loop All Registere Buyzones.
   loop
        exitwhen Loop_A > udg_IFShop_Buy_Zones_Last
       //Is Shopper inside BuyZone and is his owner allowed to use it? yes = true
      if ( RectContainsCoords(udg_IFShop_Buy_Zones[Loop_A], x,y) and not (IsPlayerInForce ( GetOwningPlayer (u), udg_IFShop_Buy_Zones_Excluded[Loop_A] )) ) then
           return true
       endif
        set Loop_A = Loop_A + 1
   endloop
   return false
endfunction

function IFShopIsBagpackUseable takes unit shopper, unit bagpack returns boolean
   //Developer don't want Bagpack?
   if not(udg_IFShop_Bagpack_Enabled[GetPlayerId(GetOwningPlayer(shopper))+1])then
       return false
   endif
   //null Pointer?
   if GetUnitTypeId (bagpack) == 0 then
       return false
   endif
   //Bagpack is dead?
   if IsUnitType(bagpack, UNIT_TYPE_DEAD) then
       return false
   endif
   //In Range Check?
   if not IsUnitInRange(shopper, bagpack, udg_IFShop_Bagpack_Hero_Max_Distan) then
       return false
   endif
   return true
endfunction

//Helper Function
//Saves old Custom Value and loads into the stack
function IFShopCheckAndMarkItem takes item mat, integer itemType returns boolean
   //Filters other Item Types, Marked Items and Not existing items
   if(itemType != GetItemTypeId(mat) or HaveSavedBoolean(udg_IFShop_Table, GetHandleId(mat),0) or mat == null ) then
       return false
   endif

   //Inser into Item stack and  Mark it.
   set udg_IFShop_Item_Stack_Last = ( udg_IFShop_Item_Stack_Last + 1 )
   set udg_IFShop_Item_Stack[udg_IFShop_Item_Stack_Last] = mat
   call SaveBoolean(udg_IFShop_Table, GetHandleId(mat),0, true)
   return true
endfunction

//Resets the found itemTypes stack for this player.
//Playerindexes are in this system overall GUI-Like
//But if you do not use the shops you don't have care about that.
function IFShopResetPossibleFusion takes integer playerIndex returns nothing
   set udg_IFShop_Shop_Avaible_Fuse_First[playerIndex] = ( IFShopPlayerShopSize() * playerIndex )
   set udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] = ( udg_IFShop_Shop_Avaible_Fuse_First[playerIndex] - 1 )
   set udg_IFShop_Page_Max[playerIndex] = 0
   set udg_IFShop_Page_Current[playerIndex] = 0
endfunction

function IFShopGetPossibleFusions takes integer itemType, integer playerIndex returns nothing
   local integer Loop_B = 1
   local integer Loop_A = 0
   local integer plan
   local integer pageMembersReamining = IFShopPageSize()
  local integer counter = ( udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] - udg_IFShop_Shop_Avaible_Fuse_First[playerIndex]) +1
   local boolean skip

   //Loop the Material of current Fusion
   loop
       //Exceeds Players Array Size? yes -> stop. Should normally not happen.
       if ( counter >= IFShopPlayerShopSize() ) then
           //show Stacksize to small only in singleplayer.
           if bj_isSinglePlayer then
               call DisplayTimedTextToPlayer( GetLocalPlayer(),0,0, 30, udg_IFShop_Strings[9] )
           endif
           return
       endif
       set plan = LoadInteger(udg_IFShop_Table, itemType, Loop_B)
       set skip = false
       exitwhen plan == 0
       //filter out duplicates.
       set Loop_A = udg_IFShop_Shop_Avaible_Fuse_First[playerIndex]
       loop
           exitwhen Loop_A > udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] or skip
           if plan == udg_IFShop_Shop_Avaible_Fuse_plans[Loop_A] then
               set skip = true
           endif
           set Loop_A = Loop_A +1
       endloop
       // if no duplicate load it in.
       if not skip then
           set udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] = ( udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] + 1 )
         set udg_IFShop_Shop_Avaible_Fusions[udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex]] = LoadInteger(udg_IFShop_Table, plan, IFShopTableResult())
        
           set udg_IFShop_Shop_Avaible_Fuse_plans[udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex]] = plan
           set counter = counter + 1
           set pageMembersReamining = pageMembersReamining - 1
           //Is a new Page needed?
           if pageMembersReamining == -1 then
               set udg_IFShop_Page_Max[playerIndex] = udg_IFShop_Page_Max[playerIndex] + 1
               set pageMembersReamining = IFShopPageSize() - 1
           endif
           //Find Upgrade's Upgrades?
           if udg_IFShop_ShowMaxUpgrades[playerIndex] then
             call IFShopGetPossibleFusions(udg_IFShop_Shop_Avaible_Fusions[udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex]],playerIndex)
           endif
       endif
       set Loop_B = Loop_B + 1
   endloop
endfunction

function IFShopGetAllFusions takes integer playerIndex, integer start returns nothing
   local integer plan = start
   local integer result
  local integer counter = ( udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] - udg_IFShop_Shop_Avaible_Fuse_First[playerIndex]) +1
   local integer pageMembersReamining = IFShopPageSize()
   //Loop the Material of current Fusion
   loop
       //Exceeds Players Array Size? yes -> stop. Should normally not happen.
       if ( counter >= IFShopPlayerShopSize() ) then
           //show Stacksize to small only in singleplayer.
           if bj_isSinglePlayer then
               call DisplayTimedTextToPlayer( GetLocalPlayer(),0,0, 30, udg_IFShop_Strings[9] )
           endif
           return
       endif
       set result = LoadInteger(udg_IFShop_Table, plan, IFShopTableResult())
       exitwhen result == 0
       set udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] = ( udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] + 1 )
       set udg_IFShop_Shop_Avaible_Fusions[udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex]] = result
    
       set udg_IFShop_Shop_Avaible_Fuse_plans[udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex]] = plan
       set counter = counter + 1
       set pageMembersReamining = pageMembersReamining - 1
       //Is a new Page needed?
       if pageMembersReamining == -1 then
           set udg_IFShop_Page_Max[playerIndex] = udg_IFShop_Page_Max[playerIndex] + 1
           set pageMembersReamining = IFShopPageSize() - 1
       endif
       set plan = plan + 1
   endloop

endfunction

function IFShopCheckInventory takes unit u, integer itemType returns boolean
   local integer Loop_B = 0
   //Checks Full Inventory
   loop
       exitwhen Loop_B == bj_MAX_INVENTORY
       if IFShopCheckAndMarkItem(UnitItemInSlot(u, Loop_B), itemType) then
           return true
       else
           set Loop_B = Loop_B + 1
       endif
   endloop
   return false
endfunction

function IFShopInventorySlotBased takes unit first, unit second, integer itemType returns boolean
   local integer Loop_B = 0
   //Checks Shopper Bagpacks Items in turns.
   loop
       exitwhen Loop_B == bj_MAX_INVENTORY
       if IFShopCheckAndMarkItem(UnitItemInSlot(first, Loop_B), itemType) then
           return true
       endif
       if IFShopCheckAndMarkItem(UnitItemInSlot(second, Loop_B), itemType) then
           return true
       endif
       set Loop_B = Loop_B + 1
   endloop
   return false
endfunction

//Unmarks Items starting from start and setting size to the approached amount
function IFShopUnmarkMats takes integer start returns nothing
   local integer Loop_A = start
   loop
       exitwhen Loop_A > udg_IFShop_Item_Stack_Last
       call RemoveSavedBoolean(udg_IFShop_Table, GetHandleId(udg_IFShop_Item_Stack[Loop_A]),0)
       set Loop_A = Loop_A +1
   endloop
   set udg_IFShop_Item_Stack_Last = start - 1
endfunction

function IFShopGetSubFusions takes integer playerIndex, unit shopper, unit bagpack, integer plan returns integer
   local integer Loop_A = IFShopTableMatStart()
   local integer Loop_B = -1
   local integer subChoosen = Loop_B
   local integer subCurrent
   local integer subChoosenGold
   local integer subCurrentGold
   local integer costs = 0
   local integer unmarkStart
   local integer itemType
   local boolean matAvailable
   local integer subChoosenTry
   loop
       set itemType = LoadInteger(udg_IFShop_Table, plan, Loop_A )
       exitwhen itemType == null
       set matAvailable = false
       //Followng Defines the Order of accessing the inventories.
       //Is No Bagpack used or not allowed? yes -> simply check the Shopper.
       if not(   udg_IFShop_Shop_Bagpack_Accessable[playerIndex] ) then
           set matAvailable = IFShopCheckInventory(shopper,itemType)
       else
           //Check Inventories in Turns?
           if udg_IFShop_Bagpack_Pick_SlotBased then
               //In Turns; Start with who?
               if udg_IFShop_Bagpack_Shopper_First then
                   set matAvailable = IFShopInventorySlotBased(shopper,bagpack,itemType)
               else
                   set matAvailable = IFShopInventorySlotBased(bagpack,shopper,itemType)
               endif
           else
               //Slotbased
               //Start with Shopper?
               if udg_IFShop_Bagpack_Shopper_First then
                   set matAvailable = IFShopCheckInventory(shopper,itemType)
                   //Still missing?
                   if not (matAvailable) then
                       set matAvailable = IFShopCheckInventory(bagpack,itemType)
                   endif
               else
                   set matAvailable = IFShopCheckInventory(bagpack,itemType)
                   if not (matAvailable) then
                       set matAvailable = IFShopCheckInventory(shopper,itemType)
                   endif
               endif
           endif
       endif
    
       //Mat unavaible?
       if not (matAvailable) then
           //Is Mat a Fusion? yes -> search for sub Material; Recursiv
           //Fusionitems have numbers saved in the -side aka built ways
           if(LoadInteger(   udg_IFShop_Table, itemType, -1) != 0) then
               //Remember Index from where to unmark.
             //Without this sets the loop below won't work in recursion, why ever i had them before at the local init but it didn't work.
               set unmarkStart = udg_IFShop_Item_Stack_Last+1
               set subChoosenGold = 99999
               set Loop_B = -1
               //Loop all Builtways of this item and choose the cheapest.
               loop
                   set subCurrent = LoadInteger(udg_IFShop_Table,itemType,Loop_B)
                   exitwhen  subCurrent == 0
                   call IFShopUnmarkMats(unmarkStart)
                   set subCurrentGold = IFShopGetSubFusions(playerIndex, shopper, bagpack, subCurrent )
                   //Calced one Cheaper then cheapest?
                   if subCurrentGold < subChoosenGold then
                       set subChoosenTry = Loop_B
                       set subChoosen = subCurrent
                       set subChoosenGold = subCurrentGold
                   endif
                
                   set Loop_B = Loop_B - 1
               endloop
               //mark + Load choosen items again
               //if was not found on last try
               if subChoosenTry != Loop_B + 1 then
                   call IFShopUnmarkMats(unmarkStart)
                   call IFShopGetSubFusions(playerIndex, shopper, bagpack, subChoosen )
               endif
               set costs = costs + subChoosenGold
           else
               //No Fusion; Increment Gold if wanted.
               set costs = costs + LoadInteger(udg_IFShop_Table, itemType, 0)
           endif
       endif
       set Loop_A = Loop_A + 1
   endloop

   return costs
endfunction

//This is called to calculate Gold Costs of all avaibleFusions for this player.
function IFShopCalcCost takes integer playerIndex, unit shopper, unit bagpack returns nothing
   local integer Loop_A = udg_IFShop_Shop_Avaible_Fuse_First[playerIndex]
   call IFShopUnmarkMats(0)
   //loop all Upgrade Options
   loop
       exitwhen Loop_A > udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex]
     set udg_IFShop_Shop_Avaible_Fuse_Costs[Loop_A] = IFShopGetSubFusions(playerIndex,shopper,bagpack,udg_IFShop_Shop_Avaible_Fuse_plans[Loop_A])
       call IFShopUnmarkMats(0)
       set Loop_A = Loop_A + 1
   endloop
endfunction

function IFShopTimerAction   takes nothing returns nothing
   local integer playerIndex = 1
   local boolean isAvaible=false
   //loop all Players
   loop
       exitwhen playerIndex >  bj_MAX_PLAYERS
       if udg_IFShop_Is_Shopping[playerIndex] and udg_IFShop_Bagpack_Enabled[playerIndex] then
         set isAvaible = IFShopIsBagpackUseable (udg_IFShop_Shop_Shopper[playerIndex],udg_IFShop_Shop_Shopper_Bagpack[playerIndex])
           //Bagpack accessability Changed?
           if udg_IFShop_Shop_Bagpack_Accessable[playerIndex] != isAvaible then
               //Access Changed Recalc Gold Costs.
               set udg_IFShop_Shop_Bagpack_Accessable[playerIndex] = isAvaible
              call IFShopCalcCost(playerIndex,udg_IFShop_Shop_Shopper[playerIndex],udg_IFShop_Shop_Shopper_Bagpack[playerIndex])
               call IFShopUpdate(playerIndex)
           endif
       endif
   set playerIndex = playerIndex + 1
   endloop   
endfunction

function IFShopShow takes integer playerIndex, unit shopper, unit bagpack, integer itemType returns nothing
   local integer Loop_A = 0
   set udg_IFShop_Shop_Bagpack_Accessable[playerIndex] = IFShopIsBagpackUseable(shopper,bagpack)
   //IFShopGetPossibleFusions only if not the same as last try or it is 0 aka whole inventory?
   if udg_IFShop_Shop_LastTry[playerIndex] != itemType or itemType == 0 or itemType == -1 then
       set udg_IFShop_Shop_LastTry[playerIndex] = itemType
       call IFShopResetPossibleFusion(playerIndex)
       //specific item
       if itemType > 0 then
           call IFShopGetPossibleFusions(itemType,playerIndex)
       elseif itemType == 0 then //all upgrades of carried Items
           //Non specific item show all avaible Upgrades of all items in shopper's and bagpack's inventory
           //Load Inventory
           set Loop_A = 0
           //Hero
           loop
               exitwhen Loop_A == bj_MAX_INVENTORY
               set itemType =  GetItemTypeId(UnitItemInSlot(shopper, Loop_A))
               if itemType != 0 then
                   call IFShopGetPossibleFusions(itemType,playerIndex)
               endif
               set Loop_A = Loop_A + 1
           endloop
           //bagpack exists?
           if    GetUnitTypeId(bagpack) != 0 and udg_IFShop_Bagpack_Enabled[playerIndex] then
               //Bagpack
               set Loop_A = 0
               loop
                   exitwhen Loop_A == bj_MAX_INVENTORY
                   set itemType = GetItemTypeId( UnitItemInSlot(bagpack, Loop_A))
                   if itemType != 0 then
                       call IFShopGetPossibleFusions(itemType,playerIndex)
                   endif
                   set Loop_A = Loop_A + 1
               endloop
           endif
       elseif itemType == -1 then //all plans registered
           call IFShopGetAllFusions(playerIndex, 1)
       endif
   endif

   //Does an Upgrade Exist?
   if( udg_IFShop_Shop_Avaible_Fuse_Last[playerIndex] >= udg_IFShop_Shop_Avaible_Fuse_First[playerIndex] ) then
       set udg_IFShop_Shopper_Count = udg_IFShop_Shopper_Count + 1
       //First Player Shopping? start Periodic check.
       if( udg_IFShop_Shopper_Count ==1 and udg_IFShop_Bagpack_Enabled[playerIndex]) then
           call TimerStart ( udg_IFShop_Bagpack_Timer, IFShopTimerIntervale(), true, function IFShopTimerAction)
       endif
       //Save Current Shopping Situation
       set udg_IFShop_Is_Shopping[playerIndex] = true
        set udg_IFShop_Shop_Shopper[playerIndex] = shopper
        set udg_IFShop_Shop_Shopper_Bagpack[playerIndex] = bagpack
       call IFShopCalcCost(playerIndex,shopper,bagpack)
       //Inser upgrade Options and Open Shop
       call ShowUnit( udg_IFShop_Shop[playerIndex],true )
       call SetUnitX(udg_IFShop_Shop[playerIndex], GetUnitX(shopper))
       call SetUnitY(udg_IFShop_Shop[playerIndex], GetUnitY(shopper))
       call IFShopUpdate(playerIndex)
       call SelectUnitForPlayerSingle( udg_IFShop_Shop[playerIndex], Player(playerIndex - 1) )
       //Make Shop target Shopper.
     call IssueNeutralTargetOrderById( Player(playerIndex - 1), udg_IFShop_Shop[playerIndex], IFShopSelectShopTarget() , shopper)
   else
       //No Upgrades avaible Reselect Shopper.
       call SelectUnitForPlayerSingle( shopper, GetOwningPlayer(shopper) )
   endif
endfunction

function IFShopShowGUI takes nothing returns nothing
   local integer itemType
   local integer eid = GetHandleId(GetTriggerEventId())
   local unit shopper

   if eid == GetHandleId(EVENT_PLAYER_UNIT_SPELL_EFFECT) or eid == GetHandleId(EVENT_UNIT_SPELL_EFFECT) then
       set itemType = GetItemTypeId(GetSpellTargetItem())
       set shopper = GetTriggerUnit()
   elseif eid == GetHandleId(EVENT_PLAYER_UNIT_PICKUP_ITEM) or eid == GetHandleId(EVENT_UNIT_PICKUP_ITEM) then
       set itemType = GetItemTypeId(GetManipulatedItem())
       set shopper = GetTriggerUnit()
   else
       set itemType = 0
       set shopper = udg_IFShop_Shop_Shopper[0]
   endif
   if IFShopIsInShopZone(GetTriggerUnit()) then
       call IFShopShow(GetConvertedPlayerId(GetOwningPlayer(shopper)), shopper, udg_IFShop_Shop_Shopper_Bagpack[0], itemType)
   endif
   set udg_IFShop_Shop_Shopper_Bagpack[0] = null
   set shopper = null
endfunction

function IFShopDoFusion takes integer spell, integer playerIndex returns nothing
   local integer Loop_A = IFShopPageSize()
   local integer Loop_A_End
   local integer Loop_B = 0
   local integer itemType
   local integer indexInShop = 0

   local unit bagpack = udg_IFShop_Shop_Shopper_Bagpack[playerIndex]
   local unit shopper = udg_IFShop_Shop_Shopper[playerIndex]
   call IFShopUnmarkMats(0)
   loop
       exitwhen Loop_A <= 0
       //Was this one bought?
       if ( udg_IFShop_Page_Skill_Button[Loop_A] == spell) then
         set indexInShop = udg_IFShop_Shop_Avaible_Fuse_First[playerIndex] + ( IFShopPageSize() * udg_IFShop_Page_Current[playerIndex] ) + Loop_A -1
           set itemType = udg_IFShop_Shop_Avaible_Fuse_plans[indexInShop]
           exitwhen true
       endif
       set Loop_A = Loop_A - 1
   endloop
   //Enough Gold?
  if( GetPlayerState( Player(playerIndex - 1), PLAYER_STATE_RESOURCE_GOLD) >= udg_IFShop_Shop_Avaible_Fuse_Costs[indexInShop] )then
     call AdjustPlayerStateBJ( ( -1 * udg_IFShop_Shop_Avaible_Fuse_Costs[indexInShop] ), Player(playerIndex - 1), PLAYER_STATE_RESOURCE_GOLD )
       // Collect avaible Fusion-Material
       call IFShopGetSubFusions(playerIndex, shopper, bagpack, itemType)
       //Destory Found material
       loop
           exitwhen Loop_B > udg_IFShop_Item_Stack_Last
           call RemoveSavedBoolean(udg_IFShop_Table, GetHandleId(udg_IFShop_Item_Stack[Loop_B]),0)
           call RemoveItem( udg_IFShop_Item_Stack[Loop_B] )
           set Loop_B = Loop_B + 1
       endloop
       //Create Fusion
       set itemType = udg_IFShop_Shop_Avaible_Fusions[indexInShop]
       call UnitAddItemByIdSwapped( itemType, shopper )
       call DestroyEffect( AddSpecialEffectTarget(udg_IFShop_Fusion_SFX_Path, shopper, "origin") )
    
       call IFShopHide()
       //continue Shopping, with gained Fusion?
       if udg_IFShop_Continue_After_Fusion[playerIndex] then
           call IFShopShow (playerIndex, shopper, bagpack, itemType)
       else
           call SelectUnitForPlayerSingle( shopper, GetTriggerPlayer() )
       endif
   else
       call StartSoundForPlayerBJ(GetTriggerPlayer() ,udg_IFShop_Sound_No_Gold)
   endif

   set shopper = null
   set bagpack = null
endfunction

//When an shop casts a spell
function IFShopCast takes nothing returns nothing
   local integer playerIndex = GetPlayerId(GetTriggerPlayer()) + 1
   local integer spell = GetSpellAbilityId()
   //Next Page used?
   if (spell == udg_IFShop_Page_Skill_Next or spell == udg_IFShop_Page_Skill_Previous) then
       call IFShopPageControl(spell, playerIndex)
   else
       call IFShopDoFusion(spell, playerIndex)
   endif
endfunction

//Creates all needed stuff.
function IFShopInit takes nothing returns nothing
   local trigger switchPage =CreateTrigger()
   local trigger hideShops =CreateTrigger()
   local integer playerIndex = 0
   local integer skillLoop
   local unit shop
   // Basic Setup

   set udg_IFShop_Shopper_Count = 0
   set udg_IFShop_Table = InitHashtable()
   call TriggerAddAction( switchPage, function IFShopCast )
   call TriggerAddAction(hideShops, function IFShopHide)

   //Loop all Players;
   loop
       exitwhen playerIndex == bj_MAX_PLAYERS
       //Is Playing? Is User?
     if ( GetPlayerSlotState(Player(playerIndex)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(playerIndex)) == MAP_CONTROL_USER  ) then
           //Create Shops, Register: Page Controll, Shop Closing
         set shop = CreateUnit( Player(playerIndex), udg_IFShop_Shop_UnitType, GetStartLocationX(playerIndex), GetStartLocationY(playerIndex), 270.0)
           call UnitAddAbility(shop, udg_IFShop_Page_Skill_Next)
           call UnitAddAbility(shop, udg_IFShop_Page_Skill_Previous)
           call UnitAddAbility(shop, udg_IFShop_Page_Skill_Select)
           set skillLoop = IFShopPageSize()
           loop
               exitwhen skillLoop <= 0
               call UnitAddAbility(shop, udg_IFShop_Page_Skill_Button[skillLoop])
               set skillLoop = skillLoop - 1
           endloop
           call SetUnitPathing( shop, false )
        
           call TriggerRegisterUnitEvent( switchPage, shop, EVENT_UNIT_SPELL_CAST )
           call TriggerRegisterUnitEvent( hideShops, shop, EVENT_UNIT_DESELECTED )
           set udg_IFShop_Shop[playerIndex+1] = shop
       endif
       set playerIndex = playerIndex + 1
   endloop
   set shop = null
   call TriggerClearActions(gg_trg_Item_Fusion_shop)
   call IFShopInitStrings()
   call TriggerAddAction(gg_trg_Item_Fusion_shop, function IFShopShowGUI)
endfunction

//===========================================================================
function InitTrig_Item_Fusion_shop takes nothing returns nothing
   set gg_trg_Item_Fusion_shop = CreateTrigger(  )
   call TriggerAddAction( gg_trg_Item_Fusion_shop, function IFShopInit )
endfunction


Changelog

V2.0.2a
Fixed usage for warcraft 3 1.31+​
V2.0.2
Item FusionShop now uses dynamic Abilities instead of powerup - items.
Removes the need of additional items created for Item Fusion Shop.
lost the stock amount as gold feature.
Gold costs are now added as suffix to the items tooltip.​
Requierment Lists for fusions are now autogenerated.
Gain Lists are on default the object Field description of the item one gains from a fusion.
Installing should be now more easy.
GUI shop opening is now done by executing Item Fusion shop trigger (after it was executed once to setup it).
Item fusion shop can now add all registered Fusions into the shop by calling IFShopShow wit itemType = -1
Various code improvements.​

V1.6)
One can now show all available upgrades of items in inventories ( shopper + backpack)
the demo spell shows now this behaviour by casting it on the hero himself.​
It is now possible to show max upgrade level of items.
default off.​
The GUI registering trigger now cleans off fusion result/fake.
The Fusion Init now starts itself at 0.00 to allow printing out error messages.
the Entries per page are now changeable inside the jass code.
cleans now the bought plan instantly.
fixed a bug with using an material multiple times in one built when jumping tier levels -> took less gold if wanted.​
V1.5
Reworked the system, it now performs better with big itempools.
fixed a bug in which a more expensive built way was choosen
the primary key for fusion-Plans is now the itemTypeId (tech info).
takes only 1 Hashtable.​
V1.3a
Insert "return true" at the end of function CreateFusion()​
V1.3
Material-Amount was registered with 1 too much.
Option: Start with Bagpack/Shopper for Material finding
Option: Check Material Slot/Inventory based
Default: Shopper & Inventory-Based
Renamed some Variables​
V1.2a/b
Insert the Option to exclude a Player Group from a Buyzone
Changed Blues Hero to blademaster
Replaced Some BJ-functions
Break out of loops is now done with exitwhen (true)
Optimized the calculation time of function BuyFusion dramatically​
V1.2
Now in Jass
Gold Costs are saved in another Hashtabel
Moved not configerable basic setup into Item Fusion shop Code.
Added an Option: Show further Upgrades after Fusing
Fixed 2 buggs with Multi-Page​
V1.1d
Custom Value of Items are now correctly restored
Insert 2 Global Constants (One is the OrderID from select Shopper the other makes it easier to find a not used Custom Value)
Not selected Units won't Open the Shop anymore
Added a Blue Player with a own horse.
Altered the Get Bagpack Trigger showing how to use with 2 MPI Heroes.
Reordered the Init General Trigger
Inserter a break in IsInShopzone
Insert a Variable for the Show Upgrade Spell​
V1.1c
Systems Prefix: IFS -> IFShop
Some Names were shortend to accept the new Prefix
Added a New Item to the Demo Map: Built to Many. It shows the Multi paging.​
V1.1b
Uses Blizzard's Function: StartSoundForPlayerBJ​
V1.1a
The "No-Gold" Sound is now played only on the Local PC.
V1.1
Added the Feature: "Multiple Pages", the Page-Control is only Shown if needed.
Now Prices will be updated in Real time, if the accessablity of the used backpack changes; Frequenz 2,5 Hz.
Now the Shopper is always The "Shown"-Target of the Shop, this Requiers the "Pick User Button" to be shown in the Shop, as the in the map contained ability does.
Some Code updates
Demo Map-Text updated.

V1.0a
Outsourced IFS_Shopper_Bagpack into the new Trigger IFS getBagpack
-> this allows easier Customizing and less touching of the System.
Changed the Trigger Order, to simplfy Importing.
Added a New Variable IFS_Sound_No_Gold, is set in IFS Init General


Previews
Contents

Item Fusion Shop 1.6 (Map)

Item Fusion Shop 2.0.2ab (Map)

Reviews
KILLCIDE
The system seemed small at first, but as I began to read the code and see the mechanics, I began to see the entirety of the system. I rather like how you managed to get this to work with the WC3 interface. The movement between pages and the...
Level 37
Joined
Jul 22, 2015
Messages
3,485

Needs Fixed

  • loc as a variable name is way too generic
  • IFS - Show Upgrade should be stored into a configurable variable
  • loc2 as a variable name is way too generic
  • It should be mentioned that the custom value of item's is manipulated by this system
  • Boolean as a variable name is way too generic
  • Sell Items, Page_Skill_Next, & Page_Skill_Previous should be stored into configurable variables

Suggestions

  • Documentation for the Basic Setup variables in Init General would be appreciated. As of right now, I have no idea what they mean, especially Fusions_Last
  • In the player group loop in IFS Init General, I would store (Picked player) and (Last created unit) into variables
  • I would avoid using (Integer A) because it might clash with other user's maps, and it is also slower
  • I would add an exitwhen (true) in the for loop inside IFS shopper is in Shopzone. It seems useless to be continuing the loop if you already found that it's in one of the regions
  • Does the preplaced backpack unit work for all players? Do they only have to place one of these backpack units down or must they place one for each player?
  • In Show Upgrades Spell, you store (Triggering unit) into a variable, but you don't use it
  • Error messages should only be shown locally
  • LoadIntegerBJ() -> LoadInteger()
  • Instead of setting loop integers to an arbitary value that will exit the loop, make use of the exitwhen (true) operator

Status

Awaiting Update
 
Thanks for your Feedback.

It should be mentioned that the custom value of item's is manipulated by this system
It is not mentioned cause the System should restore the current custom value after usage. Currently In Version 1.1c it does not restore it cause of a simple misstake.
In Show Upgrades Spell, you store (Triggering unit) into a variable, but you don't use it
Its used and needed in the Triggers called.
Sell Items, Page_Skill_Next, & Page_Skill_Previous should be stored into configurable variables
Sell Items is the basic Ability of market which can't be modyfied at all, so I don't see any value in giving it a variable.
Page_Next/Previous are allready variable based.

Does the preplaced backpack unit work for all players? Do they only have to place one of these backpack units down or must they place one for each player?
In the demo Map the packhorse is used by all Units. But this kind of Bagpack finding, in a own trigger, was choosen to allow free customizing.

Uploaded Version 1.1d
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
Its used and needed in the Triggers called.
I'm referring to here: Set IFS_Index_Player = (Player number of (Owner of (Triggering unit)))

Sell Items is the basic Ability of market which can't be modyfied at all, so I don't see any value in giving it a variable.
Page_Next/Previous are allready variable based.
If you are storing them into the variables, then you aren't using them in the code correctly. There are parts of the code where you refer to the actual ability in the Object Editor instead of the variable.
 
I'm referring to here: Set IFS_Index_Player = (Player number of (Owner of (Triggering unit)))


If you are storing them into the variables, then you aren't using them in the code correctly. There are parts of the code where you refer to the actual ability in the Object Editor instead of the variable.
You are right i did this. Currently i converting this to jass which is more suited, will be released as soon as it works as intended and fills the JAPG.
IFShop 1.1d was a hotfix.
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
Meh I'm going to have to throw this at the bottom of the moderation list for now unless another reviewer comes by. There are other submissions we must go to, and I was expecting to keep reviewing this from the GUI version. Since you decided to convert it to JASS after I did my review, I'm going to have to review it all over again.

Feel free to keep updating it if you find any bugs. For now, please get rid of the unnecessary BJs and use exitwhen true to exit a loop instead of setting the loop integer to some arbitarily large value.
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
The system seemed small at first, but as I began to read the code and see the mechanics, I began to see the entirety of the system. I rather like how you managed to get this to work with the WC3 interface. The movement between pages and the combination of items feel smooth. The only con I can see is some inefficiency in the code and the rather large learning curve. Fortunately though, the system isn't periodic, so I can't imagine this causing any issues. I sort of don't feel like taking the time to re-read your code again given that it was originally in GUI, so I'm going to trust that the JASS is okay.

Needs Fixed

  • Nothing

Suggestions

  • I would highly appreciate it if you can leave some documentation in your code. The logics make sense to you because you made it, but you must consider that the Reviewers and Moderators just see this as arbitary code.
  • I would make use of bj_MAX_PLAYER_SLOTS instead of using random numbers like 11 or 16

Status

Approved
 
Added some Documentation to the Code uploaded on Hive. (Not in the Map)
Fixed a Error in "IFS Add Item" on Hive showing an old version. (was correct in the map)


Edit: Updated to 1.5.
This patch overworked the System overall, improving performance on big itempools by presaving connections between Plans, Fusions and Mats which takes away alot of calcing power during game time.
Edit: Updated to 1.6.
1.6 improves 1.5 and adds new features:
setting items per page
showing upgrades of upgrades.
improved error messages for registering fusions
show upgrades for any item hold by shopper and bagpack.
 
Last edited:
Top