System AutoCombine

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
I'm here to present :
AutoCombine​
v1.0.1​
JASS:
/******************************************************************************************************
	AutoCombine by kingking
			  v1.0.1
			   
******************************************************************************************************
	  
    What is AutoCombine?
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    AutoCombine is an automatic item combiner. 
    Example(In DotA) : Preservance + Claymore + Broadsword -> Battle Fury.
    
    How to implement?
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    Copy this trigger and Event into your map.
	
    Requirements
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    • Event by Jesus4Lyf
    • Jasshelper 0.2.A.B or later (<a href="http://www.wc3c.net/showthread.php?p=1122566" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.wc3c.net/showthread.php?p=1122566</a>)

    Detail
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
	• AutoCombine will search the most common used combination instead of iterating all combinations.
	  This enhances AutoCombine&#039;s effiency greatly because it does not search unliked combinations.
	• AutoCombine uses a linked list as it&#039;s storage. This is faster than an array stack in iteration process.
	
******************************************************************************************************
	API
******************************************************************************************************
	
	Normal API
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    • ItemCombo.create() -&gt; ItemCombo
      Create an combination
    
    • call vars.addItem( integer id )
      Add an item type.
    
    • call vars.removeItem( integer id )
      Remove an item type.
    
    • set vars.result = integer id
      Set the type of combined item.
    
    • set vars.model = string
      Effect created when a item is successfully combined.
    
    • set vars.attachment = string
      Atttachment point for model.
    
    • set vars.enable = boolean
      Enable the combination?
    
    • call vars.destroy()
      Destroy the combination.
    
    • ItemCombo[integer id] -&gt; ItemCombo
      Get the combination from item type (Returns last combination if you have &gt;1 combinations for 1 item type)
	
	Wrapped AI
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    For better readability, more like JASS syntax.
	
    • CreateItemCombination() -&gt; ItemCombo
	
    • AddItemToCombination(ItemCombo, integer id)
	
    • RemoveItemFromCombination(ItemCombo, integer id)
	
    • SetOnCombineEffect(ItemCombo, string model, string attachment point)
	
    • GetCombinationById(integer id) -&gt; ItemCombo
	
    • SetCombinationResult(ItemCombo,integer id)
	
    • GetCombinationResult(ItemCombo) -&gt; id
	
    • EnableItemCombination(ItemCombo,boolean)
	
    • IsCombinationEnabled(ItemCombo,boolean)
	
    • DestroyItemCombination(ItemCombo)
	
	BJ-Like API
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
	Does not require you to store the ItemCombo variable, useful for normal item combinations.

    • CreateItemCombinationBJ(integer result)
    • AddItemToCombinationBJ(integer id)
    • SetOnCombineEffectBJ(string model, string attachment point)
    
	Other API
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    • DisassembleItem(item) (Uses last combination if you have &gt;1 combinations for 1 item type)
    • EnableAutoChargeMerging(integer id) (Merge the charges of items.)

	Event API
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    • GetCombiner() 	-&gt; unit - The unit who recieves the combined item.
    • GetCombinedItem() -&gt; item - The item which is made.
    • AutoCombine_RegisterEvent(trigger) -&gt; EventReg
    • AutoCombine_UnregisterEvent(trigger)
    • AutoCombine_EnableEvent(boolean)
    
*******************************************************************************************************/

