• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Recipe Engine Help

Status
Not open for further replies.
Something's wrong the code I'm writing for my RecipeEngine.
My first method was a linked list of struct instances, but it needed about a hundred iterations if a hundred recipes were in the map.
My new method needs a maximum of 5 iterations if the item aquired is included in 5 recipes.

The problem is, the system only combines the items for the last created recipe =(

JASS:
library RecipeEngine
    globals
        // The effect that appears on Recipe Compiling
        private constant string EFFECT                      = "Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl"
        // The attachment point of the effect
        private constant string ATTACHMENT                  = "origin"
    endglobals
    
    private keyword Init
    
    struct Recipe
        private         Table       recipeItemIds
        private         integer     recipeResultId
        private         integer     itemCountRecipe
        private static  Table       recipeInstancePointers
        private static  Table       recipeInstancePointersIndex
        private static  Table       recipeDisassembleData
                static  boolean     enabled
        private static method getItem takes unit whichUnit, integer whichItem returns item
            local integer index = 0
            // Loop through the units inventory
            loop
                exitwhen index > 5
                // Find the first item in his slot with the desired item id
                if GetItemTypeId(UnitItemInSlot(whichUnit,index)) == whichItem then
                    // return that item
                    return UnitItemInSlot(whichUnit,index)
                endif
                // increase index
                set index = index + 1
            endloop
            // else, return null
            return null
        endmethod
        private method hasItems takes unit whichUnit returns boolean
            local integer       index0  = 0
            local integer       index1  = 1
            local integer       id
            local integer array count
            // Loop through the items in his inventory
            loop
                exitwhen index0 > 5
                set id = GetItemTypeId(UnitItemInSlot(whichUnit,index0))
                // if it's a null id, set it to -1 because 0 could 
                // be a value defaulted in the Table
                if 0 == id then
                    set id = -1
                endif
                // We loop through the recipe items
                loop
                    exitwhen index1 > 6
                    // If the current item is equal to one of the recipe items, we increase
                    // the number of items found by 1
                    // This was made to function with double items ('I000' and 'I000' in a recipe for example)
                    if id == this.recipeItemIds[index1] and count[index1] == 0 then
                        set count[index1] = 1
                        // if we found an item, we exit the loop
                        set index1 = 6
                    endif
                    // increase index
                    set index1 = index1 + 1
                endloop
                // We check if the number of items found is equal to the item count of the recipe
                if count[1] + count[2] + count[3] + count[4] + count[5] + count[6] == this.itemCountRecipe then
                    // if yes, the unit has the items and we'd return true
                    return true
                endif
                // reconfigure indicies
                set index0 = index0 + 1
                set index1 = 1
            endloop
            // else, the unit doesn't have the items.
            return false
        endmethod
        // This function returns the amount of empty
        // slots in a units inventory
        private static method inventorySpace takes unit whichUnit returns integer
            local integer index = 0
            local integer count = 0
            // loop through all the inventory items
            loop
                exitwhen index > 5
                // if the item is null, the space is empty
                if UnitItemInSlot(whichUnit,index) == null then
                    // we increase the count
                    set count = count + 1
                endif
                // we increase the index
                set index = index + 1
            endloop
            // return the space count
            return count
        endmethod
        private static method run takes nothing returns boolean
            local thistype  this
            local integer   id          = GetItemTypeId(GetManipulatedItem())
            local integer   index0      = 1
            local integer   index       = 1
            local unit      whichUnit   = GetTriggerUnit()
            local item      whichItem
            // If the system is enabled, we run the algorithm
            if thistype.enabled then
                loop
                    // When the count of the pointers for an item to a recipe instance
                    // is less than the index, we exit the loop
                    exitwhen index0 > integer(recipeInstancePointersIndex[id])
                    // we set this = the current instance of the struct using the id of the item
                    // and the index
                    set this = recipeInstancePointers[id][index0]
                    // if the recipe isn't null and the unit has the items
                    if this != 0 and this.hasItems(whichUnit) then
                        // we loop through the correct recipe items and remove them
                        loop
                            exitwhen index > this.itemCountRecipe
                            call RemoveItem(thistype.getItem(whichUnit,this.recipeItemIds[index]))
                            set index = index + 1
                        endloop
                        // we add and destroy the sfx
                        call DestroyEffect(AddSpecialEffectTarget(EFFECT,whichUnit,ATTACHMENT))
                        // we create the recipe item
                        set whichItem = CreateItem(this.recipeResultId,GetUnitX(whichUnit),GetUnitY(whichUnit))
                        // we give it to the unit
                        call UnitAddItem(whichUnit,whichItem)
                        // we attach the instance of the struct to the item so we can easily
                        // disassemble it without any searches
                        set recipeDisassembleData[GetHandleId(whichItem)] = this
                        // we set the index to force the loop to exit
                        set index0 = recipeInstancePointersIndex[id]
                    endif
                    // we increase the index
                    set index0 = index0 + 1
                endloop
            endif
            // we null the handles
            set whichUnit = null
            set whichItem = null
            return false
        endmethod
        static method disassemble takes unit whichUnit, item whichItem returns boolean
            local thistype  this        = recipeDisassembleData[GetHandleId(whichItem)]
            local real      whichUnitX  = GetUnitX(whichUnit)
            local real      whichUnitY  = GetUnitY(whichUnit)
            local integer   index       = 1
            // If the item instance isn't null and there's enough space
            // in the units inventory, we continue.
            if 0 != this and this.itemCountRecipe <= thistype.inventorySpace(whichUnit) + 1 then
                // we disable the system to prevent reassembling
                set thistype.enabled = false
                // we remove the item
                call RemoveItem(whichItem)
                loop
                    // we give the unit all the items needed
                    exitwhen index > 6
                    if 0 != this.recipeItemIds[index] then
                        call UnitAddItem(whichUnit,CreateItem(this.recipeItemIds[index],whichUnitX,whichUnitY))
                    endif
                    // increase index
                    set index = index + 1
                endloop
                // enable the system
                set thistype.enabled = true
                // return true to indicate successful disassembling
                return true
            endif
            // return false to indicate an error
            return false
        endmethod
        static method create takes integer i1, integer i2, integer i3, integer i4, integer i5, integer i6, integer i7 returns thistype
            local thistype  this        = thistype.allocate()
            local integer   index       = 1
            // The dynamic Table is used to avoid
            // increasing the InstancePointersIndex multiple times.
            // This way, searches are less redundant in the run method.
            local Table     booleans    = Table.create()
            
            set this.recipeItemIds      = Table.create()
            
            // If the item id isn't null
            if i1 != 0 then
                // we increase the pointers index/count by 1
                set recipeInstancePointersIndex[i1] = recipeInstancePointersIndex[i1] + 1
                // we set the item id pointer of the current index to this
                set recipeInstancePointers[i1][recipeInstancePointersIndex[i1]]=this
                // we increase the item count
                set this.itemCountRecipe = this.itemCountRecipe + 1
                // we set the item id in the Table to i1
                set this.recipeItemIds[this.itemCountRecipe] = i1
                // we set the boolean to true to indicate that we already configured the pointers 
                // of the current item id
                set booleans.boolean[i1] = true
            endif
            
            // If the item id isn't null
            if i2 != 0 then
                // If we didn't encounter the id, we configure the pointers
                if not booleans.boolean[i2] then
                    // we increase the pointers index/count by 1
                    set recipeInstancePointersIndex[i2] = recipeInstancePointersIndex[i2] + 1
                    // we set the item id pointer of the current index to this
                    set recipeInstancePointers[i2][recipeInstancePointersIndex[i2]] = this
                    // we set the boolean to true to indicate that we already configured the pointers 
                    // of the current item id
                    set booleans.boolean[i2] = true
                endif
                // we increase the item count
                set this.itemCountRecipe = this.itemCountRecipe + 1
                // we set the item id in the Table to i2
                set this.recipeItemIds[this.itemCountRecipe] = i2
            endif
            
            // If the item id isn't null
            if i3 != 0 then
                // If we didn't encounter the id, we configure the pointers
                if not booleans.boolean[i3] then
                    // we increase the pointers index/count by 1
                    set recipeInstancePointersIndex[i3] = recipeInstancePointersIndex[i3] + 1
                    // we set the item id pointer of the current index to this
                    set recipeInstancePointers[i3][recipeInstancePointersIndex[i3]] = this
                    // we set the boolean to true to indicate that we already configured the pointers 
                    // of the current item id
                    set booleans.boolean[i3] = true
                endif
                // we increase the item count
                set this.itemCountRecipe = this.itemCountRecipe + 1
                // we set the item id in the Table to i3
                set this.recipeItemIds[this.itemCountRecipe] = i3
            endif
            
            // If the item id isn't null
            if i4 != 0 then
                // If we didn't encounter the id, we configure the pointers
                if not booleans.boolean[i4] then
                    // we increase the pointers index/count by 1
                    set recipeInstancePointersIndex[i4] = recipeInstancePointersIndex[i4] + 1
                    // we set the item id pointer of the current index to this
                    set recipeInstancePointers[i4][recipeInstancePointersIndex[i4]] = this
                    // we set the boolean to true to indicate that we already configured the pointers 
                    // of the current item id
                    set booleans.boolean[i4] = true
                endif
                // we increase the item count
                set this.itemCountRecipe = this.itemCountRecipe + 1
                // we set the item id in the Table to i4
                set this.recipeItemIds[this.itemCountRecipe] = i4
            endif
            
            // If the item id isn't null
            if i5 != 0 then
                // If we didn't encounter the id, we configure the pointers
                if not booleans.boolean[i5] then
                    // we increase the pointers index/count by 1
                    set recipeInstancePointersIndex[i5] = recipeInstancePointersIndex[i5] + 1
                    // we set the item id pointer of the current index to this
                    set recipeInstancePointers[i5][recipeInstancePointersIndex[i5]] = this
                    // we set the boolean to true to indicate that we already configured the pointers 
                    // of the current item id
                    set booleans.boolean[i5] = true
                endif
                // we increase the item count
                set this.itemCountRecipe = this.itemCountRecipe + 1
                // we set the item id in the Table to i5
                set this.recipeItemIds[this.itemCountRecipe] = i5
            endif
            
            // If the item id isn't null
            if i6 != 0 then
                // If we didn't encounter the id, we configure the pointers
                if not booleans.boolean[i6] then
                    // we increase the pointers index/count by 1
                    set recipeInstancePointersIndex[i6] = recipeInstancePointersIndex[i6] + 1
                    // we set the item id pointer of the current index to this
                    set recipeInstancePointers[i6][recipeInstancePointersIndex[i6]] = this
                    // we set the boolean to true to indicate that we already configured the pointers 
                    // of the current item id
                    set booleans.boolean[i6] = true
                endif
                // we increase the item count
                set this.itemCountRecipe = this.itemCountRecipe + 1
                // we set the item id in the Table to i6
                set this.recipeItemIds[this.itemCountRecipe] = i6
            endif
            
            // we configure the id of the result
            set this.recipeResultId = i7
            // we destroy the dynamic table
            call booleans.destroy()
            // we return this
            return this
        endmethod
        method destroy takes nothing returns nothing
            call this.recipeItemIds.destroy()
            call this.deallocate()
        endmethod
        implement Init
    endstruct
    
    private module Init
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_PICKUP_ITEM)
            call TriggerAddCondition(t,Condition(function thistype.run))
            // we create the static tables
            set thistype.recipeInstancePointersIndex    = Table.create()
            set thistype.recipeInstancePointers         = Table.create()
            set thistype.recipeDisassembleData          = Table.create()
            // we enable the system
            set thistype.enabled=true
            set t = null
        endmethod
    endmodule
    
    // Optional Jass API
    function CreateRecipe takes integer i1, integer i2, integer i3, integer i4, integer i5, integer i6, integer i7 returns Recipe
        return Recipe.create(i1,i2,i3,i4,i5,i6,i7)
    endfunction
    
    function DestroyRecipe takes Recipe this returns nothing
        call this.destroy()
    endfunction
    
    function EnableRecipes takes nothing returns nothing
        set Recipe.enabled = true
    endfunction
    
    function DisableRecipes takes nothing returns nothing
        set Recipe.enabled = false
    endfunction
    
    function RecipesEnabled takes nothing returns boolean
        return Recipe.enabled
    endfunction
    
    function DisassembleItem takes unit u, item it returns boolean
        return Recipe.disassemble(u,it)
    endfunction
