• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

latest news: next gen Trigger, save/load, attack indexing

Status
Not open for further replies.
Level 31
Joined
Jul 10, 2007
Messages
6,306
There have been a few new developments in the past months that are pretty cool that people may be unaware of ; ).

Lua:
Research is being conducted as to the cause of why some machines can't run the object merger exe with Lua. There are two possible causes. One is a lack of registry entries due to an illegal copy of wc3. The other could have to do with copying jassnewgen. Remember how it asks for your wc3 directory the first time you run it?

Trigger:
BooleanExpression currently uses a list of complete binary search trees that are then built into a balanced binary search tree. This results in good behavior and a slight speed boost on evaluation, but incurs hefty memory costs and severe overhead for building trees. The new design calls for a single tree, which would eliminate the tree build step and reduce memory usage.

Save/Load:
arhowk came up witg a new synchronization technique making use of a dummy unit selected by a player, ForceUIKey, spellbooks, abilities, and ability events. The data is still capped, but it transmits much less than the gamecache does, resulting in much faster speeds and feasible usage in maps. It takes 1 to 2 seconds, as claimed by the author, to synchronize a mountain of data. Combined with my special network code that packs and broadcasts data in streams, we'll have something epic.

Attack indexing:
I recently discored that damage is stored on an attack. When changing the damage on a unit around in between attacks is done, original damage used in attacks is preserved. The damage is actually calculated during attack. With this approach, damage can be treated as instance pointers to structs.

Targeting:
Adding/removing wind orb ability may enable units to be able to toggle between being able to hit air and not. Think of a bow that can be equipped.

BigInt Division:
A digit may be negative. When all digits are summed together, keeping in mind place, the number is put into standard form. This makes it possible to divide one number by another number 1 digit at a time only needing to divide by the leading digit of the divisor to get an estimate. This also enables subtraction that is on par with the speed of addition. Division turns into single digit division, followed by multiplication, followed by fast subtraction. At the end, multiplication and addition are used to bring the number to standard form. The answer is also absolutely accurate and there is no chance of overflow.


There are still a lot of things left to be solved, like custom cooldowns, custom attack ranges, and item indexing, all with minimal overhead of course.
 
Last edited:
Level 14
Joined
Jun 3, 2005
Messages
209
Hi Nestharus,

Thank you for your inspiring work on pushing the limits of Wc3 modding. You mentioned not having solutions for custom cooldowns or attack ranges yet, maybe I can offer some possible approaches from work on my project RoW.

I've implemented custom cooldowns on items and units by using a Spell Shield dummy ability. My setup for hero abilities which need this functionality requires the following:
  • An Attribute Bonus with Show Icon=false so the ability can be learned by a hero and show a learn tooltip.
  • A Channel (or other) base ability to be used when casting the ability.
  • Spell Shield(s) with the appropriate tooltips for each level of the base ability, and variable cooldown values.
When the ability is learned, I add the base ability to the hero. When it is cast, or needs to go on cooldown, SetPlayerAbilityAvailable(owner, base_ability_aid, false), add the Spell Shield, set the level as needed for the desired cooldown, and use a hostile dummy to cast Cripple on the unit to start the cooldown. Then a timer will swap the spell shield out for the base ability once it comes off cooldown.

It is possible to dynamically reset the cooldown so that, for example, when a hero attacks an enemy, his cooldowns advance by 1 second. The "clock" effect on the ability will restart from 12'o'clock when this happens.

The same is easily achieved with items, by substituting the real item with a Spell Shield version of the item. I use this to have, for example, a healing salve go on cooldown *after* the unit has taken damage and the effect ended. I have found this approach exceptionally clean and effective. The only caveat is an occasional "our units are under attack!" warning ping, or in the case of items, the subtle sound of dropping/picking up an item.

As for attack ranges, I wrote a system which enables dynamic cast range on abilities by intercepting orders, which makes use of Rising_Dusk's LastOrder library. It could easily be adapted to intercept attacks, though I don't think a queued orders would be preserved. If there's a demand for it, I wouldn't have a problem uploading it.

I don't know what item indexing refers to, but I've done work with items as well so maybe I can help?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
@Softmints

By custom cooldown, I mean custom cooldowns for unit attacks ; ), but for abilities/items are pretty cool too =).