library AutoCombine requires Event
    
    globals
        private Event OnCombineEvent
        private boolean EventFlag = true
        private unit array CombinerStack
        private item array CombinedItemStack
        private integer EventStackLevel = 0
        //Prevent recursion.
    endglobals
    
    function GetCombiner takes nothing returns unit
        return CombinerStack[EventStackLevel]
    endfunction
    
    function GetCombinedItem takes nothing returns item
        return CombinedItemStack[EventStackLevel]
    endfunction
    
    public function RegisterEvent takes trigger trig returns EventReg
        return OnCombineEvent.register(trig)
    endfunction
    
    public function UnregisterEvent takes trigger trig returns nothing
        call OnCombineEvent.unregister(trig)
    endfunction
    
    public function EnableEvent takes boolean flag returns nothing
        set EventFlag = flag
    endfunction
    
    private function FireEvent takes unit u, item i returns nothing
        if EventFlag == true and GetItemTypeId(i) != 0 then
            set EventStackLevel = EventStackLevel + 1
            set CombinerStack[EventStackLevel] = u
            set CombinedItemStack[EventStackLevel] = i
            call OnCombineEvent.fire()
            set EventStackLevel = EventStackLevel - 1
        endif
    endfunction
    
    private struct IdList
        integer id
        thistype prev
        thistype next
        //Doubly linked list.
        
        static method createHead takes nothing returns thistype
            local thistype this = thistype.allocate()
            set this.prev = this
            set this.next = this
            return this
        endmethod
            
        method add takes integer id returns nothing
            local thistype new = thistype.allocate()
            set new.id = id
            
            set this.next.prev = new
            set new.prev = this
            set new.next = this.next
            set this.next = new
        endmethod
        
        method search takes integer id returns thistype
            local thistype list = this
            set this = this.next
            loop
            exitwhen this == list
                if this.id == id then
                    return this
                endif
                set this = this.next
            endloop
            return 0
        endmethod
        
        method remove takes integer id returns boolean
            set this = this.search(id)
            if this != 0 then
                set this.next.prev = this.prev
                set this.prev.next = this.next
                call this.destroy()
                return true
            endif
            return false
        endmethod
        
        method destroyHead takes nothing returns nothing
            local thistype list = this
            set this = this.next
            loop
            exitwhen this == list
                set this.next.prev = this.prev
                set this.prev.next = this.next
                call this.destroy()
                set this = this.next
            endloop
            call this.destroy()
        endmethod
    endstruct
    
    private keyword ItemComboList
    
    struct ItemCombo
        private IdList list
        readonly integer size
        private integer resultx
        string model
        string attachment
        boolean enable
        //Doubly linked list.
        
        static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
            set this.list = IdList.createHead()
            set this.enable = true
            return this
        endmethod
        
        method operator result= takes integer id returns nothing
            call RemoveSavedInteger(ItemComboList.hasht,0,.resultx)
            call SaveInteger(ItemComboList.hasht,0,id,this)
            //Hook for [] operator.
            set .resultx = id
        endmethod
        
        method operator result takes nothing returns integer
            return .resultx
        endmethod
        
        static method operator [] takes integer id returns thistype
            return LoadInteger(ItemComboList.hasht,0,id)
        endmethod
        
        method addItem takes integer id returns nothing
            local ItemComboList cl = ItemComboList[id]
            call .list.add(id)
            set .size = .size + 1
            
            if cl == 0 then
                set cl = ItemComboList.createHead(id)
            endif
            call cl.addCombo(this)
        endmethod
        
        method removeItem takes integer id returns nothing
            if .list.remove(id) then
                set .size = .size - 1
            endif
        endmethod
        
        method tryCombine takes unit u returns nothing
            local IdList idStack = .list.next
            local boolean array picked
            local item array items
            local integer iterator
            local integer success = 0
            loop
                set iterator = 0
                loop
                    if picked[iterator] == false and GetItemTypeId(UnitItemInSlot(u,iterator)) == idStack.id then
                        set picked[iterator] = true
                        set success = success + 1
                        set items[success] = UnitItemInSlot(u,iterator)
                        set iterator = 5
                    endif
                    set iterator = iterator + 1
                exitwhen iterator == 6
                endloop
                set idStack = idStack.next
            exitwhen idStack == .list
            endloop
            
            if success == .size then
                loop
                exitwhen success == 0
                    call RemoveItem(items[success])
                    set items[success] = null
                    set success = success - 1
                endloop
                call FireEvent(u,UnitAddItemById(u,.result))
                call AddSpecialEffectTarget(.model,u,.attachment)
            else 
                loop
                exitwhen success == 0
                    set items[success] = null
                    set success = success - 1
                endloop
            endif
        endmethod
        
        method onDestroy takes nothing returns nothing
            local IdList idStack = .list.next
            loop
            exitwhen idStack == .list
                call ItemComboList[idStack.id].removeCombo(this)
                //Remove this struct from any list.
                set idStack = idStack.next
            endloop
            call .list.destroyHead()
            call RemoveSavedInteger(ItemComboList.hasht,0,this.resultx)
            //Destroy all.
        endmethod
        
        static method disassemble takes item i, real x, real y returns nothing
            local thistype this = thistype[GetItemTypeId(i)]
            local IdList idStack
            if this != 0 then
                call RemoveItem(i)
                set idStack = .list.next
                loop
                exitwhen idStack == .list
                    call CreateItem(idStack.id,x,y)
                    set idStack = idStack.next
                endloop
            endif
        endmethod
    endstruct
    
    private struct ItemComboList
        static hashtable hasht = InitHashtable()
        thistype prev
        thistype next
        ItemCombo combo
        
        static method createHead takes integer itemId returns thistype
            local thistype this = thistype.allocate()
            set this.prev = this
            set this.next = this
            call SaveInteger(.hasht,itemId,0,this)
            return this
        endmethod
        
        static method operator [] takes integer itemId returns thistype
            return LoadInteger(.hasht,itemId,0)
        endmethod
        
        method addCombo takes ItemCombo c returns nothing
            local thistype new
            if HaveSavedInteger(.hasht,this,c) == false then
                set new = thistype.allocate()
                set new.combo = c
                call SaveInteger(.hasht,this,c,this)
                
                set this.next.prev = new
                set new.prev = this
                set new.next = this.next
                set this.next = new
            endif
        endmethod
        
        method removeCombo takes ItemCombo c returns nothing
            local thistype list = this
            if HaveSavedInteger(.hasht,this,c) then
                set this = LoadInteger(.hasht,this,c)
                set this.next.prev = this.prev
                set this.prev.next = this.next
                call this.destroy()
                call RemoveSavedInteger(.hasht,list,c)
            endif
        endmethod
        
        method checkCombo takes unit u returns nothing
            local thistype list = this
            set this = this.next
            loop
            exitwhen this == list
                if this.combo.enable == true then
                    call this.combo.tryCombine(u)
                    //Is this combination ok?
                endif
                set this = this.next
            endloop
        endmethod
    endstruct
    
    private struct ChargeMerging extends array
        static integer iterator = 0
        static item toAdd = null
        static item currItem = null //locals
        static method tryMerge takes unit u, item i, integer id returns nothing
            set iterator = 0
            set toAdd = null
            loop
                set currItem = UnitItemInSlot(u,iterator)
                if GetItemTypeId(currItem) == id and currItem != i then
                    set toAdd = currItem
                    set iterator = 5
                endif
                set iterator = iterator + 1
            exitwhen iterator == 0
            endloop
            if toAdd != null then
                call SetItemCharges(toAdd,GetItemCharges(toAdd) + GetItemCharges(i))
                call RemoveItem(i)
            endif
        endmethod
        
    endstruct
    // -&gt; Wrappers. &lt;-
    function CreateItemCombination takes nothing returns ItemCombo
        return ItemCombo.create()
    endfunction
    function AddItemToCombination takes ItemCombo c, integer itemId returns nothing
        call c.addItem(itemId)
    endfunction
    function RemoveItemFromCombination takes ItemCombo c, integer itemId returns nothing
        call c.removeItem(itemId)
    endfunction
    function SetOnCombineEffect takes ItemCombo c, string path, string att returns nothing
        set c.model = path
        set c.attachment = att
    endfunction
    function GetCombinationById takes integer itemId returns ItemCombo
        return ItemCombo[itemId]
    endfunction
    function SetCombinationResult takes ItemCombo c, integer itemId returns nothing
        set c.result = itemId
    endfunction
    function GetCombinationResult takes ItemCombo c returns integer
        return c.result
    endfunction
    function EnableItemCombination takes ItemCombo c, boolean flag returns nothing
        set c.enable = flag
    endfunction
    function IsCombinationEnabled takes ItemCombo c returns boolean
        return c.enable
    endfunction
    function DestroyItemCombination takes ItemCombo c returns nothing
        call c.destroy()
    endfunction
    function DisassembleItem takes item i, real x, real y returns nothing
        call ItemCombo.disassemble(i,x,y)
    endfunction
    //
    //BJ-liked wrappers
    globals
        private ItemCombo bj_lastCreatedCombination = 0
    endglobals
    function CreateItemCombinationBJ takes integer id returns nothing
        set bj_lastCreatedCombination = ItemCombo.create()
        set bj_lastCreatedCombination.result = id
    endfunction
    function AddItemToCombinationBJ takes integer id returns nothing
        call bj_lastCreatedCombination.addItem(id)
    endfunction
    function SetOnCombineEffectBJ takes string model, string attach returns nothing
        set bj_lastCreatedCombination.model = model
        set bj_lastCreatedCombination.attachment = attach
    endfunction
    //
    //Auto Charge Merging
    function EnableAutoChargeMerging takes integer itemId returns nothing
        call SaveBoolean(ItemComboList.hasht,itemId,1,true)
    endfunction
    //
    //Initializer...
    private struct Initializer extends array
        private static method check takes nothing returns boolean
            local unit u = GetTriggerUnit()
            local integer id = GetItemTypeId(GetManipulatedItem())              
            if LoadBoolean(ItemComboList.hasht,id,1) == true then
                call ChargeMerging.tryMerge(u,GetManipulatedItem(),id)
            endif
            call ItemComboList[id].checkCombo(u)
            //Iterate those most likely combination, more efficient than looping all combinations.
            set u = null
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger trig = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_PICKUP_ITEM)
            //I &lt;3 this BJ.
            call TriggerAddCondition(trig,Condition(function thistype.check))
            
            set OnCombineEvent = Event.create()
        endmethod
    endstruct
    
