1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  5. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  6. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  7. The results are out! Check them out.
    Dismiss Notice
  8. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  9. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  10. 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.

[System] Melee/Ranged Attack Switch v1.1.1.1

Submitted by Maker
This bundle is marked as approved. It works and satisfies the submission rules.
Code (vJASS):

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
 *      Melee/Ranged system v1.1.1.1 by Maker                           *
 *                                                                      *
 *      Melee/ranged switching system allows a unit to switch between   *
 *      ranged and melee attacks.                                       *
 *                                                                      *
 *      Has two modes, automatic and manual.                            *
 *                                                                      *
 *      In auto mode, the unit switches automatically based on          *
 *      distance to target. In manual mode, player can switch           *
 *      the mode with an ability.                                       *
 *                                                                      *
 *      Supports Last Order, the unit doesn't stop when switching.      *
 *                                                                      *
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/


library MeleeRanged initializer Init requires UnitIndexer optional LastOrder

    globals
        // Configure unit types at Setup function
        // at the bottom of the library
   
        // Do units change tome melee/ranged automatically
        private constant    boolean     AUTO        = true
        // Ability with which unit can toggle attack
        private constant    integer     TOGGLEABI   = 'A005'
        // Order id of the transform, default = metamorphosis
        private constant    integer     TOGGLEOID   = 852180
        // Order id of toggle activation, default = magicdefence
        private constant    integer     TOGGLEON    = 852478
       
       
        private             hashtable   HT          = InitHashtable()
        private             trigger     TRG1
        private             trigger     TRG2         = CreateTrigger()
        private             timer       T1
        private             timer       T2
        private             group       G1
        private             group       G2
        private             group       U
        private             group       TEMP        
       
        private             integer     LEAKS       = 0
        private             integer     LEAKS_MAX   = 10
    endglobals
   
    // Disables given ability for players, won't show up in UI
    private function DisableAbil takes integer a returns nothing
        local integer i = 0
        loop
            call SetPlayerAbilityAvailable(Player(i), a, false)
            exitwhen i == 15
            set i = i + 1
        endloop
    endfunction
   
    // Adds a delay to order, allows to akncowledge the
    // change in unit's attack range
    private function Delay3 takes nothing returns nothing
        static if  LIBRARY_LastOrder then
            local unit u
            call DisableTrigger(TRG2)
            loop
                set u = FirstOfGroup(G1)
                exitwhen u == null
                if GetPastOrder(u, 3) != null then
                    call IssuePastOrder(u, 3)
                endif
                call GroupRemoveUnit(G1, u)
            endloop
            call EnableTrigger(TRG2)
        endif
    endfunction
   
    // Adds a delay to order, allows to akncowledge the
    // change in unit's attack range
    private function Delay1 takes nothing returns nothing
        local unit u
        call DisableTrigger(TRG2)
        loop
            set u = FirstOfGroup(G1)
            exitwhen u == null
            call IssueTargetOrderById(u, 851983, LoadUnitHandle(HT, GetHandleId(u), 2))
            call FlushChildHashtable(HT, GetHandleId(u))
            call GroupRemoveUnit(G1, u)
        endloop
        call EnableTrigger(TRG2)
    endfunction
   
    function ToggleMeleeRanged takes unit u, unit target, boolean toRanged returns nothing
        // Load correct ability for the unit type
        local integer a = LoadInteger(HT, GetUnitTypeId(u), 1)
        // Enable ability to be able to use it, then disable it to hide it
        //call GroupRemoveUnit(U, u)
        call SetPlayerAbilityAvailable(GetOwningPlayer(u), a, true)
        call IssueImmediateOrderById(u, TOGGLEOID)
        call SetPlayerAbilityAvailable(GetOwningPlayer(u), a, false)
        //call GroupAddUnit(U, u)
        // Save whether unit is melee or ranged
        static if AUTO then
            // Makes the unit attack the target
            // Use delay so the new range is used
            call SaveUnitHandle(HT, GetHandleId(u), 2, target)
            call GroupAddUnit(G1, u)
            call TimerStart(T1, 0.00, false, function Delay1)
        elseif LIBRARY_LastOrder then
            // Makes the unit stop when it transforms
            call GroupAddUnit(G1, u)
            call TimerStart(T1, 0.00, false, function Delay3)
        endif
    endfunction
   
    // Detects which event was triggered and whether the unit
    // should switch to melee/ranged or not
    private function Actions takes nothing returns boolean
        local unit u1
        local unit u2
        local real r1
        local real r2
        local integer uid
        local integer id = GetHandleId(GetTriggerEventId())
        if id == 18 then // A Unit is Attacked
            set u1 = GetAttacker()
            set uid = GetUnitTypeId(u1)
            if HaveSavedInteger(HT, uid, 1) then
                set u2 = GetTriggerUnit()
            else
                set u1 = null
                return false
            endif
        else
            set u1 = GetTriggerUnit()
            set uid = GetUnitTypeId(u1)
            if HaveSavedInteger(HT, uid, 1) then
                if id == 60 then // A Unit Acquires a Target
                    set u2 = GetEventTargetUnit()
                else // A Unit Is Issued an Order Targeting an Object
                    set u2 = GetOrderTargetUnit()
                    if GetIssuedOrderId() == 851971  then // Order is smart
                        if not IsUnitEnemy(u2, GetOwningPlayer(u1)) or u2 == null then
                            set u1 = null
                            set u2 = null
                            return false
                        endif
                    elseif GetIssuedOrderId() != 851983 then // Order is not attack
                        set u1 = null
                        set u2 = null
                        return false // Spells won't trigger the system
                    endif
                endif
            else
                set u1 = null
                return false
            endif
        endif
       
        set r1 = GetUnitX(u1)-GetUnitX(u2)
        set r2 = GetUnitY(u1)-GetUnitY(u2)
       
        // Checks melee distance
        if r1*r1+r2*r2 > LoadReal(HT, GetUnitTypeId(u1), 0) then
            if LoadInteger(HT, uid, 2) == 0 then
                call ToggleMeleeRanged(u1, u2, true)
            endif
        elseif LoadInteger(HT, uid, 2) == 1 then
            call ToggleMeleeRanged(u1, u2, false)
        endif
       
        set u1 = null
        set u2 = null
        return false
    endfunction
   
    // Recreates the trigger
    private function Recreate takes nothing returns nothing
        static if AUTO then
            local unit u
            call DestroyTrigger(TRG1)
            set TRG1 = CreateTrigger()
            call TriggerAddCondition(TRG1, Condition(function Actions))
            loop
                set u = FirstOfGroup(U)
                exitwhen u == null
                call GroupAddUnit(TEMP, u)
                call TriggerRegisterUnitEvent(TRG1, u, EVENT_UNIT_ACQUIRED_TARGET)
                call GroupRemoveUnit(U, u)
            endloop
            loop
                set u = FirstOfGroup(TEMP)
                exitwhen u == null
                call GroupAddUnit(U, u)
                call GroupRemoveUnit(TEMP, u)
            endloop
        endif
    endfunction

    // Adds delay to transform order to prevent the toggle
    // order firing twice, due to the instant transform
    private function Delay2 takes nothing returns nothing
        static if not AUTO then
            local unit u
            loop
                set u = FirstOfGroup(G2)
                exitwhen u == null
                call ToggleMeleeRanged(u, null, not LoadBoolean(HT, GetHandleId(u), 0))
                call GroupRemoveUnit(G2, u)
            endloop
        endif
    endfunction
   
    // Detects the toggle order
    private function Toggle takes nothing returns boolean
        static if not AUTO then
            if GetIssuedOrderId() == TOGGLEON then
                call GroupAddUnit(G2, GetTriggerUnit())
                call TimerStart(T2, 0.0, false, function Delay2)
            endif
        endif
        return false
    endfunction
   
    // Initializes a spesific unit for the system
    private function AddUnit takes unit u returns nothing
        local integer ut = GetUnitTypeId(u)
        local integer ab = LoadInteger(HT, ut, 1)
       
        call UnitAddAbility(u, ab)
        call UnitMakeAbilityPermanent(u, true, ab)
        if LoadInteger(HT, ut, 2) == 1 then // Is it the ranged version
            call SetPlayerAbilityAvailable(GetOwningPlayer(u), ab, true)
            call IssueImmediateOrderById(u, TOGGLEOID)
            call SetPlayerAbilityAvailable(GetOwningPlayer(u), ab, false)
        endif
       
        static if AUTO then
            call GroupAddUnit(U, u)
            call TriggerRegisterUnitEvent(TRG1, u, EVENT_UNIT_ACQUIRED_TARGET)
        else
            call UnitAddAbility(u, TOGGLEABI)
            call UnitMakeAbilityPermanent(u, true, TOGGLEABI)
        endif
    endfunction
   
    // Detects possible even leaks
    private function Die takes nothing returns boolean
        static if AUTO then
            if HaveSavedInteger(HT, GetUnitTypeId(GetIndexedUnit()), 1) then
                call GroupRemoveUnit(U, GetIndexedUnit())
                call GroupRemoveUnit(G1, GetIndexedUnit())
                if LEAKS == LEAKS_MAX then
                    set LEAKS = 0
                    call Recreate()
                else
                    set LEAKS = LEAKS + 1
                endif
            endif
        else
            call GroupRemoveUnit(G2, GetIndexedUnit())
            static if LIBRARY_LastOrder then
                call GroupRemoveUnit(G1, GetIndexedUnit())
            endif
        endif
        return false
    endfunction
   
    // Is unit type valid
    private function UnitFilt takes nothing returns boolean
        if HaveSavedInteger(HT, GetUnitTypeId(GetFilterUnit()), 1) then
            call AddUnit(GetFilterUnit())
        endif
        return false
    endfunction
   
    // Initializes unit types
    private function AddUT takes integer i1, integer i2, integer a, real r returns nothing
        call SaveReal(HT, i1, 0, r*r)
        call SaveReal(HT, i2, 0, r*r)
        call SaveInteger(HT, i1 ,1, a)
        call SaveInteger(HT, i2 ,1, a)
        call SaveInteger(HT, i1, 2, 0)  // Is melee type
        call SaveInteger(HT, i2, 2, 1)  // Is ranged type
        call DisableAbil(a)            
    endfunction
   
     private function Setup takes nothing returns nothing
        // Parameters are:
        // (Melee unit type, ranged unit type, transform ability, melee range)
        call AddUT('Hpal', 'H000', 'A000', 200)
        call AddUT('H001', 'Hamg', 'A001', 220)
        call AddUT('e000', 'earc', 'A002', 180)
        call AddUT('n000', 'n001', 'A003', 200)
        call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, function UnitFilt)
    endfunction
   
    private function Init takes nothing returns nothing
        local region r = CreateRegion()
       
        call RegionAddRect(r, bj_mapInitialPlayableArea)
        call TriggerRegisterEnterRegion(CreateTrigger(), r, function UnitFilt)
        call RegisterUnitIndexEvent(Condition(function Die), UnitIndexer.DEINDEX)
       
        static if AUTO then
            set T1 = CreateTimer()
            set G1 = CreateGroup()
            set U = CreateGroup()
            set TEMP = CreateGroup()
            set TRG1 = CreateTrigger()
       
            call TriggerAddCondition(TRG1, function Actions)
            call TriggerAddCondition(TRG2, function Actions)
           
            call TriggerRegisterAnyUnitEventBJ(TRG2, EVENT_PLAYER_UNIT_ATTACKED)
            call TriggerRegisterAnyUnitEventBJ(TRG2, EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER)
        else
            static if LIBRARY_LastOrder then
                set T1 = CreateTimer()
                set G1 = CreateGroup()
            endif
            set T2 = CreateTimer()
            set G2 = CreateGroup()
            call TriggerAddCondition(TRG2, function Toggle)
            call TriggerRegisterAnyUnitEventBJ(TRG2, EVENT_PLAYER_UNIT_ISSUED_ORDER)
        endif
        call Setup()
        set r = null
    endfunction