Item indexing is assigning a unique integer to an item via SetItemUserData. When the item goes out of scope, this integer is recycled. When the item goes into scope, this integer is assigned. There should be no delay for these operations.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
almia came up witg a new synchronization technique making use of a dummy unit selected by a player, ForceUIKey, spellbooks, abilities, and ability event
the f*k you talkin bout.

5 AP classes + 2 300-level college courses isnt exactly wc3 modding friendly

JASS:
library ArhowksNetwork initializer init requires Table, Ascii, GetDummy //everything is little endian
    globals
        private integer A0 = 'A#*0'
        private integer A1 = 'A#*1'
        private integer A2 = 'A#*2'
        private integer A3 = 'A#*3'
        private integer AF = 'A#*/'
        private integer A4 = 'A#*4'
        private integer array ABILS
        
        private string O0 = "A"
        private string O1 = "B"
        private string O2 = "C"
        private string O3 = "D"
        private string OF = "T"
        private string O4 = "E"
        private string array ORDERS
        
        
        private integer B_ALL = 'A%%7'
        private string B_AK = "W"
        private string B_LV = "E"
        private string B_WXYZ = "R"
        private string B_NUM = "Q"
        private string BIG_AK = "T"
        private string BIG_LV = "Y"
        private string BIG_WXYZ = "U"
        
        private string array oCache
        private string array bCache
   //     private integer cacheIndex = 0
        private boolean Syncing = false
        private unit dummyUnit
        private Table timerData
    endglobals
    
    function ClearUnit takes unit u returns nothing
        local location l = GetUnitLoc(u)
        call SetUnitPositionLoc(u, l)
        call RemoveLocation(l)
        set l = null
    endfunction
    
    struct BinaryDecode extends array
        implement Alloc
        integer val
        
        public method isFinished takes nothing returns boolean
            return val == 0
        endmethod
        
        public method next takes nothing returns integer
            local integer one = ModuloInteger(val, 4)
            set val = val / 4
            return one
        endmethod
        
        public static method create takes integer input returns thistype
            local thistype this = thistype.allocate()
            set this.val = input
            return this
        endmethod
    endstruct
    
    struct BinaryStream
    
        integer val
        integer res
        integer bakedRes
        integer count
        static integer DEFAULT_RES = 3
        
        public method add takes integer i returns nothing
            set val = val + (i * R2I(Pow(bakedRes, count)))
            set count = count + 1
        endmethod
        
        public method get takes nothing returns integer
            return val
        endmethod
        
        public method flush takes nothing returns nothing
            set val = 0
            set count = 0
        endmethod
        
        public method destroy takes nothing returns nothing
            call deallocate()
        endmethod
        
        public static method create takes integer res returns thistype
            local thistype this = thistype.allocate()
        
            set val = 0
            set this.res = res
            if res == 2 then
                set bakedRes = 4
            else
                set bakedRes = R2I(Pow(2, res))
            endif
            set count = 0
        
            return this
        endmethod
        
    endstruct
    
    struct UnitData extends array
        implement Alloc
        
        integer typee
        integer value
        
        public method recieve takes integer abilId returns nothing
            if typee == 0 then
               // call FMsg("iqu")
                call IntegerPacket(value).recieve(abilId)
            elseif typee == 1 then
                call IntegerQueuePacket(value).recieve(abilId)
            else
                call StringQueuePacket(value).recieve(abilId)
            endif
        endmethod
        
        public method destroy takes nothing returns nothing
            call deallocate()
        endmethod
        
        public static method create takes integer typ, integer thisv returns thistype
            local thistype this = thistype.allocate()
            set this.typee = typ
            set this.value = thisv
            return this
        endmethod
        
    endstruct
    
    struct IntegerPacket extends array
        implement Alloc
        integer val
        BinaryStream incoming
        UnitData unitData
        boolean fin
        integer value
        player p
        unit u
        
        method getValue takes nothing returns integer
            return value
        endmethod
        
        method destroy takes nothing returns nothing
            if not fin then
                call Network_RemoveDummy(u)
                call unitData.destroy()
                set value = incoming.get()
                call incoming.destroy()
            endif
            call deallocate()
        endmethod
        
        method wait takes boolean b returns boolean
            if b then
                call TriggerSyncStart()
                call TriggerSyncReady()
            endif
            return fin
        endmethod
        
        method recieve takes integer i returns nothing
            local integer l = 0
            if i == AF then
                call Network_RemoveDummy(u)
                call unitData.destroy()
                set value = incoming.get()
                call incoming.destroy()
                set fin = true 
            else
                set l = 0
                loop
                    if ABILS[l] == i then
                        call incoming.add(l)
                        exitwhen true
                    endif
                    set l = l + 1
                    exitwhen l == 16
                endloop
            endif
        endmethod
        static thistype tem
        static trigger broadc = null
        private static method broad2 takes nothing returns nothing
            local integer i
            local thistype this = tem
            local BinaryDecode stream = BinaryDecode.create(val)
            
            set u= Network_GetDummy(p)
            call UnitAddAbility(u, A0)
            call UnitAddAbility(u, A1)
            call UnitAddAbility(u, A2)
            call UnitAddAbility(u, A3)
            call UnitAddAbility(u, AF)
            call SetUnitUserData(u, unitData)
            
            if GetLocalPlayer() == p then
                call ClearSelection(  )
                call SelectUnit( u, true)
            endif
            
          //  call TriggerSyncStart()
           // call TriggerSyncReady()
            if not Syncing then
                set Syncing = true
                call SyncSelections()
                set Syncing = false
            else
                call TriggerSyncStart()
                call TriggerSyncReady()
            endif
            
            if GetLocalPlayer() == p then
                if stream.isFinished() then
                    call ForceUIKey(ORDERS[0])
                endif
                loop
                    exitwhen stream.isFinished()
                    call ForceUIKey(ORDERS[stream.next()])
                endloop
                call ForceUIKey(OF)
            endif
            call stream.deallocate()
        endmethod
        
        public method broadcast takes nothing returns nothing
            set tem = this
            call TriggerExecute(broadc)
        endmethod
        
        public static method create takes integer value, player playerFor returns thistype
            local thistype this = thistype.allocate()
            set val = value
            set incoming = BinaryStream.create(0)
            set unitData = UnitData.create(0, this) 
            set p = playerFor
            set u = null
            if broadc == null then
                set broadc = CreateTrigger()
                call TriggerAddAction(broadc, function thistype.broad2)
            endif
            set fin = false
            return this
        endmethod
        
    endstruct
    
    struct IntegerQueuePacket extends array
        implement Alloc
        
        BinaryStream incoming
        UnitData unitData
        Table incomingQueue
        integer incomingCount 
        integer incomingQueuePos
        integer popPos
        boolean recievingCount 
        
        Table Queue
        integer count
        boolean fin
        player p
        unit u
        
        method pop takes nothing returns integer
            set popPos = popPos + 1
            return incomingQueue[popPos-1]
        endmethod
        
        method getCount takes nothing returns integer
            return incomingCount
        endmethod
        
        
        method outOfData takes nothing returns boolean
            return popPos == incomingCount
        endmethod
        
        method add takes integer value returns nothing
            set Queue[count] = value
            set count = count + 1
        endmethod
        
        method destroy takes nothing returns nothing
            call Queue.destroy()
            call incoming.destroy()
            call unitData.destroy()
            set p = null
            call incomingQueue.destroy()
            if not fin then
                call Network_RemoveDummy(u)
            endif
            call deallocate()
        endmethod
            
        method wait takes boolean b returns boolean
            if b then
                call TriggerSyncStart()
                call TriggerSyncReady()
            endif
            return fin
        endmethod
        
        method recieve takes integer i returns nothing
            local integer l = 0
            if fin then
                return
            endif
      //      call BJDebugMsg("RECIEVED")
     //       call BJDebugMsg("RECIEVED ORDER : " + I2S(i))
            if i == AF then
                if recievingCount then
      //              call BJDebugMsg("RECIEVD CCUNT")
                    set incomingCount = incoming.get()
                    set recievingCount = false
                    if incomingCount == 0 then
                        call Network_RemoveDummy(u)
                        set fin = true
                    endif
                else
                    //if incomingQueuePos = 100 then
                    //    call BJDebugMsg("count : " + I2S(incomingCount))
                    //endif
                    set incomingQueue[incomingQueuePos] = incoming.get() 
                    set incomingQueuePos = incomingQueuePos + 1
                endif
                call incoming.flush()
                if incomingQueuePos == incomingCount then
                    call Network_RemoveDummy(u)
                    set fin = true
                endif
            else
                set l = 0
                loop
                    if ABILS[l] == i then
                        call incoming.add(l)
                        exitwhen true
                    endif
                    set l = l + 1
                    exitwhen l == 16
                endloop
            endif
            call ClearUnit(u)
        endmethod
        
        
        static integer tr_i
        static trigger t = null
        
        private method broadcastint takes integer i returns nothing
            local BinaryDecode stream = BinaryDecode.create(i)
            local integer next
            
            if GetLocalPlayer() == p then
                if stream.isFinished() then
         //           call BJDebugMsg("FINIHSED ORDER : " + ORDERS[0])
                    call ForceUIKey(ORDERS[0])
                else
                    loop
                        exitwhen stream.isFinished()
                        set next = stream.next()
          //          call BJDebugMsg("NEXT ORDER : " + ORDERS[next])
                        call ForceUIKey(ORDERS[next])
                        
                    endloop
                endif
            
                call ForceUIKey( OF )
            endif
            call stream.deallocate()
        endmethod
        
        public method broadcast takes nothing returns nothing
            local integer i
            
            set recievingCount = true
            set u = Network_GetDummy(p)
            call UnitAddAbility(u, B_ALL)
            //call PauseUnit(u, true)
            //call PauseUnit(u, false)
            call SetUnitUserData(u, unitData)
            
                call TriggerSyncStart()
                call TriggerSyncReady()
            if GetLocalPlayer() == p then
                call ForceUICancel()
            endif
            if GetLocalPlayer() == p then
                call ClearSelection()
                call SelectUnit(u, true)
            endif
         //   call BJDebugMsg("1")
            if not Syncing then
                set Syncing = true
                call SyncSelections()
                set Syncing = false
                call TriggerSyncStart()
                call TriggerSyncReady()
            else
                call TriggerSyncStart()
                call TriggerSyncReady()
            endif
            
            if GetLocalPlayer() == p then
                call ForceUICancel()
            endif
            call UnitRemoveAbility(u, B_ALL)
            call UnitAddAbility(u, A0)
            call UnitAddAbility(u, A1)
            call UnitAddAbility(u, A2)
            call UnitAddAbility(u, A3)
            call UnitAddAbility(u, AF)
            
            call TriggerSyncStart()
            call TriggerSyncReady()
            
            
            
            call broadcastint(count)
            set i = 0
            loop
                exitwhen i == count
     //           call BJDebugMsg("BROADCASTING INT : " + I2S(Queue[i]))
                call broadcastint(Queue[i])
                set i = i + 1
            endloop
      //      call BJDebugMsg("3")
        endmethod
        
        public static method create takes player playerFor returns thistype
            local thistype this = thistype.allocate()
            set incoming = BinaryStream.create(2)
            set p = playerFor
            set u = null
            set Queue = Table.create()
            set popPos = 0
            set incomingCount = 0
            set incomingQueuePos = 0
            
            set incomingQueue = Table.create()
            set count = 0
            set unitData = UnitData.create(1, this) 
            set fin = false
            return this
        endmethod
    endstruct
    
    struct StringQueuePacket extends array
        implement Alloc
        player player
        unit u
        UnitData unitData
        Table stringData
        
        Table bTable
        Table oTable
        string packet 
        integer sDataIndex
        integer sCacheIndex
        integer packetIndex
        integer cacheIndex
        
        public method operator [] takes integer i returns string
            return stringData.string[i]
        endmethod
        
        public method wait takes boolean pause returns boolean
            if pause then
                call TriggerSyncStart()
                call TriggerSyncReady()
            endif
            if packetIndex >= sCacheIndex and u != null then
                call RemoveUnit(u)
                set u = null
            endif
            return packetIndex >= sCacheIndex
        endmethod
        
        public method recieve takes integer i returns nothing
            local string name = GetObjectName(i)
          //  call BJDebugMsg("GOT")
            if name != "invalid" then
          //      call BJDebugMsg("not invalid")
                if name == "/" then
                 //   call BJDebugMsg("PACKET : " + packet)
                //    call BJDebugMsg(
                    set stringData.string[sDataIndex] = packet
                    set sDataIndex = sDataIndex + 1
                    set packet = ""
                else
         //           call BJDebugMsg("PACKET : " + packet)
                    if name == "space" then
                        set packet = packet + " "
                    else
                        set packet = packet + name
                    endif
                endif
            endif
            set packetIndex = packetIndex + 1
            if packetIndex > sCacheIndex then  
                call Network_RemoveDummy(u)
                set u = null
            endif
        endmethod
        
        public method broadcast takes nothing returns nothing
            local integer i = 0
            set sCacheIndex = cacheIndex
            set packet = ""
            
            set u= Network_GetDummy(player)
            call UnitRemoveAbility(u, A0)
            call UnitRemoveAbility(u, A1)
            call UnitRemoveAbility(u, A2)
            call UnitRemoveAbility(u, A3)
            call UnitRemoveAbility(u, AF)
            call UnitAddAbility(u,B_ALL)
            call SetUnitLifeBJ(u, 1)
            call SetUnitUserData(u, unitData)
            
                call TriggerSyncStart()
                call TriggerSyncReady()
            if GetLocalPlayer() == player then
                call ClearSelection(  )
                call SelectUnit( u, true)
            endif
            if not Syncing then
                set Syncing = true
                call SyncSelections()
                set Syncing = false
                call TriggerSyncStart()
                call TriggerSyncReady()
            else
                call TriggerSyncStart()
                call TriggerSyncReady()
            endif
            
            call ForceUIKey("Q")
            
         //       call BJDebugMsg("cacheINdex : " + I2S(cacheIndex))
     //   call BJDebugMsg("broadcast broadcast broadcast")
            loop
                exitwhen i == cacheIndex
                    if GetRandomInt(0,10) == 1 then
                        call PrintTextConditional(GetLocalPlayer() == player, bCache[i])
                    endif
                if GetLocalPlayer() == player then
           //         call BJDebugMsg("book cache : " + bCache[i])
                    call ForceUIKey(bTable.string[i])
                    call ForceUIKey(oTable.string[i])
                    call ForceUICancel()
                endif
                
                set i = i + 1
            endloop
            
        endmethod
        public method add takes string orderKey returns nothing
            local integer asc = S2A(orderKey)
            if asc >= 'a' and asc <= 'k' then
                set bTable.string[cacheIndex] = B_AK
                set oTable.string[cacheIndex] = orderKey
            elseif asc >= 'l' and asc <= 'v' then
                set bTable.string[cacheIndex] = B_LV
                set oTable.string[cacheIndex] = orderKey
            elseif asc >= 'w' and asc <= 'z'  then
                set bTable.string[cacheIndex] = B_WXYZ
                set oTable.string[cacheIndex] = orderKey
            elseif asc == '/' then
                set bTable.string[cacheIndex] = B_WXYZ
                set oTable.string[cacheIndex] = "T"
            elseif asc == ' ' then
                set bTable.string[cacheIndex] = B_WXYZ
                set oTable.string[cacheIndex] = "B"
            elseif asc >= '0' and asc <= '9' then
                set oTable.string[cacheIndex] = Ascii2Char(asc + 17)
                set bTable.string[cacheIndex] = B_NUM
            elseif asc >= 'A' and asc <= 'K' then
                set bTable.string[cacheIndex] = BIG_AK
                set oTable.string[cacheIndex] = orderKey
            elseif asc >= 'L' and asc <= 'V' then
                set bTable.string[cacheIndex] = BIG_LV
                set oTable.string[cacheIndex] = orderKey
            elseif asc >= 'W' and asc <= 'Z' then
                set bTable.string[cacheIndex] = BIG_WXYZ
                set oTable.string[cacheIndex] = orderKey
            else
                set oTable.string[cacheIndex] = "A"
                set bTable.string[cacheIndex] = B_WXYZ
            endif
            set cacheIndex = cacheIndex + 1
        endmethod
        
        public method destroy takes nothing returns nothing
            set cacheIndex = 0
            call unitData.destroy()
            call stringData.destroy()
            call oTable.destroy()
            call bTable.destroy()
          //  if packetIndex >= sCacheIndex then  
                call Network_RemoveDummy(u)
                set u = null
            //endif
            call deallocate()
        endmethod
        
        public static method create takes player p returns thistype
            local thistype this = thistype.allocate()
            set player = p
            set unitData = UnitData.create(2, this)
            set stringData = Table.create()
            set oTable = Table.create()
            set bTable = Table.create()
            set cacheIndex = 0
            return this
        endmethod
    endstruct
    
    struct StringPacket extends array
        implement Alloc
        player p

        Table data
        integer length
        boolean hasRecievedLength
        boolean hasRecievedData
        IntegerQueuePacket lengthPacket
        StringQueuePacket dataPacket
        integer dataIndex
        
        public method pop takes nothing returns string
            set dataIndex = dataIndex + 1
            return dataPacket[dataIndex - 1]
        endmethod
        
        public method operator [] takes integer i returns string
            return dataPacket[i]
        endmethod
        
        private method broadcastData takes nothing returns nothing
            local integer i = length
            local integer ib = 0
            local string bc
            local string add 
            local boolean b = GetLocalPlayer() == p
            local integer len
            set dataPacket = StringQueuePacket.create(p)
            loop
                exitwhen ib == dataIndex
                set bc = data.string[ib]
                set i = 0
                set len = lengthPacket.pop()
                loop
                    exitwhen len == 0
                    set len = len - 1
                    
                    if b then
                        set add = SubString(bc, 0, 1)
                        set bc = SubString(bc, 1, StringLength(bc))
                    else
                        set add = ""
                    endif
                    
                    call dataPacket.add(add)
                    
                endloop
                call dataPacket.add("/")
                set ib = ib + 1
            endloop
            //call dataPacket.add("/")
            call lengthPacket.destroy()
            call dataPacket.broadcast()
        endmethod
        
        private method compileData takes nothing returns nothing
            call data.flush()
            set dataIndex = 0
            /*local integer i = length
            local integer da 
            local boolean b = false
            call data.flush()
            set dataIndex = 0
            loop
                set da = dataPacket.pop()
                exitwhen da == ' #^Q' or (b and da == 0)
                set b = da == 0
                if da == ' #^Z' then
                    set dataIndex = dataIndex + 1
                else
                    set data.string[dataIndex] = data.string[dataIndex] + A2S(da)
                endif
            endloop
            set dataIndex = 0
            call dataPacket.destroy()*/
        endmethod
        
        
        public method wait takes boolean pause returns boolean
            if not hasRecievedLength then
                if lengthPacket.wait(false) then   
             //       call BJDebugMsg("length packet")
                    call TriggerSyncStart()
                    call TriggerSyncReady()
                    set hasRecievedLength = true
                    call broadcastData()
                    set dataIndex = 0
                endif
            elseif not hasRecievedData then
             //   call BJDebugMsg("wating data")
                if dataPacket.wait(false) then
                    set hasRecievedData = true
                    call compileData()
                endif
            endif
            
                
            if pause then
                call TriggerSyncStart()
                call TriggerSyncReady()
            endif
            return hasRecievedData
        endmethod
        integer compDataLength
        
        public method broadcast takes nothing returns nothing
            call lengthPacket.broadcast()
        endmethod
        
        public method add takes string s returns nothing
            call lengthPacket.add(StringLength(s))
            set data.string[dataIndex] = s
            set dataIndex = dataIndex + 1
        endmethod
        
        public method destroy takes nothing returns nothing
            call data.destroy()
            call lengthPacket.destroy()
            call dataPacket.destroy()
            call deallocate()
        endmethod
        
        public static method create takes player pFor returns thistype
            local thistype this = thistype.allocate()
            set compDataLength = 0
            set p = pFor
            set data = Table.create()
            set lengthPacket = IntegerQueuePacket.create(pFor)
            return this
        endmethod
        
    endstruct
    
    private function onAbil takes nothing returns nothing
     //       call BJDebugMsg("RECIEVED ORDER : " + I2S(GetSpellAbilityId()))
    
        if GetUnitTypeId(GetTriggerUnit()) == 'h000' or GetUnitTypeId(GetTriggerUnit()) == Network_GetDummyId() then
        
            call UnitData(GetUnitUserData(GetTriggerUnit())).recieve(GetSpellAbilityId())
        endif
    endfunction
    
    
    
    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_CAST )
        call TriggerAddAction( t, function onAbil )
        set t = null
        set dummyUnit = Network_GetDummy(Player(0))
        call UnitAddAbility(dummyUnit, B_ALL)
        call Network_RemoveDummy(dummyUnit)
       // call IntegerPacket.create(15,Player(0)).broadcast()
        set ORDERS[0] = O0
        set ORDERS[1] = O1
        set ORDERS[2] = O2
        set ORDERS[3] = O3
        set ABILS[0] = A0
        set ABILS[1] = A1
        set ABILS[2] = A2
        set ABILS[3] = A3
        set timerData = Table.create()
    endfunction
    