endlibrary

Link : Event

Updates :
v1.0.1 -> No longer fire if the combined item is removed.
v1.0.0 -> Release.
 

Attachments

  • AutoCombine.w3x
    29.4 KB · Views: 312

lep

Active Member
Reaction score
8
All i see is LinkedList, LinkedList, LinkedList, LinkedList...
You know, there is allready a library for this.
And there is also Table.
And, imo, there is no need for features like removing ingredents.
And i cant test i right now, but make sure you recipes work with two or more ingredents.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
You know, there is allready a library for this.
There is nothing wrong with self-made linked list.
Generally, those linked list library is made your coding easier, but I don't prefer them.
For that LinkedList library, it is slower than my internal linked list.
That's no point for using that, since I know to make linked list by myself and mine is faster.

And there is also Table.
Well, I had to use 2d array in this thingy.
Table is pointless, since I can squeeze all data in one hashtable.

And i cant test i right now, but make sure you recipes work with two or more ingredents.
...
 

Romek

Super Moderator
Reaction score
964
Why would someone use this over this?
 

sentrywiz

New Member
Reaction score
25
So uh.. this is about recipe system? That an AI can use to build recipes based on ... logic? You should of just added a short commentary on what the system does, as I am a dummy at looking at the code.
 

lep

Active Member
Reaction score
8
There is nothing wrong with self-made linked list.
Generally, those linked list library is made your coding easier, but I don't prefer them.
For that LinkedList library, it is slower than my internal linked list.
That's no point for using that, since I know to make linked list by myself and mine is faster.


