1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Head to the 33rd Modeling Contest Poll and drink to your heart's desire.
    Dismiss Notice
  3. Choose your means of doom in the 17th Mini Mapping Contest Poll.
    Dismiss Notice
  4. A slave to two rhythms, the 22nd Terraining Contest is here.
    Dismiss Notice
  5. The heavens smile on the old faithful. The 16th Techtree Contest has begun.
    Dismiss Notice
  6. The die is cast - the 6th Melee Mapping Contest results have been announced. Onward to the Hive Cup!
    Dismiss Notice
  7. The glory of the 20th Icon Contest is yours for the taking!
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Recipe System

Submitted by maddeem
This bundle is marked as pending. It has not been reviewed by a staff member yet.
This is a simple recipe system that can dynamically create, modify, enable/disable and delete recipes/components. You can have an unlimited* number of recipes, with an unlimited* number of components. The recipe results are not coded into the system, as seen in the example, because it would just limit the potential of the system.

*limited by the operations limit

Documenation & Code

Code (vJASS):

/* API DOCUMENTATION:

RECIPES
=================================================
public function New takes nothing returns integer
    - Used to create a new recipe. The integer returned is the recipe identifier.

public function Destroy takes integer recipe returns nothing
    - Used to destroy a recipe and all data attached to it.

public function SetEnabled takes integer recipe, boolean enabled returns nothing
    - Used to enable / disable a recipe.

public function IsEnabled takes integer recipe returns boolean
    - Checks recipe enable / disable status

public function GetLast takes nothing returns integer
    - Returns the last created recipe identifier.

COMPONENTS
=================================================
public function Component_Add takes integer recipe, integer itemType, integer charges returns integer
    - Adds a component requirement to a recipe. Items with no charge (ex: permanent items) get counted
    as having one charge. So if you had three permanent items, it would be counted as 3 charges.

    - Returns the component number in the recipe, which can be used to modify or remove components

public function Component_Modify takes integer recipe, integer component, integer itemType, integer charges returns nothing
    - Modify a component using the component number.

public function Component_Remove takes integer recipe, integer component returns nothing
    - Removes a component using the component number.

public function Component_GetType takes integer recipe, integer component returns integer
    - Gets a recipe component item type.

public function Component_GetCharge takes integer recipe, integer component returns integer
    - Gets a recipe component charge.

CATALOG
=================================================
function CatalogItem takes item curItem returns nothing
    - Adds a specific item to the list of items considered for recipe detection. (ex: can add items on the ground,
    in inventories etc)

function CatalogInventory takes unit u returns nothing
    - Adds all items in a unit's inventory to the current catalog.

function ClearCatalog takes nothing returns nothing
    - Clears the current catalog of all items.

RECIPE COMPLETION CHECKS
=================================================
public function Check_Recipe takes integer recipe returns boolean
    - Checks a specific recipe to see if the current catalog has the components for completion

public function Check_Item takes integer itemType returns integer
    - Checks all recipes an item is a component for.

    - Returns a recipe identifier if the component requirements are met. Returns 0 if there are not enough
    components.

public function Check_ItemsForRecipesInCommon takes integer itemType1, integer itemType2 returns integer
    - Checks and compares two item types only for recipes that they share.

    - Returns a recipe identifier if the component requirements are met. Returns 0 if there are not enough
    components.

public function Check_All takes nothing returns integer
    - Checks all recipes that the cataloged items could create.

    - Returns a recipe identifier if the component requirements are met. Returns 0 if there are not enough
    components.

public function DestroyItemComponents takes integer recipe returns nothing
    - Used to consume the specific recipe component items in a catalog (Use after a check to see if the items are present) */


