• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • Create a faction for Warcraft 3 and enter Hive's 19th Techtree Contest: Co-Op Commanders! Click here to enter!
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 21st Texturing Contest: Upgrade is now concluded, time to vote for your favourite set of icons! Click here to vote!

Beware with cone spells!

Status
Not open for further replies.
Level 13
Joined
Jan 2, 2016
Messages
978
Few months ago, when I was still new to the editor - I tried to make a cone spell, and I noticed that when I aim it towards 180 deg (west) - it hits only half of the enemies it should.
I didn't know why it's doing that until few days ago. Now that I know, I decided to share the reason with you, so players can avoid creating not fully functional cone spells.
So, world editor's "GetAngleBetweenPoints" (which GUI uses) gets angles between -180 and 180 degreese. In cone spells the simplest way to define a cone is "Angle between( Position of Picked Unit - Target point of ability being cast) +/- 45 deg".
So if you cast the spell at 179 deg, and picked unit is at 181 deg - the game will evaluate the unit's angle as -179, so 179 - 45 = 134 deg, and the condition "-179 > 134" will not be met, so the unit will not get damaged.

I'm not sure what angles would I get if I used "arctan((y2-y1)/|x2-x1|)" (would it be defined from 0 to 360 or again from -180 to 180 again, or even from -90 to 90). The best way to avoid this would be to:
set a real variable to the angle between the castin unit and the target point of ability being cast
set a real vatiable to the angle between the casting unit and the picked unit
set the 2-nd angle to 'the 2-nd - the 1-st'
if the new angle's abs value is greater than 180 - set it to RSignBJ(-the angle)*(360 -|the angle|),
And after that - set the condition "if the angle is between -xx and xx then do actions"...

This way the example I gave earlier will turn out like this:
1-st angle = 179
2-nd angle = -179
set 2-nd angle to -179 - 179 = -358
|-358| is greater than 180, so set it to (1)*|(360-358)| = 2
Then the condition would be " if '2' is between -45 and 45 then do actions" and it will run.

Let's see if any other angles wouldn't give problems:
1-st angle = 120
2-nd angle = 100
set 2-nd angle to 100-120 = -20
|-20| is less than 180, so it will remain -20
it is between -45 and 45, so the trigger will run

1-st angle = 145
2-nd angle = -145
set 2-nd angle to -145 - 145 = -290
set 2-nd angle to (1)*(360 - 290) = 70
it's less than -45, so the trigger wouldn't run.

1-st angle = 80
2-nd angle = 90
set 2-nd angle to 90-80 = 10
10 is less than 180, so keep it 10
10 is between -45 and 45, so the trigger will run.

1-st angle = -100
2-nd angle = -10
set 2-nd angle to -10+100 = 90
90 is less than 180, so it remains 90
90 is greater than 45, so the trigger doesn't run.

1-st angle = -170
2-nd angle = 170
set 2-nd angle to 170+170 = 340
340 is greater than 180, so set it to (-1)*(360-340)= -20
-20 is between -45 and 45, so the trigger will run.
 
Last edited:
Level 13
Joined
Jan 2, 2016
Messages
978
I am defining the angle from -180 to 180 too, but I put the '0' towards the targeted point, instead of 'east'. ~kind a~
1-st I get the difference between the angles, by substraction.
But since this way can get me angles from -360 to 360 (angles 179 and -179 get -358, and with -179 to 179 is 358), I check if the abs value of the angle is greater than 180 deg - I set its value to its relative angle (from -180 to 180).
This way your cone spells will work properly :p

EDIT: I kind a fixed some things in the initial post, so it'd be more accurate :p
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
JASS:
    function NormalizeAngleRad takes real angle returns real
        local real modulus = angle - I2R(R2I(angle / TAU)) * TAU
        if modulus < 0 then
            set modulus = modulus + TAU
        endif
        return modulus
    endfunction
    
    function DenormalizeAngleRad takes real angle returns real
        return NormalizeAngleRad(angle) - PI
    endfunction
    
    function GroupAddUnitsInConeRad takes group whichGroup, real x, real y, real radius, real direction, real size returns group
        local unit FoG
        local group g = CreateGroup()
        local real x2
        local real y2
        local real difference
        
        call GroupEnumUnitsInRange(g, x, y, radius, null)
        loop
            set FoG = FirstOfGroup(g)
            exitwhen FoG == null
            call GroupRemoveUnit(g,FoG)
            
            set difference = DenormalizeAngleRad(AngleBetweenCoordinatesRad(x, y, GetUnitX(FoG), GetUnitY(FoG)) - direction)
            if difference > -size and difference < size then
                call GroupAddUnit(whichGroup, FoG)
            endif
        endloop
        
        call DestroyGroup(g)
        set g = null
        return whichGroup
    endfunction
 
Status
Not open for further replies.
Top