Well, I had to use 2d array in this thingy.
Table is pointless, since I can squeeze all data in one hashtable.


...

I know a reason not to use this system: you are an idiot.
hurr durr mine is faster.

Maybe you dont remember, because you are a youg boy, but the last time one used gc instead of table he had t orewrite his whole map. just use fucking table.

And to your lists: if you are too dumb to use others code atleas generelise your own.
You wrote the same code like two fucking times.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Why would someone use this over this?
This provides better API, more efficient. (The iteration is less and faster)
JASS:
    //          call recipe.create(i1, i2, i3, i4, i5, i6, result, sfx, attPoint, charges, chargeType)

The argument is too long.
JASS:
  //              AddRecipeWithCharges    takes i1, i2, i3, i4, i5, i6, result, chargeType
    //              AddRecipeWithChargesEx  takes i1, i2, i3, i4, i5, i6, result, chargeType, sfx, attPoint

AutoCombine can let you to set the charges of combined items by using event callback.

BJ? What does 'BJ' mean, here?
If the recipe is static, you can use it.
It is more easier to use, an example helps :
JASS:
CreateItemCombinationBJ(SUPER_RING)
AddItemToCombinationBJ(CHEAP_RING)
AddItemToCombinationBJ(CHEAP_RING)
SetOnCombineEffectBJ(&quot;myModel.mdx&quot;, &quot;origin&quot;)

