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

tripple shot

Status
Not open for further replies.
Level 9
Joined
May 31, 2010
Messages
366
i want to make a skill wich hits only three targets

an archer uses the skill and if there are 3 targets there will come out 3 arrows to hit them if there are only 2 only 2 arrows should appear and if there are more than 3 it should attack the 3 nearest units

atm i have used the hammer throw ability from mountainking and when i use this it creates 2 dummys wich also use the ability, my problem is the detecting of the targets as i explained

hope someone can help me
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
1. Create a Dummy
2. Add Multishot (Barrage) to the dummy
3. Order the Dummy to attack
4. Detect damage with a Damage Detection System, and check the DamageSource = your dummy unit type
5. Cause your hero (archer) to cause triggered damage to units damaged by your dummy. For this you would need some way to index the archer. You can use the unit handle or whatever you want.
6. Remove the dummy.
 
Level 9
Joined
May 31, 2010
Messages
366
barrage will not work i think cuz i want a short stun on the targets (thats why im using "hammerthrow")
the damage is dealed from the skill

Squiggy: what do you mean? can you explain a bit more?
Dr Super Good: i've also seen it but i dont know how wich spell

there is a lightning spell wich targets automaticly units in the near of the target unit, maybe i can use this if i can replace the lightning effect with arrows... but then i have no stun there

edit: i mean forked lightning but it does not work cuz i cant replace the lightnings with arrows...
 
Last edited:
Level 20
Joined
Jul 14, 2011
Messages
3,213
Create 2 unit groups
The first one: "Pick every unit in 500 AoE"
The second one "Pick 3 random units from 'TheFristGroup'"

then, do the magic.
 
Level 5
Joined
Jun 16, 2004
Messages
108

You can expand on the idea Spartipilo gave.
Create 2 unit groups
The first one: "Pick every unit in 500 AoE"
The second one "Pick 3 random units from 'TheFristGroup'"

then, do the magic.

