//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