1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Seek unity between the elements in the 22nd Terraining Contest Poll.
    Dismiss Notice
  3. Seize the moment! The 18th Mini Mapping Contest has commenced.
    Dismiss Notice
  4. The heavens smile on the old faithful. The 16th Techtree Contest has begun.
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Combo System v1.5.2

Submitted by nhocklanhox6
This bundle is marked as approved. It works and satisfies the submission rules.
What system does

- This system will count the combo that a unit attack enemies. Affected only when a unit attack without using spell.


How to use
Code (vJASS):
//        How to use:
//                   - To start counting combo from a unit, use this function:
//      function UnitComboAdd takes unit whichUnit,real Scale,real ComboDisableTimer returns nothing
//                   => whichUnit - Which unit you want to count
//                   => Scale - Scaling size of the unit (Make the height more accurate)
//                   => ComboDisableTimer - Timer of the combo, if the unit stop attacking the enemies,
//                      Combo will be destroyed and reset to 0.
//                   - To start counting combo from a unit, use this function (Ex):
//      function UnitComboAddEx takes unit whichUnit,real Scale,real ComboDisableTimer,real whichHeight,string decorateLeft,string decorateRight,string textCombo returns nothing
//                   => whichUnit - Which unit you want to count
//                   => Scale - Scaling size of the unit (Make the height more accurate)
//                   => ComboDisableTimer - Timer of the combo, if the unit stop attacking the enemies,
//                      Combo will be destroyed and reset to 0.
//                   => whichHeight: Your height value
//                   => decorateLeft: Your decorate left text
//                   => decorateRogjt: Your decorate right text
//                   => textCombo: Your text combo text
//                   - To stop counting combo from a unit, use this function:
//      function UnitComboRemove takes unit whichUnit returns nothing
//                   => whichUnit - Which unit you want to remove from this system
//                   - To get combo count of a unit, use this function:
//      function GetUnitComboCount takes unit whichUnit returns integer
//                   => whichUnit - Which unit you want to get combo count
//                   - To change scale value from a unit, use this function:
//      function SetTextComboScale takes unit whichUnit,real whichScale returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichScale - Your scale value
//                   - To change height value from a unit, use this function:
//      function SetTextComboheighttakes unit whichUnit,real whichHeight returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichHeight - Your height value
//                   - To change text decorate left from a unit, use this function:
//      function SetTextComboDecorateLeft takes unit whichUnit,string whichText returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichText - Your text
//                   - To change text decorate right from a unit, use this function:
//      function SetTextComboDecorateRight takes unit whichUnit,string whichText returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichText - Your text
//                   - To change text combo from a unit, use this function:
//      function SetTextComboText takes unit whichUnit,string whichText returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichText - Your text
//                   - To register unit combo event, use this function:
//      function TriggerRegisterUnitComboEvent takes unit whichUnit,integer whichCombo,trigger whichTrigger returns nothing
//                   => whichUnit - Which unit you want to register
//                   => whichCombo - Which combo you want to register
//                   => whichTrigger - Which trigger you want to register
//                   - To register unit any combo event, use this function:
//      function TriggerRegisterUnitAnyComboEvent takes unit whichUnit,trigger whichTrigger returns nothing
//                   => whichUnit - Which unit you want to register
//                   => whichTrigger - Which trigger you want to register
//                   - To remove any event combo event, use this function:
//      function RemoveTriggerComboEvent takes unit whihUnit, trigger whichTrigger returns nothing
//                   => whichTrigger - Which trigger you want to remove
//                   => whichUnit - Which unit you want to remove the triger event


