• 🏆 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!

TEEquip - Equipment System

Status
Not open for further replies.
Level 6
Joined
May 19, 2004
Messages
267
Hi all,

This is an equipment system used to simulate an equipment menu. I'm posting this here to hopefully get some feedback on the functionality, as well as the code. Note that this is just a testversion, the code is not properly commented, nor is there any full documentation.
Importing is not supported yet.

I embarked on this project April 2006, where it was uploaded at clancbs.com.
In January 2009 I made a remake of it, adding new functionality and redoing alot of the code.
Today, I'm hopefully rewriting it for the last time.

It now uses vJass and ObjectMerger for easy importing and a clean code structure. So the system requires NewGen/JassHelper. The new system should support any kind of item bonuses you may want with some Jass knowledge.

It currently only functions as a template, however, I will later add modules to simplify adding basic stats.

Upcoming features:
  • Documentation
  • Set bonuses
  • Two handed weapons
  • Dualwield
  • Easy managing for basic stats
  • Proper customized stat/level requirements.
  • Option to drop items on death
  • A "validate" function if a unit delevels or looses stats etc.
  • Temporarily enabling/disabling itemtypes and units from the system.
  • Locking/Hiding slots for specific units.
  • Waffles?

Enjoy

JASS:
library TEEquip initializer Init requires Table, Stack, UnitIndexingUtils, SimError
//***********************************************************************************************************************
//*  TEEquip
//* 
//*  Author: Thunder_Eye
//* 
//*  Credits:
//*   * Vexorian for vJass, JassHelper, and the finding of the spellbook trick
//*   * PitzerMike for the ObjectMerger
//*   * PipeDream for Grimoire
//*   * SFilip for TESH
//*   * MindWorX for maintaining NewGen
//*
//*  Required Libraries:
//*   * Table by Vexorian
//*   * Stack by Anitarf
//*   * UnitIndexingUtils by Rising Dusk
//*   * SimError by Vexorian
//*
//*  Optional Libraries:
//*   * UnitMaxState by Earth-Fury
//*   * BonusMod by Earth-Fury
//* 
//*  This is an equipment system which is easy to implent, and outputs a smooth 
//*  userinterface for the endgame user. However, it requires some massive Object
//*  Editor use, and if used incorrectly, may clutter up your Ability section.
//*  It supports up to 8191 different allocated itemtypes, and the same amount of
//*  units utilizing the system.
//*
//*  The basic system only works as a template with the addition that it handles
//*  item requirements for you.
//*
//*  In a future version however, there will be additional modules that can manage
//*  changing the basic stats for you.
//*
//*  Note that using UnitIndexingUtils will render you unable to use UnitUserData().
//*  
//*  To initialize a unit, call InitUnit (with the TEEquip prefix)
//*  To add an itemtype, call AddItemType (again, with the TEEquip prefix)
//*  Note that these are just wrapper functions, I suggest creating the structs
//*  directly.
//*
//*  Function list:
//*      function InitUnit takes unit u returns nothing
//*      function AddItemType takes integer iType, integer aId, integer sbId, integer slot, code eF, code uF returns nothing
//*      function AddRestriction takes string restriction returns nothing
//*      function AddRequirement takes string requirement returns nothing
//*      function SetRequiredLevel takes integer value returns nothing
//*      function SetRequiredStr takes integer value returns nothing
//*      function SetRequiredAgi takes integer value returns nothing
//*      function SetRequiredInt takes integer value returns nothing
//*      function AddFunction takes code eF, code uF returns nothing
//*      function GetSlotId takes string s returns integer
//*  
//*  Initialize a unit and give it an equipment menu.
//*  This is just a wrapper function, I suggest creating the struct directly instead.
//*    function InitUnit takes unit u returns nothing
//*      unit u:                The unit to initialize
//*
//*  Add an itemtype to the system, making it equippable
//*  This is just a wrapper function, I suggest creating the struct directly instead.
//*    function AddItemType takes integer iType, integer aId, integer sbId, integer slot, code eF, code uF returns nothing
//*      integer iType:         The rawid of the itemtype.
//*      integer aId:           The rawid of the UI ability.
//*      integer sbId:          The rawid of the spellbook holding ability aId.
//*      integer slot:          The slot where the item is placed when equipped.
//*                             Can be anything between 0-10.
//*      code eF:               The function which runs when the item is equipped.
//*                             By passing null no function will run on equip.
//*      code uF:               The function which runs when the item is unequipped.
//*                             By passing null no function will run on unequip.
//*
//*  Add a restriction to a unit, enabling it to use items with the proper requirement.
//*  Note that units with no restrictions may only equip items with no requirements.
//*  Member of: equipunit
//*    function AddRestriction takes string restriction returns nothing
//*      string restriction:    The key of the restrictiontype, upper- or lowercase does not matter.
//*
//*  Add a requirement to an item, requiring units to have the proper restrictions to use it.
//*  Note that items with no requirements may be equipped by any initialized unit.
//*  Units must match ALL requirements to equip item.
//*  Member of: equipitem
//*    function AddRequirement takes string requirement returns nothing
//*      string requirement:    The key of the requirementtype, upper- or lowercase does not matter.
//*
//*  Temporary function to set a required level on itemtypes.
//*  Member of: equipitem
//*    function SetRequiredLevel takes integer value returns nothing
//*      integer value:         The required level.
//*
//*  Temporary function to set a required strength on itemtypes.
//*  Member of: equipitem
//*    function SetRequiredStr takes integer value returns nothing
//*      integer value:         The required strength.
//*
//*  Temporary function to set a required agility on itemtypes.
//*  Member of: equipitem
//*    function SetRequiredAgi takes integer value returns nothing
//*      integer value:         The required agility.
//*
//*  Temporary function to set a required intelligence on itemtypes.
//*  Member of: equipitem
//*    function SetRequiredInt takes integer value returns nothing
//*      integer value:         The required intelligence.
//*
//*  Adds an additional function (including the one when you add an itemtype) to an itemtype.
//*  Member of: equipitem
//*    function AddFunction takes code eF, code uF returns nothing
//*      code eF:               The function which runs when the item is equipped.
//*      code uF:               The function which runs when the item is unequipped.
//*
//*  Gets the id of a slot.
//*  Can be used if you want to clarify the slot when using AddItemType.
//*    function GetSlotId takes string slot returns integer
//*      string slot:           The slot you want the id from.
//*                             "shoulder" = 0, "head" = 1,  "neck" = 2,    "finger" = 3,
//*                             "mainhand" = 4, "chest" = 5, "offhand" = 6, "wrists" = 7
//*                             "feet" = 8,     "legs" = 9,  "hands" = 10
//*
//***********************************************************************************************************************
    globals
        private constant integer MenuId                     = 'ES00'
    endglobals

    globals
        //equipItemTable   = key is itemtype-id, value is struct-id
        //equipUnitTable   = key is id of unit, value is struct-id
        private Table           equipItemTable
        private Table           equipUnitTable
        
        //requirementTable = key is the name of the requirement, value is the id (requirementTable["plate"] = 1)
        //requirementKey   = key is the id of the requirement, value is the name (requirementKey[1] = "plate")
        //requirementTotal = Amount of requirements and key for new requirements (requirementTotal = 2)
        private StringTable     requirementTable
        private string array    requirementKey
        private integer         requirementTotal            = 0
        
        //itemTypesAtP[11] = Stack pointing to struct-ids
        //emptySlot[11]    = Array with the "unequipped" spellbooks
        private Stack array     itemTypesAtP[11]
        private integer array   emptySlot[11]
        
        //slotId           = key is the name of the slot, value is the id
        //hasInited        = set to true when a unit is initialized
        //hasRun           = set to true when the first unit has been initialized.
        private StringTable     slotId
        private boolean         hasInited                   = false
        private boolean         hasRun                      = false
        
        //passUnit         = triggering unit passed for equip/unequip functions
        //passItem         = manipulated item passed for equip/unequip functions
        public  unit            passUnit
        public  item            passItem
    endglobals
    
    struct equipitem
        private integer         itemTypeId
        private integer         abilityId
        private integer         spellbookId
        private integer         slot
        private Stack           requirements                = Stack.create()
        private trigger         equipTrigger                = CreateTrigger()
        private trigger         unequipTrigger              = CreateTrigger()
        
        //Temporary until I add some kind of table to handle this.
        private integer         statReq
        
        private integer         levelReq                    = 0
        private integer         strReq                      = 0
        private integer         agiReq                      = 0
        private integer         intReq                      = 0
        
        //************************************************************************************
        //******************************Call functions (public)*******************************
        //************************************************************************************
        
        public method AddRequirement takes string requirement returns nothing
            local integer i
            set requirement = StringCase(requirement, false)
            
            //Check so that it doesn't create duplicate keys of requirements.
            if not .requirements.contains(requirementTable[requirement]) then
                if requirementTable.exists(requirement) then
                    //Item requirement type already exists.
                    set i = requirementTable[requirement]
                else
                    //Item requirement type does not exist, so add it to the table.
                    set requirementTotal = requirementTotal + 1
                    set i = requirementTotal
                    
                    set requirementTable[requirement] = i
                    set requirementKey[i] = requirement
                endif
                
                //Add the key for the requirement type to the itemtype
                call .requirements.push(i)
            endif
        endmethod
        
        public method SetRequiredLevel takes integer value returns nothing
            set .levelReq = value
        endmethod
        public method SetRequiredStr takes integer value returns nothing
            set .strReq = value
        endmethod
        public method SetRequiredAgi takes integer value returns nothing
            set .agiReq = value
        endmethod
        public method SetRequiredInt takes integer value returns nothing
            set .intReq = value
        endmethod
        
        public method AddFunction takes code eF, code uF returns nothing
            call .AddEquipFunc(eF)
            call .AddUnequipFunc(uF)
        endmethod

        public method GetItemTypeId takes nothing returns integer
            return .itemTypeId
        endmethod
        public method GetAbilityId takes nothing returns integer
            return .abilityId
        endmethod
        public method GetSpellbookId takes nothing returns integer
            return .spellbookId
        endmethod
        public method GetRequirementList takes nothing returns Stack
            return .requirements
        endmethod
        public method GetSlot takes nothing returns integer
            return .slot
        endmethod
        
        //************************************************************************************
        //*****************************System functions (private)*****************************
        //************************************************************************************
        
        public method TryStats takes integer level, integer str, integer agi, integer int returns boolean
            if level >= .levelReq and str >= .strReq and agi >= .agiReq and int >= .intReq then
                return true
            endif
            return false
        endmethod
        
        private method AddEquipFunc takes code f returns nothing
            if f != null then
                call TriggerAddAction(.equipTrigger, f)
            endif
        endmethod
        private method AddUnequipFunc takes code f returns nothing
            if f != null then
                call TriggerAddAction(.unequipTrigger, f)
            endif
        endmethod
        
        public method Equip takes unit u, item i returns nothing
            set passUnit = u
            set passItem = i
            call TriggerExecute(.equipTrigger)
        endmethod
        public method Unequip takes unit u, item i returns nothing
            set passUnit = u
            set passItem = i
            call TriggerExecute(.unequipTrigger)
        endmethod
        
        method onDestroy takes nothing returns nothing
            //Not added yet
        endmethod
        
        static method create takes integer itemTypeId, integer abilityId, integer spellbookId, integer slot, code eF, code uF returns equipitem
            local equipitem new
            
            //If no unit has been registered, create the itemtype.
            if not hasInited then
                set new = equipitem.allocate()
                set new.itemTypeId = itemTypeId
                set new.abilityId = abilityId
                set new.spellbookId = spellbookId
                set new.slot = slot
                
                call new.AddEquipFunc(eF)
                call new.AddUnequipFunc(uF)
                call itemTypesAtP[slot].push(new)
                
                set equipItemTable[itemTypeId] = new
                set equipItemTable[abilityId] = new
                return new
            endif 
            
            return 0
        endmethod
    endstruct
    
    struct equipunit
        private unit            u
                integer array   equippedItem[11]
                Stack           res                         = Stack.create()
        
        static  group           equipUnits                  = CreateGroup()
        static  trigger         onEquip                     = CreateTrigger()
        static  trigger         onUnequip                   = CreateTrigger()
        
        //************************************************************************************
        //******************************Call functions (public)*******************************
        //************************************************************************************
        
        method AddRestriction takes string restriction returns nothing
            local integer i
            
            set restriction = StringCase(restriction, false)
            
            if requirementTable.exists(restriction) then
                //Item requirement type already exists.
                set i = requirementTable[restriction]
            else
                //Item requirement type does not exist, so add it to the table.
                set requirementTotal = requirementTotal + 1
                set i = requirementTotal
                
                set requirementTable[restriction] = i
                set requirementKey[i] = restriction
            endif
            
            //Add the key for the requirement type to the unit
            call .res.push(i)
        endmethod
        
        method onDestroy takes nothing returns nothing
            local integer i = 0
            
            call UnitRemoveAbility(.u, MenuId)
            
            loop
                exitwhen i > 10
                call UnitRemoveAbility(.u, emptySlot[i])
                set i = i + 1
            endloop
        
            call .res.destroy()
            set .u = null
        endmethod
        
        method Reset takes nothing returns nothing
            call .destroy()
        endmethod
        
        //************************************************************************************
        //*****************************System functions (private)*****************************
        //************************************************************************************
        
        private static method condition takes nothing returns boolean
            return IsUnitInGroup(GetTriggerUnit(), equipunit.equipUnits)
        endmethod
        
        private static method onequip takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local item i = GetManipulatedItem()
            local equipitem ei = equipItemTable[GetItemTypeId(i)]
            local equipunit eu = equipUnitTable[GetUnitId(u)]
            local integer slot = ei.GetSlot()
            
            local Stack unitRes = Stack.create()
            local Stack itemReq = Stack.create()
            local integer l
            local boolean b = true

            if ei != 0 and eu.equippedItem[slot] == 0 and eu != 0 then
                //Check requirements by looping through them.
                set unitRes = eu.res.copy()
                set itemReq = ei.GetRequirementList().copy()
                loop
                    set l = itemReq.pop()
                    exitwhen l == Stack.EMPTY
                    if not unitRes.contains(l) then
                        set b = false
                    endif
                endloop
                
                //If unit can equip item.
                if b and ei.TryStats(GetHeroLevel(u),GetHeroStr(u, false),GetHeroAgi(u, false),GetHeroInt(u, false)) then
                    set eu.equippedItem[slot] = ei.GetItemTypeId()
                    call UnitRemoveAbility(u, emptySlot[slot])
                    call UnitAddAbility(u, ei.GetSpellbookId())
                    call RemoveItem(i)
                    if GetLocalPlayer() == GetOwningPlayer(u) then
                        call ForceUIKey("I")
                    endif
                    call ei.Equip(u, i)
                else
                    call SimError(GetOwningPlayer(u), "You do not meet the requirements for that item.")
                endif
            elseif ei != 0 and eu != 0 then
                call SimError(GetOwningPlayer(u), "You already have an item equipped.")
            else
                call SimError(GetOwningPlayer(u), "You cannot equip that item.")
            endif
            
            call unitRes.destroy()
            call itemReq.destroy()
            set u = null
            set i = null
        endmethod
        
        private static method onunequip takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local item i
            local integer a = GetSpellAbilityId()
            local equipitem ei = equipItemTable[a]
            local equipunit eu = equipUnitTable[GetUnitId(u)]
            local integer slot = ei.GetSlot()
            
            if ei != 0 and eu.equippedItem[slot] != 0 then
                //Check if inventory is full, if so halt trigger.
                if UnitInventoryCount(u) == UnitInventorySize(u) then
                    call SimError(GetOwningPlayer(u), "Inventory is full")
                    set u = null
                    return
                endif
            
                set eu.equippedItem[slot] = 0
                set i = CreateItem(ei.GetItemTypeId(), 0, 0)
                call UnitRemoveAbility(u, ei.GetSpellbookId())
                call UnitAddAbility(u, emptySlot[slot])
                call UnitAddItem(u, i)
                if GetLocalPlayer() == GetOwningPlayer(u) then
                    call ForceUIKey("I")
                endif
                call ei.Unequip(u, i)
            endif
            
            set u = null
        endmethod
        
        private static method onInit takes nothing returns nothing  
            call TriggerRegisterAnyUnitEventBJ(equipunit.onEquip, EVENT_PLAYER_UNIT_USE_ITEM)
            call TriggerAddCondition(equipunit.onEquip, Condition(function equipunit.condition))
            call TriggerAddAction(equipunit.onEquip, function equipunit.onequip)
            call TriggerRegisterAnyUnitEventBJ(equipunit.onUnequip, EVENT_PLAYER_UNIT_SPELL_CAST)
            call TriggerAddCondition(equipunit.onUnequip, Condition(function equipunit.condition))
            call TriggerAddAction(equipunit.onUnequip, function equipunit.onunequip)
        endmethod
        
        static method create takes unit u returns equipunit
            local equipunit new = equipunit.allocate()
            local player p = GetOwningPlayer(u)
            local Stack s = Stack.create()
            local equipitem ei
            
            local integer sbId
            local integer i
            local integer pi
            
            set new.u = u
            call GroupAddUnit(equipunit.equipUnits, u)
            call UnitAddAbility(u, MenuId)
            
            set i = 0
            loop
                exitwhen i > 10
                set new.equippedItem[i] = 0
                set i = i + 1
            endloop
            
            set i = 0
            loop
                exitwhen i > 10
                call UnitAddAbility(u, emptySlot[i])
                call SetPlayerAbilityAvailable(p, emptySlot[i], false)
                if not hasRun then
                    set s = itemTypesAtP[i].copy()
                    loop
                        exitwhen s.peek()==Stack.EMPTY
                        set ei = s.peek()
                        set sbId = ei.GetSpellbookId()
                        call UnitAddAbility(u, sbId)
                        call UnitRemoveAbility(u, sbId)
                        set pi = 0
                        loop
                            exitwhen pi > 11
                            call SetPlayerAbilityAvailable(Player(pi), sbId, false)
                            set pi = pi + 1
                        endloop
                        call s.pop()
                    endloop
                endif
                set i = i + 1
            endloop
        
            //Add the unit to the table and make sure no more itemtypes are registered.
            set equipUnitTable[GetUnitId(u)] = new
            set hasInited = true
            set hasRun = true
            
            call s.destroy()
            
            return new
        endmethod
    endstruct
    
    public function InitUnit takes unit u returns equipunit
        return equipunit.create(u)
    endfunction
    public function AddItemType takes integer itemTypeId, integer abilityId, integer spellbookId, integer slot, code eF, code uF returns equipitem
        return equipitem.create(itemTypeId, abilityId, spellbookId, slot, eF, uF)
    endfunction
    
    function GetSlotId takes string s returns integer
        return slotId[StringCase(s, false)]
    endfunction
    
    private function Init takes nothing returns nothing
        local integer i = 0
        set equipItemTable = Table.create()
        set equipUnitTable = Table.create()
        set requirementTable = Table.create()
        set slotId = StringTable.create()
        
        loop
            exitwhen i > 10
            set itemTypesAtP[i] = Stack.create()
            set i = i + 1
        endloop
        
        set slotId["shoulders"]     = 0
        set slotId["head"]          = 1
        set slotId["neck"]          = 2
        set slotId["finger"]        = 3
        set slotId["mainhand"]      = 4
        set slotId["chest"]         = 5
        set slotId["offhand"]       = 6
        set slotId["wrists"]        = 7
        set slotId["feet"]          = 8
        set slotId["legs"]          = 9
        set slotId["hands"]         = 10
        
        set emptySlot[0]            = 'ES01'
        set emptySlot[1]            = 'ES02'
        set emptySlot[2]            = 'ES03'
        set emptySlot[3]            = 'ES04'
        set emptySlot[4]            = 'ES05'
        set emptySlot[5]            = 'ES06'
        set emptySlot[6]            = 'ES07'
        set emptySlot[7]            = 'ES08'
        set emptySlot[8]            = 'ES09'
        set emptySlot[9]            = 'ES0A'
        set emptySlot[10]           = 'ES0B'
    endfunction