endlibrary
//old StringPacket, binary
/*struct StringPacket extends array
        implement Alloc
        player p

        Table data
        integer length
        boolean hasRecievedLength
        boolean hasRecievedData
        IntegerQueuePacket lengthPacket
        IntegerQueuePacket dataPacket
        integer dataIndex
        
        public method pop takes nothing returns string
            set dataIndex = dataIndex + 1
            return data.string[dataIndex - 1]
        endmethod
        
        private method broadcastData takes nothing returns nothing
            local integer i = length
            local integer ib = 0
            local string bc
            local integer add = 0
            local boolean b = GetLocalPlayer() == p
            local integer len
            set dataPacket = IntegerQueuePacket.create(p)
            loop
                exitwhen ib == dataIndex
                set bc = data.string[ib]
                set i = 0
                set len = (lengthPacket.pop() - 1)/ 4 + 1
                loop
                    exitwhen len == 0
                    set len = len - 1
                    
                    if b then
                        set add = S2A(SubString(bc, 0, 4))
                        set bc = SubString(bc, 4, StringLength(bc))
                    else
                        set add = 0
                    endif
                    
                    call dataPacket.add(add)
                    
                endloop
                call dataPacket.add(' #^Z')
                set ib = ib + 1
            endloop
                call dataPacket.add(' #^Q')
            call lengthPacket.destroy()
            call dataPacket.broadcast()
        endmethod
        
        private method compileData takes nothing returns nothing
            local integer i = length
            local integer da 
            local boolean b = false
            call data.flush()
            set dataIndex = 0
            loop
                set da = dataPacket.pop()
                exitwhen da == ' #^Q' or (b and da == 0)
                set b = da == 0
                if da == ' #^Z' then
                    set dataIndex = dataIndex + 1
                else
                    set data.string[dataIndex] = data.string[dataIndex] + A2S(da)
                endif
            endloop
            set dataIndex = 0
            call dataPacket.destroy()
        endmethod
        
        public method destroy takes nothing returns nothing
            set p = null
            call deallocate()
        endmethod
        
        public method wait takes boolean pause returns boolean
            if not hasRecievedLength then
                if lengthPacket.wait(false) then
                    set hasRecievedLength = true
                    call broadcastData()
                    set dataIndex = 0
                endif
            elseif not hasRecievedData then
                if dataPacket.wait(false) then
                    set hasRecievedData = true
                    call compileData()
                endif
            endif
            
                
                
            if pause then
                call TriggerSyncStart()
                call TriggerSyncReady()
            endif
            return hasRecievedData
        endmethod
        integer compDataLength
        public method broadcast takes nothing returns nothing
            call lengthPacket.broadcast()
        endmethod
        
        public method add takes string s returns nothing
            call lengthPacket.add(StringLength(s))
            set data.string[dataIndex] = s
            set dataIndex = dataIndex + 1
        endmethod
        
        public static method create takes player pFor returns thistype
            local thistype this = thistype.allocate()
            set compDataLength = 0
            set p = pFor
            set data = Table.create()
            set lengthPacket = IntegerQueuePacket.create(p)
            
            return this
        endmethod
        
    endstruct*/