2x Cheap Ring will be combined into Super Ring, as soon as a unit took them.

I know a reason not to use this system: you are an idiot.
hurr durr mine is faster.

Maybe you dont remember, because you are a youg boy, but the last time one used gc instead of table he had t orewrite his whole map. just use fucking table.

And to your lists: if you are too dumb to use others code atleas generelise your own.
You wrote the same code like two fucking times.
Well, I don't need such posts, but constructive posts.

Highlights :
I know a reason not to use this system: you are an idiot.
Then don't use this system.
I won't force you to use it.
If you felt yours are better, then continue to use it.

Maybe you dont remember, because you are a youg boy,
Is it a problem? The most moderators at here are similar aged.

but the last time one used gc instead of table he had t orewrite his whole map. just use fucking table.
That's the people's problem.
Will this happen again?
Nobody knows.

And to your lists: if you are too dumb to use others code atleas generelise your own.
You wrote the same code like two fucking times.
Don't beat the dead horse.

So uh.. this is about recipe system? That an AI can use to build recipes based on ... logic? You should of just added a short commentary on what the system does, as I am a dummy at looking at the code.
Yeah, correct by 50%.
It is a recipe system.
 

lep

Active Member
Reaction score
8
That's the people's problem.
Will this happen again?
Nobody knows.

yeah, it's the 'peoples's problem' if they use your system, because the have to change YOUR code if blizzards decides to break maps again.

Using 'high level' libraries as an abstraction and everything is fine.
If hashtables break, just replace Table and everything works again.
If every coder hardcodes this into his systems/spells one really have to redo like a whole map if something breaks.


Also: just provide one good api. dont care if it oop or not aslong its consistent and good.
And providing two api's for the same library is no good style.

And i don't get that 'dont beat the dead horse', but really, if you feel like c'n'p-ing some code you might overthink it and abstract that kind of code.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
yeah, it's the 'peoples's problem' if they use your system, because the have to change YOUR code if blizzards decides to break maps again.
Using 'high level' libraries as an abstraction and everything is fine.
If every coder hardcodes this into his systems/spells one really have to redo like a whole map if something breaks.
You missed the point.
Just like other libraries, if the hashtable is unusable in future, just copy and paste the new version of this library.

If hashtables break, just replace Table and everything works again.
Did you realise that Table is a hashtable wrapper?

And i don't get that 'dont beat the dead horse', but really, if you feel like c'n'p-ing some code you might overthink it and abstract that kind of code.
Ask uncle google please, kindly.

BJ is the suffix for functions that are from Blizzard's Jass, and yours are not. You need to fix that...
Fine then.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top