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

Definitely not another question about Anachron's Inventory system

Status
Not open for further replies.
Level 4
Joined
Apr 19, 2013
Messages
86
Hey guys, oddly enough, I ran into another road block about this inventory system. I got a lot of things tweaked out to my liking and its running very smoothly. I love how easy it is to add items. I got a ton of neat custom items. The thing is though when I want to take things to the next level a bit, I can't quite do it. Namely when I try to make a set, I dont know where to start.

It's too bad Anachron has been innactive for a bit, so everyone's questions about it are kind of fading away into the darkness. So I wanted to just bring this to a thread here, for anyone interested in brainstorming with me about making set items. There is virtually no documentation about it in the map, but I immersed myself in the code for a while, and I'm convinced it's functional. Not exactly sure where or how to create the sets, so lets try an example...

For simplicity's sake, we'll try 3 of the pre-made items that Anachron made in the test map. Let's say, Claws of Atack +15, Claws of Attack +15 (thats right TWO!) and Hood of Cunning. My goal is to add set bonus once you have 2/3 and additional bonuses if you get all three.

I'm not all that sure about the area of code is needed to understand the commands needed to declare a set, the req item types and the quantites, but im guessing its something like what's found in the trigger: CISet.


JASS:
public static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
            
            set .ID = thistype.index
            set thistype.instances[thistype.index] = this
            set thistype.index = thistype.index +1
            
            set .SaveTable  = Table.create()
            set .items      = Table.create()
            set .ReqIDS     = Table.create()
            set .ReqAmount  = Table.create()
            
            call .save()
            
            return this
        endmethod
        
        public method addReq takes integer id, integer amount returns nothing
            set .ReqIDS[.ind] = id
            set .ReqAmount[.ind] = amount
            set .ind = .ind +1
        endmethod
        
        //: ===-------------------------------------------------------------------
        //: Add another bonus
        public method incBonus takes unit u returns nothing
            local integer times = .SaveTable[GetHandleId(u)]
            set .SaveTable[GetHandleId(u)] = times +1
            
            call .OnApply.execute(this, u)
            static if LIBRARY_CIBonus then
                call .applyBonus(u)
            endif
        endmethod

And for those of you unfamiliar with how Anachrons system applies item bonuses to champions, it's through a text macro or something where you just add a value to the desired field. Here's the first three right out of the "Items" trigger (which also happen to be the very items in my fantasy item set, imagine that!)

JASS:
set ci = CreateCustomItem('hcun')
        set ci.class = ITEM_CLASS_HELMET
        set ci.as = 35
        set ci.agy = 12
        set ci.dest = 'it04'
        set ci.icon = "ReplaceableTextures\\CommandButtons\\BTNHoodOfCunning.blp"
        set ci.name = "Hood of Cunning"
        set ci.desc = "Increases attasckspeed by 35%\n and agility by 12."
        
        set ci = CreateCustomItem('ratf')
        set ci.class = ITEM_CLASS_HAND
        set ci.dmg = 15
        set ci.dest = 'coat'
        set ci.icon = "ReplaceableTextures\\CommandButtons\\BTNClawsOfAttack.blp"
        set ci.name = "Clawns of Attack +15"
        set ci.desc = "This item increases your damage \nby 15 if carried."

That's what items are like without any set properties. I dont' know if you are supposed to put information about any set they belong to in alongside these bases stats or if you're supposed to create the set externally and just reference the req id's and stuff in a different section.

So we know what mods to add, lets just say +extra damage for the claws, and +extra int for the helm if you complete this fancy dancy set, the trick is... how and where do we code it in?

Ok I think you guys get the idea, any help or input would go a loooong way, thanks for reading!!
 
Alrighty.