endlibrary
 


Changeg Log

v1.0.0.0 Uploaded 21.10.2011
v1.0.0.1 Uploaded 21.10.2011
-Added a static if to prevent syntax error if Last Order is missing
v1.0.0.2 Uploaded 21.10.2011
-Removed a boolean
-Added optional library requirement
v1.0.0.3 Uploaded 21.10.2011
-Removed a possible unit variable leak
v1.0.0.4 Uploaded 21.10.2011
-Optimized code
-Disable/enable action detection trigger to avoid useless action checks
v1.0.0.5 Uploaded 21.10.2011
-Got rid of SquareRoot in the distance check
-Added local reals for distance calculation
v1.0.1.6 Uploaded 24.10.2011
-Added trigger recycling, events for removed units are cleared
-Uses u2 == null instead of GetManipulatedItem != null
-Static if now covers all actions in Delay3 function
v1.1.0.0 Uploaded 02.11.2011
-Combined Enter and UnitFilt functions
-Removed two integer globals
-Uses unit indexer to correctly handle revived units
-Removed unneeded variables from setup function
-Small static if change
-Two more static ifs, in Delay2 and Toggle functions
-Added a trigger to which unit acquires target events are added
-Uses filter function instead of condition for units that enter the map
v1.1.1.0 Uploaded 10.11.2011
-Changed the order of u = FirstOfGroup and exitwhen u = null
-When units die, they are removed from groups that cause them to perform actions
-Instead of creating a trigger, registers dying with RegisterUnitIndexEvent
v1.1.1.1 Uploaded 10.11.2011
-Removed leftovers from previous versions, i and j variables from Recreate function