And do this sort of thing:
  • Untitled Trigger 004
    • Events
    • Conditions
    • Actions
      • Set CastCount = 2
      • Set CastTargets = (Units within 512.00 of (Position of (Triggering unit)) matching (((Matching unit) is alive) Equal to True))
      • Set GroupSize = (Number of units in CastTargets)
      • For each (Integer A) from 1 to GroupSize, do (Actions)
        • Loop - Actions
          • Set RandomUnit = (Random unit from CastTargets)
          • Unit Group - Remove RandomUnit from CastTargets
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Owner of (Triggering unit)) is an enemy of (Owner of RandomUnit)) Equal to True
              • (RandomUnit has buff Invulnerable) Equal to False
              • (RandomUnit is Magic Immune) Equal to False
            • Then - Actions
              • -------- cast the dummy spell at RandomUnit here --------
              • Set CastCount = (CastCount - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • CastCount Equal to 0
                • Then - Actions
                  • Skip remaining actions
                • Else - Actions
            • Else - Actions
The idea is to pick all units in range, then keep picking random units until you find two that match the conditions you want (unit is an enemy, is not invulnerable, is not spell immune, etc). I have the cast count set to two in the example since I assume your main hero casts one too, otherwise you can set it to three.

Also it is just an example code, so I did not clean up the location leak.


I did not actually read the first post thoroughly I suppose, did not see you wanted the nearest units, in that case you might as well use a prepared solution like Spartipilo mentioned, GetClosestWidget looks like it will do what you want pretty easily with its
JASS:
function GetClosestNUnitsInRange takes real x, real y, real radius, integer n, group g, boolexpr filter returns nothing
 
Last edited:
Level 9
Joined
May 31, 2010
Messages
366
i dont know how to insert the jass code
also dont know how to make it work

filtering out if magic immune/invulnerabe is not important cuz in my map there are no invulnerable/immune units

is there really no way to get forked lightning to work with missiles cuz this would be exactly what i need
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
1. Create a Trigger
2. Select it, and go to Edit -> Convert to custom text
3. Delete everything inside
4. Copy this inside it:
JASS:
/*****************************************************************************
*
*    Get Closest Widget (light version)
*        by Spinnaker v2.0.0.0
*
*      Special thanks to Troll-Brain
*
******************************************************************************
*
*    This snippet contains several functions which returns closest
*       widget to given coordinates and passed filter.
*
******************************************************************************
*
*    Important:
*       Performance drop depends on amount of units currently on the map
*       Snippet functions are designed to reduce the search time as much as
*       posible, although it's recommended to use non specific functions
*       wisely, especialy if your map contains large numbers of units.
*
******************************************************************************
*
*    Functions:
*       function GetClosestUnit takes real x, real y, boolexpr filter returns unit
*          - Returns closest unit matching specific filter
*       function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
*          - Gets nearest unit in range matching specific filter
*       function GetClosestUnitInGroup takes real x, real y, group g returns unit
*          - Retrieves closest unit in given group
*
*       function GetClosestNUnitsInRange takes real x, real y, real radius, integer n, group g, boolexpr filter returns nothing
*          - Returns up to N nearest units in range of passed coordinates
*       function GetClosestNUnitsInGroup takes real x, real y, integer n, group sourceGroup, group destGroup returns nothing
*          - Retrieves up to N closest units in passed group
*
*****************************************************************************/
library GetClosestWidget

    private keyword Init
    globals
        private unit array Q
        private real array V
        private integer C=0
    endglobals
    
    struct ClosestWidget extends array
        readonly static real distance=0
        readonly static real cX=0
        readonly static real cY=0
        readonly static unit cUnit=null
        static method resetData takes real x, real y returns nothing
            set distance=100000
            set cUnit=null
            set cX=x
            set cY=y
        endmethod
        static method enumUnits takes nothing returns nothing
            local unit u=GetEnumUnit()
            local real dx=GetUnitX(u)-cX
            local real dy=GetUnitY(u)-cY
            set dx=(dx*dx+dy*dy)/10000.
            if dx<distance then
                set cUnit=u
                set distance=dx
            endif
            set u=null
        endmethod
        static method sortUnits takes integer l, integer r returns nothing
            local integer i=l
            local integer j=r
            local real v=V[(l+r)/2]
            loop
                loop
                    exitwhen V[i]>=v
                    set i=i+1
                endloop
                loop
                    exitwhen V[j]<=v
                    set j=j-1
                endloop
                if i<=j then
                    set V[0]=V[i]
                    set V[i]=V[j]
                    set V[j]=V[0]
                    set Q[0]=Q[i]
                    set Q[i]=Q[j]
                    set Q[j]=Q[0]
                    set i=i+1
                    set j=j-1
                endif
                exitwhen i>j
            endloop
            if l<j then
                call sortUnits(l,j)
            endif
            if r>i then
                call sortUnits(i,r)
            endif
        endmethod
        static method saveGroup takes nothing returns nothing
            local real dx
            local real dy
            set C=C+1
            set Q[C]=GetEnumUnit()
            set dx=GetUnitX(Q[C])-cX
            set dy=GetUnitY(Q[C])-cY
            set V[C]=(dx*dx+dy*dy)/10000.
        endmethod
    endstruct
    
    function GetClosestUnit takes real x, real y, boolexpr filter returns unit
        local real r=800.
        call ClosestWidget.resetData(x,y)
        loop
            if r>3200. then
                call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, filter)
                exitwhen true
            else
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, r, filter)
                exitwhen FirstOfGroup(bj_lastCreatedGroup)!=null
            endif
            set r=2*r
        endloop
        call ForGroup(bj_lastCreatedGroup, function ClosestWidget.enumUnits)
        return ClosestWidget.cUnit
    endfunction
    
    function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
        call ClosestWidget.resetData(x,y)
        if radius>=0 then
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, filter)
            call ForGroup(bj_lastCreatedGroup, function ClosestWidget.enumUnits)
        endif
        return ClosestWidget.cUnit
    endfunction
    
    function GetClosestUnitInGroup takes real x, real y, group g returns unit
        call ClosestWidget.resetData(x,y)
        call ForGroup(g, function ClosestWidget.enumUnits)
        return ClosestWidget.cUnit
    endfunction
    
    function GetClosestNUnitsInRange takes real x, real y, real radius, integer n, group g, boolexpr filter returns nothing
        local integer q=n+1
        call ClosestWidget.resetData(x,y)
        if radius>=0 then
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, filter)
            call ForGroup(bj_lastCreatedGroup, function ClosestWidget.saveGroup)
            call ClosestWidget.sortUnits(1,C)
            loop
            exitwhen n==0 or Q[-n+q]==null
                call GroupAddUnit(g, Q[-n+q])
                set n =n-1
            endloop
        endif
        set C=0
    endfunction
    
    function GetClosestNUnitsInGroup takes real x, real y, integer n, group sourceGroup, group destGroup returns nothing
        local integer q=n+1
        call ClosestWidget.resetData(x,y)
        call ForGroup(sourceGroup, function ClosestWidget.saveGroup)
        call ClosestWidget.sortUnits(1,C)
        loop
            exitwhen n==0 or Q[-n+q]==null
            call GroupAddUnit(destGroup, Q[-n+q])
            set n=n-1
        endloop
        set C=0
    endfunction