System Code
Code (vJASS):
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//              C O M B O   S Y S T E M
//                  Made by: Nyuu
//                  Version: 1.5.2
//
//        What system does:
//              - This system will count the combo that a unit attack
//               enemies. Affected only when a unit attack without using spell.
//        
//        How to use:
//                   - To start counting combo from a unit, use this function:
//      function UnitComboAdd takes unit whichUnit,real Scale,real ComboDisableTimer returns nothing
//                   => whichUnit - Which unit you want to count
//                   => Scale - Scaling size of the unit (Make the height more accurate)
//                   => ComboDisableTimer - Timer of the combo, if the unit stop attacking the enemies,
//                      Combo will be destroyed and reset to 0.
//                   - To start counting combo from a unit, use this function (Ex):
//      function UnitComboAddEx takes unit whichUnit,real Scale,real ComboDisableTimer,real whichHeight,string decorateLeft,string decorateRight,string textCombo returns nothing
//                   => whichUnit - Which unit you want to count
//                   => Scale - Scaling size of the unit (Make the height more accurate)
//                   => ComboDisableTimer - Timer of the combo, if the unit stop attacking the enemies,
//                      Combo will be destroyed and reset to 0.
//                   => whichHeight: Your height value
//                   => decorateLeft: Your decorate left text
//                   => decorateRogjt: Your decorate right text
//                   => textCombo: Your text combo text
//                   - To stop counting combo from a unit, use this function:
//      function UnitComboRemove takes unit whichUnit returns nothing
//                   => whichUnit - Which unit you want to remove from this system
//                   - To get combo count of a unit, use this function:
//      function GetUnitComboCount takes unit whichUnit returns integer
//                   => whichUnit - Which unit you want to get combo count
//                   - To change scale value from a unit, use this function:
//      function SetTextComboScale takes unit whichUnit,real whichScale returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichScale - Your scale value
//                   - To change height value from a unit, use this function:
//      function SetTextComboheighttakes unit whichUnit,real whichHeight returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichHeight - Your height value
//                   - To change text decorate left from a unit, use this function:
//      function SetTextComboDecorateLeft takes unit whichUnit,string whichText returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichText - Your text
//                   - To change text decorate right from a unit, use this function:
//      function SetTextComboDecorateRight takes unit whichUnit,string whichText returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichText - Your text
//                   - To change text combo from a unit, use this function:
//      function SetTextComboText takes unit whichUnit,string whichText returns nothing
//                   => whichUnit - Which unit you want to change
//                   => whichText - Your text
//                   - To register unit combo event, use this function:
//      function TriggerRegisterUnitComboEvent takes unit whichUnit,integer whichCombo,trigger whichTrigger returns nothing
//                   => whichUnit - Which unit you want to register
//                   => whichCombo - Which combo you want to register
//                   => whichTrigger - Which trigger you want to register
//                   - To register unit any combo event, use this function:
//      function TriggerRegisterUnitAnyComboEvent takes unit whichUnit,trigger whichTrigger returns nothing
//                   => whichUnit - Which unit you want to register
//                   => whichTrigger - Which trigger you want to register
//                   - To remove any event combo event, use this function:
//      function RemoveTriggerComboEvent takes unit whihUnit, trigger whichTrigger returns nothing
//                   => whichTrigger - Which trigger you want to remove
//                   => whichUnit - Which unit you want to remove the triger event
//
//         How to import:
//                       - Copy Combo system code and play with the configuration below.
//                       - Go to Variables panel (Ctrl + B) copy variable System_ComboUnit, System_ComboCount and all the variables of GDD
//                       - Be sure "Automatically create unknown variables while pasting trigger data" is
//                         enabled in the World Editor general preferences.
//          
//          Credit:
//                  - Weep - Damage Detection System - http://www.hiveworkshop.com/forums/spells-569/gui-friendly-damage-detection-v1-2-1-a-149098/?prev=search%3DDamage%2520Detection%26d%3Dlist%26r%3D20
//----------------------------------------------------------------------
//----------------------------------------------------------------------
library ComboSystem
   
    private module Init
        static method onInit takes nothing returns nothing
            call Init()
        endmethod
    endmodule
   
    globals
        //----------------------------------------------------------------
        //                     SYSTEM CONFIGURABLE
        //System period
        private constant real PERIODIC              = .0312500
        //Default size of the text tag
        private constant real TEXT_TAG_SIZE         = 10.
        //Limited size of the text tag when it increasing
        private constant real TEXT_TAG_SIZE_LIMIT   = 20.
        //Text tag size increase per period
        private constant real SIZE_INCREASE         = 2.
        //Text tag size decrease per period
        private constant real SIZE_DECREASE         = 3.
        //Height default of the text tag
        private constant real HEIGHT_DEFAULT        = 150.
        //
        private constant real TEXT_CENTER           = -65.
        //Text tag color decrease per period
        private constant integer TEXT_COLOR_DECREASE= 12
       
        private constant string COMBO_TEXT          = "Combo - "
        private constant string DECORATE_TEXT_LEFT  = "=>"
        private constant string DECORATE_TEXT_RIGHT = "<="
        //----------------------------------------------------------------
       
        //----------------------------------------------------------------
        //                       NON - CONFIGURABLE                     //
        /*-*/private integer Index                  = 0              /*-*/
        /*-*/private integer Counter                = 0              /*-*/
        /*-*/private integer EventCount             = 0              /*-*/
        /*-*/private integer DataIndex                               /*-*/
       
        /*-*/private integer array StructIndex                       /*-*/
        /*-*/private integer array ComboCount                        /*-*/
        /*-*/private integer array Color                             /*-*/
        /*-*/private integer array ComboCounter                      /*-*/
       
        /*-*/private real array SizeValue                            /*-*/
        /*-*/private real array ScaleValue                           /*-*/
        /*-*/private real array ComboTime                            /*-*/
        /*-*/private real array ComboTimeCounter                     /*-*/
        /*-*/private real array Height                               /*-*/
        /*-*/private real array HeightSetting                        /*-*/
       
        /*-*/private trigger array EventTrigger                      /*-*/
       
        /*-*/private player array ComboPlayer                        /*-*/
       
        /*-*/private unit array ComboUnit                            /*-*/
        /*-*/private unit array EventUnit                            /*-*/
       
        /*-*/private boolean array SizeBlock                         /*-*/
        /*-*/private boolean array AttackDetector                    /*-*/
       
        /*-*/private texttag array TextTag                           /*-*/
       
        /*-*/private string array Value                              /*-*/
        /*-*/private string array DecorateLeft                       /*-*/
        /*-*/private string array DecorateRight                      /*-*/
        /*-*/private string array ComboText                          /*-*/
       
        /*-*/private hashtable    ComboHashtable                     /*-*/
       
        /*-*/private constant timer TIMER = CreateTimer()            /*-*/
       
        /*-*/private constant location LOC = Location(0.,0.)         /*-*/
        //----------------------------------------------------------------
    endglobals
   
    private function eventConditions takes integer whichCombo, integer index returns nothing
   
        set udg_System_ComboUnit = EventUnit[index]
        set udg_System_ComboCount = whichCombo
   
        if ComboCounter[index] == whichCombo or ComboCounter[index] == -1 then
            call TriggerExecute(EventTrigger[index])
        endif
    endfunction
   
    private function DoesUnitExist takes integer id returns boolean
        set DataIndex=LoadInteger(ComboHashtable,0,id)
        return DataIndex != 0
    endfunction
   
    private function removeKey takes boolean isAny,integer handleId1,integer handleId2 returns nothing
        local integer key
       
        if isAny then
            set key=1
        else
            set key=2
        endif
       
        call RemoveSavedInteger(ComboHashtable,key,handleId1)
       
        if DataIndex!=EventCount then
            call SaveInteger(ComboHashtable,key,handleId2,DataIndex)
        endif
    endfunction
   
    function RemoveTriggerComboEvent takes unit whichUnit, trigger whichTrigger returns nothing
        local integer hid=GetHandleId(whichUnit)
       
        if DoesUnitExist(hid) then
       
            set DataIndex=LoadInteger(ComboHashtable,1,hid)
           
            if EventTrigger[DataIndex] != whichTrigger then
                set DataIndex=LoadInteger(ComboHashtable,2,hid)
               
                if EventTrigger[DataIndex]!=whichTrigger then
                    debug call BJDebugMsg("This trigger doesn't exist in the system.")
                    return
                endif
            endif
       
            set EventUnit[DataIndex] = EventUnit[EventCount]
            set EventUnit[EventCount] = null
            set EventTrigger[DataIndex] = EventTrigger[EventCount]
            set EventTrigger[EventCount] = null
            set ComboCounter[DataIndex] = ComboCounter[EventCount]
           
            call removeKey(ComboCounter[DataIndex]!=-1,GetHandleId(whichUnit),GetHandleId(EventUnit[DataIndex]))
           
            set EventCount = EventCount - 1
           
        else
            debug call BJDebugMsg("This unit doesn't exist in the system.")
        endif
    endfunction
   
    private function TriggerRegisterComboEventHelper takes unit whichUnit, integer whichCombo, trigger whichTrigger, integer hashIndex returns nothing
        local integer hid = GetHandleId(whichUnit)
       
        if DoesUnitExist(hid) then
            set EventCount = EventCount + 1
            call SaveInteger(ComboHashtable,hashIndex,hid,EventCount)
            set EventTrigger[EventCount] = whichTrigger
            set EventUnit[EventCount] = whichUnit
            set ComboCounter[EventCount] = whichCombo
        else
            debug call BJDebugMsg("This unit doesn't exists in the system.")
        endif
    endfunction

    function TriggerRegisterComboEvent takes unit whichUnit,integer whichCombo,trigger whichTrigger returns nothing
        if whichCombo > 0 then
            call TriggerRegisterComboEventHelper(whichUnit, whichCombo, whichTrigger, 1)
        else
            debug call BJDebugMsg("Combo = "+I2S(whichCombo)+" ?????, what kind of your combo 0.0..")
        endif
    endfunction
   
    function TriggerRegisterAnyComboEvent takes unit whichUnit,trigger whichTrigger returns nothing
        call TriggerRegisterComboEventHelper(whichUnit,-1,whichTrigger, 2)
    endfunction
   
    function GetUnitComboCount takes unit whichUnit returns integer
        if DoesUnitExist(GetHandleId(whichUnit)) then
            return ComboCount[DataIndex]
        else
            debug call BJDebugMsg("This unit doesn't exist in the system.")
        endif
           
        return 0
    endfunction
   
    function UnitAddComboEx takes unit whichUnit,real Scale,real ComboDisableTimer,real whichHeight,string decorateLeft,string decorateRight,string comboText returns nothing
        local integer hid=GetHandleId(whichUnit)
       
        if not DoesUnitExist(hid) then
            set Index = Index + 1
            call SaveInteger(ComboHashtable,0,hid,Index)
            set ComboUnit[Index] = whichUnit
            set ComboCount[Index] = 0
            set ScaleValue[Index] = Scale
            set ComboTime[Index] = ComboDisableTimer
            set StructIndex[Index] = Index
            set DecorateLeft[Index] = decorateLeft
            set DecorateRight[Index] = decorateRight
            set ComboText[Index] = comboText
            set HeightSetting[Index] = whichHeight
            set ComboPlayer[Index] = GetOwningPlayer(ComboUnit[Index])
           
            set TextTag[Index] = CreateTextTag()
            call MoveLocation(LOC,GetUnitX(ComboUnit[Index]),GetUnitY(ComboUnit[Index]))
            call SetTextTagPosUnit(TextTag[Index],ComboUnit[Index],GetUnitFlyHeight(ComboUnit[Index])+GetLocationZ(LOC))
            call SetTextTagText(TextTag[Index],null,TEXT_TAG_SIZE)
            call SetTextTagSuspended(TextTag[Index],true)
            call SetTextTagPermanent(TextTag[Index],false)
        else
            debug call BJDebugMsg("This unit already exist in the system.")
        endif
       
    endfunction
   
    function UnitComboAdd takes unit whichUnit, real Scale, real ComboDisableTimer returns nothing
        call UnitAddComboEx(whichUnit, Scale, ComboDisableTimer, HEIGHT_DEFAULT, /*
            */
DECORATE_TEXT_LEFT, DECORATE_TEXT_RIGHT, COMBO_TEXT)
    endfunction
   
    function UnitComboRemove takes unit whichUnit returns nothing
        local integer hid=GetHandleId(whichUnit)
       
        if DoesUnitExist(hid) then
            set ComboUnit[DataIndex] = ComboUnit[Index]
            set ComboCount[DataIndex] = ComboCount[Index]
            set ScaleValue[DataIndex] = ScaleValue[Index]
            set ComboTime[DataIndex] = ComboTime[Index]
            set DecorateLeft[DataIndex] = DecorateLeft[Index]
            set DecorateRight[DataIndex] = DecorateRight[Index]
            set ComboText[DataIndex] = ComboText[Index]
            set HeightSetting[DataIndex] = HeightSetting[Index]
            set ScaleValue[DataIndex] = ScaleValue[Index]
            set ComboPlayer[DataIndex] = ComboPlayer[Index]
            call DestroyTextTag(TextTag[DataIndex])
            set TextTag[DataIndex] = TextTag[Index]
            set StructIndex[DataIndex] = StructIndex[Index]
            set StructIndex[Index] = 0
            set TextTag[Index] = null
            set ComboUnit[Index] = null
           
            call RemoveSavedInteger(ComboHashtable,0,hid)
           
            if DataIndex!=Index then
                call SaveInteger(ComboHashtable,0,GetHandleId(ComboUnit[DataIndex]),DataIndex)
            endif
           
            set Index = Index - 1
        else
            debug call BJDebugMsg("This unit doesn't exist in the system.")
        endif
       
    endfunction
   
    function SetTextComboHeight takes unit whichUnit,real whichHeight returns nothing
        if DoesUnitExist(GetHandleId(whichUnit)) then
            set HeightSetting[DataIndex] = whichHeight
        else
            debug call BJDebugMsg("This unit doesn't exist in the system.")
        endif
    endfunction
   
    function SetTextComboText takes unit whichUnit,string whichText returns nothing
        if DoesUnitExist(GetHandleId(whichUnit)) then
            set ComboText[DataIndex] = whichText
        else
            debug call BJDebugMsg("This unit doesn't exist in the system.")
        endif
    endfunction
   
    function SetTextComboDecorateLeft takes unit whichUnit,string whichText returns nothing
        if DoesUnitExist(GetHandleId(whichUnit)) then
            set DecorateLeft[DataIndex] = whichText
        else
            debug call BJDebugMsg("This unit doesn't exist in the system.")
        endif
    endfunction
   
    function SetTextComboDecorateRight takes unit whichUnit,string whichText returns nothing
        if DoesUnitExist(GetHandleId(whichUnit)) then
            set DecorateRight[DataIndex] = whichText
        else
            debug call BJDebugMsg("This unit doesn't exist in the system.")
        endif
    endfunction
   
    function SetTextComboScale takes unit whichUnit,real whichScale returns nothing
        if DoesUnitExist(GetHandleId(whichUnit)) then
            set ScaleValue[DataIndex] = whichScale
        else
            debug call BJDebugMsg("This unit doesn't exist in the system.")
        endif
    endfunction
   
    private struct ComboSystem extends array
   
        static method textTag takes string whichString,integer Indexx,real Scale returns nothing
                local thistype this = Indexx
               
                call SetTextTagText(TextTag[this],whichString,TEXT_TAG_SIZE)
               
                call SetTextTagVisibility(TextTag[this], GetLocalPlayer() == ComboPlayer[this])
               
                set ComboTimeCounter[this] = ComboTime[this]
                set SizeValue[this] = TEXT_TAG_SIZE
                set SizeBlock[this] = false
                set Value[this] = whichString
                set Color[this] = 255
                set Height[this] = HeightSetting[this]*ScaleValue[this]
                call SetTextTagColor(TextTag[this],255,255,255,255)
               
                set Counter = Counter + 1
                if Counter == 1 then
                    call TimerStart(TIMER,PERIODIC,true,function thistype.onPeriodic)
                endif
               
            endmethod
       
        static method damageDetection takes nothing returns boolean
           
            if IsUnitEnemy(udg_GDD_DamageSource,GetOwningPlayer(udg_GDD_DamagedUnit)) then
                if DoesUnitExist(GetHandleId(udg_GDD_DamageSource)) then
                    if AttackDetector[DataIndex] then
                        set ComboCount[DataIndex] = ComboCount[DataIndex] + 1
                        call textTag(DecorateLeft[DataIndex]+ComboText[DataIndex]+I2S(ComboCount[DataIndex])+DecorateRight[DataIndex],DataIndex,ScaleValue[DataIndex])
                        call eventConditions(1,DataIndex)
                        call eventConditions(2,DataIndex)
                    endif
                endif
            endif
           
            return false
        endmethod
       
        private static constant real cos= TEXT_CENTER * Cos(.0174533)
        private static constant real sin= TEXT_CENTER * Sin(.0174533)
       
       static method onPeriodic takes nothing returns nothing
            local integer i = 1
            local thistype this
            local real x
            local real y
           
            loop
                exitwhen i > Index
                set this = StructIndex[i]
               
                if GetUnitTypeId(ComboUnit[this]) != 0 then
                    if not SizeBlock[this] then
                        set SizeValue[this] = SizeValue[this] + SIZE_INCREASE
                        set SizeBlock[this] = SizeValue[this] >= TEXT_TAG_SIZE_LIMIT
                    else
                        if SizeValue[this] > TEXT_TAG_SIZE then
                            set SizeValue[this] = SizeValue[this] - SIZE_DECREASE
                        endif
                    endif
                   
                    set x = GetUnitX(ComboUnit[this])+cos
                    set y = GetUnitY(ComboUnit[this])+sin
                   
                    call MoveLocation(LOC,x,y)
               
                    call SetTextTagColor(TextTag[this],255,255,255,Color[this])
                    call SetTextTagText(TextTag[this],Value[this],SizeValue[this]*0.0023)
                   
                    call SetTextTagPos(TextTag[this],x,y,GetUnitFlyHeight(ComboUnit[this])+GetLocationZ(LOC)+Height[this])
                   
                    if ComboTimeCounter[this] > 0. and not IsUnitType(ComboUnit[this],UNIT_TYPE_DEAD) then
                        set ComboTimeCounter[this] = ComboTimeCounter[this] - PERIODIC
                    else
                        if Color[this] > 0 then
                            set Color[this] = Color[this] - TEXT_COLOR_DECREASE
                            set SizeValue[this] = SizeValue[this] + SIZE_INCREASE
                        else
                            set ComboCount[this] = 0
                            call SetTextTagVisibility(TextTag[this],false)
                           
                            set Counter = Counter - 1
                           
                            if Counter == 0 then
                                call PauseTimer(TIMER)
                            endif
                        endif
                    endif
                else
                    call UnitComboRemove(ComboUnit[this])
                   
                    set Counter = Counter - 1
                           
                    if Counter == 0 then
                        call PauseTimer(TIMER)
                    endif
                endif
               
                set i = i + 1
            endloop
        endmethod
       
        static method attackDetection takes nothing returns boolean
            if DoesUnitExist(GetHandleId(GetAttacker())) then
                set AttackDetector[DataIndex] = true
            endif
           
            return false
        endmethod
       
        static method spellDetection takes nothing returns boolean
            if DoesUnitExist(GetHandleId(GetTriggerUnit())) then
                set AttackDetector[DataIndex] = false
            endif
           
            return false
        endmethod
       
        static method Init takes nothing returns nothing
            local trigger damageTrigger = CreateTrigger()
            local trigger attackTrigger = CreateTrigger()
            local trigger spellTrigger = CreateTrigger()
            local integer i = 0
           
            set ComboHashtable=InitHashtable()
           
            loop
                exitwhen i > 15
               
                call TriggerRegisterPlayerUnitEvent(attackTrigger,Player(i),EVENT_PLAYER_UNIT_ATTACKED,null)
                call TriggerRegisterPlayerUnitEvent(spellTrigger,Player(i),EVENT_PLAYER_UNIT_SPELL_CAST,null)
               
                set i = i + 1
            endloop
           
            call TriggerRegisterVariableEvent(damageTrigger, "udg_GDD_Event", EQUAL, 0 )
           
            call TriggerAddCondition(damageTrigger,function thistype.damageDetection)
            call TriggerAddCondition(attackTrigger,function thistype.attackDetection)
            call TriggerAddCondition(spellTrigger,function thistype.spellDetection)
           
            set damageTrigger = null
            set attackTrigger = null
            set spellTrigger = null
           
        endmethod
       
        implement Init
    endstruct
   