Last Order is an optional library by Rising Dusk
Unit indexer is a requires library by Nestharus
Both are included in the map

Keywords:
melee, ranged, attack, switch, toggle
Contents

Map (Map)

Reviews
Moderator
10th Nov 2011 Bribe: The system is cool, useful and Highly Recommended. Thanks for making this resource.
  1. 10th Nov 2011
    Bribe: The system is cool, useful and Highly Recommended.

    Thanks for making this resource.
     
  2. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,053
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    There are some syntax errors of LastOrder is not found.

    I recommend making it a requirement than optional, because otherwise this thing is going to get even more extreme with static if's.
     
  3. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,181
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    I added one more static if, now it won't cause syntax errors.

    Making Last Order a requirement might be a good idea.
     
  4. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,053
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Are you using JassHelper 0.A.2.B? You can comment out the whole "Delay3" function if you have that version.

    It also might not compile properly even with the LastOrder library found since you have no "requires optional LastOrder" after the "library" keyword.

    There is also the LIBRARY_LastOrder constant provided if the library is found, which you can use instead of the LAST_ORDER constant you currently have.

    But I think it's better to just have LastOrder as a total requirement. The benefit it gives to this library is strong.
     
  5. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,181
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Yeah, I have that version. Why can I commet that function out?

    The reason making Last Order optional is that if the mode change is set to auto, then Last Order isn't used for anyhting currently.
     
  6. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,053
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Well, currently you comment out the whole loop, making the entire function quite pointless if LastOrder is not found.
     
  7. BlackRangerXIII

    BlackRangerXIII

    Joined:
    Dec 25, 2010
    Messages:
    977
    Resources:
    0
    Resources:
    0
    Nice system maker ^^
    Not rating until you finish the bug fixing
     
    Last edited: Oct 24, 2011
  8. Bannar

    Bannar

    Joined:
    Mar 19, 2008
    Messages:
    3,087
    Resources:
    20
    Spells:
    5
    Tutorials:
    1
    JASS:
    14
    Resources:
    20
    No love for RegisterPlayerUnitEvent? ;/
    Code (vJASS):
            if SquareRoot((GetUnitX(u1)-GetUnitX(u2))*(GetUnitX(u1)-GetUnitX(u2))+(GetUnitY(u1)-GetUnitY(u2))*(GetUnitY(u1)-GetUnitY(u2))) > LoadReal(HT, GetUnitTypeId(u1), 0) then
                if not LoadBoolean(HT, GetHandleId(u1), 0) then
                    call ToggleMeleeRanged(u1, u2, true)
                endif
            elseif LoadBoolean(HT, GetHandleId(u1), 0) then
                call ToggleMeleeRanged(u1, u2, false)
            endif


    ->>
    Code (vJASS):
            if SquareRoot((GetUnitX(u1)-GetUnitX(u2))*(GetUnitX(u1)-GetUnitX(u2))+(GetUnitY(u1)-GetUnitY(u2))*(GetUnitY(u1)-GetUnitY(u2))) > LoadReal(HT, GetUnitTypeId(u1), 0) and not LoadBoolean(HT, GetHandleId(u1), 0) then
                call ToggleMeleeRanged(u1, u2, true)
            elseif LoadBoolean(HT, GetHandleId(u1), 0) then
                call ToggleMeleeRanged(u1, u2, false)
            endif

    >>>>>>>>>>>>>>>>>>>>>
    Code (vJASS):

            local unit u1 = GetAttacker()
            local unit u2
            if u1 == null then
                set u1 = GetTriggerUnit()
                if HaveSavedInteger(HT, GetUnitTypeId(u1), 1) then  // Unit type is initialized for the system
                    if GetHandleId(GetTriggerEventId()) == 40 then  // Target unit order
                        set u2 = GetOrderTargetUnit()
                        if GetIssuedOrderId() == 851971  then   // Order is smart
                            if not IsUnitEnemy(u2, GetOwningPlayer(u1)) or /*
                            */
    GetOrderTargetItem() != null then
                                set u1 = null
                                return
                            endif
                        elseif GetIssuedOrderId() != 851983 then // Order is not attack
                            set u1 = null
                            return  // Spells won't trigger the system
                        endif
                    else
                        set u2 = GetEventTargetUnit()
                    endif
                else
                    set u1 = null
                    return
                endif
            // Event was unit attacked
            elseif HaveSavedInteger(HT, GetUnitTypeId(u1), 1) then // Unit type is initialized
                set u2 = GetTriggerUnit()
            else
                set u1 = null
                return
            endif

    ->>
    Code (vJASS):

            local unit u1 = GetAttacker()
            local unit u2
            local integer i = GetHandleId(GetTriggerEventId()
            if u1 == null then
                set u1 = GetTriggerUnit()
                if HaveSavedInteger(HT, GetUnitTypeId(u1), 1) and i == 40 then
                    set i = GetIssuedOrderId()
                    set u2 = GetOrderTargetUnit()
                    if (i == 851971 and (not IsUnitEnemy(u2, GetOwningPlayer(u1)) or GetOrderTargetItem() != null)) or i != 851983 then
                        set u1 = null
                        return
                    endif
                elseif i != 40 then
                    set u2 = GetEventTargetUnit()
                else
                    set u1 = null
                    return
                endif
            elseif HaveSavedInteger(HT, GetUnitTypeId(u1), 1) then // Unit type is initialized
                set u2 = GetTriggerUnit()
            else
                set u1 = null
                return
            endif


    ^I'll review that part again in sec; since your 'if' spam can be cut a lot. You should think more about: since I do 'set u1 = null & return' in many cases, why shouldn't that be a main statement in that function?
     
    Last edited: Oct 21, 2011
  9. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,181
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    At the moment I have no plans to add that.

    My way: 2 comparisons for change to ranged, 2 comparisons to change to melee
    Your way: 2 comparisons to change to ranged, 3 comparisons to change to melee

    Your second suggestion will fail. Please test before suggesting changes. But I can try to improve the logic if possible.
     
  10. Bannar

    Bannar

    Joined:
    Mar 19, 2008
    Messages:
    3,087
    Resources:
    20
    Spells:
    5
    Tutorials:
    1
    JASS:
    14
    Resources:
    20
    What the hek?
    Nested 'if' is pointless, since it does nothing if not LoadBoolean(HT, GetHandleId(u1), 0) returns false.

    Omg I hate seeing 'your suggestion will fail' I had to go a walk with my dog and I've said 'I'll review that in second again'. But surely my statement is true:

    your 'if' spam can and should be prevented.
    My script will be fixed in sec.

    EDIT: Fixed. There are two options: either the one, I've posted above, or check all the conditions that lead to: 'return' statement; and in 'else' implement 'u2 =' selection. I have not posted the 2nd case, because calling so many statements in 'single/double if' may fuck up readability and may be slower than 1st method.

    EDIT2: I see you have changed Action function in meanwhile.. Anyways, this one can be improved too:
    trig
    Code (vJASS):
            local unit u1
            local unit u2
            local integer id = GetHandleId(GetTriggerEventId())
           
            if id == 18 then // A Unit is Attacked
                set u1 = GetAttacker()
                if HaveSavedInteger(HT, GetUnitTypeId(u1), 1) then
                    set u2 = GetTriggerUnit()
                else
                    set u1 = null
                    return
                endif
            elseif id == 60 then // A Unit Acquires a Target
                set u1 = GetTriggerUnit()
                if HaveSavedInteger(HT, GetUnitTypeId(u1), 1) then
                    set u2 = GetEventTargetUnit()
                else
                    set u1 = null
                    return
                endif
            else // A Unit Is Issued an Order Targeting an Object
                set u1 = GetTriggerUnit()
                if HaveSavedInteger(HT, GetUnitTypeId(u1), 1) then
                    set u2 = GetOrderTargetUnit()
                    if GetIssuedOrderId() == 851971  then   // Order is smart
                        if not IsUnitEnemy(u2, GetOwningPlayer(u1)) or GetOrderTargetItem() != null then
                            set u1 = null
                            set u2 = null
                            return
                        endif
                    elseif GetIssuedOrderId() != 851983 then // Order is not attack
                        set u1 = null
                        set u2 = null
                        return  // Spells won't trigger the system
                    endif
                else
                    set u1 = null
                    return
                endif
            endif

    Code (vJASS):
            local unit u1
            local unit u2
            local integer id = GetHandleId(GetTriggerEventId())

            if id == 18 then // A Unit is Attacked
                set u1 = GetAttacker()
                if HaveSavedInteger(HT, GetUnitTypeId(u1), 1) then
                    set u2 = GetTriggerUnit()
                else
                    set u1 = null
                    return
                endif
            else
                set u1 = GetTriggerUnit()
                if HaveSavedInteger(HT, GetUnitTypeId(u1), 1) then
                    if id == 60 then
                        set u2 = GetEventTargetUnit()
                    else
                        set u2 = GetOrderTargetUnit()
                        set id = GetIssuedOrderId()
                        if (id == 851971 and (not IsUnitEnemy(u2, GetOwningPlayer(u1)) or GetOrderTargetItem() != null)) or id != 851983 then
                            set u1 = null
                            set u2 = null
                            return
                        endif
                    endif
                else
                    set u1 = null
                    return
                endif
            endif
     
    Last edited: Oct 21, 2011
  11. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,181
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Trig
    Code (vJASS):
    if SquareRoot((GetUnitX(u1)-GetUnitX(u2))*(GetUnitX(u1)-GetUnitX(u2))+(GetUnitY(u1)-GetUnitY(u2))*(GetUnitY(u1)-GetUnitY(u2))) > LoadReal(HT, GetUnitTypeId(u1), 0) and not LoadBoolean(HT, GetHandleId(u1), 0) then
                call ToggleMeleeRanged(u1, u2, true)
            elseif LoadBoolean(HT, GetHandleId(u1), 0) then
                call ToggleMeleeRanged(u1, u2, false)
            endif


    Translates into:
    If in ranged distance and in melee mode
    ----change to ranged
    else if in ranged mode
    ----change to melee

    Spot the fail.
    Answer

    Results the unit to change to melee if it is in ranged distance and in ranged mode


    The other suggestion causes syntex error (i instead of id) and won't make the unit change the type when smart is ordered.

    I appreciate you trying to help, I really do. I'm very thankful for taking the time to post and taking a look at my spell. But please test before posting. I have wasted much time trying your solutions.

    I will update the code soon.

    EDIT:Updated to 1.0.0.4
     
  12. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Code (vJASS):
        private function Delay3 takes nothing returns nothing
            local unit u = FirstOfGroup(G1)
            call DisableTrigger(TRG)
            loop
                static if LIBRARY_LastOrder then
                    if GetPastOrder(u, 3) != null then
                        call IssuePastOrder(u, 3)
                    endif
                    call GroupRemoveUnit(G1, u)
                    set u = FirstOfGroup(G1)
                    exitwhen u == null
                endif
            endloop
            call EnableTrigger(TRG)
        endfunction


    This hits the op limit without LastOrder and crashes the calling thread.

    ->

    Code (vJASS):
        private function Delay3 takes nothing returns nothing
            local unit u = FirstOfGroup(G1)
            call DisableTrigger(TRG)
            loop
                static if LIBRARY_LastOrder then
                    if GetPastOrder(u, 3) != null then
                        call IssuePastOrder(u, 3)
                    endif
                    call GroupRemoveUnit(G1, u)
                    set u = FirstOfGroup(G1)
                    exitwhen u == null
                else
                    exitwhen true
                endif
            endloop
            call EnableTrigger(TRG)
        endfunction


    Or, better yet, comment out the entire function if LastOrder isn't present.

    Code (vJASS):
    if SquareRoot((GetUnitX(u1)-GetUnitX(u2))*(GetUnitX(u1)-GetUnitX(u2))+(GetUnitY(u1)-GetUnitY(u2))*(GetUnitY(u1)-GetUnitY(u2))) > LoadReal(HT, GetUnitTypeId(u1), 0) then
                if not LoadBoolean(HT, GetHandleId(u1), 0) then
                    call ToggleMeleeRanged(u1, u2, true)
                endif
            elseif LoadBoolean(HT, GetHandleId(u1), 0) then
                call ToggleMeleeRanged(u1, u2, false)
            endif


    Here, you should be caching the coordinates in local variables for increased performance.

    There are lots of other possible optimizations too, but I'm sure Bribe and Spinnaker stated them above :p (lol didn't read xD)
     
  13. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,181
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    ^
    There is
    Code (vJASS):
    static if LIBRARY_LastOrder then
        call GroupAddUnit(G1, u)
        call TimerStart(T1, 0.00, false, function Delay3)
    endif

    to prevent it from going to the loop :)

    I'll propably do something with the reals.

    EDIT: v1.0.0.5
    -Got rid of SquareRoot in the distance check
     
  14. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Oh and I just updated RegisterPlayerUnitEvent for your sake :p
    I added a vanilla Jass version that compiles in the normal editor.
    Thinking of using it now? :D (It will optimize large maps with lots of triggers by literally several thousands of times on event firing :D)

    This is actually a really good library ^_^
     
  15. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,181
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Yeah, it is a good library :)

    -Added local reals for distance calculation
     
  16. Bannar

    Bannar

    Joined:
    Mar 19, 2008
    Messages:
    3,087
    Resources:
    20
    Spells:
    5
    Tutorials:
    1
    JASS:
    14
    Resources:
    20
    Maker, I wasn't near WE so I couldn't test solutions in game. I was giving ideas since there was a space for improvements.

    Since you've changed your Action function during I was writing one of post it was 100% sure that was useless then.
    However, as I can see you've used my idea about removing one of 'if' statement and replaced that with
    Code (vJASS):
            if id == 60 then
                set u2 = GetEventTargetUnit()
            else
    GetIssuedOrderId() could be replaced with 'id' integer; two calls < one call + set local
    I'll run some tests tomorrow.
     
  17. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,181
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Yeah, it could. But there won't be two calls made every time, so in some cases that would lead to worse performance.
     
  18. RakEnRoL

    RakEnRoL

    Joined:
    Sep 2, 2011
    Messages:
    316
    Resources:
    0
    Resources:
    0
    Nice timing. I need this. Great job, Maker. I will be using it after it gets approved.
     
  19. Marsal

    Marsal

    Joined:
    Jun 24, 2009
    Messages:
    1,345
    Resources:
    15
    Maps:
    1
    Spells:
    14
    Resources:
    15
    Well since I can understand shit of this code I guess it works like the battle system in Warhammer 40k so it's awesome.