endlibrary

5. Create a Unit Group called "NearUnits"

6. Create the Following Trigger with Event: "A unit starts the effect of an ability" and Condition: "Ability being cast equal to YourMultiShotAbility, and the Following Actions.
  • Set Unit = (Triggering Unit)
  • Set Location = Position of Unit
  • Custom script: call GetClosestNUnitsInRange(GetunitX(udg_Unit), GetUnitY(udg_Unit), 500, 3, udg_NearUnits, null)
  • Unit Group - Pick Every unit in NearUnits and do (Actions):
    • Unit - Create 1 Dummy at Location
    • Unit - Order (last created unit) to stormbolt (Picked Unit)
    • Unit - Add 1 second Generic expiration timer to (last created unit)
    • Unit Group - Remove (Picked Unit) from NearUnits
  • Custom script: call RemoveLocation(udg_Location)
Of course, if your ability is not stormbolt, configure it to be the one you use, also the dummy name and else. You should get the idea.

<< EDIT >>

Wont work. It requires the boolexpr filter, but I don't know how to do it. Lets wait for someone to help us creating it and calling it into the function.
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
Exactly.
· 500 is the range (You can change it to whatever you want)
· 3 is the max number of units to pick in that range (you can change it to whatever you want)
· GetunitX(udg_Unit), GetUnitY(udg_Unit) is the X/Y (The Location) of your Unit (The casting unit)
· udg_NearUnits is the UnitGroup i told you to create (Just call it "NearUnits" No need to place "udg_" in the variable creation)
· The event is "Starts the effect of an ability"

That SHOULD work without any changes (be aware that I updated/edited it a bit after posting the first time) but i'm not sure. Test it.

<< EDIT >>

It wont work xD I don't know exactly how to create the boolexpr filter to use it in the function call. I know it's easy, but I still don't understand how it works. I'm sure some others in this forum may help us with this little issue.
 
Level 14
Joined
May 22, 2010
Messages
362
That forked lightning is a good idea.
You can make this skill by :
1.creating a dummy unit A that has the forked lightning ability that deals no damage and has no effects(special effect and lightning).
2.create a dummy unit B that that has the storm bolt ability
3.create a target unit dummy ability for your hero
4.make a trigger that creates dummy A when the hero cast his ability and orders it to cast the dummy FL on the target unit
5.make another trigger that detects when a unit takes damage from a unit type=dummy unit A and make it create a dummy unit B at position of damage source and order it to cast the storm bolt ability on the damaged unit.
You will need a damage detection system.
 
Level 5
Joined
Sep 28, 2010
Messages
75
For the boolexpr filter, a function acting as the filter is needed.
Example:
JASS:
function TheFilter takes nothing returns boolean
    return IsUnitAlly(GetFilterUnit(), GetOwningPlayer(udg_Caster)) and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction

After that, just put Condition(function TheFilter) as the parameter for the boolexpr function.

Spartipilo said:
  • Set Unit = (Triggering Unit)
  • Set Location = Position of Unit
  • Custom script: call GetClosestNUnitsInRange(GetunitX(udg_Unit), GetUnitY(udg_Unit), 500, 3, udg_NearUnits, null)
  • Unit Group - Pick Every unit in NearUnits and do (Actions):
    • Unit - Create 1 Dummy at Location
    • Unit - Order (last created unit) to stormbolt (Picked Unit)
    • Unit - Add 1 second Generic expiration timer to (last created unit)
    • Unit Group - Remove (Picked Unit) from NearUnits
  • Custom script: call RemoveLocation(udg_Location)

To retain the trigger in GUI format, you can make use of endfunction, that is:
  • ------The below line calls the real action function------
  • Custom script: call ExecuteFunction("TheAction")
  • Custom script: endfunction
  • ------The filter function------
  • Custom script: function TheFilter takes nothing returns boolean
  • Custom script: return (Your conditions)
  • Custom script: endfunction
  • ------The action function------
  • Custom script: function TheAction takes nothing returns nothing
  • Set Unit = (Triggering Unit)
  • Set Location = Position of Unit
  • Custom script: call GetClosestNUnitsInRange(GetunitX(udg_Unit), GetUnitY(udg_Unit), 500, 3, udg_NearUnits, Condition(function TheFilter))
  • Unit Group - Pick Every unit in NearUnits and do (Actions):
    • Unit - Create 1 Dummy at Location
    • Unit - Order (last created unit) to stormbolt (Picked Unit)
    • Unit - Add 1 second Generic expiration timer to (last created unit)
    • Unit Group - Remove (Picked Unit) from NearUnits
  • Custom script: call RemoveLocation(udg_Location)
  • ------There is no endfunction as the GUI trigger itself has an endfunction at the end------