endlibrary

JASS:
library TEEquip initializer Init requires Table, Stack, UnitIndexingUtils, SimError
//***********************************************************************************************************************
//*  TEEquip
//* 
//*  Author: Thunder_Eye
//* 
//*  Credits:
//*   * Vexorian for vJass, JassHelper, and the finding of the spellbook trick
//*   * PitzerMike for the ObjectMerger
//*   * PipeDream for Grimoire
//*   * SFilip for TESH
//*   * MindWorX for maintaining NewGen
//*
//*  Required Libraries:
//*   * Table by Vexorian
//*   * Stack by Anitarf
//*   * UnitIndexingUtils by Rising Dusk
//*   * SimError by Vexorian
//*
//*  Optional Libraries:
//*   * UnitMaxState by Earth-Fury
//*   * BonusMod by Earth-Fury
//* 
//*  This is an equipment system which is easy to implent, and outputs a smooth 
//*  userinterface for the endgame user. However, it requires some massive Object
//*  Editor use, and if used incorrectly, may clutter up your Ability section.
//*  It supports up to 8191 different allocated itemtypes, and the same amount of
//*  units utilizing the system.
//*
//*  The basic system only works as a template with the addition that it handles
//*  item requirements for you.
//*
//*  In a future version however, there will be additional modules that can manage
//*  changing the basic stats for you.
//*
//*  Note that using UnitIndexingUtils will render you unable to use UnitUserData().
//*  
//*  To initialize a unit, call InitUnit (with the TEEquip prefix)
//*  To add an itemtype, call AddItemType (again, with the TEEquip prefix)
//*  Note that these are just wrapper functions, I suggest creating the structs
//*  directly.
//*
//*  Function list:
//*      function InitUnit takes unit u returns nothing
//*      function AddItemType takes integer iType, integer aId, integer sbId, integer slot, code eF, code uF returns nothing
//*      function AddRestriction takes string restriction returns nothing
//*      function AddRequirement takes string requirement returns nothing
//*      function SetRequiredLevel takes integer value returns nothing
//*      function SetRequiredStr takes integer value returns nothing
//*      function SetRequiredAgi takes integer value returns nothing
//*      function SetRequiredInt takes integer value returns nothing
//*      function AddFunction takes code eF, code uF returns nothing
//*      function GetSlotId takes string s returns integer
//*  
//*  Initialize a unit and give it an equipment menu.
//*  This is just a wrapper function, I suggest creating the struct directly instead.
//*    function InitUnit takes unit u returns nothing
//*      unit u:                The unit to initialize
//*
//*  Add an itemtype to the system, making it equippable
//*  This is just a wrapper function, I suggest creating the struct directly instead.
//*    function AddItemType takes integer iType, integer aId, integer sbId, integer slot, code eF, code uF returns nothing
//*      integer iType:         The rawid of the itemtype.
//*      integer aId:           The rawid of the UI ability.
//*      integer sbId:          The rawid of the spellbook holding ability aId.
//*      integer slot:          The slot where the item is placed when equipped.
//*                             Can be anything between 0-10.
//*      code eF:               The function which runs when the item is equipped.
//*                             By passing null no function will run on equip.
//*      code uF:               The function which runs when the item is unequipped.
//*                             By passing null no function will run on unequip.
//*
//*  Add a restriction to a unit, enabling it to use items with the proper requirement.
//*  Note that units with no restrictions may only equip items with no requirements.
//*  Member of: equipunit
//*    function AddRestriction takes string restriction returns nothing
//*      string restriction:    The key of the restrictiontype, upper- or lowercase does not matter.
//*
//*  Add a requirement to an item, requiring units to have the proper restrictions to use it.
//*  Note that items with no requirements may be equipped by any initialized unit.
//*  Units must match ALL requirements to equip item.
//*  Member of: equipitem
//*    function AddRequirement takes string requirement returns nothing
//*      string requirement:    The key of the requirementtype, upper- or lowercase does not matter.
//*
//*  Temporary function to set a required level on itemtypes.
//*  Member of: equipitem
//*    function SetRequiredLevel takes integer value returns nothing
//*      integer value:         The required level.
//*
//*  Temporary function to set a required strength on itemtypes.
//*  Member of: equipitem
//*    function SetRequiredStr takes integer value returns nothing
//*      integer value:         The required strength.
//*
//*  Temporary function to set a required agility on itemtypes.
//*  Member of: equipitem
//*    function SetRequiredAgi takes integer value returns nothing
//*      integer value:         The required agility.
//*
//*  Temporary function to set a required intelligence on itemtypes.
//*  Member of: equipitem
//*    function SetRequiredInt takes integer value returns nothing
//*      integer value:         The required intelligence.
//*
//*  Adds an additional function (including the one when you add an itemtype) to an itemtype.
//*  Member of: equipitem
//*    function AddFunction takes code eF, code uF returns nothing
//*      code eF:               The function which runs when the item is equipped.
//*      code uF:               The function which runs when the item is unequipped.
//*
//*  Gets the id of a slot.
//*  Can be used if you want to clarify the slot when using AddItemType.
//*    function GetSlotId takes string slot returns integer
//*      string slot:           The slot you want the id from.
//*                             "shoulder" = 0, "head" = 1,  "neck" = 2,    "finger" = 3,
//*                             "mainhand" = 4, "chest" = 5, "offhand" = 6, "wrists" = 7
//*                             "feet" = 8,     "legs" = 9,  "hands" = 10
//*
//***********************************************************************************************************************
    globals
        //equipItemTable   = key is itemtype-id, value is struct-id
        //equipUnitTable   = key is id of unit, value is struct-id
        private Table           equipItemTable
        private Table           equipUnitTable
        
        //requirementTable = key is the name of the requirement, value is the id (requirementTable["plate"] = 1)
        //requirementKey   = key is the id of the requirement, value is the name (requirementKey[1] = "plate")
        //requirementTotal = Amount of requirements and key for new requirements (requirementTotal = 2)
        private StringTable     requirementTable
        private string array    requirementKey
        private integer         requirementTotal            = 0
        
        //itemTypesAtP[11] = Stack pointing to struct-ids
        //emptySlot[11]    = Array with the "unequipped" spellbooks
        private Stack array     itemTypesAtP[11]
        private integer array   emptySlot[11]
        
        //slotId           = key is the name of the slot, value is the id
        //hasInited        = set to true when a unit is initialized
        private StringTable     slotId
        private boolean         hasInited                   = false
        
        //passUnit         = triggering unit passed for equip/unequip functions
        //passItem         = manipulated item passed for equip/unequip functions
        public  unit            passUnit
        public  item            passItem
    endglobals
    
    struct equipitem
        private integer         itemTypeId
        private integer         abilityId
        private integer         spellbookId
        private integer         slot
        private Stack           requirements                = Stack.create()
        private trigger         equipTrigger                = CreateTrigger()
        private trigger         unequipTrigger              = CreateTrigger()
        
        //Temporary until I add some kind of table to handle this.
        private integer         statReq
        
        private integer         levelReq                    = 0
        private integer         strReq                      = 0
        private integer         agiReq                      = 0
        private integer         intReq                      = 0
        
        //************************************************************************************
        //******************************Call functions (public)*******************************
        //************************************************************************************
        
        public method AddRequirement takes string requirement returns nothing
            local integer i
            set requirement = StringCase(requirement, false)
            
            //Check so that it doesn't create duplicate keys of requirements.
            if not .requirements.contains(requirementTable[requirement]) then
                if requirementTable.exists(requirement) then
                    //Item requirement type already exists.
                    set i = requirementTable[requirement]
                else
                    //Item requirement type does not exist, so add it to the table.
                    set requirementTotal = requirementTotal + 1
                    set i = requirementTotal
                    
                    set requirementTable[requirement] = i
                    set requirementKey[i] = requirement
                endif
                
                //Add the key for the requirement type to the itemtype
                call .requirements.push(i)
            endif
        endmethod
        
        public method SetRequiredLevel takes integer value returns nothing
            set .levelReq = value
        endmethod
        public method SetRequiredStr takes integer value returns nothing
            set .strReq = value
        endmethod
        public method SetRequiredAgi takes integer value returns nothing
            set .agiReq = value
        endmethod
        public method SetRequiredInt takes integer value returns nothing
            set .intReq = value
        endmethod
        
        public method AddFunction takes code eF, code uF returns nothing
            call .AddEquipFunc(eF)
            call .AddUnequipFunc(uF)
        endmethod

        public method GetItemTypeId takes nothing returns integer
            return .itemTypeId
        endmethod
        public method GetAbilityId takes nothing returns integer
            return .abilityId
        endmethod
        public method GetSpellbookId takes nothing returns integer
            return .spellbookId
        endmethod
        public method GetRequirementList takes nothing returns Stack
            return .requirements
        endmethod
        public method GetSlot takes nothing returns integer
            return .slot
        endmethod
        
        //************************************************************************************
        //*****************************System functions (private)*****************************
        //************************************************************************************
        
        public method TryStats takes integer level, integer str, integer agi, integer int returns boolean
            if level >= .levelReq and str >= .strReq and agi >= .agiReq and int >= .intReq then
                return true
            endif
            return false
        endmethod
        
        private method AddEquipFunc takes code f returns nothing
            if f != null then
                call TriggerAddAction(.equipTrigger, f)
            endif
        endmethod
        private method AddUnequipFunc takes code f returns nothing
            if f != null then
                call TriggerAddAction(.unequipTrigger, f)
            endif
        endmethod
        
        public method Equip takes unit u, item i returns nothing
            set passUnit = u
            set passItem = i
            call TriggerExecute(.equipTrigger)
        endmethod
        public method Unequip takes unit u, item i returns nothing
            set passUnit = u
            set passItem = i
            call TriggerExecute(.unequipTrigger)
        endmethod
        
        static method create takes integer itemTypeId, integer abilityId, integer spellbookId, integer slot, code eF, code uF returns equipitem
            local equipitem new
            
            //If no unit has been registered, create the itemtype.
            if not hasInited then
                set new = equipitem.allocate()
                set new.itemTypeId = itemTypeId
                set new.abilityId = abilityId
                set new.spellbookId = spellbookId
                set new.slot = slot
                
                call new.AddEquipFunc(eF)
                call new.AddUnequipFunc(uF)
                call itemTypesAtP[slot].push(new)
            endif 
            
            set equipItemTable[itemTypeId] = new
            set equipItemTable[abilityId] = new
            return new
        endmethod
    endstruct
    
    struct equipunit
        private unit            u
                integer array   equippedItem[11]
                Stack           res                         = Stack.create()
        
        static  group           equipUnits                  = CreateGroup()
        static  trigger         onEquip                     = CreateTrigger()
        static  trigger         onUnequip                   = CreateTrigger()
        
        //************************************************************************************
        //******************************Call functions (public)*******************************
        //************************************************************************************
        
        method AddRestriction takes string restriction returns nothing
            local integer i
            
            set restriction = StringCase(restriction, false)
            
            if requirementTable.exists(restriction) then
                //Item requirement type already exists.
                set i = requirementTable[restriction]
            else
                //Item requirement type does not exist, so add it to the table.
                set requirementTotal = requirementTotal + 1
                set i = requirementTotal
                
                set requirementTable[restriction] = i
                set requirementKey[i] = restriction
            endif
            
            //Add the key for the requirement type to the unit
            call .res.push(i)
        endmethod
        
        method onDestroy takes nothing returns nothing
            local integer i = 0
            
            call UnitRemoveAbility(.u, 'A000')
            
            loop
                exitwhen i > 10
                call UnitAddAbility(.u, emptySlot[i])
                set i = i + 1
            endloop
        
            call .res.destroy()
            set .u = null
        endmethod
        
        method Reset takes nothing returns nothing
            call .destroy()
        endmethod
        
        //************************************************************************************
        //*****************************System functions (private)*****************************
        //************************************************************************************
        
        private static method condition takes nothing returns boolean
            return IsUnitInGroup(GetTriggerUnit(), equipunit.equipUnits)
        endmethod
        
        private static method onequip takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local item i = GetManipulatedItem()
            local equipitem ei = equipItemTable[GetItemTypeId(i)]
            local equipunit eu = equipUnitTable[GetUnitId(u)]
            local integer slot = ei.GetSlot()
            
            local Stack unitRes = Stack.create()
            local Stack itemReq = Stack.create()
            local integer l
            local boolean b = true

            if ei != 0 and eu.equippedItem[slot] == 0 and eu != 0 then
                //Check requirements by looping through them.
                set unitRes = eu.res.copy()
                set itemReq = ei.GetRequirementList().copy()
                loop
                    set l = itemReq.pop()
                    exitwhen l == Stack.EMPTY
                    if not unitRes.contains(l) then
                        set b = false
                    endif
                endloop
                
                //If unit can equip item.
                if b and ei.TryStats(GetHeroLevel(u),GetHeroStr(u, false),GetHeroAgi(u, false),GetHeroInt(u, false)) then
                    set eu.equippedItem[slot] = ei.GetItemTypeId()
                    call UnitRemoveAbility(u, emptySlot[slot])
                    call UnitAddAbility(u, ei.GetSpellbookId())
                    call RemoveItem(i)
                    if GetLocalPlayer() == GetOwningPlayer(u) then
                        call ForceUIKey("I")
                    endif
                    call ei.Equip(u, i)
                else
                    call SimError(GetOwningPlayer(u), "You do not meet the requirements for that item.")
                endif
            elseif ei != 0 and eu != 0 then
                call SimError(GetOwningPlayer(u), "You already have an item equipped.")
            else
                call SimError(GetOwningPlayer(u), "You cannot equip that item.")
            endif
            
            call unitRes.destroy()
            call itemReq.destroy()
            set u = null
            set i = null
        endmethod
        
        private static method onunequip takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local item i
            local integer a = GetSpellAbilityId()
            local equipitem ei = equipItemTable[a]
            local equipunit eu = equipUnitTable[GetUnitId(u)]
            local integer slot = ei.GetSlot()
            
            if ei != 0 and eu.equippedItem[slot] != 0 then
                //Check if inventory is full, if so halt trigger.
                if UnitInventoryCount(u) == UnitInventorySize(u) then
                    call SimError(GetOwningPlayer(u), "Inventory is full")
                    set u = null
                    return
                endif
            
                set eu.equippedItem[slot] = 0
                set i = CreateItem(ei.GetItemTypeId(), 0, 0)
                call UnitRemoveAbility(u, ei.GetSpellbookId())
                call UnitAddAbility(u, emptySlot[slot])
                call UnitAddItem(u, i)
                if GetLocalPlayer() == GetOwningPlayer(u) then
                    call ForceUIKey("I")
                endif
                call ei.Unequip(u, i)
            endif
            
            set u = null
        endmethod
        
        private static method onInit takes nothing returns nothing  
            call TriggerRegisterAnyUnitEventBJ(equipunit.onEquip, EVENT_PLAYER_UNIT_USE_ITEM)
            call TriggerAddCondition(equipunit.onEquip, Condition(function equipunit.condition))
            call TriggerAddAction(equipunit.onEquip, function equipunit.onequip)
            call TriggerRegisterAnyUnitEventBJ(equipunit.onUnequip, EVENT_PLAYER_UNIT_SPELL_CAST)
            call TriggerAddCondition(equipunit.onUnequip, Condition(function equipunit.condition))
            call TriggerAddAction(equipunit.onUnequip, function equipunit.onunequip)
        endmethod
        
        static method create takes unit u returns equipunit
            local equipunit new = equipunit.allocate()
            local player p = GetOwningPlayer(u)
            local Stack s = Stack.create()
            local equipitem ei
            
            local integer sbId
            local integer i
            
            set new.u = u
            call GroupAddUnit(equipunit.equipUnits, u)
            call UnitAddAbility(u, 'A000')
            
            set i = 0
            loop
                exitwhen i > 10
                set new.equippedItem[i] = 0
                set i = i + 1
            endloop
            
            set i = 0
            loop
                exitwhen i > 10
                call UnitAddAbility(u, emptySlot[i])
                call SetPlayerAbilityAvailable(p, emptySlot[i], false)
                set s = itemTypesAtP[i].copy()
                loop
                    exitwhen s.peek()==Stack.EMPTY
                    set ei = s.peek()
                    set sbId = ei.GetSpellbookId()
                    call UnitAddAbility(u, sbId)
                    call UnitRemoveAbility(u, sbId)
                    call SetPlayerAbilityAvailable(p, sbId, false)
                    call s.pop()
                endloop
                set i = i + 1
            endloop
        
            //Add the unit to the table and make sure no more itemtypes are registered.
            set equipUnitTable[GetUnitId(u)] = new
            set hasInited = true
            
            call s.destroy()
            
            return new
        endmethod
    endstruct
    
    public function InitUnit takes unit u returns equipunit
        return equipunit.create(u)
    endfunction
    public function AddItemType takes integer itemTypeId, integer abilityId, integer spellbookId, integer slot, code eF, code uF returns equipitem
        return equipitem.create(itemTypeId, abilityId, spellbookId, slot, eF, uF)
    endfunction
    
    function GetSlotId takes string s returns integer
        return slotId[StringCase(s, false)]
    endfunction
    
    private function Init takes nothing returns nothing
        local integer i = 0
        set equipItemTable = Table.create()
        set equipUnitTable = Table.create()
        set requirementTable = Table.create()
        set slotId = StringTable.create()
        
        loop
            exitwhen i > 10
            set itemTypesAtP[i] = Stack.create()
            set i = i + 1
        endloop
        
        set slotId["shoulders"]     = 0
        set slotId["head"]          = 1
        set slotId["neck"]          = 2
        set slotId["finger"]        = 3
        set slotId["mainhand"]      = 4
        set slotId["chest"]         = 5
        set slotId["offhand"]       = 6
        set slotId["wrists"]        = 7
        set slotId["feet"]          = 8
        set slotId["legs"]          = 9
        set slotId["hands"]         = 10
        
        set emptySlot[0]            = 'ES01'
        set emptySlot[1]            = 'ES02'
        set emptySlot[2]            = 'ES03'
        set emptySlot[3]            = 'ES04'
        set emptySlot[4]            = 'ES05'
        set emptySlot[5]            = 'ES06'
        set emptySlot[6]            = 'ES07'
        set emptySlot[7]            = 'ES08'
        set emptySlot[8]            = 'ES09'
        set emptySlot[9]            = 'ES0A'
        set emptySlot[10]           = 'ES0B'
    endfunction