endlibrary

What could be the problem D=
I've been banging my head against the wall for 2 days now >.<
 
Last edited:
The only thing I can think of is to create debug messages displaying I2S(this) in the loop in the "run" method.
JASS:
loop
    exitwhen i>integer(w[k])
    set this=q[k][i]

    call BJDebugMsg(I2S(this))

Maybe there is something wrong with the list. Anyway, I can't really tell what is going on. One useful tip, don't shorten the names of your variables until you've finished the system. :p

Otherwise, you may suffer severe brain damage and head trauma from banging your head against the wall.

Add some comments and/or make the var names more clear, and we'll probably be able to find the problem. :)
 
One useful tip, don't shorten the names of your variables until you've finished the system. :p

Otherwise, you may suffer severe brain damage and head trauma from banging your head against the wall.

Add some comments and/or make the var names more clear, and we'll probably be able to find the problem. :)

In cases where the code starts to become harder for me to read, I start adding comments =P.
 
The test script would be something like:

JASS:
function test takes nothing returns nothing
    call CreateRecipe('rde1','rde1',0,0,0,0,'rde2')
    call CreateRecipe('rde1','rde2',0,0,0,0,'rde3')
    call CreateRecipe('rde2','rde3',0,0,0,0,'rde1') // lol
endfunction

private module Init
    private static method onInit takes nothing returns nothing
        call CreateUnit(Player(0),'Hpal',0,0,270)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call CreateItem('rde1',0,0)
        call test()
    endmethod
endmodule
private struct Inits
    implement Init
endstruct
 
Status
Not open for further replies.
Top