For the filter, here is an example:
If you want the unit to be an enemy of the caster and that it is not dead yet, the filter function would be:
  • Custom script: function TheFilter takes nothing returns boolean
  • Custom script: return IsUnitAlly(GetFilterUnit(), GetTriggerPlayer()) and GetWidgetLife(GetFilterUnit()) > 0.405
  • Custom script: endfunction
 
Level 5
Joined
Sep 28, 2010
Messages
75
Follow Spartipilo's instructions on his second post in this thread, and then just replace
  • Set Unit = (Triggering Unit)
  • Set Location = Position of Unit
  • Custom script: call GetClosestNUnitsInRange(GetunitX(udg_Unit), GetUnitY(udg_Unit), 500, 3, udg_NearUnits, null)
  • Unit Group - Pick Every unit in NearUnits and do (Actions):
    • Unit - Create 1 Dummy at Location
    • Unit - Order (last created unit) to stormbolt (Picked Unit)
    • Unit - Add 1 second Generic expiration timer to (last created unit)
    • Unit Group - Remove (Picked Unit) from NearUnits
  • Custom script: call RemoveLocation(udg_Location)
with:
  • Custom script: call ExecuteFunction("TripleShot_Action")
  • Custom script: endfunction
  • Custom script: function TripleShot_Filter takes nothing returns boolean
  • Custom script: return IsUnitAlly(GetFilterUnit(), GetTriggerPlayer()) and GetWidgetLife(GetFilterUnit()) > 0.405
  • Custom script: endfunction
  • Custom script: function TripleShot_Action takes nothing returns nothing
  • Set Unit = (Triggering Unit)
  • Set Location = Position of Unit
  • Custom script: call GetClosestNUnitsInRange(GetunitX(udg_Unit), GetUnitY(udg_Unit), 500, 3, udg_NearUnits, Condition(function TripleShot_Filter))
  • Unit Group - Pick Every unit in NearUnits and do (Actions):
    • Unit - Create 1 Dummy at Location
    • Unit - Order (last created unit) to stormbolt (Picked Unit)
    • Unit - Add 1 second Generic expiration timer to (last created unit)
    • Unit Group - Remove (Picked Unit) from NearUnits
  • Custom script: call RemoveLocation(udg_Location)
Note that you will still have to customize the filter. Maybe someone else can help you with which units you want to pick.

Also note that I haven't tested the trigger yet so i can not guarantee that the trigger will work.
 
Level 9
Joined
May 31, 2010
Messages
366
so does it mean that i have to replace every line wich is called:

function GetClosestUnit takes real x, real y, boolexpr filter returns unit

with:

function TheFilter takes nothing returns boolean
return IsUnitAlly(GetFilterUnit(), GetOwningPlayer(udg_Caster)) and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction

??

then all other things from spartipilo and replace the thing flashb0nd said in gui? and this should work?
 
Level 5
Joined
Sep 28, 2010
Messages
75
so does it mean that i have to replace every line wich is called:

function GetClosestUnit takes real x, real y, boolexpr filter returns unit

with:

function TheFilter takes nothing returns boolean
return IsUnitAlly(GetFilterUnit(), GetOwningPlayer(udg_Caster)) and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction

??

then all other things from spartipilo and replace the thing flashb0nd said in gui? and this should work?

Not necessarily, don't touch the system "GetClosestWidget".

This code:
  • Custom script: function TripleShot_Filter takes nothing returns boolean
  • Custom script: return IsUnitAlly(GetFilterUnit(), GetTriggerPlayer()) and GetWidgetLife(GetFilterUnit()) > 0.405
  • Custom script: endfunction
Should only be entered once or else it would cause a compile error.

Just create a new trigger and insert the actions i provided.

By the way, i made a mistake.
  • Custom script: call ExecuteFunction("TripleShot_Action")
Should be:
  • Custom script: call ExecuteFunc("TripleShot_Action")
 
Level 9
Joined
May 31, 2010
Messages
366
i tried it last night but im really confused by trying to summary that all and implement it to my map but i failed... i don't know what i should replace with and where

pls can someone summary it up so that there is one post with exactly that what i need?

im sorry for annoying you with that....
 
Level 5
Joined
Sep 28, 2010
Messages
75
These are the two triggers you need for your triple shot.