endlibrary

JASS:
library TEEquip initializer Init requires Table, Stack, UnitIndexingUtils, SimError
//***********************************************************************************************************************
//*  TEEquip
//* 
//*  Author: Thunder_Eye
//* 
//*  Credits:
//*   * Vexorian for vJass, JassHelper, and the finding of the spellbook trick
//*   * PitzerMike for the ObjectMerger
//*   * PipeDream for Grimoire
//*   * SFilip for TESH
//*   * MindWorX for maintaining NewGen
//*   * Earth-Fury for UnitMaxState and BonusMod
//*
//*  Required Libraries:
//*   * Table by Vexorian
//*   * Stack by Anitarf
//*   * UnitIndexingUtils by Rising Dusk
//*   * SimError by Vexorian
//* 
//*  This is an equipment system which is easy to implent, and outputs a smooth 
//*  userinterface for the endgame user. However, it requires some massive Object
//*  Editor use, and if used incorrectly, may clutter up your Ability section.
//*  It supports up to 8191 different allocated itemtypes, and the same amount of
//*  units utilizing the system.
//*
//*  The basic system only works as a template with the addition that it handles
//*  item requirements for you.
//*
//*  In a future version however, there will be additional modules that can manage
//*  changing the basic stats for you.
//*
//*  Note that using UnitIndexingUtils will make you unable to use UnitUserData().
//*  
//*  To initialize a unit, call InitUnit (with the TEEquip prefix)
//*  To add an itemtype, call AddItemType (again, with the TEEquip prefix)
//*
//*  Function list:
//*      function InitUnit takes unit u returns nothing
//*      function AddItemType takes integer iType, integer aId, integer sbId, integer slot, code eF, code uF returns nothing
//*      function UnitAddRestriction takes unit u, string restriction returns nothing
//*      function ItemTypeAddRequirement takes integer iType, string requirement returns nothing
//*      function SetItemTypeLevel takes integer iType, integer level returns nothing
//*      function ItemTypeAddFunction takes integer iType, code eF, code uF returns nothing
//*      function GetSlotId takes string s returns integer
//*  
//*  Initialize a unit and give it an equipment menu.
//*    function InitUnit takes unit u returns nothing
//*      unit u:                The unit to initialize
//*
//*  Add an itemtype to the system, making it equippable
//*    function AddItemType takes integer iType, integer aId, integer sbId, integer slot, code eF, code uF returns nothing
//*      integer iType:         The rawid of the itemtype.
//*      integer aId:           The rawid of the UI ability.
//*      integer sbId:          The rawid of the spellbook holding ability aId.
//*      integer slot:          The slot where the item is placed when equipped.
//*                             Can be anything between 0-10.
//*      code eF:               The function which runs when the item is equipped.
//*      code uF:               The function which runs when the item is unequipped.
//*
//*  Add a restriction to a unit, enabling it to use items with the proper requirement.
//*  Note that units with no restrictions may only equip items with no requirements.
//*    function UnitAddRestriction takes unit u, string restriction returns nothing
//*      unit u:                The unit to add a restriction to.
//*      string restriction:    The key of the restrictiontype, upper- or lowercase does not matter.
//*
//*  Add a requirement to an item, requiring units to have the proper restrictions to use it.
//*  Note that items with no requirements may be equipped by any initialized unit.
//*  Units must match ALL requirements to equip item.
//*    function ItemTypeAddRequirement takes integer iType, string requirement returns nothing
//*      integer iType:         The rawid of the itemtype.
//*      string requirement:    The key of the requirementtype, upper- or lowercase does not matter.
//*
//*  Temporary function to set a required level on itemtypes.
//*    function SetItemTypeLevel takes integer iType, integer level returns nothing
//*      integer iType:         The rawid of the itemtype.
//*      integer level:         The required level.
//*
//*  Adds an additional function (including the one when you add an itemtype) to an itemtype.
//*    function ItemTypeAddFunction takes integer iType, code eF, code uF returns nothing
//*      integer iType:         The rawid of the itemtype.
//*      code eF:               The function which runs when the item is equipped.
//*      code uF:               The function which runs when the item is unequipped.
//*
//*  Gets the id of a slot.
//*  Can be used if you want to clarify the slot when using AddItemType.
//*    function GetSlotId takes string slot returns integer
//*      string slot:           The slot you want the id from.
//*                             "shoulder" = 0, "head" = 1,  "neck" = 2,    "finger" = 3,
//*                             "mainhand" = 4, "chest" = 5, "offhand" = 6, "wrists" = 7
//*                             "feet" = 8,     "legs" = 9,  "hands" = 10
//*
//***********************************************************************************************************************
    globals
        private Table           itemTypeTable
        private Table           unitTable
        private Stack array     itemTypesAtP[11]
        private integer array   emptySlot[11]
        
        private StringTable     requirementTable
        private string array    requirementKey
        private integer         requirementCount            = 0
        
        private StringTable     slotId
        private boolean         hasInited                   = false
        
        public  unit            passUnit
        public  item            passItem
    endglobals
    
    private struct itemType
        private integer         iType
        private integer         aId
        private integer         sbId
        private integer         slot
        private Stack           req                         = Stack.create()
        private trigger         eT                          = CreateTrigger()
        private trigger         uT                          = CreateTrigger()
        
        //Temporary until I add some kind of table to handle this.
        public integer          levelReq                    = 0
        
        public method AddEquipFunc takes code f returns nothing
            if f != null then
                call TriggerAddAction(.eT, f)
            endif
        endmethod
        public method AddUnequipFunc takes code f returns nothing
            if f != null then
                call TriggerAddAction(.uT, f)
            endif
        endmethod
        
        public method Equip takes unit u, item i returns nothing
            set passUnit = u
            set passItem = i
            call TriggerExecute(.eT)
        endmethod
        public method Unequip takes unit u, item i returns nothing
            set passUnit = u
            set passItem = i
            call TriggerExecute(.uT)
        endmethod
        
        public method GetItemTypeId takes nothing returns integer
            return .iType
        endmethod
        public method GetSlot takes nothing returns integer
            return .slot
        endmethod
        public method GetSpellbookId takes nothing returns integer
            return .sbId
        endmethod
        public method GetAbilityId takes nothing returns integer
            return .aId
        endmethod
        public method GetRequirementList takes nothing returns Stack
            return .req
        endmethod
        
        static method create takes integer iType, integer aId, integer sbId, integer slot returns itemType
            local itemType new = itemType.allocate()
            
            set new.iType = iType
            set new.aId = aId
            set new.sbId = sbId
            set new.slot = slot
            
            set itemTypeTable[iType] = new
            set itemTypeTable[aId] = new
            return new
        endmethod
    endstruct
    
    private struct equipunit
        private unit            u
                integer array   equippedItem[11]
                Stack           res                         = Stack.create()
        
        static  group           equipUnits                  = CreateGroup()
        static  trigger         onEquip                     = CreateTrigger()
        static  trigger         onUnequip                   = CreateTrigger()
        
        private static method condition takes nothing returns boolean
            return IsUnitInGroup(GetTriggerUnit(), equipunit.equipUnits)
        endmethod
        
        private static method onequip takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local item i = GetManipulatedItem()
            local itemType iT = itemTypeTable[GetItemTypeId(i)]
            local equipunit eu = unitTable[GetUnitId(u)]
            local integer slot = iT.GetSlot()
            
            local Stack unitRes = Stack.create()
            local Stack itemReq = Stack.create()
            local integer l
            local boolean b = true

            if iT != 0 and eu.equippedItem[slot] == 0 and eu != 0 then
                //Check requirements by looping through them.
                set unitRes = eu.res.copy()
                set itemReq = iT.GetRequirementList().copy()
                loop
                    set l = itemReq.pop()
                    exitwhen l == Stack.EMPTY
                    if not unitRes.contains(l) then
                        set b = false
                    endif
                endloop
                
                //If unit can equip item.
                if b and iT.levelReq <= GetHeroLevel(u) then
                    set eu.equippedItem[slot] = iT.GetItemTypeId()
                    call UnitRemoveAbility(u, emptySlot[slot])
                    call UnitAddAbility(u, iT.GetSpellbookId())
                    call RemoveItem(i)
                    if GetLocalPlayer() == GetOwningPlayer(u) then
                        call ForceUIKey("I")
                    endif
                    call iT.Equip(u, i)
                else
                    call SimError(GetOwningPlayer(u), "You do not meet the requirements for that item.")
                endif
            elseif iT != 0 and eu != 0 then
                call SimError(GetOwningPlayer(u), "You already have an item equipped.")
            else
                call SimError(GetOwningPlayer(u), "You cannot equip that item.")
            endif
            
            call unitRes.destroy()
            call itemReq.destroy()
            set u = null
            set i = null
        endmethod
        
        private static method onunequip takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local item i
            local integer a = GetSpellAbilityId()
            local itemType iT = itemTypeTable[a]
            local equipunit eu = unitTable[GetUnitId(u)]
            local integer slot = iT.GetSlot()
            
            if iT != 0 and eu.equippedItem[slot] != 0 then
                //Check if inventory is full, if so halt trigger.
                if UnitInventoryCount(u) == UnitInventorySize(u) then
                    call SimError(GetOwningPlayer(u), "Inventory is full")
                    set u = null
                    return
                endif
            
                set eu.equippedItem[slot] = 0
                set i = CreateItem(iT.GetItemTypeId(), 0, 0)
                call UnitRemoveAbility(u, iT.GetSpellbookId())
                call UnitAddAbility(u, emptySlot[slot])
                call UnitAddItem(u, i)
                if GetLocalPlayer() == GetOwningPlayer(u) then
                    call ForceUIKey("I")
                endif
                call iT.Unequip(u, i)
            endif
            
            set u = null
        endmethod
        
        method onDestroy takes nothing returns nothing
            call .res.destroy()
            set .u = null
        endmethod
        
        static method create takes unit u returns equipunit
            local equipunit new = equipunit.allocate()
            local integer i = 0
            
            set new.u = u
            call GroupAddUnit(equipunit.equipUnits, u)
            
            loop
                exitwhen i > 10
                set new.equippedItem[i] = 0
                set i = i + 1
            endloop
            
            return new
        endmethod
        
        static method onInit takes nothing returns nothing
            call TriggerRegisterAnyUnitEventBJ(equipunit.onEquip, EVENT_PLAYER_UNIT_USE_ITEM)
            call TriggerAddCondition(equipunit.onEquip, Condition(function equipunit.condition))
            call TriggerAddAction(equipunit.onEquip, function equipunit.onequip)
            call TriggerRegisterAnyUnitEventBJ(equipunit.onUnequip, EVENT_PLAYER_UNIT_SPELL_CAST)
            call TriggerAddCondition(equipunit.onUnequip, Condition(function equipunit.condition))
            call TriggerAddAction(equipunit.onUnequip, function equipunit.onunequip)
        endmethod
    endstruct
    
    public function InitUnit takes unit u returns nothing
        local player p = GetOwningPlayer(u)
        local integer i = 0
        local itemType iT
        local Stack s = Stack.create()
        local equipunit eu = equipunit.create(u)
        local integer sbId
        
        //Equipment spellbook ability
        call UnitAddAbility(u, 'A000')
        
        set i = 0
        loop
            exitwhen i > 10
            call UnitAddAbility(u, emptySlot[i])
            call SetPlayerAbilityAvailable(p, emptySlot[i], false)
            set s = itemTypesAtP[i].copy()
            loop
                exitwhen s.peek()==Stack.EMPTY
                set iT = s.peek()
                set sbId = iT.GetSpellbookId()
                call UnitAddAbility(u, sbId)
                call UnitRemoveAbility(u, sbId)
                call SetPlayerAbilityAvailable(p, sbId, false)
                call s.pop()
            endloop
            set i = i + 1
        endloop
        
        //Add the unit to the table and make sure no more itemtypes are registered.
        set unitTable[GetUnitId(u)] = eu
        set hasInited = true
        
        call s.destroy()
    endfunction
    
    public function AddItemType takes integer iType, integer aId, integer sbId, integer slot, code eF, code uF returns nothing
        local itemType i
        //If no unit has been registered, create the itemtype.
        if not hasInited then
            set i = itemType.create(iType, aId, sbId, slot)
            call i.AddEquipFunc(eF)
            call i.AddUnequipFunc(uF)
            call itemTypesAtP[slot].push(i)
        endif
    endfunction
    
    public function ResetUnit takes unit u returns nothing
        local equipunit eu = unitTable[GetUnitId(u)]
        local integer i = 0
        
        call UnitRemoveAbility(u, 'A000')
        
        loop
            exitwhen i > 10
            call UnitAddAbility(u, emptySlot[i])
            set i = i + 1
        endloop
        
        call eu.destroy()
    endfunction
    
    public function UnitAddRestriction takes unit u, string restriction returns nothing
        local equipunit eu = unitTable[GetUnitId(u)]
        local integer count
        
        set restriction = StringCase(restriction, false)
        
        if requirementTable.exists(restriction) then
            //Item requirement type already exists.
            set count = requirementTable[restriction]
        else
            //Item requirement type does not exist, so add it to the table.
            set requirementCount = requirementCount + 1
            set count = requirementCount
            
            set requirementTable[restriction] = count
            set requirementKey[count] = restriction
        endif
        
        //Add the key for the requirement type to the unit
        call eu.res.push(count)
    endfunction
    
    public function ItemTypeAddRequirement takes integer iType, string requirement returns nothing
        local itemType i = itemTypeTable[iType]
        local integer count
        set requirement = StringCase(requirement, false)
        
        if requirementTable.exists(requirement) then
            //Item requirement type already exists.
            set count = requirementTable[requirement]
        else
            //Item requirement type does not exist, so add it to the table.
            set requirementCount = requirementCount + 1
            set count = requirementCount
            
            set requirementTable[requirement] = count
            set requirementKey[count] = requirement
        endif
        
        //Add the key for the requirement type to the itemtype
        call i.GetRequirementList().push(count)
    endfunction
    
    public function ItemTypeAddStatRequirement takes integer iType, string requirement, integer level returns nothing
        local itemType i = itemTypeTable[iType]
        local integer count
        set requirement = StringCase(requirement, false)
        
        if requirementTable.exists(requirement) then
            //Item requirement type already exists.
            set count = requirementTable[requirement]
        else
            //Item requirement type does not exist, so add it to the table.
            set requirementCount = requirementCount + 1
            set count = requirementCount
            
            set requirementTable[requirement] = count
            set requirementKey[count] = requirement
        endif
        
        //Add the key for the requirement type to the itemtype
        call i.GetRequirementList().push(count)
    endfunction
    
    public function SetItemTypeLevel takes integer iType, integer level returns nothing
        local itemType i = itemTypeTable[iType]
        set i.levelReq = level
    endfunction
    
    public function ItemTypeAddFunction takes integer iType, code eF, code uF returns nothing
        local itemType i = itemTypeTable[iType]
        call i.AddEquipFunc(eF)
        call i.AddUnequipFunc(uF)
    endfunction
    
    public function GetSlotId takes string s returns integer
        return slotId[StringCase(s, false)]
    endfunction
    
    private function Init takes nothing returns nothing
        local integer i = 0
        set itemTypeTable = Table.create()
        set unitTable = Table.create()
        set requirementTable = Table.create()
        set slotId = StringTable.create()
        
        loop
            exitwhen i > 10
            set itemTypesAtP[i] = Stack.create()
            set i = i + 1
        endloop
        
        set slotId["shoulders"]     = 0
        set slotId["head"]          = 1
        set slotId["neck"]          = 2
        set slotId["finger"]        = 3
        set slotId["mainhand"]      = 4
        set slotId["chest"]         = 5
        set slotId["offhand"]       = 6
        set slotId["wrists"]        = 7
        set slotId["feet"]          = 8
        set slotId["legs"]          = 9
        set slotId["hands"]         = 10
        
        set emptySlot[0]            = 'ES01'
        set emptySlot[1]            = 'ES02'
        set emptySlot[2]            = 'ES03'
        set emptySlot[3]            = 'ES04'
        set emptySlot[4]            = 'ES05'
        set emptySlot[5]            = 'ES06'
        set emptySlot[6]            = 'ES07'
        set emptySlot[7]            = 'ES08'
        set emptySlot[8]            = 'ES09'
        set emptySlot[9]            = 'ES0A'
        set emptySlot[10]           = 'ES0B'
    endfunction
