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

[JASS/AI] Attack Range Melee Unit Change funcional in War 3 and Reforged (still testing)

Level 7
Joined
Mar 14, 2021
Messages
43
This is for a plugin for missile systems and use of in-game attack range changers, using the Web ability method that Dat-C3 found.

The method

As Dat-C3 explains here Changing Attack Range in-game in this case a similar ability like Ensnare that does the same thing.

1650423661869.png
along with the Destructor Form morph
1650423963029.png
ability which can be removed from his silence caused by Ensnare using Silence Ex from leandrotp SilenceEx - Everything you don't know about Silence.

JASS:
call IssueTargetOrderById(Dummy,OrderEnsnare_ID,TesUnit)// 852106 -> OrderEnsnare_ID, Ensnare spell is cast on TestUnit
call TriggerSleepAction(0.) //Wait for it to take effect Ensnare to the TesUnit unit
call UnitRemoveAbility(TesUnit,'Amov')//Remove Amov to reset the counter that makes the unit unable to move to 0.
call UnitAddAbility(TesUnit,ExMorph) //Add Form Destroyer skill, to recover the Amov skill
call SetUnitAbilitySilenced(TesUnit,ExMorph,false)//Unsilence Morph into Destroyer (On condition that this spell has 1 mana)
call IssueImmediateOrderById(TesUnit,String2OrderIdBJ(OrderMorph)) // "avengerform" -> OrderMorph, The unit is made to transform
//And that's it, at the end of the Ensnare effect, the counter for immobilizing a
//unit from 0 will be subtracted and will remain at -1, now the unit does not move,
//because only the value 0 will be taken as the unit can move.

Once we have the unit not moving due to the -1 counter another Ensnare spell or web ability will be cast which will change the attack range value this will add the immobilize counter by 1 making the current value 0 this will do that the unit can move again, this way you would have a unit able to change its range using these spells and not be immobilized.

1650432090821.png

Its uses

Reforged is currently used for this as it comes with functions that alter a unit's range normally. But this does not happen in previous versions, in addition to giving a utility to the range change and especially to the missile system that uses normal type attacks, to generate dummy projectiles, which will be the missiles that will damage the attacked unit.
Note 1: Heroes using Morph into Destroyer with their normal form value empty tend to increase their base damage due to Stats, so I guess leaving them at 0 before swapping a unit would have to be considered for this trick to work.
Note 2: When you cast Ensnare twice the buff disappears, so it would be a way to not get in the way of this in the game interface. (the same happens with web)
Note 3: Oddly enough, the Ensnare or Web buff will not be removed by buff dispels, or avatar. Only with data can it be eliminated or the unit dies. So if a unit dies I could add this buff again (taking into account that its duration must be permanent, and this is put in the editor in the item editor of the ability with value 0). The Bribe library GUI Unit Event v2.5.3.0 can be useful when a normal unit resurrects and you want to put the Ensnare effect back on.
Note 4: Naturally, since everything is a counter, if the unit already has a buff that makes it move, another buff that immobilizes them will have an effect because the counter will go from 0 to 1, so other immobilize will continue to work, unless it is the same buff from the same skill as these are replaced and will keep the counter at 0.
Note 5: The immobilize counter will return to 0 if Amov is removed and a transformation is used to make Amov recover so the counter will return to 0.
Note 6: The counter is permanent in its values and can only be altered by these spells (also with the Root spell) or by using Note 5.

- Credits to leandrotp and Dat-C3.

I leave a map with the explained
 

Attachments

  • Attack_Range_Change_Melee.w3x
    39.4 KB · Views: 23
Last edited:
I always expect this sort of stuff in the lab aka advanced scripting, never thought to look through tutorials or its submission section...
Though I like putting the methods on how to do this stuff by chat command and having it done automatically, mainly because expecting the user to follow instructions never works. I was able to see how to hide move/patrol/hold-position, but it still showed stop and attack and haven't been able to follow your instructions to see a unit able to move during ensnare or web with either tutorial.

Edit: Also using it twice removes the bonus range and sets the level of buff to 1 from 2 instead of removing the buff.
 
Level 7
Joined
Mar 14, 2021
Messages
43
I always expect this sort of stuff in the lab aka advanced scripting, never thought to look through tutorials or its submission section...
Though I like putting the methods on how to do this stuff by chat command and having it done automatically, mainly because expecting the user to follow instructions never works. I was able to see how to hide move/patrol/hold-position, but it still showed stop and attack and haven't been able to follow your instructions to see a unit able to move during ensnare or web with either tutorial.