JASS:
/*****************************************************************************
*
*    Get Closest Widget (light version)
*        by Spinnaker v2.0.0.0
*
*      Special thanks to Troll-Brain
*
******************************************************************************
*
*    This snippet contains several functions which returns closest
*       widget to given coordinates and passed filter.
*
******************************************************************************
*
*    Important:
*       Performance drop depends on amount of units currently on the map
*       Snippet functions are designed to reduce the search time as much as
*       posible, although it's recommended to use non specific functions
*       wisely, especialy if your map contains large numbers of units.
*
******************************************************************************
*
*    Functions:
*       function GetClosestUnit takes real x, real y, boolexpr filter returns unit
*          - Returns closest unit matching specific filter
*       function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
*          - Gets nearest unit in range matching specific filter
*       function GetClosestUnitInGroup takes real x, real y, group g returns unit
*          - Retrieves closest unit in given group
*
*       function GetClosestNUnitsInRange takes real x, real y, real radius, integer n, group g, boolexpr filter returns nothing
*          - Returns up to N nearest units in range of passed coordinates
*       function GetClosestNUnitsInGroup takes real x, real y, integer n, group sourceGroup, group destGroup returns nothing
*          - Retrieves up to N closest units in passed group
*
*****************************************************************************/
library GetClosestWidget

    private keyword Init
    globals
        private unit array Q
        private real array V
        private integer C=0
    endglobals
    
    struct ClosestWidget extends array
        readonly static real distance=0
        readonly static real cX=0
        readonly static real cY=0
        readonly static unit cUnit=null
        static method resetData takes real x, real y returns nothing
            set distance=100000
            set cUnit=null
            set cX=x
            set cY=y
        endmethod
        static method enumUnits takes nothing returns nothing
            local unit u=GetEnumUnit()
            local real dx=GetUnitX(u)-cX
            local real dy=GetUnitY(u)-cY
            set dx=(dx*dx+dy*dy)/10000.
            if dx<distance then
                set cUnit=u
                set distance=dx
            endif
            set u=null
        endmethod
        static method sortUnits takes integer l, integer r returns nothing
            local integer i=l
            local integer j=r
            local real v=V[(l+r)/2]
            loop
                loop
                    exitwhen V[i]>=v
                    set i=i+1
                endloop
                loop
                    exitwhen V[j]<=v
                    set j=j-1
                endloop
                if i<=j then
                    set V[0]=V[i]
                    set V[i]=V[j]
                    set V[j]=V[0]
                    set Q[0]=Q[i]
                    set Q[i]=Q[j]
                    set Q[j]=Q[0]
                    set i=i+1
                    set j=j-1
                endif
                exitwhen i>j
            endloop
            if l<j then
                call sortUnits(l,j)
            endif
            if r>i then
                call sortUnits(i,r)
            endif
        endmethod
        static method saveGroup takes nothing returns nothing
            local real dx
            local real dy
            set C=C+1
            set Q[C]=GetEnumUnit()
            set dx=GetUnitX(Q[C])-cX
            set dy=GetUnitY(Q[C])-cY
            set V[C]=(dx*dx+dy*dy)/10000.
        endmethod
    endstruct
    
    function GetClosestUnit takes real x, real y, boolexpr filter returns unit
        local real r=800.
        call ClosestWidget.resetData(x,y)
        loop
            if r>3200. then
                call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, filter)
                exitwhen true
            else
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, r, filter)
                exitwhen FirstOfGroup(bj_lastCreatedGroup)!=null
            endif
            set r=2*r
        endloop
        call ForGroup(bj_lastCreatedGroup, function ClosestWidget.enumUnits)
        return ClosestWidget.cUnit
    endfunction
    
    function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
        call ClosestWidget.resetData(x,y)
        if radius>=0 then
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, filter)
            call ForGroup(bj_lastCreatedGroup, function ClosestWidget.enumUnits)
        endif
        return ClosestWidget.cUnit
    endfunction
    
    function GetClosestUnitInGroup takes real x, real y, group g returns unit
        call ClosestWidget.resetData(x,y)
        call ForGroup(g, function ClosestWidget.enumUnits)
        return ClosestWidget.cUnit
    endfunction
    
    function GetClosestNUnitsInRange takes real x, real y, real radius, integer n, group g, boolexpr filter returns nothing
        local integer q=n+1
        call ClosestWidget.resetData(x,y)
        if radius>=0 then
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, filter)
            call ForGroup(bj_lastCreatedGroup, function ClosestWidget.saveGroup)
            call ClosestWidget.sortUnits(1,C)
            loop
            exitwhen n==0 or Q[-n+q]==null
                call GroupAddUnit(g, Q[-n+q])
                set n =n-1
            endloop
        endif
        set C=0
    endfunction
    
    function GetClosestNUnitsInGroup takes real x, real y, integer n, group sourceGroup, group destGroup returns nothing
        local integer q=n+1
        call ClosestWidget.resetData(x,y)
        call ForGroup(sourceGroup, function ClosestWidget.saveGroup)
        call ClosestWidget.sortUnits(1,C)
        loop
            exitwhen n==0 or Q[-n+q]==null
            call GroupAddUnit(destGroup, Q[-n+q])
            set n=n-1
        endloop
        set C=0
    endfunction