endlibrary
 

Attachments

  • pic.JPG
    pic.JPG
    89.3 KB · Views: 142
  • TEEquip v0.2.w3x
    610.4 KB · Views: 63
Last edited:
Level 14
Joined
Apr 20, 2009
Messages
1,543
I dont think this is the right place to post this...

Triggers & Scripts Discussions regarding GUI triggers & JASS/AI scripts may be found here.

it's not a discussion its a release ;)
you should probably post this in
submissions

But this sure is a nice system :D I like it! +rep
 
Level 6
Joined
May 19, 2004
Messages
267
argh! just another bad-ass-looking thing I can't start! (must be cause of the complexity .... I'm never able to test the best spells...)

I can save it and so on (I have JNGP) but I can't start it
however I'm sure it's great :grin:
spellbooks are imba

I'm unsure of why it wouldn't work for you.

Anyway you could try downloading it directly into your maps folder, and try to play it through wc3.
 
Level 10
Joined
Sep 21, 2007
Messages
517
i suggest that you make a version where its for premade items, since many people usually get items and then acquire them in their inventory, im saying this so you can avoid the loop and directly attach the data to the item itself. good job man, like the configurability, especially changing position of slots since it takes some tricks to pull it. Think there is a thread about it on w3c.

o and btw use earthfurys Stats mod or w/e its called for the item stats, think u already know that though, well good luck man, its not necessarily one of the easiest projects if ur adding such configurability :S ;)
 