Edit: Also using it twice removes the bonus range and sets the level of buff to 1 from 2 instead of removing the buff.
On the subject of using the ensnare ability twice, I found it using book of power, adding this item twice to the unit causes that effect. I didn't know that you wanted to remove all the buttons themselves. For this you need the ability 'Abun' that silences and hides 'Aatk', combined with silentex you remove the silence from attacking and that's it. But you have to do some change things in the Library to take care of using channel smart and include the code for the attack to work.

Here I leave you the example with all the free buttons using the other previous root method combined with Abun. You could apply the same with this method.
All Comand Free Buttons Ensare Move.jpg

JASS:
private function CheckLife takes nothing returns boolean
    call DisableTrigger(GetTriggeringTrigger())
    call KillUnit(GetTriggerUnit())
    call ReviveHero(GetTriggerUnit(),GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),false)
    call UnitRemoveAbility(GetTriggerUnit(), BURROW)
    return false
endfunction

private function CheckLife4 takes nothing returns boolean
    if (GetIssuedOrderId() == 852479) then
        call UnitRemoveAbility(GetTriggerUnit(),'Aro1')
        call UnitRemoveAbility(GetTriggerUnit(), 'Amdf')
    endif
    return false
endfunction

function ConverUnitFreeAllButtons takes unit u returns nothing
    local integer i = GetHandleId(GetUnitRace(u))
    local trigger t = null
    if (i > 6) then
        set i=i-1
    endif
 
    //call SetUnitAbilitySilenced(u,'Amov',false)//I return to the ability 'Amov' immune to silence
    call UnitAddAbility(u,SmartIDHide)//Added the channel skill with the "smart" order
    call UnitMakeAbilityPermanent(u,true,SmartIDHide)//The permanent ability to not be removed by a morph
    call SetUnitAbilitySilenced(u,SmartIDHide,true)
    call UnitAddAbility(u,HoldIDHide)
    call UnitMakeAbilityPermanent(u,true,HoldIDHide)

    set t = CreateTrigger()
    call SetUnitAbilityLevel(Dummy2, DARK_CONVERSION, i)
    call SetUnitOwner(Dummy2, GetOwningPlayer(u), false)
    call UnitAddAbility(u, BURROW)
    call UnitAddAbility(u, 'AIs1')
    call UnitMakeAbilityPermanent(u, true, 'AIs1')
 
    if IsUnitType(u,UNIT_TYPE_HERO) then
        call SetHeroAgi(u,0,true)
        call SetHeroInt(u,0,true)
        call SetHeroStr(u,0,true)
        call TriggerRegisterUnitStateEvent(t, u, UNIT_STATE_LIFE, LESS_THAN, GetWidgetLife(u)-0.1)
        call TriggerAddCondition(t, Condition(function CheckLife))
    else
        call TriggerRegisterUnitStateEvent(t, u, UNIT_STATE_LIFE, GREATER_THAN, 100.1)
        call TriggerAddCondition(t, Condition(function CheckLife))
    endif

    call IssueTargetOrderById(Dummy2, 852228, u)
    call UnitRemoveAbility(u,'BNdc')
    call UnitRemoveAbility(u,'AIs1')
    if IsUnitType(u,UNIT_TYPE_HERO) then
        call UnitAddAbility(u, 'AIs1')
        call UnitRemoveAbility(u, 'AIs1')
    endif
    call DestroyTrigger(t)
    set t = null
 
    call UnitRemoveAbility(u,'AInv')
    call UnitAddAbility(u,'AInv')
 
    if IsUnitType(u,UNIT_TYPE_HERO) then
        call UnitAddAbility(u,ResetStatUnit)
        call KillUnit(u)
        call UnitRemoveAbility(u,ResetStatUnit)
    
        call UnitAddAbility(u,ResetStatHero)
        call KillUnit(u)
    else
        call UnitAddAbility(u,ResetStatUnit)
        call KillUnit(u)
    endif
 
    set t = CreateTrigger()
    call TriggerRegisterUnitEvent(t,u,EVENT_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(t, Condition(function CheckLife4))
    call UnitAddAbility(u,'Amdf')
    call UnitAddAbility(u,'Aro1')
    call UnitRemoveAbility(u,'Aro1')
    call UnitAddAbility(u,'Aro1')
    call IssueImmediateOrderById(u, String2OrderIdBJ("unroot"))
    call DestroyTrigger(t)
    set t = null
    if IsUnitType(u,UNIT_TYPE_HERO) then
        call UnitRemoveAbility(u,ResetStatHero)
    else
        call UnitRemoveAbility(u,ResetStatUnit)
    endif
 
    call SetUnitState(u,UNIT_STATE_LIFE,GetUnitState(u,UNIT_STATE_MAX_LIFE))
    call SetUnitState(u,UNIT_STATE_MANA,GetUnitState(u,UNIT_STATE_MAX_MANA))
    call SetUnitAbilitySilenced(u,'Amov',false)
 
//Add this new code for Attack buttoms.
    call UnitAddAbility(u,'Abun')
    call UnitMakeAbilityPermanent(u,true,'Abun')
    call SetUnitAbilitySilenced(u,'Aatk',false)
    set u = null
 
    call SetUnitOwner(Dummy2, Player(15), false)
endfunction

Note: Both like Amov and Aatk, they have stop, so to get rid of this button you have to hide both buttons, clearly this is for all versions since reforged you don't need this anymore obviously. 😑 All this in itself is for testing, you have to accommodate things, and of course it can be for laboratory things, but people stopped investigating these things like that a long time ago, plus you have to code all the events that detect the orders that smart gives since sometimes there can be loops in orders and that should be avoided.

Greetings...
 

Attachments

  • Convert_Unit_AllFree_Buttons.w3x
    77 KB · Views: 5
Last edited:
On the subject of using the ensnare ability twice, I found it using book of power, adding this item twice to the unit causes that effect. I didn't know that you wanted to remove all the buttons themselves. For this you need the ability 'Abun' that silences and hides 'Aatk', combined with silentex you remove the silence from attacking and that's it. But you have to do some change things in the Library to take care of using channel smart and include the code for the attack to work.

Here I leave you the example with all the free buttons using the other previous root method combined with Abun. You could apply the same with this method.
View attachment 413204
JASS:
private function CheckLife takes nothing returns boolean
    call DisableTrigger(GetTriggeringTrigger())
    call KillUnit(GetTriggerUnit())
    call ReviveHero(GetTriggerUnit(),GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit()),false)
    call UnitRemoveAbility(GetTriggerUnit(), BURROW)
    return false