endlibrary
  • TripleShot
    • Events
      • Unit - A unit starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Triple Shot
    • Actions
      • Custom script: call ExecuteFunction("TripleShot_Action")
      • Custom script: endfunction
      • Custom script: function TripleShot_Filter takes nothing returns boolean
      • Custom script: return IsUnitAlly(GetFilterUnit(), GetTriggerPlayer()) and GetWidgetLife(GetFilterUnit()) > 0.405
      • Custom script: endfunction
      • Custom script: function TripleShot_Action takes nothing returns nothing
      • Set Unit = (Triggering Unit)
      • Set Location = Position of Unit
      • Custom script: call GetClosestNUnitsInRange(GetunitX(udg_Unit), GetUnitY(udg_Unit), 500, 3, udg_NearUnits, Condition(function TripleShot_Filter))
      • Unit Group - Pick Every unit in NearUnits and do (Actions):
        • Unit - Create 1 Dummy at Location
        • Unit - Order (last created unit) to stormbolt (Picked Unit)
        • Unit - Add 1 second Generic expiration timer to (last created unit)
        • Unit Group - Remove (Picked Unit) from NearUnits
      • Custom script: call RemoveLocation(udg_Location)
Unit, Location and NearUnits are unit, point and unit group variables respectively. Dummy is a dummy unit.
 
Level 9
Joined
May 31, 2010
Messages
366
after i added all this to my map and wanted to test it in we i see no player slots when i was about to open my map... while saving i also got an error...

error:
function TripleShot_Filter takes nothing returns nothing


this is what i did copy and paste:

  • Tripple shot
    • Ereignisse
      • Einheit - A unit Beginnt, eine Fähigkeit zu wirken
    • Bedingungen
      • (Ability being cast) Gleich (==) Mithril Pfeil lvl3
    • Aktionen
      • Custom script: call ExecuteFunction("TripleShot_Action")
      • Custom script: endfunction
      • Custom script: function TripleShot_Filter takes nothing returns boolean
      • Custom script: return IsUnitEnemy(GetFilterUnit(), GetTriggerPlayer()) and GetWidgetLife(GetFilterUnit()) > 0.405
      • Custom script: endfunction
      • Custom script: function TripleShot_Filter takes nothing returns nothing
      • Set Unit = (Triggering unit)
      • Set Location = (Position of Unit)
      • Custom script: call GetClosestUnitsInRange(GetUnitX(udg_Unit), GetUnitY(udg_Unit), 400, 3, udg_NearUnits, Condition(function TripleShot_Filter))
      • Einheitengruppe - Pick every unit in NearUnits and do (Actions)
        • Schleifen - Aktionen
          • Einheit - Create 1 Dummy unit for (Owner of Unit) at (Position of Unit) facing Vorgabe für Gebäude-Ausrichtung (270.0) degrees
          • Einheit - Order (Last created unit) to Neutral - 'Feuerblitz' (Picked unit)
          • Einheit - Add a 1.00 second Standard expiration timer to (Last created unit)
          • Einheitengruppe - Remove (Picked unit) from NearUnits
      • Custom script: call RemoveLocation(udg_Location)
