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: 306

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
963
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.
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/
  • The Helper The Helper:
    Decided to put up a healthier type recipe to mix it up - Honey Garlic Shrimp Stir-Fry https://www.thehelper.net/threads/recipe-honey-garlic-shrimp-stir-fry.193595/

      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