obviously this isnt the entire system nor is it completed or optimized
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Fixed ; P, mixed up the nicks, my bad =)

:p

unless things REALLY change, i'll be out of the wc3 modding scene for ~10 years except for weekends so my shitty undocumented research is still with me if someone wants it or to just start from scratch using the same reasoning.
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
In other news, forgot to mention this, but Alloc will be getting an update to use Ruk's algorithm by default :). He will also get credits for his work in documentation.

I still gotta clean up whatevet modules people asked me to clean up too for UnitIndexer and/or DDS :).

No API changes planned for the foresseable future.

UnitEvent also needs some loving so that it works with latest UnitIndexer, but i found a lot of new hidden flaws in it :(.

So much to do and no coders willing to help for the overall betterment if the community :(.

Who knows when I'll get to coding AttackIndexer. It's a revolutionairy system complete with solution. Free DC in Spells section to whoever codes it, lol.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
could u elaborate what attack indexer should do

I recently discored that damage is stored on an attack. When changing the damage on a unit around in between attacks is done, original damage used in attacks is preserved. The damage is actually calculated during attack. With this approach, damage can be treated as instance pointers to structs.

so instead of doing 12-14 dmg, you actually do 1 damage and that would deal damage[1] = 13 dmg or etc

sounds like a neat idea in theory but I see no way to control the damage that a unit deals without using bonus to add 1291293 dmg etc

also inb4 damage is a real
 
Last edited:
Status
Not open for further replies.
Top