library Recipe

    globals
        private item array RETURN_ITEMS
        private integer array RETURN_CHARGES
        private integer RETURNED_ITEMS
        private integer array RETURN_TYPES
        private integer array RETURN_TYPES_CHARGES
        private integer RETURNED_TYPES
        private integer RECIPE_MAX = 0
        private hashtable HASHTABLE = InitHashtable()
        private integer array RECIPE_LIST
        private integer RECIPE_LIST_MAX = 0
        private integer RECIPE_LAST
    endglobals

    private function GetOffset takes integer component returns integer
        return 2 + component * 2
    endfunction

    public function Component_Remove takes integer recipe, integer component returns nothing
        local integer componentLast = LoadInteger(HASHTABLE, recipe, 0)
        local integer offset = GetOffset(component)
        local integer offsetNext = GetOffset(componentLast)
        local integer itemType = LoadInteger(HASHTABLE, recipe, offset)
        local integer recipesInItem = LoadInteger(HASHTABLE, itemType, 0)
        local integer curCount = 0

        call SaveInteger(HASHTABLE, recipe, offset, LoadInteger(HASHTABLE, recipe, offsetNext))
        call SaveInteger(HASHTABLE, recipe, offset + 1, LoadInteger(HASHTABLE, recipe, offsetNext + 1))
        call RemoveSavedInteger(HASHTABLE, recipe, offsetNext)
        call RemoveSavedInteger(HASHTABLE, recipe, offsetNext + 1)
        call SaveInteger(HASHTABLE, recipe, 0, componentLast - 1)
        loop
            set curCount = curCount + 1
            exitwhen curCount > recipesInItem or LoadInteger(HASHTABLE, itemType, curCount) == recipe
        endloop
        call SaveInteger(HASHTABLE,itemType, curCount, LoadInteger(HASHTABLE, itemType, recipesInItem))
        call RemoveSavedInteger(HASHTABLE, itemType, recipesInItem)
        call SaveInteger(HASHTABLE, itemType, 0, recipesInItem - 1)
    endfunction

    public function Component_Modify takes integer recipe, integer component, integer itemType, integer charges returns nothing
        local integer offset = GetOffset(component)

        call SaveInteger(HASHTABLE, recipe, offset, itemType)
        call SaveInteger(HASHTABLE, recipe, offset + 1, charges)
    endfunction

    public function Component_Add takes integer recipe, integer itemType, integer charges returns integer
        local integer component = LoadInteger(HASHTABLE, recipe, 0) + 1
        local integer recipeInItem = LoadInteger(HASHTABLE, itemType, 0)
        local integer offset = GetOffset(component)
        local integer i = 0

        call SaveInteger(HASHTABLE, recipe, 0, component)
        call SaveInteger(HASHTABLE, recipe, offset, itemType)
        call SaveInteger(HASHTABLE, recipe, offset + 1, charges)

        loop
            set i = i + 1
            exitwhen i > recipeInItem or recipe == LoadInteger(HASHTABLE, itemType, i)
        endloop
        if i > recipeInItem then
            call SaveInteger(HASHTABLE, itemType, 0, i)
            call SaveInteger(HASHTABLE, itemType, i, recipe)
              endif
        return component
    endfunction

    public function Component_GetType takes integer recipe, integer component returns integer
        return LoadInteger(HASHTABLE, recipe, GetOffset(component))
    endfunction

    public function Component_GetCharge takes integer recipe, integer component returns integer
        return LoadInteger(HASHTABLE, recipe, GetOffset(component) + 1)
    endfunction

    public function New takes nothing returns integer
        if RECIPE_LIST_MAX > 0 then
            set RECIPE_LAST = RECIPE_LIST[RECIPE_LIST_MAX]
            set RECIPE_LIST_MAX = RECIPE_LIST_MAX - 1
        else
            set RECIPE_MAX = RECIPE_MAX + 1
            set RECIPE_LAST = RECIPE_MAX
        endif
        call SaveBoolean(HASHTABLE,RECIPE_LAST, 1, true)
        return RECIPE_LAST
    endfunction

    public function Destroy takes integer recipe returns nothing
        local integer curItemType
        local integer forItemsInRecipe = 0
        local integer itemsInRecipe = LoadInteger(HASHTABLE, recipe, 0)
        local integer itemInRecipeOffset
        local integer recipesInItem

        loop
            set forItemsInRecipe = forItemsInRecipe + 1
            exitwhen forItemsInRecipe > itemsInRecipe
            set curItemType = LoadInteger(HASHTABLE, recipe, GetOffset(forItemsInRecipe))
            set itemInRecipeOffset = 0
            loop
                set itemInRecipeOffset = itemInRecipeOffset + 1
                exitwhen recipe == LoadInteger(HASHTABLE, curItemType, itemInRecipeOffset)
            endloop
            set recipesInItem = LoadInteger(HASHTABLE, curItemType, 0)
            call SaveInteger(HASHTABLE, curItemType, itemInRecipeOffset, LoadInteger(HASHTABLE, curItemType, recipesInItem))
            call RemoveSavedInteger(HASHTABLE, curItemType, recipesInItem)
            call SaveInteger(HASHTABLE, curItemType, 0, recipesInItem - 1)
        endloop
        call FlushChildHashtable(HASHTABLE, recipe)
        set RECIPE_LIST_MAX = RECIPE_LIST_MAX + 1
        set RECIPE_LIST[RECIPE_LIST_MAX] = recipe
    endfunction

    public function SetEnabled takes integer recipe, boolean enabled returns nothing
        call SaveBoolean(HASHTABLE, recipe, 1, enabled)
    endfunction

    public function IsEnabled takes integer recipe returns boolean
        return LoadBoolean(HASHTABLE, recipe, 1)
    endfunction

    public function GetLast takes nothing returns integer
        return RECIPE_LAST
    endfunction

    function ClearCatalog takes nothing returns nothing
        set RETURNED_ITEMS = 0
        set RETURNED_TYPES = 0
    endfunction

    function CatalogItem takes item curItem returns nothing
        local integer curType
        local integer charge
        local integer forType = 0

        set RETURNED_ITEMS = RETURNED_ITEMS + 1
        set RETURN_ITEMS[RETURNED_ITEMS] = curItem
        set charge = GetItemCharges(curItem)
        if charge == 0 then
            set charge = 1
        endif
        set RETURN_CHARGES[RETURNED_ITEMS] = charge
        set curType = GetItemTypeId(curItem)
        loop
            set forType = forType + 1
            exitwhen forType > RETURNED_TYPES or curType == RETURN_TYPES[forType]
        endloop
        if RETURNED_TYPES < forType then
            set RETURN_TYPES_CHARGES[forType] = 0
            set RETURNED_TYPES = forType
        endif
        set RETURN_TYPES[forType] = curType
        set RETURN_TYPES_CHARGES[forType] = RETURN_TYPES_CHARGES[forType] + charge
    endfunction

    function CatalogInventory takes unit u returns nothing
        local integer forSlot = 0
        local integer forType
        local item curItem

        loop
            set curItem = UnitItemInSlot(u, forSlot)
            if curItem != null then
                call CatalogItem(curItem)
            endif
            exitwhen forSlot > 5
            set forSlot = forSlot + 1
        endloop
        set curItem = null
    endfunction

    public function Check_Recipe takes integer recipe returns boolean
        local integer completedComponents = 0
        local integer itemsInRecipe = LoadInteger(HASHTABLE, recipe, 0)
        local integer typeNumber = 0
        local integer recipeListNumber
        local integer offset

        if LoadBoolean(HASHTABLE, recipe, 1) then
            loop
                set typeNumber = typeNumber + 1
                exitwhen typeNumber > RETURNED_TYPES
                set recipeListNumber = 0
                loop
                    set recipeListNumber = recipeListNumber + 1
                    exitwhen recipeListNumber > itemsInRecipe
                    set offset = GetOffset(recipeListNumber)
                    if LoadInteger(HASHTABLE, recipe, offset) == RETURN_TYPES[typeNumber] then
                        if LoadInteger(HASHTABLE, recipe, offset + 1) <= RETURN_TYPES_CHARGES[typeNumber] then
                            set completedComponents = completedComponents + 1
                        endif
                    endif
                endloop
            endloop
            return completedComponents >= itemsInRecipe
        else
            return false
        endif
    endfunction

    public function Check_Item takes integer itemType returns integer
        local integer recipeNumber = 0
        local integer curRecipe
        local integer recipesMax = LoadInteger(HASHTABLE, itemType, 0)

        loop
            set recipeNumber = recipeNumber + 1
            exitwhen recipeNumber > recipesMax
            set curRecipe = LoadInteger(HASHTABLE, itemType, recipeNumber)
            if Check_Recipe(curRecipe) then
                return curRecipe
            endif
        endloop
        return 0
    endfunction

    public function Check_ItemsForRecipesInCommon takes integer itemType1, integer itemType2 returns integer
        local integer array recipeList
        local boolean array recipeInCommon
        local integer listCur
        local integer listMax = 0
        local integer recipesMax
        local integer recipeNumber
        local integer curRecipe
        local integer forType
        local integer i = 0

        loop
            set i = i + 1
            exitwhen i > 2
            if i == 1 then
                set forType = itemType1
            else
                set forType = itemType2
            endif
            set recipesMax = LoadInteger(HASHTABLE, forType, 0)
            set recipeNumber = 0
            loop
                set recipeNumber = recipeNumber + 1
                exitwhen recipeNumber > recipesMax
                set curRecipe = LoadInteger(HASHTABLE, forType, recipeNumber)
                set listCur = 0
                loop
                    set listCur = listCur + 1
                    exitwhen listCur > listMax or curRecipe == recipeList[listCur]
                endloop
                if curRecipe != recipeList[listCur] then
                    set listMax = listCur
                    set recipeList[listCur] = curRecipe
                elseif curRecipe == recipeList[listCur] then
                    set recipeInCommon[listCur] = true
                endif
            endloop
        endloop
        loop
            exitwhen listMax <= 0
            set curRecipe = recipeList[listMax]
            if recipeInCommon[listMax] then
                if Check_Recipe(curRecipe) then
                    return curRecipe
                endif
            endif
            set listMax = listMax - 1
        endloop
        return 0
    endfunction

    public function Check_All takes nothing returns integer
        local integer array recipes
        local integer recipesTotal = 0
        local integer recipesCheck
        local integer typeNumber = 0
        local integer curRecipe
        local integer recipesMax
        local integer recipeNumber
        local integer itemType

        loop
            set typeNumber = typeNumber + 1
            exitwhen typeNumber > RETURNED_TYPES
            set itemType = RETURN_TYPES[typeNumber]
            set recipesMax = LoadInteger(HASHTABLE, itemType, 0)
            set recipeNumber = 0
            loop
                set recipeNumber = recipeNumber +1
                exitwhen recipeNumber > recipesMax
                set curRecipe = LoadInteger(HASHTABLE, itemType, recipeNumber)
                set recipesCheck = 0
                loop
                    set recipesCheck = recipesCheck + 1
                    exitwhen recipesCheck > recipesTotal or curRecipe == recipes[recipesCheck]
                endloop
                if recipesTotal < recipesCheck then
                    set recipesTotal = recipesCheck
                    set recipes[recipesCheck] = curRecipe
                endif
            endloop
        endloop
        loop
            exitwhen recipesTotal == 0
            if Check_Recipe(recipes[recipesTotal]) then
                return recipes[recipesTotal]
            endif
            set recipesTotal = recipesTotal - 1
        endloop
        return 0
    endfunction

    public function DestroyItemComponents takes integer recipe returns nothing
        local integer itemsInRecipe = LoadInteger(HASHTABLE, recipe, 0)
        local integer itemNumber
        local integer curType
        local integer curCharge
        local integer curRecipeStep = 0
        local integer offset
        loop
            set curRecipeStep = curRecipeStep + 1
            exitwhen curRecipeStep > itemsInRecipe
            set offset = GetOffset(curRecipeStep)
            set curType = LoadInteger(HASHTABLE, recipe, offset)
            set curCharge = LoadInteger(HASHTABLE, recipe, offset + 1)
            set itemNumber = 0
            loop
                set itemNumber = itemNumber + 1
                exitwhen itemNumber > RETURNED_ITEMS or curCharge == 0
                if curType == GetItemTypeId(RETURN_ITEMS[itemNumber]) then
                    if RETURN_CHARGES[itemNumber] > curCharge then
                        set RETURN_CHARGES[itemNumber] = RETURN_CHARGES[itemNumber] - curCharge
                        call SetItemCharges(RETURN_ITEMS[itemNumber], RETURN_CHARGES[itemNumber])
                        set curCharge = 0
                    else
                        call RemoveItem(RETURN_ITEMS[itemNumber])
                        set curCharge = curCharge - RETURN_CHARGES[itemNumber]
                        set RETURN_ITEMS[itemNumber] = null
                        set RETURN_CHARGES[itemNumber] = 0
                    endif
                endif
            endloop
        endloop
    endfunction

endlibrary
 
Contents

Recipe System (Map)

  1. AIfred

    AIfred

    Joined:
    Jul 1, 2020
    Messages:
    22
    Resources:
    0
    Resources:
    0
    Why not implement a command -recipe [Itemname] aswell..
     
  2. maddeem

    maddeem

    Joined:
    Jan 1, 2011
    Messages:
    1,324
    Resources:
    6
    Icons:
    1
    Maps:
    2
    Spells:
    3
    Resources:
    6
    Because an item could be used in multiple recipes both as a component and as a result.
     
  3. AIfred

    AIfred

    Joined:
    Jul 1, 2020
    Messages:
    22
    Resources:
    0
    Resources:
    0
    And how would that effect the -recipe command?
    You can search for components to see what they can be made into.
    And Search for Results and see what they can be made into. no biggy.
     
  4. GhostHunter123

    GhostHunter123

    Joined:
    Oct 17, 2012
    Messages:
    479
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Such a chat command should not be a part of the core system itself. The user should implement it himself via the core system because everyone wants different things.

    @maddeem The check recipe functions would be better off returning a list of valid recipes, not just one. It is rather limiting as is. I would like to combine a whole slew of items simultaneously.