• 🏆 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] [Solved] (New SFX API) Orientation is facing wrong way, why?

Level 7
Joined
Sep 16, 2016
Messages
185
JASS:
function RetsuQ_act takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local effect eff = null
    if GetSpellAbilityId() == 'A002' then
        set eff = AddSpecialEffectLoc("BladeBeamFinalLarger.mdx", PolarProjectionBJ(GetUnitLoc(u), 200, AngleBetweenPoints(GetUnitLoc(u), GetSpellTargetLoc())))
        call BlzSetSpecialEffectOrientation(eff, AngleBetweenPoints(GetUnitLoc(u), GetSpellTargetLoc()), 0, 0)
    else
        return
    endif
endfunction
function RetsuQ_init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_CAST)
    call TriggerAddAction(trig, function RetsuQ_act)
endfunction
1701945133701.png

1701945146385.png

What am I doing wrong, why is the effect not facing the proper way? Also is using "Loc" bad? what other way if so could I do this?
 
Level 7
Joined
Sep 16, 2016
Messages
185
Tried another approach, but no work

JASS:
function NewX takes real LocX, real Dist, real Angle returns real
    return LocX + Dist * Cos( Deg2Rad( Angle ) )
endfunction
function NewY takes real LocY, real Dist, real Angle returns real
    return LocY + Dist * Sin( Deg2Rad( Angle ) )
endfunction
function GetAxisAngle takes real FromX, real FromY, real TargetX, real TargetY returns real
    return Rad2Deg( Atan2( TargetY - FromY, TargetX - FromX ) )
endfunction
function GetAngleCast takes unit Caster, real TargetX, real TargetY returns real
    local real FromX = GetUnitX( Caster )
    local real FromY = GetUnitY( Caster )
    if FromX == TargetX and FromY == TargetY then
        return GetUnitFacing( Caster )
    endif
    return GetAxisAngle( FromX, FromY, TargetX, TargetY )
endfunction

function RetsuQ_act takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local effect eff = null
    local real eff_x = BlzGetLocalSpecialEffectX(eff)
    local real eff_y = BlzGetLocalSpecialEffectY(eff)
    local real abil_x = GetSpellTargetX()
    local real abil_y = GetSpellTargetY()
    if GetSpellAbilityId() == 'A002' then
        set eff = AddSpecialEffect("BladeBeamFinalLarger.mdx", NewX(GetUnitX(u), 250, GetAngleCast(u, GetUnitX(u), GetUnitY(u))), NewY(GetUnitY(u), 250, GetAngleCast(u, GetUnitX(u), GetUnitY(u))))
        // call BlzSetSpecialEffectYaw(eff, GetAxisAngle(eff_x, eff_y, abil_x, abil_y)) <-- tried this
        // call BlzSetSpecialEffectYaw(eff, GetAngleCast(u, eff_x, eff_y)) <-- and this, separately
    else
        return
    endif
endfunction
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,543
It's nice to get used to using x/y coordinates when working in Jass/Lua. Locations are often an extra and unnecessary step.