JASS:
/*****************************************************************************
*
*    Get Closest Widget (light version)
*        by Spinnaker v2.0.0.0
*
*      Special thanks to Troll-Brain
*
******************************************************************************
*
*    This snippet contains several functions which returns closest
*       widget to given coordinates and passed filter.
*
******************************************************************************
*
*    Important:
*       Performance drop depends on amount of units currently on the map
*       Snippet functions are designed to reduce the search time as much as
*       posible, although it's recommended to use non specific functions
*       wisely, especialy if your map contains large numbers of units.
*
******************************************************************************
*
*    Functions:
*       function GetClosestUnit takes real x, real y, boolexpr filter returns unit
*          - Returns closest unit matching specific filter
*       function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
*          - Gets nearest unit in range matching specific filter
*       function GetClosestUnitInGroup takes real x, real y, group g returns unit
*          - Retrieves closest unit in given group
*
*       function GetClosestNUnitsInRange takes real x, real y, real radius, integer n, group g, boolexpr filter returns nothing
*          - Returns up to N nearest units in range of passed coordinates
*       function GetClosestNUnitsInGroup takes real x, real y, integer n, group sourceGroup, group destGroup returns nothing
*          - Retrieves up to N closest units in passed group
*
*****************************************************************************/
library GetClosestWidget

    private keyword Init
    globals
        private unit array Q
        private real array V
        private integer C=0
    endglobals
    
    struct ClosestWidget extends array
        readonly static real distance=0
        readonly static real cX=0
        readonly static real cY=0
        readonly static unit cUnit=null
        static method resetData takes real x, real y returns nothing
            set distance=100000
            set cUnit=null
            set cX=x
            set cY=y
        endmethod
        static method enumUnits takes nothing returns nothing
            local unit u=GetEnumUnit()
            local real dx=GetUnitX(u)-cX
            local real dy=GetUnitY(u)-cY
            set dx=(dx*dx+dy*dy)/10000.
            if dx<distance then
                set cUnit=u
                set distance=dx
            endif
            set u=null
        endmethod
        static method sortUnits takes integer l, integer r returns nothing
            local integer i=l
            local integer j=r
            local real v=V[(l+r)/2]
            loop
                loop
                    exitwhen V[i]>=v
                    set i=i+1
                endloop
                loop
                    exitwhen V[j]<=v
                    set j=j-1
                endloop
                if i<=j then
                    set V[0]=V[i]
                    set V[i]=V[j]
                    set V[j]=V[0]
                    set Q[0]=Q[i]
                    set Q[i]=Q[j]
                    set Q[j]=Q[0]
                    set i=i+1
                    set j=j-1
                endif
                exitwhen i>j
            endloop
            if l<j then
                call sortUnits(l,j)
            endif
            if r>i then
                call sortUnits(i,r)
            endif
        endmethod
        static method saveGroup takes nothing returns nothing
            local real dx
            local real dy
            set C=C+1
            set Q[C]=GetEnumUnit()
            set dx=GetUnitX(Q[C])-cX
            set dy=GetUnitY(Q[C])-cY
            set V[C]=(dx*dx+dy*dy)/10000.
        endmethod
    endstruct
    
    function GetClosestUnit takes real x, real y, boolexpr filter returns unit
        local real r=800.
        call ClosestWidget.resetData(x,y)
        loop
            if r>3200. then
                call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, filter)
                exitwhen true
            else
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, r, filter)
                exitwhen FirstOfGroup(bj_lastCreatedGroup)!=null
            endif
            set r=2*r
        endloop
        call ForGroup(bj_lastCreatedGroup, function ClosestWidget.enumUnits)
        return ClosestWidget.cUnit
    endfunction
    
    function GetClosestUnitInRange takes real x, real y, real radius, boolexpr filter returns unit
        call ClosestWidget.resetData(x,y)
        if radius>=0 then
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, filter)
            call ForGroup(bj_lastCreatedGroup, function ClosestWidget.enumUnits)
        endif
        return ClosestWidget.cUnit
    endfunction
    
    function GetClosestUnitInGroup takes real x, real y, group g returns unit
        call ClosestWidget.resetData(x,y)
        call ForGroup(g, function ClosestWidget.enumUnits)
        return ClosestWidget.cUnit
    endfunction
    
    function GetClosestNUnitsInRange takes real x, real y, real radius, integer n, group g, boolexpr filter returns nothing
        local integer q=n+1
        call ClosestWidget.resetData(x,y)
        if radius>=0 then
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, filter)
            call ForGroup(bj_lastCreatedGroup, function ClosestWidget.saveGroup)
            call ClosestWidget.sortUnits(1,C)
            loop
            exitwhen n==0 or Q[-n+q]==null
                call GroupAddUnit(g, Q[-n+q])
                set n =n-1
            endloop
        endif
        set C=0
    endfunction
    
    function GetClosestNUnitsInGroup takes real x, real y, integer n, group sourceGroup, group destGroup returns nothing
        local integer q=n+1
        call ClosestWidget.resetData(x,y)
        call ForGroup(sourceGroup, function ClosestWidget.saveGroup)
        call ClosestWidget.sortUnits(1,C)
        loop
            exitwhen n==0 or Q[-n+q]==null
            call GroupAddUnit(destGroup, Q[-n+q])
            set n=n-1
        endloop
        set C=0
    endfunction
endlibrary

as variables i set
Unit - as Unit
Location - as Point (Location)
and
NearUnits as Unitgroup

so i did all you telled me and it will not work, what im doing wrong?
(hate jass >.<)
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
WRONG...