endfunction

private function CheckLife4 takes nothing returns boolean
    if (GetIssuedOrderId() == 852479) then
        call UnitRemoveAbility(GetTriggerUnit(),'Aro1')
        call UnitRemoveAbility(GetTriggerUnit(), 'Amdf')
    endif
    return false
endfunction

function ConverUnitFreeAllButtons takes unit u returns nothing
    local integer i = GetHandleId(GetUnitRace(u))
    local trigger t = null
    if (i > 6) then
        set i=i-1
    endif
 
    //call SetUnitAbilitySilenced(u,'Amov',false)//I return to the ability 'Amov' immune to silence
    call UnitAddAbility(u,SmartIDHide)//Added the channel skill with the "smart" order
    call UnitMakeAbilityPermanent(u,true,SmartIDHide)//The permanent ability to not be removed by a morph
    call SetUnitAbilitySilenced(u,SmartIDHide,true)
    call UnitAddAbility(u,HoldIDHide)
    call UnitMakeAbilityPermanent(u,true,HoldIDHide)

    set t = CreateTrigger()
    call SetUnitAbilityLevel(Dummy2, DARK_CONVERSION, i)
    call SetUnitOwner(Dummy2, GetOwningPlayer(u), false)
    call UnitAddAbility(u, BURROW)
    call UnitAddAbility(u, 'AIs1')
    call UnitMakeAbilityPermanent(u, true, 'AIs1')
 
    if IsUnitType(u,UNIT_TYPE_HERO) then
        call SetHeroAgi(u,0,true)
        call SetHeroInt(u,0,true)
        call SetHeroStr(u,0,true)
        call TriggerRegisterUnitStateEvent(t, u, UNIT_STATE_LIFE, LESS_THAN, GetWidgetLife(u)-0.1)
        call TriggerAddCondition(t, Condition(function CheckLife))
    else
        call TriggerRegisterUnitStateEvent(t, u, UNIT_STATE_LIFE, GREATER_THAN, 100.1)
        call TriggerAddCondition(t, Condition(function CheckLife))
    endif

    call IssueTargetOrderById(Dummy2, 852228, u)
    call UnitRemoveAbility(u,'BNdc')
    call UnitRemoveAbility(u,'AIs1')
    if IsUnitType(u,UNIT_TYPE_HERO) then
        call UnitAddAbility(u, 'AIs1')
        call UnitRemoveAbility(u, 'AIs1')
    endif
    call DestroyTrigger(t)
    set t = null
 
    call UnitRemoveAbility(u,'AInv')
    call UnitAddAbility(u,'AInv')
 
    if IsUnitType(u,UNIT_TYPE_HERO) then
        call UnitAddAbility(u,ResetStatUnit)
        call KillUnit(u)
        call UnitRemoveAbility(u,ResetStatUnit)
   
        call UnitAddAbility(u,ResetStatHero)
        call KillUnit(u)
    else
        call UnitAddAbility(u,ResetStatUnit)
        call KillUnit(u)
    endif
 
    set t = CreateTrigger()
    call TriggerRegisterUnitEvent(t,u,EVENT_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(t, Condition(function CheckLife4))
    call UnitAddAbility(u,'Amdf')
    call UnitAddAbility(u,'Aro1')
    call UnitRemoveAbility(u,'Aro1')
    call UnitAddAbility(u,'Aro1')
    call IssueImmediateOrderById(u, String2OrderIdBJ("unroot"))
    call DestroyTrigger(t)
    set t = null
    if IsUnitType(u,UNIT_TYPE_HERO) then
        call UnitRemoveAbility(u,ResetStatHero)
    else
        call UnitRemoveAbility(u,ResetStatUnit)
    endif
 
    call SetUnitState(u,UNIT_STATE_LIFE,GetUnitState(u,UNIT_STATE_MAX_LIFE))
    call SetUnitState(u,UNIT_STATE_MANA,GetUnitState(u,UNIT_STATE_MAX_MANA))
    call SetUnitAbilitySilenced(u,'Amov',false)
 
//Add this new code for Attack buttoms.
    call UnitAddAbility(u,'Abun')
    call UnitMakeAbilityPermanent(u,true,'Abun')
    call SetUnitAbilitySilenced(u,'Aatk',false)
    set u = null
 
    call SetUnitOwner(Dummy2, Player(15), false)
endfunction

Note: Both like Amov and Aatk, they have stop, so to get rid of this button you have to hide both buttons, clearly this is for all versions since reforged you don't need this anymore obviously. 😑 All this in itself is for testing, you have to accommodate things, and of course it can be for laboratory things, but people stopped investigating these things like that a long time ago, plus you have to code all the events that detect the orders that smart gives since sometimes there can be loops in orders and that should be avoided.

Greetings...
Ah, thank you however was actually wondering about the moving during webbed/ensnared because being able to change attack range is a very important thing as I am not able to use reforged.
 
Level 7
Joined
Mar 14, 2021
Messages
43
Which ability is Abun? And does the unit need to be ensnared first or Abun'd first?
Well here is what this spell does. Abun (Cargo Hold): If added to a unit it disables the unit's ability to attack other units. Even the attack icon and shortcut are removed from the command card. To enable the attack again simply remove the cargo hold ability. Together with orb abilities it should give you complete control over the attack indices of units.

Well, as I did, the Abun code would have to be the last one added after the unit is already with its -1 ensnare counter.
 
Oh, it works in legacy but doesn't in reforged. Ironic that I was using reforged to test this for my legacy project... Next is to learn how to use ai files to switch code between legacy and reforged range changes. . .

Edit: Guess having the unit dying in reforged is why it probably doesn't work while in legacy it functions as mentioned without killing the unit.
Even with negative health for main unit and morphs it still fail's somewhere around when the unit gets turned into a banshee however the unit doesn't die then but instead is stuck as the dummy hero icon banshee unit.
 
Last edited:
Level 7
Joined
Mar 14, 2021
Messages
43
Oh, it works in legacy but doesn't in reforged. Ironic that I was using reforged to test this for my legacy project... Next is to learn how to use ai files to switch code between legacy and reforged range changes. . .
Rather sorry for replying so late. But I think it was worth it. I suppose that as you say, Blizzard repaired this, because in previous versions it did work. But what irony I found another method. The detail of this is that if it becomes known, they will consider patching this other way of having a unit immune to silence and that it is used to hide icons, it is not convenient for them. So it would be better to comment on this in DM. ¯\

Ah, thank you however was actually wondering about the moving during webbed/ensnared because being able to change attack range is a very important thing as I am not able to use reforged.
I suppose that many of us still have maps, or colleagues who have projects in 1.27b since it is a version that did not have the option to hide icons.
So I had to learn certain things to make a change. And well I do not post it here, since many would not agree. But I suppose it will work if it is for that version. If it's not normal. :infl_thumbs_up:

Greetings...
 
Top