Here's a little Utility library I threw together, nothing special but it has some useful functions that could make your life easier. There's probably a better version of this on Hive and I recommend customizing it yourself to fit your specific needs:
vJASS:
library Util

    globals
        real PI = 3.14159274
        real DEG2RAD = PI / 180
        real RAD2DEG = 180 / PI
        real X = 0 // Used to mimic returning two reals at once
        real Y = 0 // Used to mimic returning two reals at once
        effect SFX = null // Helps avoid a memory leak
    endglobals

    // Angle between points
    function AngleBetweenXY takes real x1, real y1, real x2, real y2 returns real
        return 180 + (RAD2DEG * Atan2(y1 - y2, x1 - x2))
    endfunction

    function AngleBetweenXYRad takes real x1, real y1, real x2, real y2 returns real
        return PI + Atan2(y1 - y2, x1 - x2)
    endfunction

    function AngleBetweenUXY takes unit u, real x2, real y2 returns real
        local real x1 = GetUnitX(u)
        local real y1 = GetUnitY(u)
        return 180 + (RAD2DEG * Atan2(y1 - y2, x1 - x2))
    endfunction

    function AngleBetweenUXYRad takes unit u, real x2, real y2 returns real
        local real x1 = GetUnitX(u)
        local real y1 = GetUnitY(u)
        return PI + Atan2(y1 - y2, x1 - x2)
    endfunction

    // Polar offset
    function GetOffsetPosition takes real x, real y, real offset, real degrees returns nothing
        set X = x + (offset * Cos(DEG2RAD * degrees))
        set Y = y + (offset * Sin(DEG2RAD * degrees))
    endfunction

    function GetOffsetPositionRad takes real x, real y, real offset, real radians returns nothing
        set X = x + (offset * Cos(radians))
        set Y = y + (offset * Sin(radians))
    endfunction

    function GetOffsetPositionU takes unit u, real offset, real degrees returns nothing
        set X = GetUnitX(u) + (offset * Cos(DEG2RAD * degrees))
        set Y = GetUnitY(u) + (offset * Sin(DEG2RAD * degrees))
    endfunction

    function GetOffsetPositionURad takes unit u, real offset, real radians returns nothing
        set X = GetUnitX(u) + (offset * Cos(radians))
        set Y = GetUnitY(u) + (offset * Sin(radians))
    endfunction

    // Creates a special effect offset by a set distance in a direction based on the given coordinates:
    public function AddSpecialEffectOffset takes string modelName, real x1, real y1, real x2, real y2, real offset returns effect
        local real angle = AngleBetweenXY(x1, y1, x2, y2) // reverse parameters to reverse direction
        call GetOffsetPosition(x1, y1, offset, angle) // sets the global X and Y variables
        return AddSpecialEffect(modelName, X, Y)
    endfunction

    // Like AddSpecialEffectOffset, but also makes the special effect face the direction:
    public function AddSpecialEffectOffsetEx takes string modelName, real x1, real y1, real x2, real y2, real offset returns effect
        local real angle = AngleBetweenXY(x1, y1, x2, y2) // reverse parameters to reverse direction
        call GetOffsetPosition(x1, y1, offset, angle) // sets the global X and Y variables
        set SFX = AddSpecialEffect(modelName, X, Y)
        call BlzSetSpecialEffectYaw(SFX, angle * DEG2RAD) // yaw uses radians so we need to convert
        return SFX
    endfunction

endlibrary

Here's your code, rewritten to use it's own library as well as the Util library. I also fixed the memory leaks:
vJASS:
library Retsu initializer Retsu_init requires Util

function RetsuQ_act takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local effect e = null
    local real x1
    local real y1
    local real x2
    local real y2

    if GetSpellAbilityId() == 'A002' then
        set x1 = GetUnitX(u)
        set y1 = GetUnitY(u)
        set x2 = GetSpellTargetX()
        set y2 = GetSpellTargetY()
        set e = Util_AddSpecialEffectOffsetEx("BladeBeamFinalLarger.mdx", x1, y1, x2, y2, 200)
    endif

    set u = null
    set e = null
endfunction

function Retsu_init takes nothing returns nothing
    local trigger trig = CreateTrigger()

    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_CAST)
    call TriggerAddAction(trig, function RetsuQ_act)

    set trig = null
endfunction

endlibrary
Util_AddSpecialEffectOffsetEx() is from the Util library. It creates a Special Effect at a position offset by your specified distance (200 in this case) based on the given x/y coordinates (angle between caster's x/y and spell's x/y). This Ex() version also makes the Special Effect face the direction it's going to move towards, which I believe is exactly what you're trying to achieve.

Note that the Special Effect e will leak if you don't destroy it when you're finished with it. I assumed you wanted to do more with it so I didn't destroy it myself.
 

Attachments

  • Math Utility Example 1.w3m
    19 KB · Views: 1
Last edited:
Level 7
Joined
Sep 16, 2016
Messages
185
It's nice to get used to using x/y coordinates when working in Jass/Lua. Locations are often an extra and unnecessary step.