Level 6
Joined
May 19, 2004
Messages
267
i suggest that you make a version where its for premade items

What? Are you suggestion I apply the system for specific items rather then itemtypes? In that case in my opinion it'll make to much of a hassle when creating items.

since many people usually get items and then acquire them in their inventory, im saying this so you can avoid the loop and directly attach the data to the item itself.

I've got several loops in the system, can you specify which one(s) I could avoid?

like the configurability, especially changing position of slots since it takes some tricks to pull it. Think there is a thread about it on w3c.

I already know most there is to know about the spellbook bug. I assume you're refering to this thread?

o and btw use earthfurys Stats mod or w/e its called for the item stats, think u already know that though

As is stated in the documentation, I'm already using UnitMaxState and BonusMod (I'm assuming you mean these) for the demo map. Thanks anyway.
 
Level 10
Joined
Sep 21, 2007
Messages
517
oh yea man, i was talking about premade items in the map itself, where the acquired item determines everything, and u attach data to it insetad of looping based on itemtype or whatnot ) since youll avoid using the loop that way, atleast im pretty sure an item is a handle which can have data attached to it. Just a suggestion ^^
 
Level 6
Joined
May 19, 2004
Messages
267
Refering to specific items instead of itemtypes would make the system much more cluttered than it already is. Besides, I don't see how It'd remove any of the loops as they're all necessary for the spellbook-bug.

