• 🏆 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!

Dummy Hotkeys

This bundle is marked as pending. It has not been reviewed by a staff member yet.
  • Like
Reactions: Vinz
A quite small system that allows you to bind a dummy ability to a hidden ability.
This allows you to more or less "change ability hotkeys with triggers".

Note system is limited to MPI.

JASS:
library DummyHotkeys initializer init

    //NOTE THIS SYSTEM DOES ONLY SUPPORT ACTIVLY USED ABILITIES. DOES NOT WORK WITH AUTOCAST ABILITIES.
    //Written By CanFight

    globals
 
        private integer array DummySpells
        private integer DummySpellCount
        private integer array RealSpellId
        private string array RealSpellOrder
        private boolean array RealSpellTargeting
        private integer SpellCount
        private integer PlayerCount = 24             
 
    endglobals
 
    //make sure that the unit has the Abillity before you apply this.
    //takes player id (0 based), your spells ID, the spells Order Id, its target Type (instant, unit, point or both) and if its an area target spell.
    function SetDummyHotkey takes unit u, integer sid, integer index, string order, integer targetType, boolean aoe returns nothing
        local integer pid = GetPlayerId(GetOwningPlayer(u))
        local integer alvl = GetUnitAbilityLevel(u,sid) - 1
        if RealSpellId[index * PlayerCount + pid] == 0 then
            call UnitRemoveAbility(u, RealSpellId[index * PlayerCount + pid]) 
        endif
     
        set RealSpellId[index * PlayerCount + pid] = sid
        set RealSpellOrder[index * PlayerCount + pid] = order
     
        if targetType != 0 then
            set RealSpellTargeting[index * PlayerCount + pid] = true
        else
            set RealSpellTargeting[index * PlayerCount + pid] = false
        endif 
 
        if GetLocalPlayer() == Player(pid) then
            call BlzSetAbilityIcon(DummySpells[index], BlzGetAbilityIcon(sid) )
            call BlzSetAbilityTooltip(DummySpells[index], BlzGetAbilityTooltip(sid, alvl), 0 )
            call BlzSetAbilityExtendedTooltip(DummySpells[index], BlzGetAbilityExtendedTooltip(sid, alvl), 0 )
        endif
       
        if aoe then
            call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(u, DummySpells[index]), ABILITY_ILF_OPTIONS, 0, 3 )
            call BlzSetAbilityRealLevelField(BlzGetUnitAbility(u, DummySpells[index]), ABILITY_RLF_AREA_OF_EFFECT, 0, BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, sid), ABILITY_RLF_AREA_OF_EFFECT, alvl) )
        else 
            call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(u, DummySpells[index]), ABILITY_ILF_OPTIONS, 0, 1 )
        endif
     
        call BlzSetAbilityRealLevelField(BlzGetUnitAbility(u, DummySpells[index]), ABILITY_RLF_CAST_RANGE, 0, BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, sid), ABILITY_RLF_CAST_RANGE, alvl) - 10 )
                   
        call BlzUnitHideAbility(u, sid, true )
        call BlzSetAbilityIntegerLevelField( BlzGetUnitAbility(u, DummySpells[index]), ABILITY_ILF_TARGET_TYPE, 0, targetType)
        call BlzSetUnitAbilityManaCost(u, DummySpells[index], 0, BlzGetAbilityManaCost(sid, alvl) )
        call BlzSetUnitAbilityCooldown(u, DummySpells[index], 0, BlzGetAbilityCooldown(sid, alvl) )
     
    endfunction

    private function DummyCast takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local integer pid = GetPlayerId(GetOwningPlayer(caster))
        local location castPos = GetUnitLoc(caster)
        local location p
        local integer DAbiId = GetSpellAbilityId()
        local integer SAbiIndex = -1
        local integer i = 0
        loop
            exitwhen i >= DummySpellCount
            if DAbiId == DummySpells[i] then
                set SAbiIndex = i
            endif
            set i = i + 1
        endloop
     
        if SAbiIndex == -1 then
            return
        endif
        call BlzSetUnitAbilityManaCost(caster,RealSpellId[SAbiIndex * PlayerCount + pid], GetUnitAbilityLevel(caster,RealSpellId[SAbiIndex * PlayerCount + pid]) - 1,0)
        call BlzUnitHideAbility( caster, RealSpellId[SAbiIndex * PlayerCount + pid], false ) //abillity cant be hidden while being cast.
                                           
        set p = GetSpellTargetLoc()
     
        if RealSpellTargeting[SAbiIndex * PlayerCount + pid] then
            call IssuePointOrderLoc( caster, RealSpellOrder[SAbiIndex * PlayerCount + pid], p)
        else
            call IssueImmediateOrder(caster, RealSpellOrder[SAbiIndex * PlayerCount + pid])
        endif
     
        call RemoveLocation(p)
     
        call BlzUnitHideAbility( caster, RealSpellId[SAbiIndex * PlayerCount + pid], true )
     
        call RemoveLocation(castPos)
        call SetUnitState(caster, UNIT_STATE_MANA, GetUnitState(caster, UNIT_STATE_MANA) + I2R(BlzGetUnitAbilityManaCost(caster, DummySpells[SAbiIndex] , 0)))
    endfunction
 
    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
     
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT  )
        call TriggerAddAction(t, function DummyCast)
 
        //setup the dummy spells they should be based on a blank channel spell. All of them need base order ids that are not used by other spells.
 
        set DummySpells[0] = 'A000'
        set DummySpells[1] = 'A001'
        set DummySpells[2] = 'A002'
        set DummySpells[3] = 'A003'
        set DummySpellCount = 4
 
    endfunction

endlibrary
Contents

Dummy Hotkeys (Map)

Level 14
Joined
Oct 19, 2014
Messages
187
I have to suggest this,
1. As you share this system obviously a user will read and will look for descriptions, I suggestto document each ability what they does, what will dummy do, how the whole system work.

2. In SetDummyHotkey, think you have to declare even one local player for getting ID and so the very sensitive GetLocalPlayer()

Edit: ps dont forget to null the local player

3. DummyCast, why have to use location when you have the opportunity to use the x,y coords, seems you did used of jass, you have to know location is only good for getting ground heights

Edit: I guess it is better to use OrderID
After all the system is useful :D
 
Last edited:
Level 12
Joined
Jun 12, 2010
Messages
413
I dont think so, but we dont do that XD we never left local handle in filled.
That just shows that you don't know the reason why handle types are nulled. The reason handles are nulled is to avoid a bug that causes JASS to not reduce the reference counter for declared locals when they go out of scope. Players can't be destroyed, so they aren't refrence counted. Which means there is no need to null them at the end of a function.
 
Level 14
Joined
Oct 19, 2014
Messages
187
That just shows that you don't know the reason why handle types are nulled. The reason handles are nulled is to avoid a bug that causes JASS to not reduce the reference counter for declared locals when they go out of scope. Players can't be destroyed, so they aren't refrence counted. Which means there is no need to null them at the end of a function.
Thank you for sharing knowledge sir :D
 
Level 9
Joined
May 27, 2012
Messages
116
A thats my mistake actually, might as well have used xy. Will see if i get around fixing it. This system is sadly obsolete as GRID HOTKEYS in reforged more or less make this system useless.

Edit: Realised i couldnt find a way to not use "GetSpellTargetLoc()". As i already aquire the location no reason to not use the IssuePointOrderLoc instead of IssuePointOrder.
 
Last edited:
Level 11
Joined
Jul 4, 2016
Messages
626
Instead of forcing grid hotkeys, because I'm not sure it works with abilities whose position was changed by triggers, how's the delay on this?
 
Top