Here's a little Utility library I threw together, nothing special but it has some useful functions that could make your life easier. There's probably a better version of this on Hive and I recommend customizing it yourself to fit your specific needs:
vJASS:
library Util

    globals
        real PI = 3.14159274
        real DEG2RAD = PI / 180
        real RAD2DEG = 180 / PI
        real X = 0 // Used to mimic returning two reals at once
        real Y = 0 // Used to mimic returning two reals at once
        effect SFX = null // Helps avoid a memory leak
    endglobals

    // Angle between points
    function AngleBetweenXY takes real x1, real y1, real x2, real y2 returns real
        return 180 + (RAD2DEG * Atan2(y1 - y2, x1 - x2))
    endfunction

    function AngleBetweenXYRad takes real x1, real y1, real x2, real y2 returns real
        return PI + Atan2(y1 - y2, x1 - x2)
    endfunction

    function AngleBetweenUXY takes unit u, real x2, real y2 returns real
        local real x1 = GetUnitX(u)
        local real y1 = GetUnitY(u)
        return 180 + (RAD2DEG * Atan2(y1 - y2, x1 - x2))
    endfunction

    function AngleBetweenUXYRad takes unit u, real x2, real y2 returns real
        local real x1 = GetUnitX(u)
        local real y1 = GetUnitY(u)
        return PI + Atan2(y1 - y2, x1 - x2)
    endfunction

    // Polar offset
    function GetOffsetPosition takes real x, real y, real offset, real degrees returns nothing
        set X = x + (offset * Cos(DEG2RAD * degrees))
        set Y = y + (offset * Sin(DEG2RAD * degrees))
    endfunction

    function GetOffsetPositionRad takes real x, real y, real offset, real radians returns nothing
        set X = x + (offset * Cos(radians))
        set Y = y + (offset * Sin(radians))
    endfunction

    function GetOffsetPositionU takes unit u, real offset, real degrees returns nothing
        set X = GetUnitX(u) + (offset * Cos(DEG2RAD * degrees))
        set Y = GetUnitY(u) + (offset * Sin(DEG2RAD * degrees))
    endfunction

    function GetOffsetPositionURad takes unit u, real offset, real radians returns nothing
        set X = GetUnitX(u) + (offset * Cos(radians))
        set Y = GetUnitY(u) + (offset * Sin(radians))
    endfunction

    // Creates a special effect offset by a set distance in a direction based on the given coordinates:
    public function AddSpecialEffectOffset takes string modelName, real x1, real y1, real x2, real y2, real offset returns effect
        local real angle = AngleBetweenXY(x1, y1, x2, y2) // reverse parameters to reverse direction
        call GetOffsetPosition(x1, y1, offset, angle) // sets the global X and Y variables
        return AddSpecialEffect(modelName, X, Y)
    endfunction

    // Like AddSpecialEffectOffset, but also makes the special effect face the direction:
    public function AddSpecialEffectOffsetEx takes string modelName, real x1, real y1, real x2, real y2, real offset returns effect
        local real angle = AngleBetweenXY(x1, y1, x2, y2) // reverse parameters to reverse direction
        call GetOffsetPosition(x1, y1, offset, angle) // sets the global X and Y variables
        set SFX = AddSpecialEffect(modelName, X, Y)
        call BlzSetSpecialEffectYaw(SFX, angle * DEG2RAD) // yaw uses radians so we need to convert
        return SFX
    endfunction

endlibrary

Here's your code, rewritten to use it's own library as well as the Util library. I also fixed the memory leaks:
vJASS:
library Retsu initializer Retsu_init requires Util

function RetsuQ_act takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local effect e = null
    local real x1
    local real y1
    local real x2
    local real y2

    if GetSpellAbilityId() == 'A002' then
        set x1 = GetUnitX(u)
        set y1 = GetUnitY(u)
        set x2 = GetSpellTargetX()
        set y2 = GetSpellTargetY()
        set e = Util_AddSpecialEffectOffsetEx("BladeBeamFinalLarger.mdx", x1, y1, x2, y2, 200)
    endif

    set u = null
    set e = null
endfunction

function Retsu_init takes nothing returns nothing
    local trigger trig = CreateTrigger()

    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_CAST)
    call TriggerAddAction(trig, function RetsuQ_act)

    set trig = null
endfunction

endlibrary
Util_AddSpecialEffectOffsetEx() is from the Util library. It creates a Special Effect at a position offset by your specified distance (200 in this case) based on the given x/y coordinates (angle between caster's x/y and spell's x/y). This Ex() version also makes the Special Effect face the direction it's going to move towards, which I believe is exactly what you're trying to achieve.

Note that the Special Effect e will leak if you don't destroy it when you're finished with it. I assumed you wanted to do more with it so I didn't destroy it myself.

I never expected to wake up to this detailed, amazing answer. Thank you so much Uncle, this is EXACTLY what I want. Vinz comment did help me fix the issue, but this library and your code snippet helps me a lot on better coding, thanks so much, unbelievable help.

Where could I find more jass libraries like this, specifically for moving this effect forward? Like the carrion swarm moves at 1500missile speed
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,543
I never expected to wake up to this detailed, amazing answer. Thank you so much Uncle, this is EXACTLY what I want. Vinz comment did help me fix the issue, but this library and your code snippet helps me a lot on better coding, thanks so much, unbelievable help.

Where could I find more jass libraries like this?
No problem, this thread is pretty new and seems to have exactly what you need:

All of these are found here:
 
Level 7
Joined
Sep 16, 2016
Messages
185
No problem, this thread is pretty new and seems to have exactly what you need:

All of these are found here:
Thank you again <3
 
Top