Additionally, I believe it's much more user-friendly to be able to do all the settings at init, instead of manually setting them each time you create a new item.

You will be able to achieve the effect you're looking for in a future patch anyway by disabling certain items from the system.
 
Level 10
Joined
Sep 21, 2007
Messages
517
oright you loop through spellbook IDs, well you can still attach the spellbook id to the item itself, im not really planning to use the system, but if i would use any system, i would prob use this :p and btw im talking about userfriendly methods to set the items settings, like SetItem( item ) and itll do all the work for it, or is that simply not possible? i didnt look through the code, but im offering suggestions that usually work

btw what does ObjectMerger do?
 
Level 6
Joined
May 19, 2004
Messages
267
and btw im talking about userfriendly methods to set the items settings, like SetItem( item ) and itll do all the work for it, or is that simply not possible? i didnt look through the code, but im offering suggestions that usually work

You'd still need to specify the bonuses an item has. At the moment adding an item looks like this:

JASS:
    //'I000'               = the id of the itemtype
    //'A00C'               = the id of the menu ability
    //'A001'               = the id of the spellbook ability
    //0                    = the position (0 being shoulders)
    //function EquipI000   = the function where you script what bonuses the item gives
    //function UnequipI000 = the function which removes said bonuses
    local equipitem ei = equipitem.create('I000', 'A00C', 'A001', 0, function EquipI000, function UnequipI000)
    //Adds the "plate" requirement to the item (you can make up your own requirements here)
    call ei.AddRequirement("plate")
    //Sets required level to equip to 2
    call ei.SetRequiredLevel(2)