It took me a while, but I managed to get it to work with putting this code in the trigger "Items" in the test map:
JASS:
local CISet is = 0
// .... the other code here
set is = CISet.create()
call is.addReq('rat9', 1)
call is.addReq('hcun', 1)
set is.str = 5
set is.agy = 5
That worked. After getting the claws of attack + 9 and the hood of cunning, it increased my strength and agility by 5 each. However, it seems that it is bugged. After removing one and reequipping it, I would no longer gain a bonus. :(

And after about 2 hours of testing and fiddling with it, I couldn't get it to work properly without bugging (because Anachron didn't implement it correctly/didn't test it properly). Maybe I'll try a bit later (but I almost got an ulcer trying to find the appropriate functions). For now you may want to experiment with your own methods of checking it.

The problem is that the system adds events for everything that you can already check for, but not for things like when it is equipped (as far as I can tell). Even if it does, it is incredibly difficult to find because there is no real documentation (at all) and the test map literally shows none of the system's actual features.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
I'd recommend switching to another system, that's not his best work.

If you dont care about fullscreen, you can use The_Witcher's system that uses the command card. If you want fullscreen, mine will be finished sometime next week (though i never release my resoruces to the public, might make an exception)
 
Level 4
Joined
Apr 19, 2013
Messages
86
Dang guys, I'm deeply moved haha. I also spend about an hour a day slaving over this masterful yet poorly documented code.

I kept thinking there has to be someone whos figured it out, maybe to someone who knows vjass well you dont need documentation. So yeah thats what i thought anyway, totally wish there was.

In the spell section Anachron says he implemented set features in the latest update, but I read every page of the following forum and there was only one question about set items, and it wasn't even that helpful.

for what it's worth, here is an area of code in the CIEquips trigger that I think refers to equiping and unequiping items

JASS:
 public method pick takes CustomItem ci returns nothing
            local unit eventUnit = .inventory.getOwner()
            
            call ci.addBoni(eventUnit)
            call ci.lock()
            call ci.equip()
            call ci.addEffects(eventUnit)

hope I helped.

I'm pretty stoked to be taking steps towards figuring out these item sets and hearing about upcoming systems!

Btw, if you got the skill to make an inventory system, have you ever made a talent tree system? That's something I, for one, have always wanted.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Dang guys, I'm deeply moved haha. I also spend about an hour a day slaving over this masterful yet poorly documented code.

I kept thinking there has to be someone whos figured it out, maybe to someone who knows vjass well you dont need documentation. So yeah thats what i thought anyway, totally wish there was.

In the spell section Anachron says he implemented set features in the latest update, but I read every page of the following forum and there was only one question about set items, and it wasn't even that helpful.

for what it's worth, here is an area of code in the CIEquips trigger that I think refers to equiping and unequiping items

JASS:
 public method pick takes CustomItem ci returns nothing
            local unit eventUnit = .inventory.getOwner()
            
            call ci.addBoni(eventUnit)
            call ci.lock()
            call ci.equip()
            call ci.addEffects(eventUnit)

hope I helped.

I'm pretty stoked to be taking steps towards figuring out these item sets and hearing about upcoming systems!

Btw, if you got the skill to make an inventory system, have you ever made a talent tree system? That's something I, for one, have always wanted.

Thats actually what i made before this inventory system..
http://www.hiveworkshop.com/forums/triggers-scripts-269/using-offsets-228074/#post2269790
(that pic is old, i changed a decent bit)

though atm its not nearly up to the quality to be a public resource, i need to rewrite basically all of it. Still usuable, though

JASS:
library TTDemo initializer init
    private function init takes nothing returns nothing
        local Button a
        set a = Button.create (1,1,0,'B00N','B00N',10,5,2,"Transformation ","Transforms the hero into a vampire")
        call a.push()
        call a.reCreate       (2,2,0,'B009','B00C',10,5,2,"Wall of Fire","|cffffcc00Description|r : Creates a wall of fire at the point that deals damage to all that stand in it. \n|cffff0000Requires : Level 2 Transformation|r")
        call a.createLink     (1,1,2)
        call a.push()
        call a.reCreate       (2,3,0,'B00J','B00K',10,5,2,"Axe (Passive)","|cffffcc00Description|r : Increases your physical damage by 50% \n|cffff0000Requires : Level 3 Wall of Fire|r")
        call a.createLink     (2,2,3)
        call a.push()
        call a.reCreate         (2,4,0,'B00D','B00H',10,5,2,"Finger of Death","|cffffcc00Description|r : Eradicate that scum!. \n|cffff0000Requires : Level 4 Axe|r")
        call a.createLink(2,3,4)
        call a.push()
        call a.reCreate(2,5,0,'B00I','B00L',10,5,2,"Strength! (Passive)","|cffffcc00Description|r : Increases your strength by 25%. \n|cffff0000Requires : Level 5 Finger of Death|r")
        call a.createLink(2,4,5)
        call a.push()
        call a.reCreate(14,7,0,'B00V','B00W',10,5,2,"Next Menu","|cffffcc00Description|r : The Runemaster creates a ward that periodically releases frost novas")
        call a.isMenu(true)
        call a.addData(1)
        call a.push()
        call a.reCreate(0,0,1,'B00O','B00M',10,5,2,"Chilling Revival","|cffffcc00Description|r : Explodes a corpse with ice, dealing damage and slowing all nearby enemies. \n|cffffcc00Can be Autocast|r")
        call a.createLink(1,0,5)
        call a.push()
        call a.reCreate(0,1,1,'B009','B00N',10,5,2,"Ice Tremor","|cffffcc00Description|r : Ice breaks out at random points near the caster, chilling any who stand near it. Targets directly in the path of the ice are frozen for 3 seconds. \n|cffff0000Requires : Level 3 Chilling Revival|r")
        call a.createLink(0,0,5)
        call a.push()
        call a.reCreate(0,2,1,'B00R','B00S',10,5,2,"Snowball","|cffffcc00Description|r : Shoots a massive ball of ice towards the target, knockbacking any targets in its path and exploding at its end for extra damage. \n|cffff0000Requires : Level 1 Ice Tremor|r")
        call a.createLink(1,1,5)
        call a.createLink(1,3,5)
        call a.push()
        call a.reCreate(1,0,1,'B00T','B00U',10,5,2,"Death by Chocolate","|cffffcc00Description|r : The Runemaster conjures an iceicle and sends it to the target.")
        call a.push()
        call a.reCreate(1,1,1,'B00T','B00U',10,5,2,"Death by Chocolate","|cffffcc00Description|r : The Runemaster conjures an iceicle and sends it to the target.")
        call a.push()
        call a.reCreate(1,3,1,'B00V','B00W',10,5,2,"Frost Ward","|cffffcc00Description|r : The Runemaster creates a ward that periodically releases frost novas")
        call a.createLink(0,0,5)
        call a.push()
        call a.reCreate(14,7,1,'B00V','B00W',10,5,2,"Next Menu","|cffffcc00Description|r : The Runemaster creates a ward that periodically releases frost novas")
        call a.isMenu(true)
        call a.addData(0)
        call a.push()
    //    call a.reCreate(2,2,1,'B009','B009',10,5,2,"firefirefire","Transforms tfirehe hero into a vampire")
     //   call a.createLink(0,0,0)
      //  call a.push()
 //       call VJassTalentTree.showUI(Player(0),0)*/
    endfunction
endlibrary
 

Attachments

  • t2k.png
    t2k.png
    426.8 KB · Views: 111
I took another crack at it. It took a while, but it seems to be working and bug-free. Thanks for that post about where it is equipped, btw.

I had to make a few changes to the system, however, particularly the triggers:
CustomItem:
Change:
JASS:
private item        handle          = null
To:
JASS:
readonly item        handle          = null
CIEquips:
Copy this code, and replace all the text in that trigger with this:
JASS:
/* ----------------------------------- *//*
    Version: 0.1
    Author: Anachron
    Date: 04th Jan 2010
    
    Release information:
    Do not use this library without 
    copyright information.
    
    Copyright 2009
    
    This is the container for equipment
*/
/* ----------------------------------- */
library CIEquips initializer initSlots requires CIAll, CIItemSlot

    globals
        private real tmpX = 0.
        private real tmpY = 0.
        private integer         array   Slots[12]
        private integer         array   SlotIcons[12]
    endglobals
    
    private function initSlots takes nothing returns nothing
        //! textmacro CWEquipment__addItemClasses takes CLASS, I
        set Slots[$I$] = ITEM_CLASS_$CLASS$
        set SlotIcons[$I$] = ITEM_CLASS_ICON_$CLASS$
        //! endtextmacro
        
        //! runtextmacro CWEquipment__addItemClasses("RING", "0")
        //! runtextmacro CWEquipment__addItemClasses("RING", "1")
        //! runtextmacro CWEquipment__addItemClasses("MISC", "2")
        //! runtextmacro CWEquipment__addItemClasses("BOOTS", "3")
        //! runtextmacro CWEquipment__addItemClasses("MAIN", "4")
        //! runtextmacro CWEquipment__addItemClasses("TROUSER", "5")
        //! runtextmacro CWEquipment__addItemClasses("AMULET", "6")
        //! runtextmacro CWEquipment__addItemClasses("GLOVE", "7")
        //! runtextmacro CWEquipment__addItemClasses("HELMET", "8")
        //! runtextmacro CWEquipment__addItemClasses("SHOULDER", "9")
        //! runtextmacro CWEquipment__addItemClasses("HAND", "10")
        //! runtextmacro CWEquipment__addItemClasses("HAND", "11")
    endfunction

    struct CIEquips extends CIAll
    
        public method init takes nothing returns nothing
            local integer r = 0
            local integer c = 0
            
            loop
                exitwhen c >= 5
                
                //! runtextmacro CIAll_NewButton("SlotIcons[r]", "-128", "288 +(c - 2.5) * 64", ".Buttons[r]", ".Tracks[r]", ".window", "GetOwningPlayer(.inventory.getOwner())", ".75")
                set .HasItem[r] = false
                set .Items[r] = null
                set r = r +1
                
                //! runtextmacro CIAll_NewButton("SlotIcons[r]", "128", "288 +(c - 2.5) * 64", ".Buttons[r]", ".Tracks[r]", ".window", "GetOwningPlayer(.inventory.getOwner())", ".75")
                set .HasItem[r] = false
                set .Items[r] = null
                set r = r +1
                
                set c = c +1
            endloop
            
            //! runtextmacro CIAll_NewButton("SlotIcons[r]", "-48", "128", ".Buttons[10]", ".Tracks[10]", ".window", "GetOwningPlayer(.inventory.getOwner())", ".75")
            set HasItem[10] = false
            set .Items[10] = null
            set r = r +1
            
            //! runtextmacro CIAll_NewButton("SlotIcons[r]", "48", "128", ".Buttons[11]", ".Tracks[11]", ".window", "GetOwningPlayer(.inventory.getOwner())", ".75")
            set .HasItem[11] = false
            set .Items[11] = null       
            set r = r +1
        endmethod
        
        public method refresh takes nothing returns nothing
        endmethod
        
        private method getSlotIcon takes integer slot returns integer
            local integer destID = -1
            static if LIBRARY_CIItemDest then
                if .getSlotItem(slot) != 0 then
                    set destID = .getSlotItem(slot).dest
                endif
            endif
            
            if destID != -1 then
                return destID
            endif
            return SlotIcons[slot]
        endmethod
        
        private static trigger onEquip = CreateTrigger()
        private static trigger unEquip = CreateTrigger()
        static CustomItem EQUIP_ITEM = 0
        static unit       EQUIP_UNIT = null
        
        static method registerEquip takes code c returns nothing
            call TriggerAddCondition(onEquip, Condition(c))
        endmethod
        
        static method registerUnequip takes code c returns nothing
            call TriggerAddCondition(unEquip, Condition(c))
        endmethod
        
        public method pick takes CustomItem ci returns nothing
            local unit eventUnit = .inventory.getOwner()
            local thistype prev = EQUIP_ITEM
            local unit temp = EQUIP_UNIT
            
            call ci.addBoni(eventUnit)
            call ci.lock()
            call ci.equip()
            call ci.addEffects(eventUnit)
    
            set EQUIP_ITEM = ci
            set EQUIP_UNIT = eventUnit
            call TriggerEvaluate(onEquip)
            set EQUIP_ITEM = prev
            set EQUIP_UNIT = temp
            
            set temp = null
            set eventUnit = null
        endmethod
        
        public method pickCond takes CustomItem ci, integer slot returns boolean
            local boolean pick = true
            local CustomItem tmpOne = 0
            local CustomItem tmpTwo = 0
            
            static if LIBRARY_CIItemSlot then
                if slot == 10 or slot == 11 then
                    set tmpOne = .getSlotItem(10)
                    set tmpTwo = .getSlotItem(11)
                    
                    if ci.class == ITEM_CLASS_TWOHANDER then
                        set pick = tmpOne.class == 0 and tmpTwo.class == 0
                    elseif ci.class == ITEM_CLASS_HAND then
                        set pick = tmpOne.class != ITEM_CLASS_TWOHANDER and tmpTwo.class != ITEM_CLASS_TWOHANDER
                    else
                        set pick = false
                    endif
                else
                    set pick = (Slots[slot] == ci.class)
                endif
            endif
            
            set pick = pick and ci.check(.inventory.getOwner())
            set pick = pick and GetUnitState(.inventory.getOwner(), UNIT_STATE_LIFE) >= 1.
            return pick
        endmethod
        
        public method drop takes CustomItem ci returns nothing
            local unit eventUnit = .inventory.getOwner()
            local thistype prev = EQUIP_ITEM
            local unit temp = EQUIP_UNIT
            
            call ci.remBoni(eventUnit)
            call ci.unLock()
            call ci.unEquip()
            call ci.removeEffects()
            
            set EQUIP_ITEM = ci
            set EQUIP_UNIT = eventUnit
            call TriggerEvaluate(unEquip)
            set EQUIP_ITEM = prev
            set EQUIP_UNIT = temp
            
            set temp = null
            set eventUnit = null
        endmethod
        
        public method dropCond takes CustomItem ci, integer slot returns boolean
            return GetUnitState(.inventory.getOwner(), UNIT_STATE_LIFE) >= 1.
        endmethod
        
    endstruct

endlibrary
CustomInventory (optional):
I like to conserve code. You can comment out the following lines, like so:
JASS:
//: Refresh the sets
            //static if ENABLE_MODULE_SETS then
                //call .checkSets()
            //endif
And then you should be able to disable/delete the trigger "CISet", without any issues.


Here is the code for my system. Just make a trigger titled "CIItemSet":
JASS:
library CIItemSet requires CIBonus
/************************************************************************
*
*   struct CIItemSet
*
*       static method create ( unit inventoryUnit ) returns CIItemSet
*
*           - Creates an item set for the specified unit!
*
*       method addItem ( integer itemId ) returns nothing
*
*           - Adds a custom item object to the item set requirements.
*           - The "itemId" should be the item's rawcode.
*
*************************************************************************
*   Sample:
*
*   local CIItemSet cis = CIItemSet.create( udg_MyUnit )
*   call cis.addItem('rat9')
*   call cis.addItem('rat3')
*   call cis.addItem('hcun')
*   set cis.str = 5
*   set cis.agy = 10
*   set cis.int = 25
*
*************************************************************************
*
*   Changes made to: CustomItem; CIEquips
*
*************************************************************************/

    private struct CIItemIdList
        thistype next
        thistype prev
        integer itemId
        boolean eq
        
        method destroy takes nothing returns nothing
            set this.next.prev = this.prev
            set this.prev.next = this.next
            call this.deallocate()
        endmethod
        
        method remove takes integer ci returns nothing
            local thistype node = this.next
            loop
                exitwhen node == 0
                if node.itemId == ci then
                    call node.destroy()
                endif
                set node = node.next
            endloop
        endmethod
        
        method attach takes integer ci returns nothing
            local thistype node = thistype.allocate()
            set node.itemId = ci
            set node.eq = false
            
            set this.next.prev = node
            set node.prev = this
            set node.next = this.next
            set this.next = node
        endmethod
        
        static method createHead takes nothing returns thistype
            local thistype this = thistype.allocate()
            set this.itemId = 0
            set this.eq = false // equipped
            set this.next = 0
            set this.prev = 0
            return this
        endmethod
    endstruct
    
    struct CIItemSet 
        private thistype next
        private thistype prev
        private CIItemIdList head 
        private unit hero
        private boolean bonusApplied
        
        implement CIBonus
    
        static method create takes unit invUnit returns thistype
            local thistype this = thistype.allocate()
            set this.head = CIItemIdList.create()
            set this.hero = invUnit
            set this.bonusApplied = false
            
            set thistype(0).next.prev = head
            set head.next = thistype(0).next
            set head.prev = thistype(0)
            set thistype(0).next = head
            return this
        endmethod
        
        method addItem takes integer itemId returns nothing
            call head.attach(itemId)
        endmethod
        
        private method setEquipped takes integer itemRawId, boolean flag returns boolean
            local CIItemIdList node = this.head.next
            loop
                exitwhen node == 0
                if node.eq != flag and node.itemId == itemRawId then
                    set node.eq = flag
                    return true
                endif
                set node = node.next
            endloop
            return false
        endmethod
        
        private static method onEquip takes nothing returns boolean
            local thistype this = thistype(0).next
            local CIItemIdList node = 0
            local boolean equipped = false
            loop
                exitwhen this == 0
                if this.hero == CIEquips.EQUIP_UNIT and not this.bonusApplied then
                    set node = this.head.next
                    set equipped = true
                    
                    if not this.setEquipped(GetItemTypeId(CIEquips.EQUIP_ITEM.handle), true) then
                        return false
                    endif
                    
                    loop
                        exitwhen node == 0
                        if not node.eq then
                            set equipped = false
                            exitwhen true
                        endif
                        set node = node.next
                    endloop
                    
                    if equipped then
                        call this.applyBonus(CIEquips.EQUIP_UNIT)
                        set this.bonusApplied = true
                    endif
                endif
                set this = this.next
            endloop
            return false
        endmethod
        
        private static method unEquip takes nothing returns boolean
            local thistype this = thistype(0).next
            local CIItemIdList node = 0
            loop
                exitwhen this == 0
                if this.hero == CIEquips.EQUIP_UNIT and this.bonusApplied then
                    set node = this.head.next
                    if this.setEquipped(GetItemTypeId(CIEquips.EQUIP_ITEM.handle), false) then
                        call this.removeBonus(CIEquips.EQUIP_UNIT)
                        set this.bonusApplied = false
                    endif
                endif
                set this = this.next
            endloop
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            call CIEquips.registerEquip(function thistype.onEquip)
            call CIEquips.registerUnequip(function thistype.unEquip)
        endmethod
    endstruct

endlibrary

Here is the sample code:
JASS:
        set cis = CIItemSet.create(pally)
        call cis.addItem('rat9')
        call cis.addItem('rat9')
        call cis.addItem('hcun')
        set cis.str = 25
        set cis.agy = 15
        set cis.int = 35
This will require you to equip two of 'rat9', which is Claws of attack + 9, as well as hood of cunning. Upon having all 3, it will give you 25 strength, 15 agility, 35 intelligence. I tested it quite a bit and didn't have any bugs, but if you encounter any, just let me know. Here is the test map:
 

Attachments

  • CI_UP_v.0.2.2.6.w3x
    233.7 KB · Views: 28
Last edited:
Level 4
Joined
Apr 19, 2013
Messages
86
wow sweet guys, that inventory system looks awesome man!

And purgeandfire, I will try out your tweaks real soon.

Quick question, is it hard to add new ability bonuses other than stat bonuses?

Lets just say I wanted to add something real fancy once one completes the whole set like cleave, or bash passives.

If I was to guess, all you have to do is reference the target item ability in the object editor and give it a nickname like he does, ci.cleave = 1 as a binary bonus, you know what I mean? Since ci.cleave = 15 or some arbitrary number my not make sense, since this ability is more complex than stat bonuses.

thanks! the inspiration for new items is just overflowing now. awww yeah

EDIT: I keep getting this compile error even after I import all the triggers: Undefined Type CISet and Cannot convert integer to null

is there a way around that?
 
Last edited:
Sorry I didn't see your message sooner. For the compile error, you have to change the "tests" trigger (remove the line where it says "local CISet cis = 0" or something like that). I think that should fix it.

As for your question about bonuses, I suppose you can do something like that. I'd take a bit more easier of a route. I'll add an event so that you can register when a set it is complete or no longer complete:
JASS:
library CIItemSet requires CIBonus
/************************************************************************
*
*   struct CIItemSet
*
*       static method create ( unit inventoryUnit ) returns CIItemSet
*
*           - Creates an item set for the specified unit!
*
*       method addItem ( integer itemId ) returns nothing
*
*           - Adds a custom item object to the item set requirements.
*           - The "itemId" should be the item's rawcode.
*
*       static method registerSetComplete takes code c returns nothing
*
*           - Fires a code when any set is completed.
*
*       static method registerSetIncomplete takes code c returns nothing
*
*           - Fires a code when a set that WAS completed is no longer complete.
*
*       function GetTriggeringItemSet() returns CIItemSet
*
*           - When using the two register events above, this returns 
*             the item set that was completed or that is now incomplete.
*
*************************************************************************
*   Sample:
*
*   local CIItemSet cis = CIItemSet.create( udg_MyUnit )
*   call cis.addItem('rat9')
*   call cis.addItem('rat3')
*   call cis.addItem('hcun')
*   set cis.str = 5
*   set cis.agy = 10
*   set cis.int = 25
*
*************************************************************************
*
*   Changes made to: CustomItem; CIEquips
*
*************************************************************************/

    private struct CIItemIdList
        thistype next
        thistype prev
        integer itemId
        boolean eq
        
        method destroy takes nothing returns nothing
            set this.next.prev = this.prev
            set this.prev.next = this.next
            call this.deallocate()
        endmethod
        
        method remove takes integer ci returns nothing
            local thistype node = this.next
            loop
                exitwhen node == 0
                if node.itemId == ci then
                    call node.destroy()
                endif
                set node = node.next
            endloop
        endmethod
        
        method attach takes integer ci returns nothing
            local thistype node = thistype.allocate()
            set node.itemId = ci
            set node.eq = false
            
            set this.next.prev = node
            set node.prev = this
            set node.next = this.next
            set this.next = node
        endmethod
        
        static method createHead takes nothing returns thistype
            local thistype this = thistype.allocate()
            set this.itemId = 0
            set this.eq = false // equipped
            set this.next = 0
            set this.prev = 0
            return this
        endmethod
    endstruct
    
    struct CIItemSet 
        private thistype next
        private thistype prev
        private CIItemIdList head 
        private unit hero
        private boolean bonusApplied
        
        implement CIBonus

        private static trigger onSetComplete = CreateTrigger()
        private static trigger onSetIncomplete = CreateTrigger()
        static thistype TRIGGER_ITEM_SET = 0

        static method registerSetComplete takes code c returns nothing
            call TriggerAddAction(onSetComplete, c)
        endmethod
        static method registerSetIncomplete takes code c returns nothing
            call TriggerAddAction(onSetIncomplete, c)
        endmethod
    
        static method create takes unit invUnit returns thistype
            local thistype this = thistype.allocate()
            set this.head = CIItemIdList.create()
            set this.hero = invUnit
            set this.bonusApplied = false
            
            set thistype(0).next.prev = head
            set head.next = thistype(0).next
            set head.prev = thistype(0)
            set thistype(0).next = head
            return this
        endmethod
        
        method addItem takes integer itemId returns nothing
            call head.attach(itemId)
        endmethod
        
        private method setEquipped takes integer itemRawId, boolean flag returns boolean
            local CIItemIdList node = this.head.next
            loop
                exitwhen node == 0
                if node.eq != flag and node.itemId == itemRawId then
                    set node.eq = flag
                    return true
                endif
                set node = node.next
            endloop
            return false
        endmethod
        
        private static method onEquip takes nothing returns boolean
            local thistype this = thistype(0).next
            local CIItemIdList node = 0
            local boolean equipped = false
            local thistype temp = 0
            loop
                exitwhen this == 0
                if this.hero == CIEquips.EQUIP_UNIT and not this.bonusApplied then
                    set node = this.head.next
                    set equipped = true
                    
                    if not this.setEquipped(GetItemTypeId(CIEquips.EQUIP_ITEM.handle), true) then
                        return false
                    endif
                    
                    loop
                        exitwhen node == 0
                        if not node.eq then
                            set equipped = false
                            exitwhen true
                        endif
                        set node = node.next
                    endloop
                    
                    if equipped then
                        call this.applyBonus(CIEquips.EQUIP_UNIT)
                        set this.bonusApplied = true
                        set temp = TRIGGER_ITEM_SET
                        set TRIGGER_ITEM_SET = this
                        call TriggerExecute(onSetComplete)
                        set TRIGGER_ITEM_SET = temp
                    endif
                endif
                set this = this.next
            endloop
            return false
        endmethod
        
        private static method unEquip takes nothing returns boolean
            local thistype this = thistype(0).next
            local thistype temp = 0
            local CIItemIdList node = 0
            loop
                exitwhen this == 0
                if this.hero == CIEquips.EQUIP_UNIT and this.bonusApplied then
                    set node = this.head.next
                    if this.setEquipped(GetItemTypeId(CIEquips.EQUIP_ITEM.handle), false) then
                        call this.removeBonus(CIEquips.EQUIP_UNIT)
                        set this.bonusApplied = false
                        set temp = TRIGGER_ITEM_SET
                        set TRIGGER_ITEM_SET = this
                        call TriggerExecute(onSetIncomplete)
                        set TRIGGER_ITEM_SET = temp
                    endif
                endif
                set this = this.next
            endloop
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            call CIEquips.registerEquip(function thistype.onEquip)
            call CIEquips.registerUnequip(function thistype.unEquip)
        endmethod
    endstruct

    function GetTriggeringItemSet takes nothing returns CIItemSet
        return CIItemSet.TRIGGER_ITEM_SET
    endfunction

endlibrary

I haven't tested this though. I assume it should work. Basically you use the register functions to register when a set is complete. Then you can just check if GetTriggeringItemSet() == <MY ITEM SET> then, replacing <MY ITEM SET> with the variable that represents your item set. Within that if you will do whatever you'd like, such as add an ability or something. You can use the other event, CIItemSet.registerSetIncomplete(function f...), to remove the ability in case the unit no longer has the set (such as by removing an item).
 
Last edited:
Level 4
Joined
Apr 19, 2013
Messages
86
Hey, I got this implemented in my map now. Thank you!

Sometimes though when I equip the item set, then unequip them, then equip other items, then equip the item set again I am rewarded with full set bonus even if I only have 2 or sometimes 1 of the set of 3.

and also how do I declare the variable that represents my set? Maybe if I understood your last post more and where it refers to in the code, it would fix that little gltich. forgive my ignorance haha.

very nice work though man, this is revolutionary!
 
Oops. Thanks for finding that bug. Change the static method "unEquip" to this and it should work fine:
JASS:
        private static method unEquip takes nothing returns boolean
            local thistype this = thistype(0).next
            local CIItemIdList node = 0
            local thistype temp = 0
            loop
                exitwhen this == 0
                if this.hero == CIEquips.EQUIP_UNIT then
                    set node = this.head.next
                    if this.setEquipped(GetItemTypeId(CIEquips.EQUIP_ITEM.handle), false) and this.bonusApplied then
                        call this.removeBonus(CIEquips.EQUIP_UNIT)
                        set this.bonusApplied = false
                        set temp = TRIGGER_ITEM_SET
                        set TRIGGER_ITEM_SET = this
                        call TriggerExecute(onSetIncomplete)
                        set TRIGGER_ITEM_SET = temp
                    endif
                endif
                set this = this.next
            endloop
            return false
        endmethod

As for the variable that represents your set, it would be something like this:
JASS:
scope MyItemSet initializer Init

    globals
        unit pally
        CIItemSet myAwesomeSet = 0
    endglobals

    private function onIncomplete takes nothing returns nothing
        if GetTriggeringItemSet() == myAwesomeSet then
            call UnitRemoveAbility(pally, 'Aprg') // the set is no longer complete
            // therefore you should remove the purge ability
        endif
    endfunction
    
    private function onComplete takes nothing returns nothing
        if GetTriggeringItemSet() == myAwesomeSet then
            call UnitAddAbility(pally, 'Aprg') // add the ability purge
        endif
    endfunction

    private function Init takes nothing returns nothing
         local unit fake = CreateInventoryUnit(Player(0), 'h000')
         set pally = CreateUnit(Player(0), 'Hpal', 0, 0, 0)
         call CreateInventoryUI(pally, fake)
         // the code above is just to create the inventory 
         
         // the code below will set up the actual set
         set myAwesomeSet = CIItemSet.create(pally)
         call myAwesomeSet.addItem('rat9')
         call myAwesomeSet.addItem('hcun')
         call myAwesomeSet.addItem('rat3')
         set myAwesomeSet.str = 10
         set myAwesomeSet.agy = 10
         set myAwesomeSet.int = 10

         call CIItemSet.registerSetComplete(function onComplete)
         call CIItemSet.registerSetIncomplete(function onIncomplete)
    endfunction

endscope

Here is the test map if you need it:
 

Attachments

  • CI_UP_v.0.2.2.6.w3x
    234.7 KB · Views: 35
Level 4
Joined
Apr 19, 2013
Messages
86
Hey, I got the item sets working, I'm very happy about that. It's mad fun.

The only thing I can really think of to perfect it would be to display what exactly the set bonuses are in the item info. and maybe make the text green so it stands out against the normal item info when you scroll over it.

Is that possible or is that one of the feature's that is not easily customizable?
 
Level 4
Joined
Apr 19, 2013
Messages
86
Hey man, you got me off to a hell of a start, but things got complicated. I tried for 3 days to figure it out myself. If you got a sec, here is what I've found...

I'm trying to replicate the itemset you made that gave an item ability, but I got 3 questions.

1. Upon completion, my set, "Satyros Set" doesn't reward the unit with any set bonus stats. I'm guessing because it doesn't register the completion of the set. Where should I start to try to debug that? Is it in the test trigger, or the itemset trigger?

2. Is it possible to create sets that have 9 parts for full set bonuses, and maybe 3 parts for partial set bonuses? Like any 3, not like a specific 3.

3. Anachron's system add bonuses using item abilities to reward things like damage and health right? When they are added, there is no sign of the ability. However when I try to add other item abilities this way, i.e. vampiric aura (item) the icon is added to the spell console. Is there a way around that other than like a crazy spell book dummy?

Here is my code, it also has code from syncing special effects from the real unit to the inventory dummy, which you helped me with earlier. Maybe I just got confused with all the madness vjass going around in this trigger. It didn't throw me any errors though...

JASS:
scope test initializer init
globals
    hashtable herohash = InitHashtable()
    unit pally = null
    CIItemSet SatyrosSet = 0
endglobals

 private function onIncomplete takes nothing returns nothing
        if GetTriggeringItemSet() == SatyrosSet then
            call UnitRemoveAbility(pally, 'AIav') // the set is no longer complete
            // therefore you should remove the purge ability
        endif
    endfunction
    
    private function onComplete takes nothing returns nothing
        if GetTriggeringItemSet() == SatyrosSet then
            call UnitAddAbility(pally, 'AIav') // add the ability purge
        endif
    endfunction    

    private function init takes nothing returns nothing
        local unit fakeInv = null
        local unit hero = null
        local integer i = 0
        
        loop
            exitwhen i >= 12
        
            if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER then
                set fakeInv = CreateInventoryUnit(Player(i), 'h00P')
                set hero = CreateUnit(Player(i), 'U006', 5400., 3000., 270.)
                call CreateInventoryUI(hero, fakeInv)
                set pally = hero
                call SaveUnitHandle(herohash, GetHandleId(hero), 1337, fakeInv)
            endif
        
            set i = i +1
        endloop
        
         // the code below will set up the actual set
         set SatyrosSet = CIItemSet.create(pally)
         call SatyrosSet.addItem('I01E')
         call SatyrosSet.addItem('I01F')
         call SatyrosSet.addItem('I01G')
         set SatyrosSet.str = 10
         set SatyrosSet.mp = 300
         set SatyrosSet.amr = 10

         call CIItemSet.registerSetComplete(function onComplete)
         call CIItemSet.registerSetIncomplete(function onIncomplete)
        
    endfunction
    
endscope
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
For #2, No you cant (untill P&F rewrites it)

For #3, you also cant (must add to spellbook and hide the spellbook)
 
Hey DiggetyBo,

Sorry, I forgot about this thread.

As for your first issue, it seems to work fine for me. I recreated a similar scenario based off of your code, and it worked just fine. Make sure that the unit is equipping the correct items.

Also make sure you properly declared them all in another trigger for the CustomItem stats and all that. Here is my test code:
JASS:
// this is an excerpt from the trigger
// it contains the declaration of those items
        set ci = CreateCustomItem('I01E')
        set ci.class = ITEM_CLASS_HELMET
        set ci.dest = 'it05'
        set ci.icon = "ReplaceableTextures\\CommandButtons\\BTNHelmOfValor.blp"
        set ci.name = "Helm of Valor"
        set ci.desc = "Boosts strength and agility by 4."
        set ci.str = 4
        set ci.agy = 4
        
        set ci = CreateCustomItem('I01F')
        set ci.class = ITEM_CLASS_RING
        set ci.dest = 'it06'
        set ci.icon = "ReplaceableTextures\\CommandButtons\\BTNRingGreen.blp"
        set ci.name = "Ring of Protection +2"
        set ci.desc = "Boosts armor by 2."
        set ci.amr = 2
        
        set ci = CreateCustomItem('I01G')
        set ci.class = ITEM_CLASS_BOOTS
        set ci.dest = 'it07'
        set ci.icon = "ReplaceableTextures\\CommandButtons\\BTNSlippersOfAgility.blp"
        set ci.name = "Slippers of Agility +3"
        set ci.desc = "Boosts agility by 3."
        set ci.agy = 3
JASS:
// The area where I create my item set

scope MyItemSet initializer Init

    globals
        unit pally
        CIItemSet SatyrosSet = 0
    endglobals

    private function onIncomplete takes nothing returns nothing
        if GetTriggeringItemSet() == SatyrosSet then
            call UnitRemoveAbility(pally, 'Aprg')
        endif
    endfunction
    
    private function onComplete takes nothing returns nothing
        if GetTriggeringItemSet() == SatyrosSet then
            call UnitAddAbility(pally, 'Aprg')
        endif
    endfunction

    private function Init takes nothing returns nothing
         local unit fake = CreateInventoryUnit(Player(0), 'h000')
         set pally = CreateUnit(Player(0), 'U006', 0, 0, 0)
         call CreateInventoryUI(pally, fake)
         // the code above is just to create the inventory 
         
         // the code below will set up the actual set
         set SatyrosSet = CIItemSet.create(pally)
         call SatyrosSet.addItem('I01E')
         call SatyrosSet.addItem('I01F')
         call SatyrosSet.addItem('I01G')
         set SatyrosSet.str = 10
         set SatyrosSet.mp = 300
         set SatyrosSet.amr = 10

         call CIItemSet.registerSetComplete(function onComplete)
         call CIItemSet.registerSetIncomplete(function onIncomplete)
    endfunction

endscope

Or you can check out the test map below. It works fine for me.

Can you post your map? Maybe there was something wrong with the rawcodes, it is easy to mess those up. It is probably some simple typo.

For #2, I'll get back to you on that a bit later. For your question about displaying set bonus texts and updating them and the like, I'll try to work on that problem a bit later as well.

For #3, you have to use either a dummy spellbook or use an invisible locust dummy with the aura. If it isn't an aura, but just a passive (like bash), then you have to use a dummy spellbook.
 

Attachments

  • CI_UP_v.0.2.2.6.w3x
    235.4 KB · Views: 35
Level 4
Joined
Apr 19, 2013
Messages
86
Hey guys,

Thanks for getting back to me, and not giving up haha! I tried what you suggested, couldn't get it working. Woe is me.

This map I've been working on for like 5 years on and off, its probably too big to upload. It's almost 20GB :(

I guess what I'll do next is just to make a test map with only the item set and triggers to let you have a look. So yeah, I'll have that out soon.

I'm also eagerly awaiting your mod for partial / full set bonuses with window display info!

I'll edit this post soon!
 
Level 4
Joined
Apr 19, 2013
Messages
86
Ok here is the test map guys,

and yeah ahaha, what a terrible typo, it's only 20MB, not GB. I use a lot of custom models and music, i'm a sucker for it.

All the items used are towards the bottom of the map, about 10 paces from the hero's starting position. There are 9 in total. But only 3 are incorporated in the "Satyros" test set (armor, shoulders, and helm). The remaining items I included for the heck of it, maybe it can help you work with making full set and partial set bonuses.

Let me know if you figure out why the set doesn't register on completion :(
 

Attachments

  • Diggety's Dilemma2.w3x
    276.3 KB · Views: 33
Level 4
Joined
Apr 19, 2013
Messages
86
Yo, how's it going guys?

Is there anything I can do to help out? I can make another test map or something. Just want to pitch in.
 
I'm sorry. I forgot to check this.

It was another bug in my system. (1) I attached the wrong things to the list (2) I broke from the list early by mistake. Change the code in the trigger "CIItemSet" to this and it should work:
JASS:
library CIItemSet requires CIBonus
/************************************************************************
*
*   struct CIItemSet
*
*       static method create ( unit inventoryUnit ) returns CIItemSet
*
*           - Creates an item set for the specified unit!
*
*       method addItem ( integer itemId ) returns nothing
*
*           - Adds a custom item object to the item set requirements.
*           - The "itemId" should be the item's rawcode.
*
*       static method registerSetComplete takes code c returns nothing
*
*           - Fires a code when any set is completed.
*
*       static method registerSetIncomplete takes code c returns nothing
*
*           - Fires a code when a set that WAS completed is no longer complete.
*
*       function GetTriggeringItemSet() returns CIItemSet
*
*           - When using the two register events above, this returns 
*             the item set that was completed or that is now incomplete.
*
*************************************************************************
*   Sample:
*
*   local CIItemSet cis = CIItemSet.create( udg_MyUnit )
*   call cis.addItem(ci[0]) // ci[index] is all defined in 
*   call cis.addItem(ci[1]) // some other trigger
*   call cis.addItem(ci[2])
*   set cis.str = 5
*   set cis.agy = 10
*   set cis.int = 25
*
*************************************************************************
*
*   Changes made to: CustomItem; CIEquips
*
*************************************************************************/

    private struct CIItemIdList
        thistype next
        thistype prev
        integer itemId
        boolean eq
        
        method destroy takes nothing returns nothing
            set this.next.prev = this.prev
            set this.prev.next = this.next
            call this.deallocate()
        endmethod
        
        method remove takes integer ci returns nothing
            local thistype node = this.next
            loop
                exitwhen node == 0
                if node.itemId == ci then
                    call node.destroy()
                endif
                set node = node.next
            endloop
        endmethod
        
        method attach takes integer ci returns nothing
            local thistype node = thistype.allocate()
            set node.itemId = ci
            set node.eq = false
            
            set this.next.prev = node
            set node.prev = this
            set node.next = this.next
            set this.next = node
        endmethod
        
        static method createHead takes nothing returns thistype
            local thistype this = thistype.allocate()
            set this.itemId = 0
            set this.eq = false // equipped
            set this.next = 0
            set this.prev = 0
            return this
        endmethod
    endstruct
    
    struct CIItemSet 
        private thistype next
        private thistype prev
        private CIItemIdList head 
        private unit hero
        private boolean bonusApplied
        
        implement CIBonus

        private static trigger onSetComplete = CreateTrigger()
        private static trigger onSetIncomplete = CreateTrigger()
        static thistype TRIGGER_ITEM_SET = 0

        static method registerSetComplete takes code c returns nothing
            call TriggerAddAction(onSetComplete, c)
        endmethod
        static method registerSetIncomplete takes code c returns nothing
            call TriggerAddAction(onSetIncomplete, c)
        endmethod
    
        static method create takes unit invUnit returns thistype
            local thistype this = thistype.allocate()
            set this.head = CIItemIdList.create()
            set this.hero = invUnit
            set this.bonusApplied = false
            
            set this.prev = thistype(0)
            set this.next = thistype(0).next
            set this.next.prev = this
            set thistype(0).next = this
            return this
        endmethod
        
        method addItem takes integer itemId returns nothing
            call head.attach(itemId)
        endmethod
        
        private method setEquipped takes integer itemRawId, boolean flag returns boolean
            local CIItemIdList node = this.head.next
            loop
                exitwhen node == 0
                if node.eq != flag and node.itemId == itemRawId then
                    set node.eq = flag
                    return true
                endif
                set node = node.next
            endloop
            return false
        endmethod
        
        private static method onEquip takes nothing returns boolean
            local thistype this = thistype(0).next
            local CIItemIdList node = 0
            local boolean equipped = false
            local thistype temp = 0
            loop
                exitwhen this == 0
                if this.hero == CIEquips.EQUIP_UNIT and not this.bonusApplied then
                    if this.setEquipped(GetItemTypeId(CIEquips.EQUIP_ITEM.handle), true) then
                        set node = this.head.next
                        set equipped = true
                        
                        loop
                            exitwhen node == 0
                            if not node.eq then
                                set equipped = false
                                exitwhen true
                            endif
                            set node = node.next
                        endloop
                    
                        if equipped then
                            call this.applyBonus(CIEquips.EQUIP_UNIT)
                            set this.bonusApplied = true
                            set temp = TRIGGER_ITEM_SET
                            set TRIGGER_ITEM_SET = this
                            call TriggerExecute(onSetComplete)
                            set TRIGGER_ITEM_SET = temp
                        endif
                    endif
                endif
                set this = this.next
            endloop
            return false
        endmethod
        
        private static method unEquip takes nothing returns boolean
            local thistype this = thistype(0).next
            local CIItemIdList node = 0
            local thistype temp = 0
            loop
                exitwhen this == 0
                if this.hero == CIEquips.EQUIP_UNIT then
                    set node = this.head.next
                    if this.setEquipped(GetItemTypeId(CIEquips.EQUIP_ITEM.handle), false) and this.bonusApplied then
                        call this.removeBonus(CIEquips.EQUIP_UNIT)
                        set this.bonusApplied = false
                        set temp = TRIGGER_ITEM_SET
                        set TRIGGER_ITEM_SET = this
                        call TriggerExecute(onSetIncomplete)
                        set TRIGGER_ITEM_SET = temp
                    endif
                endif
                set this = this.next
            endloop
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            call CIEquips.registerEquip(function thistype.onEquip)
            call CIEquips.registerUnequip(function thistype.unEquip)
        endmethod
    endstruct

    function GetTriggeringItemSet takes nothing returns CIItemSet
        return CIItemSet.TRIGGER_ITEM_SET
    endfunction

endlibrary

EDIT: Tested this and it worked. Sorry for the super long wait. If no one responds to the thread in time you can always shoot me a PM! :) Those I usually answer a bit more quickly.
 
Level 4
Joined
Apr 19, 2013
Messages
86
Hey,

Thanks for the fix, I tested it too, very solid!

Take your time with the full/partial set thing. This system is getting very cooooooool.

EDIT: One question though, if I wanted to make the spell book a dummy, I have to disable it, correct? That way any passives it contains will appear truly passive and not take any console space.

I tried this, but it didn't do anything. My aim is to add a dummy spell book and disabled it immediately.

JASS:
private function onComplete takes nothing returns nothing
        if GetTriggeringItemSet() == SatyrosSet then
            call UnitAddAbility(pally, 'A04S') // add the ability purge
            native SetPlayerAbilityAvailable takes GetPlayersAll, A04S, false returns nothing
        endif
    endfunction

any thoughts?
 
Last edited:
Status
Not open for further replies.
Top