endlibrary


Test trigger
Click
  • Hero Create
    • Events
      • Player - Player 1 (Red) types a chat message containing -test as An exact match
    • Conditions
    • Actions
      • Custom script: set udg_TestMap = CreateUnit(Player(0),'Hpal',0.,0.,0.)

  • Combo 20
    • Events
    • Conditions
    • Actions
      • Game - Display to (All players) for 30.00 seconds the text: Cool, you get 20 co...
      • Player - Set (Owner of System_ComboUnit) Current gold to 99999

  • Combo Any
    • Events
    • Conditions
    • Actions
      • Game - Display to (All players) for 30.00 seconds the text: (Your Combo: + (String(System_ComboCount)))

  • Combo Add
    • Events
      • Unit - A unit enters (Playable map area)
    • Conditions
    • Actions
      • Custom script: call UnitComboAdd(GetEnteringUnit(),1.,1.)
      • -------- ----------------------------------------- --------
      • Custom script: call TriggerRegisterComboEvent(udg_TestMap,20,gg_trg_Combo_20)
      • Custom script: call TriggerRegisterAnyComboEvent(udg_TestMap,gg_trg_Combo_Any)
      • -------- ----------------------------------------- --------
      • Game - Display to (All players) for 30.00 seconds the text: -remove to remove c...
      • Trigger - Turn on Combo Remove <gen>
      • Trigger - Turn on Combo Add Again <gen>
      • Trigger - Turn on Combo Change <gen>
      • Trigger - Turn on Remove Event <gen>
      • Trigger - Turn off (This trigger)

  • Combo Remove
    • Events
      • Player - Player 1 (Red) types a chat message containing -remove as An exact match
    • Conditions
    • Actions
      • Custom script: call UnitComboRemove(udg_TestMap)

  • Combo Add Again
    • Events
      • Player - Player 1 (Red) types a chat message containing -add as An exact match
    • Conditions
    • Actions
      • Custom script: call UnitComboAdd(udg_TestMap,1.,0.7)

  • Combo Change
    • Events
      • Player - Player 1 (Red) types a chat message containing -change as An exact match
    • Conditions
    • Actions
      • Custom script: call SetTextComboDecorateLeft(udg_TestMap,"|CffFFFF00=>|r")
      • Custom script: call SetTextComboDecorateRight(udg_TestMap,"|CffFFFF00<=|r")
      • Custom script: call SetTextComboText(udg_TestMap,"|Cff00CC99Combo: |r")
      • Custom script: call SetTextComboHeight(udg_TestMap,140.)
      • Custom script: call SetTextComboScale(udg_TestMap,0.9)

  • Remove Event
    • Events
      • Player - Player 1 (Red) types a chat message containing -removeevent as An exact match
    • Conditions
    • Actions
      • Custom script: call RemoveTriggerComboEvent(gg_trg_Combo_Any)