In a future version you'll be able to disable specific items with something like this:

JASS:
    call DisableItem(item i)

btw what does ObjectMerger do?

Object Mergers manual:
There are two basic use cases for the Object Merger plugin. First of all it can import object editor data, but it won't replace the existing data, instead it will merge the existing and the imported data, there are different modes available that control how collisions of object ids are handled. This can be useful for distributing systems that require certain objects, like for example the caster unit from the caster system. A vJASS external call to this tool will make sure that the required unit exists in the map. Also in a team people can work separately on certain aspects of the map and later merge their work this way. The other use case is generating larger amounts of similar objects using vJASS external calls. Again this is useful to distribute systems that require object data. I'm thinking of systems like Bonus Mod which requires a number of bonus abilites. Finally it allows you to specify custom rawcodes for your objects, although this is conveniently possible with a Grimoire hack already.

Basically it'll be used to simplify importing the abilities.

Update to v0.2b
 
Level 10
Joined
Sep 21, 2007
Messages
517
Ah yes, you are correct, once its added, it cant ever be changed again if that method is used, hmm... im thinking of using S2I-->I2H, H2I>>I2S ? i dont know why people so much complain about the return bug and so forth, when this cna be used as the alternative >_<

btw can you help me out on the problem im having with cursor detection of units? its in trigger section, im sure ur vast experience is able to help me xP
 
Level 6
Joined
May 19, 2004
Messages
267
The "return bug", as we know it, was fixed in patch 1.24. Fortunately this system doesn't use it nor any 1.24-only features, so it should be compatible with old patches as well.
 
Status
Not open for further replies.
Top