GetClosestNUnitsInRange You forgot the N
  • Custom script: call GetClosestUnitsInRange(GetUnitX(udg_Unit), GetUnitY(udg_Unit), 400, 3, udg_NearUnits, Condition(function TripleShot_Filter))
Also
  • Einheit - Create 1 Dummy unit for (Owner of Unit) at (Position of Unit) facing Vorgabe für Gebäude-Ausrichtung (270.0) degrees
(Position of Unit) leaks. Why did you set the Location before into a Variable, if you aren't going to use it? Replace (Position of Unit) with the Location variable.

Even't is not "Begins casting an ability". It's "Starts the Effect of an Ability"
 
Level 9
Joined
May 31, 2010
Messages
366
okay i changed the N and fixed the leak but when i'm trying to save the same error appears:
Line 6755: Function redeclared TripleSHot_Filter

in the function is marked: function TripleShot_Filter takes nothing returns nothing



another error appears when i mark the trigger as unactive and then back to active:
Der Auslöser 'get closed' muss über eine Initialisierungsfunktion namens 'InitTrig_get_closed' verfügen.
im not able to translate this into english hope you know the error
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
RE-DECLARED = You declared the same function twice
  • Custom script: function TripleShot_Filter takes nothing returns boolean
  • Custom script: return IsUnitEnemy(GetFilterUnit(), GetTriggerPlayer()) and GetWidgetLife(GetFilterUnit()) > 0.405
  • Custom script: endfunction
  • Custom script: function TripleShot_Filter takes nothing returns nothing <--- DELETE THIS LINE
 
Level 9
Joined
May 31, 2010
Messages
366
i don't think so but i can try

you mean i should post all triggers from my map?
this is an map i'm working over than 5 years
there are too many triggers to post them all
i just can upload an version here... but i'ts full of leaks.... cuz i don't care about

but as spartipilo said the distance is also from the system
 
Level 9
Joined
May 31, 2010
Messages
366
  • Tripple shot
    • Ereignisse
      • Einheit - A unit Startet den Effekt einer Fähigkeit
    • Bedingungen
      • (Ability being cast) Gleich Mithril Pfeil lvl3
    • Aktionen
      • Custom script: call ExecuteFunction("TripleShot_Action")
      • Custom script: endfunction
      • Custom script: function TripleShot_Filter takes nothing returns boolean
      • Custom script: return IsUnitEnemy(GetFilterUnit(), GetTriggerPlayer()) and GetWidgetLife(GetFilterUnit()) > 0.405
      • Custom script: endfunction
      • Set Unit = (Triggering unit)
      • Set Location = (Position of Unit)
      • Custom script: call GetClosestNUnitsInRange(GetUnitX(udg_Unit), GetUnitY(udg_Unit), 400, 3, udg_NearUnits, Condition(function TripleShot_Filter))
      • Einheitengruppe - Pick every unit in NearUnits and do (Actions)
        • Schleifen - Aktionen
          • Einheit - Create 1 Dummy unit for (Owner of Unit) at Location facing Vorgabe für Gebäude-Ausrichtung degrees
          • Einheit - Order (Last created unit) to Neutral - 'Feuerblitz' (Picked unit)
          • Einheit - Add a 1.00 second Standard expiration timer to (Last created unit)
          • Einheitengruppe - Remove (Picked unit) from NearUnits
      • Custom script: call RemoveLocation(udg_Location)
this is the gui trigger

Btw: it shows me more than only that one trigger for example things like undefined variable Y, X etc.
the error with the distance also appears after re copy the trigger
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
· In the GUI trigger replace "Owner of Unit" with "Triggering Player"

About the other bugs, they're all related to the ClosesWidget snippet. To copy it correctly you have to:

1. Create a Trigger
2. Convert it to custom text
3. Delete EVERYTHING inside it
4. Paste the ClosesWidget Library.

YOU NEED JNPG to use this.
 
Level 9
Joined
May 31, 2010
Messages
366
i replaced "owner of unit" with "triggering player"

and did it like you said
-create
-convert
-delete
-copy&paste

but the errors still come again
i'm using jass new gen pack we if you want i can upload the map so u can check it by yourself
 
Level 9
Joined
May 31, 2010
Messages
366
du you think i didn't tried this? but it looks wierd when you play an crossbowman an then he pierces the big fat demon wihtout dealing any damage with his shot, to hit the small rat behind...

thats why i'm looking for the nearest unit

in the attachment is the map
under the the folder abilitys in the trigger editor are the tripple shot triggers
 

Attachments

  • DK 1.30.w3x
    4.3 MB · Views: 50
Status
Not open for further replies.
Top