ScreenShot
[​IMG]


Changelog
v1.0: First release version.
v1.1: Code optimized, add some function.
v1.2: Add some event.
v1.3: Add remove event, optimize function CheckEventIndex
v1.4: Use hashtable instead if indexing, minor thing changes
v1.5: Code optimized
v1.5.2: Code optimized


Keywords:
combo,system
Contents

Combo System (Map)

Reviews
Moderator
12:48, 29th Aug 2014 PurgeandFire: (old) Long-awaited review: http://www.hiveworkshop.com/forums/2579635-post9.html It looks better. Approved.
  1. 12:48, 29th Aug 2014
    PurgeandFire: (old) Long-awaited review:
    http://www.hiveworkshop.com/forums/2579635-post9.html

    It looks better. Approved.
     
  2. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,327
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    .031250000
    ->
    .0312500
    Because JASS can handle up to 8 digits (including the one before the .)

    Use a unit indexer because linear searching can be a bit slow :/
    (Or AVL and search ^^')

    Code (vJASS):
    private function CreateTextTagUnit takes unit whichUnit,real x,real y,string whichString returns texttag
            local texttag t = CreateTextTag()
           
            call MoveLocation(LOC,x,y)
           
            call SetTextTagPosUnit(t,whichUnit,GetUnitFlyHeight(whichUnit)+GetLocationZ(LOC))
            call SetTextTagText(t,whichString,TEXT_TAG_SIZE)
            call SetTextTagColor(t,255,255,255,255)
            call SetTextTagSuspended(t,true)
            call SetTextTagPermanent(t,false)
           
            return t
        endfunction

    This leak a reference (except if they fix the leak with texttag I read something a while ago...)

    Starts your index to -1 to use the 0 index.

    That's all for the moment ;)
     
  3. ILH

    ILH

    Joined:
    May 8, 2012
    Messages:
    606
    Resources:
    16
    Models:
    14
    Icons:
    1
    Tutorials:
    1
    Resources:
    16
    Nice :O
     
  4. EmoBrother

    EmoBrother

    Joined:
    Dec 15, 2012
    Messages:
    559
    Resources:
    0
    Resources:
    0
    The picture inside "ScreenShot" couldn't be seen :/

    Your system seems cool :)
    Gonna download it for testing.

    EDIT :
    Suggestions after using :

    1. The color of text tag will be changed when the combos are more than a number for extracting a set of COOL combos
    2. More configurable settings. Exp :
    --------The combo ends when the unit is being ordered to something else than attack
    --------The combo won't stop after the unit was being ordered to do something else than attack (original).

    It's a nice system :)
    4/5
     
    Last edited: Mar 28, 2014
  5. nhocklanhox6

    nhocklanhox6

    Joined:
    Feb 12, 2012
    Messages:
    335
    Resources:
    28
    Models:
    6
    Spells:
    21
    Tutorials:
    1
    Resources:
    28
    @Ah_Xian: Thanks for your suggestions.

    Oh yes, it will more cooler, but I think I will let it depending on the users :).
    Some methods will support for that:
    call SetTextComboDecorateLeft()
    call SetTextComboDecorateRight()
    call SetTextComboText()


    I think attack is more accurate :)

    EDIT: If you want to do that, you can setting ComboDisableTimer very long :p...

    @Mal: Ok my friend ^^~.
     
    Last edited: Mar 29, 2014
  6. Anggi Oktaviani P

    Anggi Oktaviani P

    Joined:
    Mar 22, 2014
    Messages:
    6
    Resources:
    0
    Resources:
    0
  7. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,709
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    IsUnitExist ---> DoesUnitExist, UnitExists, CheckUnit, .....

    if GetUnitTypeId(ComboUnit[this]) > 0 then
    -->
    if GetUnitTypeId(ComboUnit[this]) != 0 then


    static method textTag should be above static method damageDetection to avoid needless extra code generation. Furthermore it should be non static. You can refer to a struct instance like this: struct(index)/ thistype(index).

    TriggerExecute should be TriggerEvaluate.

    You could use Table + HandleId or UnitUserData in order to refer to the correct "Combo unit". It is much more neat than looping through every unit registered to the system.
    Consider someone wants to register +100 units.
    I also dislike the way you fire Events, like I said hashtable lookups can make ones life very easy.
     
  8. GreeN!X

    GreeN!X

    Joined:
    Oct 20, 2012
    Messages:
    2,348
    Resources:
    2
    Maps:
    1
    Template:
    1
    Resources:
    2
    Might be useful for me. Downloading and testing later. +repped


    BTW, I might ask you through VM if I'm having trouble in configuring this thing. I am a potato when it comes to VJass.
     
  9. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,429
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Review
    • In the method "texttag", this:
      Code (vJASS):
      call SetTextTagVisibility(TextTag[this],false)
                     
      if GetLocalPlayer() == ComboPlayer[this] then
          call SetTextTagVisibility(TextTag[this],true)
      endif

      Can be compressed to:
      Code (vJASS):
      call SetTextTagVisibility(TextTag[this], GetLocalPlayer() == ComboPlayer[this])
    • debug call BJDebugMsg("This unit doesn't exists in the system.")

      Just a quick grammar fix, change "exists" to "exist".
    • call SetTextTagColor(TextTag[Index],255,255,255,255)

      I might be wrong, but I think the texttags are set to (255, 255, 255, 255) (r, g, b, a) by default. I don't think
      you need to add that line when you create the texttag.
    • Code (vJASS):
      /* excerpt of UnitAddComboEx */
      call MoveLocation(LOC,GetUnitX(ComboUnit[Index]),GetUnitY(ComboUnit[Index]))
      call SetTextTagPosUnit(TextTag[Index],ComboUnit[Index],GetUnitFlyHeight(ComboUnit[Index])+GetLocationZ(LOC))

      Just a little tip: always prefer the non-arrayed version over the array. The array has extra overhead of
      looking up the value at that index. As such, you should replace ComboUnit[Index] in this function
      with "whichUnit". It doesn't make a big
      difference, but it is good to know.
    • These functions can be merged:
      Code
      Code (vJASS):
          function UnitComboAdd takes unit whichUnit,real Scale,real ComboDisableTimer returns nothing
              if not DoesUnitExist(whichUnit) then
                  set Index = Index + 1
                  call SaveInteger(ComboHashtable,0,GetHandleId(whichUnit),Index)
                  set ComboUnit[Index] = whichUnit
                  set ComboCount[Index] = 0
                  set ScaleValue[Index] = Scale
                  set ComboTime[Index] = ComboDisableTimer
                  set StructIndex[Index] = Index
                  set DecorateLeft[Index] = DECORATE_TEXT_LEFT
                  set DecorateRight[Index] = DECORATE_TEXT_RIGHT
                  set ComboText[Index] = COMBO_TEXT
                  set HeightSetting[Index] = HEIGHT_DEFAULT
                  set ComboPlayer[Index] = GetOwningPlayer(ComboUnit[Index])
                 
                  set TextTag[Index] = CreateTextTag()
                  call MoveLocation(LOC,GetUnitX(ComboUnit[Index]),GetUnitY(ComboUnit[Index]))
                  call SetTextTagPosUnit(TextTag[Index],ComboUnit[Index],GetUnitFlyHeight(ComboUnit[Index])+GetLocationZ(LOC))
                  call SetTextTagText(TextTag[Index],null,TEXT_TAG_SIZE)
                  call SetTextTagColor(TextTag[Index],255,255,255,255)
                  call SetTextTagSuspended(TextTag[Index],true)
                  call SetTextTagPermanent(TextTag[Index],false)
              else
                  debug call BJDebugMsg("This unit already exists in the system.")
              endif
          endfunction
         
          function UnitComboAddEx takes unit whichUnit,real Scale,real ComboDisableTimer,real whichHeight,string decorateLeft,string decorateRight,string comboText returns nothing
         
              if not DoesUnitExist(whichUnit) then
                  set Index = Index + 1
                  call SaveInteger(ComboHashtable,0,GetHandleId(whichUnit),Index)
                  set ComboUnit[Index] = whichUnit
                  set ComboCount[Index] = 0
                  set ScaleValue[Index] = Scale
                  set ComboTime[Index] = ComboDisableTimer
                  set StructIndex[Index] = Index
                  set DecorateLeft[Index] = decorateLeft
                  set DecorateRight[Index] = decorateRight
                  set ComboText[Index] = comboText
                  set HeightSetting[Index] = whichHeight
                  set ComboPlayer[Index] = GetOwningPlayer(ComboUnit[Index])
                 
                  set TextTag[Index] = CreateTextTag()
                  call MoveLocation(LOC,GetUnitX(ComboUnit[Index]),GetUnitY(ComboUnit[Index]))
                  call SetTextTagPosUnit(TextTag[Index],ComboUnit[Index],GetUnitFlyHeight(ComboUnit[Index])+GetLocationZ(LOC))
                  call SetTextTagText(TextTag[Index],null,TEXT_TAG_SIZE)
                  call SetTextTagColor(TextTag[Index],255,255,255,255)
                  call SetTextTagSuspended(TextTag[Index],true)
                  call SetTextTagPermanent(TextTag[Index],false)
              else
                  debug call BJDebugMsg("This unit already exists in the system.")
              endif
             
          endfunction

      Change it to this:
      Code
      Code (vJASS):
          function UnitComboAddEx takes unit whichUnit,real Scale,real ComboDisableTimer,real whichHeight,string decorateLeft,string decorateRight,string comboText returns nothing
         
              if not DoesUnitExist(whichUnit) then
                  set Index = Index + 1
                  call SaveInteger(ComboHashtable,0,GetHandleId(whichUnit),Index)
                  set ComboUnit[Index] = whichUnit
                  set ComboCount[Index] = 0
                  set ScaleValue[Index] = Scale
                  set ComboTime[Index] = ComboDisableTimer
                  set StructIndex[Index] = Index
                  set DecorateLeft[Index] = decorateLeft
                  set DecorateRight[Index] = decorateRight
                  set ComboText[Index] = comboText
                  set HeightSetting[Index] = whichHeight
                  set ComboPlayer[Index] = GetOwningPlayer(ComboUnit[Index])
                 
                  set TextTag[Index] = CreateTextTag()
                  call MoveLocation(LOC,GetUnitX(ComboUnit[Index]),GetUnitY(ComboUnit[Index]))
                  call SetTextTagPosUnit(TextTag[Index],ComboUnit[Index],GetUnitFlyHeight(ComboUnit[Index])+GetLocationZ(LOC))
                  call SetTextTagText(TextTag[Index],null,TEXT_TAG_SIZE)
                  call SetTextTagColor(TextTag[Index],255,255,255,255)
                  call SetTextTagSuspended(TextTag[Index],true)
                  call SetTextTagPermanent(TextTag[Index],false)
              else
                  debug call BJDebugMsg("This unit already exists in the system.")
              endif
             
          endfunction

          function UnitComboAdd takes unit whichUnit, real Scale, real ComboDisableTimer returns nothing
              call UnitAddComboEx(whichUnit, Scale, ComboDisableTimer, HEIGHT_DEFAULT, /*
                  */
      DECORATE_TEXT_LEFT, DECORATE_TEXT_RIGHT, COMBO_TEXT)
          endfunction

      Try to avoid repeating code whenever possible. ;)
    • This:
      Code (vJASS):
          private function DoesUnitExist takes unit whichUnit returns boolean
              set DataIndex=LoadInteger(ComboHashtable,0,GetHandleId(whichUnit))
         
              if DataIndex == 0 then
                  return false
              endif
             
              return true
          endfunction

      Can become:
      Code (vJASS):
      private function DoesUnitExist takes unit whichUnit returns boolean
          set DataIndex = LoadInteger(ComboHashtable, 0, GetHandleId(whichUnit))
          return DataIndex != 0
      endfunction
    • You have some repeated code in TriggerRegister/Any/ComboEvent. Yet, they have some differences
      (such as the hashtable index, and the error msg). How do you remedy this? Use a private helper function. It should end up like this:
      Code (vJASS):
          private function TriggerRegisterComboEventHelper takes unit whichUnit, integer whichCombo, trigger whichTrigger, integer hashIndex returns nothing
              if DoesUnitExist(whichUnit) then
                  set EventCount = EventCount + 1
                  call SaveInteger(ComboHashtable,hashIndex,GetHandleId(whichUnit),EventCount)
                  set EventTrigger[EventCount] = whichTrigger
                  set EventUnit[EventCount] = whichUnit
                  set ComboCounter[EventCount] = whichCombo
              else
                  debug call BJDebugMsg("This unit doesn't exists in the system.")
              endif
          endfunction

          function TriggerRegisterComboEvent takes unit whichUnit,integer whichCombo,trigger whichTrigger returns nothing
              if whichCombo > 0 then
                  call TriggerRegisterComboEventHelper(whichUnit, whichCombo, whichTrigger, 1)
              else
                  debug call BJDebugMsg("Combo = "+I2S(whichCombo)+" ?????, what kind of your combo 0.0..")
              endif
          endfunction
         
          function TriggerRegisterAnyComboEvent takes unit whichUnit,trigger whichTrigger returns nothing
              call TriggerRegisterComboEventHelper(whichUnit, -1, whichCombo, 2)
          endfunction

      It only saves 4 lines, but it is good to avoid repetition.
     
  10. nhocklanhox6

    nhocklanhox6

    Joined:
    Feb 12, 2012
    Messages:
    335
    Resources:
    28
    Models:
    6
    Spells:
    21
    Tutorials:
    1
    Resources:
    28
    Yup!, Long-awaited.

    And thanks >_^

    System updated.
     
  11. deathismyfriend

    deathismyfriend

    Joined:
    Oct 24, 2012
    Messages:
    6,526
    Resources:
    14
    Spells:
    12
    Tutorials:
    2
    Resources:
    14
    You constantly call GetHandleId(). You should use one call and pass that to all functions needed rather than calling that in each function.
     
  12. nhocklanhox6

    nhocklanhox6

    Joined:
    Feb 12, 2012
    Messages:
    335
    Resources:
    28
    Models:
    6
    Spells:
    21
    Tutorials:
    1
    Resources:
    28

    Read my code :) and tell me how to do it. Thanks.
     
  13. deathismyfriend

    deathismyfriend

    Joined:
    Oct 24, 2012
    Messages:
    6,526
    Resources:
    14
    Spells:
    12
    Tutorials:
    2
    Resources:
    14
    I did read your code.
    It will make some things look longer as you have to pass the handle id to the functions.

    If you don't understand I will update your code when I get home and explain it better then.
     
  14. nhocklanhox6

    nhocklanhox6

    Joined:
    Feb 12, 2012
    Messages:
    335
    Resources:
    28
    Models:
    6
    Spells:
    21
    Tutorials:
    1
    Resources:
    28
    I did understand, but I need to know how to optimize it :). Can you show some of your coding about that? (That will helped me alot >_^)..Plz... ^^
     
    Last edited: Aug 30, 2014
  15. Kazeon

    Kazeon

    Joined:
    Oct 12, 2011
    Messages:
    3,296
    Resources:
    38
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    3
    JASS:
    4
    Resources:
    38
    • Code (vJASS):
              private static real cos= TEXT_CENTER * Cos(.0174533)
              private static real sin= TEXT_CENTER * Sin(.0174533)

      should be static constant. And what value is that
      .0174533
      anyway?
    • Code (vJASS):
          private function eventConditions takes integer whichCombo returns nothing
         
              set udg_System_ComboUnit = EventUnit[DataIndex]
              set udg_System_ComboCount = whichCombo
         
              if ComboCounter[DataIndex] == whichCombo or ComboCounter[DataIndex] == -1 then
                  call TriggerExecute(EventTrigger[DataIndex])
              endif
          endfunction
         
         
          private function CheckEventCombo takes integer key,unit whichUnit,integer whichCombo returns nothing
              set DataIndex=LoadInteger(ComboHashtable,key,GetHandleId(whichUnit))
              call eventConditions(whichCombo)
          endfunction

      you could inline those two functions
    • Though, I still don't understand why do you ever need two udg_ variables whereas you have
      GetUnitComboCount(whichUnit)
      ? If it's just for demonstration, then you should not include the variable creator there.
    • Code (vJASS):
              if DoesUnitExist(whichUnit) then
             
                      set hid=GetHandleId(whichUnit)
             
                      set DataIndex=LoadInteger(ComboHashtable,1,hid)
                     
                      if EventTrigger[DataIndex] != whichTrigger then
                          set DataIndex=LoadInteger(ComboHashtable,2,hid)
                         
                          if EventTrigger[DataIndex]!=whichTrigger then
                              debug call BJDebugMsg("This trigger doesn't exist in the system.")
                             
                              return
                          endif
                      endif
      ...

      Weird indentation :p
    • Code (vJASS):
              if DoesUnitExist(whichUnit) then
             
                      set hid=GetHandleId(whichUnit)
             
                      set DataIndex=LoadInteger(ComboHashtable,1,hid)

      You set
      DataIndex
      twice there
    • This is just my personal opinion:
      Code (vJASS):
          private function DoesUnitExist takes unit whichUnit returns boolean
              set DataIndex=LoadInteger(ComboHashtable,0,GetHandleId(whichUnit))
              return DataIndex != 0
          endfunction

      that function better returns the
      DataIndex
      and should be renamed to something like getDataIndex. Then just use
      DataIndex != 0
      to check whether a unit exists or not:
      Code (vJASS):
          private function getDataIndex takes unit whichUnit returns boolean
              return LoadInteger(ComboHashtable,0,GetHandleId(whichUnit))
          endfunction

      call it:
      Code (vJASS):
              static method spellDetection takes nothing returns boolean
                  set DataIndex = getDataIndex(GetTriggerUnit())
                  if DataIndex != 0 then
                      set AttackDetector[DataIndex] = false
                  endif
                 
                  return false
              endmethod

      Because, setting a variable at other function then use it, imo, is very not convincing.

    Also I have a question: Are we allowed/able to determine actions for every combo? For example I want to deal 100 damage on the first combo, then I want to stun the target for the second, then I want to knock the target for the third, etc.
     
  16. deathismyfriend

    deathismyfriend

    Joined:
    Oct 24, 2012
    Messages:
    6,526
    Resources:
    14
    Spells:
    12
    Tutorials:
    2
    Resources:
    14
    This made the multiple GetHandleId calling more efficient.

    Code (vJASS):
    //----------------------------------------------------------------------
    //----------------------------------------------------------------------
    //              C O M B O   S Y S T E M
    //                  Made by: Nyuu
    //                  Version: 1.5
    //
    //        What system does:
    //              - This system will count the combo that a unit attack
    //               enemies. Affected only when a unit attack without using spell.
    //        
    //        How to use:
    //                   - To start counting combo from a unit, use this function:
    //      function UnitComboAdd takes unit whichUnit,real Scale,real ComboDisableTimer returns nothing
    //                   => whichUnit - Which unit you want to count
    //                   => Scale - Scaling size of the unit (Make the height more accurate)
    //                   => ComboDisableTimer - Timer of the combo, if the unit stop attacking the enemies,
    //                      Combo will be destroyed and reset to 0.
    //                   - To start counting combo from a unit, use this function (Ex):
    //      function UnitComboAddEx takes unit whichUnit,real Scale,real ComboDisableTimer,real whichHeight,string decorateLeft,string decorateRight,string textCombo returns nothing
    //                   => whichUnit - Which unit you want to count
    //                   => Scale - Scaling size of the unit (Make the height more accurate)
    //                   => ComboDisableTimer - Timer of the combo, if the unit stop attacking the enemies,
    //                      Combo will be destroyed and reset to 0.
    //                   => whichHeight: Your height value
    //                   => decorateLeft: Your decorate left text
    //                   => decorateRogjt: Your decorate right text
    //                   => textCombo: Your text combo text
    //                   - To stop counting combo from a unit, use this function:
    //      function UnitComboRemove takes unit whichUnit returns nothing
    //                   => whichUnit - Which unit you want to remove from this system
    //                   - To get combo count of a unit, use this function:
    //      function GetUnitComboCount takes unit whichUnit returns integer
    //                   => whichUnit - Which unit you want to get combo count
    //                   - To change scale value from a unit, use this function:
    //      function SetTextComboScale takes unit whichUnit,real whichScale returns nothing
    //                   => whichUnit - Which unit you want to change
    //                   => whichScale - Your scale value
    //                   - To change height value from a unit, use this function:
    //      function SetTextComboheighttakes unit whichUnit,real whichHeight returns nothing
    //                   => whichUnit - Which unit you want to change
    //                   => whichHeight - Your height value
    //                   - To change text decorate left from a unit, use this function:
    //      function SetTextComboDecorateLeft takes unit whichUnit,string whichText returns nothing
    //                   => whichUnit - Which unit you want to change
    //                   => whichText - Your text
    //                   - To change text decorate right from a unit, use this function:
    //      function SetTextComboDecorateRight takes unit whichUnit,string whichText returns nothing
    //                   => whichUnit - Which unit you want to change
    //                   => whichText - Your text
    //                   - To change text combo from a unit, use this function:
    //      function SetTextComboText takes unit whichUnit,string whichText returns nothing
    //                   => whichUnit - Which unit you want to change
    //                   => whichText - Your text
    //                   - To register unit combo event, use this function:
    //      function TriggerRegisterUnitComboEvent takes unit whichUnit,integer whichCombo,trigger whichTrigger returns nothing
    //                   => whichUnit - Which unit you want to register
    //                   => whichCombo - Which combo you want to register
    //                   => whichTrigger - Which trigger you want to register
    //                   - To register unit any combo event, use this function:
    //      function TriggerRegisterUnitAnyComboEvent takes unit whichUnit,trigger whichTrigger returns nothing
    //                   => whichUnit - Which unit you want to register
    //                   => whichTrigger - Which trigger you want to register
    //                   - To remove any event combo event, use this function:
    //      function RemoveTriggerComboEvent takes unit whihUnit, trigger whichTrigger returns nothing
    //                   => whichTrigger - Which trigger you want to remove
    //                   => whichUnit - Which unit you want to remove the triger event
    //
    //         How to import:
    //                       - Copy Combo system code and play with the configuration below.
    //                       - Go to Variables panel (Ctrl + B) copy variable System_ComboUnit, System_ComboCount and all the variables of GDD
    //                       - Be sure "Automatically create unknown variables while pasting trigger data" is
    //                         enabled in the World Editor general preferences.
    //          
    //          Credit:
    //                  - Weep - Damage Detection System - [url]http://www.hiveworkshop.com/forums/spells-569/gui-friendly-damage-detection-v1-2-1-a-149098/?prev=search%3DDamage%2520Detection%26d%3Dlist%26r%3D20[/url]
    //----------------------------------------------------------------------
    //----------------------------------------------------------------------
    library ComboSystem
       
        private module Init
            static method onInit takes nothing returns nothing
                call Init()
            endmethod
        endmodule
       
        globals
            //----------------------------------------------------------------
            //                     SYSTEM CONFIGURABLE
            //System period
            private constant real PERIODIC              = .0312500
            //Default size of the text tag
            private constant real TEXT_TAG_SIZE         = 10.
            //Limited size of the text tag when it increasing
            private constant real TEXT_TAG_SIZE_LIMIT   = 20.
            //Text tag size increase per period
            private constant real SIZE_INCREASE         = 2.
            //Text tag size decrease per period
            private constant real SIZE_DECREASE         = 3.
            //Height default of the text tag
            private constant real HEIGHT_DEFAULT        = 150.
            //
            private constant real TEXT_CENTER           = -65.
            //Text tag color decrease per period
            private constant integer TEXT_COLOR_DECREASE= 12
           
            private constant string COMBO_TEXT          = "Combo - "
            private constant string DECORATE_TEXT_LEFT  = "=>"
            private constant string DECORATE_TEXT_RIGHT = "<="
            //----------------------------------------------------------------
           
            //----------------------------------------------------------------
            //                       NON - CONFIGURABLE                     //
            /*-*/private integer Index                  = 0              /*-*/
            /*-*/private integer Counter                = 0              /*-*/
            /*-*/private integer EventCount             = 0              /*-*/
            /*-*/private integer DataIndex                               /*-*/
           
            /*-*/private integer array StructIndex                       /*-*/
            /*-*/private integer array ComboCount                        /*-*/
            /*-*/private integer array Color                             /*-*/
            /*-*/private integer array ComboCounter                      /*-*/
           
            /*-*/private real array SizeValue                            /*-*/
            /*-*/private real array ScaleValue                           /*-*/
            /*-*/private real array ComboTime                            /*-*/
            /*-*/private real array ComboTimeCounter                     /*-*/
            /*-*/private real array Height                               /*-*/
            /*-*/private real array HeightSetting                        /*-*/
           
            /*-*/private trigger array EventTrigger                      /*-*/
           
            /*-*/private player array ComboPlayer                        /*-*/
           
            /*-*/private unit array ComboUnit                            /*-*/
            /*-*/private unit array EventUnit                            /*-*/
           
            /*-*/private boolean array SizeBlock                         /*-*/
            /*-*/private boolean array AttackDetector                    /*-*/
           
            /*-*/private texttag array TextTag                           /*-*/
           
            /*-*/private string array Value                              /*-*/
            /*-*/private string array DecorateLeft                       /*-*/
            /*-*/private string array DecorateRight                      /*-*/
            /*-*/private string array ComboText                          /*-*/
           
            /*-*/private hashtable    ComboHashtable                     /*-*/
           
            /*-*/private constant timer TIMER = CreateTimer()            /*-*/
           
            /*-*/private constant location LOC = Location(0.,0.)         /*-*/
            //----------------------------------------------------------------
        endglobals
       
        private function eventConditions takes integer whichCombo returns nothing
       
            set udg_System_ComboUnit = EventUnit[DataIndex]
            set udg_System_ComboCount = whichCombo
       
            if ComboCounter[DataIndex] == whichCombo or ComboCounter[DataIndex] == -1 then
                call TriggerExecute(EventTrigger[DataIndex])
            endif
        endfunction
       
       
        private function CheckEventCombo takes integer key,integer whichCombo,integer id returns nothing
            set DataIndex=LoadInteger(ComboHashtable,key,id)
            call eventConditions(whichCombo)
        endfunction
       
        private function DoesUnitExist takes integer id returns boolean
            set DataIndex=LoadInteger(ComboHashtable,0,id)
            return DataIndex != 0
        endfunction
       
        private function removeKey takes boolean isAny,integer handleId1,integer handleId2 returns nothing
            local integer key
           
            if isAny then
                set key=1
            else
                set key=2
            endif
           
            call RemoveSavedInteger(ComboHashtable,key,handleId1)
           
            if DataIndex!=EventCount then
                call SaveInteger(ComboHashtable,key,handleId2,DataIndex)
            endif
        endfunction
       
        function RemoveTriggerComboEvent takes unit whichUnit, trigger whichTrigger returns nothing
            local integer id = GetHandleId(whichUnit)
           
            if DoesUnitExist(id) then
           
                    set DataIndex=LoadInteger(ComboHashtable,1,id)
                   
                    if EventTrigger[DataIndex] != whichTrigger then
                        set DataIndex=LoadInteger(ComboHashtable,2,id)
                       
                        if EventTrigger[DataIndex]!=whichTrigger then
                            debug call BJDebugMsg("This trigger doesn't exist in the system.")
                           
                            return
                        endif
                    endif
               
                    set EventUnit[DataIndex] = EventUnit[EventCount]
                    set EventUnit[EventCount] = null
                    set EventTrigger[DataIndex] = EventTrigger[EventCount]
                    set EventTrigger[EventCount] = null
                    set ComboCounter[DataIndex] = ComboCounter[EventCount]
                   
                    call removeKey(ComboCounter[DataIndex]!=-1,id,GetHandleId(EventUnit[DataIndex]))
                   
                    set EventCount = EventCount - 1
               
            else
                debug call BJDebugMsg("This unit doesn't exist in the system.")
            endif
        endfunction
       
        private function TriggerRegisterComboEventHelper takes unit whichUnit, integer whichCombo, trigger whichTrigger, integer hashIndex returns nothing
            local integer id = GetHandleId(whichUnit)
            if DoesUnitExist(id) then
                set EventCount = EventCount + 1
                call SaveInteger(ComboHashtable,hashIndex,id,EventCount)
                set EventTrigger[EventCount] = whichTrigger
                set EventUnit[EventCount] = whichUnit
                set ComboCounter[EventCount] = whichCombo
            else
                debug call BJDebugMsg("This unit doesn't exists in the system.")
            endif
        endfunction

        function TriggerRegisterComboEvent takes unit whichUnit,integer whichCombo,trigger whichTrigger returns nothing
            if whichCombo > 0 then
                call TriggerRegisterComboEventHelper(whichUnit, whichCombo, whichTrigger, 1)
            else
                debug call BJDebugMsg("Combo = "+I2S(whichCombo)+" ?????, what kind of your combo 0.0..")
            endif
        endfunction
       
        function TriggerRegisterAnyComboEvent takes unit whichUnit,trigger whichTrigger returns nothing
            call TriggerRegisterComboEventHelper(whichUnit,-1,whichTrigger, 2)
        endfunction
       
        function GetUnitComboCount takes unit whichUnit returns integer
            if DoesUnitExist(GetHandleId(whichUnit)) then
                return ComboCount[DataIndex]
            else
                debug call BJDebugMsg("This unit doesn't exist in the system.")
            endif
               
            return 0
        endfunction
       
        function UnitAddComboEx takes unit whichUnit,real Scale,real ComboDisableTimer,real whichHeight,string decorateLeft,string decorateRight,string comboText returns nothing
            local integer id = GetHandleId(whichUnit)
            if not DoesUnitExist(id) then
                set Index = Index + 1
                call SaveInteger(ComboHashtable,0,id,Index)
                set ComboUnit[Index] = whichUnit
                set ComboCount[Index] = 0
                set ScaleValue[Index] = Scale
                set ComboTime[Index] = ComboDisableTimer
                set StructIndex[Index] = Index
                set DecorateLeft[Index] = decorateLeft
                set DecorateRight[Index] = decorateRight
                set ComboText[Index] = comboText
                set HeightSetting[Index] = whichHeight
                set ComboPlayer[Index] = GetOwningPlayer(ComboUnit[Index])
               
                set TextTag[Index] = CreateTextTag()
                call MoveLocation(LOC,GetUnitX(ComboUnit[Index]),GetUnitY(ComboUnit[Index]))
                call SetTextTagPosUnit(TextTag[Index],ComboUnit[Index],GetUnitFlyHeight(ComboUnit[Index])+GetLocationZ(LOC))
                call SetTextTagText(TextTag[Index],null,TEXT_TAG_SIZE)
                call SetTextTagColor(TextTag[Index],255,255,255,255)
                call SetTextTagSuspended(TextTag[Index],true)
                call SetTextTagPermanent(TextTag[Index],false)
            else
                debug call BJDebugMsg("This unit already exist in the system.")
            endif
           
        endfunction
       
        function UnitComboAdd takes unit whichUnit, real Scale, real ComboDisableTimer returns nothing
            call UnitAddComboEx(whichUnit, Scale, ComboDisableTimer, HEIGHT_DEFAULT, /*
                */
    DECORATE_TEXT_LEFT, DECORATE_TEXT_RIGHT, COMBO_TEXT)
        endfunction
       
        function UnitComboRemove takes unit whichUnit returns nothing
            local integer id = GetHandleId(whichUnit)
            if DoesUnitExist(id) then
                set ComboUnit[DataIndex] = ComboUnit[Index]
                set ComboCount[DataIndex] = ComboCount[Index]
                set ScaleValue[DataIndex] = ScaleValue[Index]
                set ComboTime[DataIndex] = ComboTime[Index]
                set DecorateLeft[DataIndex] = DecorateLeft[Index]
                set DecorateRight[DataIndex] = DecorateRight[Index]
                set ComboText[DataIndex] = ComboText[Index]
                set HeightSetting[DataIndex] = HeightSetting[Index]
                set ScaleValue[DataIndex] = ScaleValue[Index]
                set ComboPlayer[DataIndex] = ComboPlayer[Index]
                call DestroyTextTag(TextTag[DataIndex])
                set TextTag[DataIndex] = TextTag[Index]
                set StructIndex[DataIndex] = StructIndex[Index]
                set StructIndex[Index] = 0
                set TextTag[Index] = null
                set ComboUnit[Index] = null
               
                call RemoveSavedInteger(ComboHashtable,0,id)
               
                if DataIndex!=Index then
                    call SaveInteger(ComboHashtable,0,GetHandleId(ComboUnit[DataIndex]),DataIndex)
                endif
               
                set Index = Index - 1
            else
                debug call BJDebugMsg("This unit doesn't exist in the system.")
            endif
           
        endfunction
       
        function SetTextComboHeight takes unit whichUnit,real whichHeight returns nothing
            if DoesUnitExist(GetHandleId(whichUnit)) then
                set HeightSetting[DataIndex] = whichHeight
            else
                debug call BJDebugMsg("This unit doesn't exist in the system.")
            endif
        endfunction
       
        function SetTextComboText takes unit whichUnit,string whichText returns nothing
            if DoesUnitExist(GetHandleId(whichUnit)) then
                set ComboText[DataIndex] = whichText
            else
                debug call BJDebugMsg("This unit doesn't exist in the system.")
            endif
        endfunction
       
        function SetTextComboDecorateLeft takes unit whichUnit,string whichText returns nothing
            if DoesUnitExist(GetHandleId(whichUnit)) then
                set DecorateLeft[DataIndex] = whichText
            else
                debug call BJDebugMsg("This unit doesn't exist in the system.")
            endif
        endfunction
       
        function SetTextComboDecorateRight takes unit whichUnit,string whichText returns nothing
            if DoesUnitExist(GetHandleId(whichUnit)) then
                set DecorateRight[DataIndex] = whichText
            else
                debug call BJDebugMsg("This unit doesn't exist in the system.")
            endif
        endfunction
       
        function SetTextComboScale takes unit whichUnit,real whichScale returns nothing
            if DoesUnitExist(GetHandleId(whichUnit)) then
                set ScaleValue[DataIndex] = whichScale
            else
                debug call BJDebugMsg("This unit doesn't exist in the system.")
            endif
        endfunction
       
        private struct ComboSystem extends array
       
            static method textTag takes string whichString,integer Indexx,real Scale returns nothing
                    local thistype this = Indexx
                   
                    call SetTextTagText(TextTag[this],whichString,TEXT_TAG_SIZE)
                   
                    call SetTextTagVisibility(TextTag[this], GetLocalPlayer() == ComboPlayer[this])
                   
                    set ComboTimeCounter[this] = ComboTime[this]
                    set SizeValue[this] = TEXT_TAG_SIZE
                    set SizeBlock[this] = false
                    set Value[this] = whichString
                    set Color[this] = 255
                    set Height[this] = HeightSetting[this]*ScaleValue[this]
                    call SetTextTagColor(TextTag[this],255,255,255,255)
                   
                    set Counter = Counter + 1
                    if Counter == 1 then
                        call TimerStart(TIMER,PERIODIC,true,function thistype.onPeriodic)
                    endif
                   
                endmethod
           
            static method damageDetection takes nothing returns boolean
               
                if IsUnitEnemy(udg_GDD_DamageSource,GetOwningPlayer(udg_GDD_DamagedUnit)) then
                    if DoesUnitExist(GetHandleId(udg_GDD_DamageSource)) then
                        if AttackDetector[DataIndex] then
                            set ComboCount[DataIndex] = ComboCount[DataIndex] + 1
                            call textTag(DecorateLeft[DataIndex]+ComboText[DataIndex]+I2S(ComboCount[DataIndex])+DecorateRight[DataIndex],DataIndex,ScaleValue[DataIndex])
                            call CheckEventCombo(1,ComboCount[DataIndex],GetHandleId(ComboUnit[DataIndex]))
                            call CheckEventCombo(2,ComboCount[DataIndex],GetHandleId(ComboUnit[DataIndex]))
                        endif
                    endif
                endif
               
                return false
            endmethod
           
            private static real cos= TEXT_CENTER * Cos(.0174533)
            private static real sin= TEXT_CENTER * Sin(.0174533)
           
           static method onPeriodic takes nothing returns nothing
                local integer i = 1
                local thistype this
                local real x
                local real y
               
                loop
                    exitwhen i > Index
                    set this = StructIndex[i]
                   
                    if GetUnitTypeId(ComboUnit[this]) != 0 then
                        if not SizeBlock[this] then
                            set SizeValue[this] = SizeValue[this] + SIZE_INCREASE
                            set SizeBlock[this] = SizeValue[this] >= TEXT_TAG_SIZE_LIMIT
                        else
                            if SizeValue[this] > TEXT_TAG_SIZE then
                                set SizeValue[this] = SizeValue[this] - SIZE_DECREASE
                            endif
                        endif
                       
                        set x = GetUnitX(ComboUnit[this])+cos
                        set y = GetUnitY(ComboUnit[this])+sin
                       
                        call MoveLocation(LOC,x,y)
                   
                        call SetTextTagColor(TextTag[this],255,255,255,Color[this])
                        call SetTextTagText(TextTag[this],Value[this],SizeValue[this]*0.0023)
                       
                        call SetTextTagPos(TextTag[this],x,y,GetUnitFlyHeight(ComboUnit[this])+GetLocationZ(LOC)+Height[this])
                       
                        if ComboTimeCounter[this] > 0. and not IsUnitType(ComboUnit[this],UNIT_TYPE_DEAD) then
                            set ComboTimeCounter[this] = ComboTimeCounter[this] - PERIODIC
                        else
                            if Color[this] > 0 then
                                set Color[this] = Color[this] - TEXT_COLOR_DECREASE
                                set SizeValue[this] = SizeValue[this] + SIZE_INCREASE
                            else
                                set ComboCount[this] = 0
                                call SetTextTagVisibility(TextTag[this],false)
                               
                                set Counter = Counter - 1
                               
                                if Counter == 0 then
                                    call PauseTimer(TIMER)
                                endif
                            endif
                        endif
                    else
                        call UnitComboRemove(ComboUnit[this])
                       
                        set Counter = Counter - 1
                               
                        if Counter == 0 then
                            call PauseTimer(TIMER)
                        endif
                    endif
                   
                    set i = i + 1
                endloop
            endmethod
           
            static method attackDetection takes nothing returns boolean
                if DoesUnitExist(GetHandleId(GetAttacker())) then
                    set AttackDetector[DataIndex] = true
                endif
               
                return false
            endmethod
           
            static method spellDetection takes nothing returns boolean
                if DoesUnitExist(GetHandleId(GetTriggerUnit())) then
                    set AttackDetector[DataIndex] = false
                endif
               
                return false
            endmethod
           
            static method Init takes nothing returns nothing
                local trigger damageTrigger = CreateTrigger()
                local trigger attackTrigger = CreateTrigger()
                local trigger spellTrigger = CreateTrigger()
                local integer i = 0
               
                set ComboHashtable=InitHashtable()
               
                loop
                    exitwhen i > 15
                   
                    call TriggerRegisterPlayerUnitEvent(attackTrigger,Player(i),EVENT_PLAYER_UNIT_ATTACKED,null)
                    call TriggerRegisterPlayerUnitEvent(spellTrigger,Player(i),EVENT_PLAYER_UNIT_SPELL_CAST,null)
                   
                    set i = i + 1
                endloop
               
                call TriggerRegisterVariableEvent(damageTrigger, "udg_GDD_Event", EQUAL, 0 )
               
                call TriggerAddCondition(damageTrigger,function thistype.damageDetection)
                call TriggerAddCondition(attackTrigger,function thistype.attackDetection)
                call TriggerAddCondition(spellTrigger,function thistype.spellDetection)
               
                set damageTrigger = null
                set attackTrigger = null
                set spellTrigger = null
               
            endmethod
           
            implement Init
        endstruct
       
    endlibrary
     
  17. nhocklanhox6

    nhocklanhox6

    Joined:
    Feb 12, 2012
    Messages:
    335
    Resources:
    28
    Models:
    6
    Spells:
    21
    Tutorials:
    1
    Resources:
    28
    should be static constant. And what value is that .0174533 anyway?

    PI/180 :D

    you could inline those two functions

    Done!.

    Though, I still don't understand why do you ever need two udg_ variables whereas you have GetUnitComboCount(whichUnit) ? If it's just for demonstration, then you should not include the variable creator there.

    For more convenient :). For GUI user, they are very lazy to use Custom Script to get combocount, so Set System_ComboCount = 0 is born to serve.

    You set DataIndex twice there
    that function better returns the DataIndex and should be renamed to something like getDataIndex. Then just use DataIndex != 0 to check whether a unit exists or not:


    Hmm, maybe not, set DataIndex is really cool here :p.

    Weird indentation :p

    Yup!, so weird :D. Fixed!

    Because, setting a variable at other function then use it, imo, is very not convincing.

    Don't worry. Today's computer run super-fast >_^, I think it's fine.

    Also I have a question: Are we allowed/able to determine actions for every combo? For example I want to deal 100 damage on the first combo, then I want to stun the target for the second, then I want to knock the target for the third, etc.

    Affected only when a unit attack without using spell.

    As your example: First combo depend on unit attacking (The answer is Yes) or casting spell (The answer is No)

    Second and third depend on unit using dummy (The answer is Yes) or self-casting. (The answer is No).

    @deathismyfriend: Cool, you have done it for me?, thanks ;).
     
  18. deathismyfriend

    deathismyfriend

    Joined:
    Oct 24, 2012
    Messages:
    6,526
    Resources:
    14
    Spells:
    12
    Tutorials:
    2
    Resources:
    14
    Yes it was the easiest way I could show you what I meant.