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

[Trigger] 3 Missiles Cone Spell

Status
Not open for further replies.

sentrywiz

S

sentrywiz

I'm wondering how to make a spell that fires 3 projectiles at the same time with about 30-45 degree difference. I already know how to make a custom missile fired with triggers but I also tried to make this myself and I tried to find the other points like:

- point 1
- point 2 (point 1, 90 degrees, 200 offset)
- point 3 (point 1, 270 degrees, 200 offset)

However this didn't pan out as I would of hoped.

Basically its a multishot spell.

Either way here's an image of what I am aiming for:

multishot.jpg

I know the main point is found by [Target point of Ability being cast] but I don't know how to find the other two points.
 
  • Unit - Order (Your Dummy Unit) to (Your Spell) ((Position of (Your Unit)) offset by ((Angle from (Position of (Your Unit)) to (Target point of issued order)) -/+ 45.00) towards 0.00 degrees)

Should be "Distance" I guess, not "Angle" from two points?

@sentrywiz, if you dont know about memory leaks, read Things That Leak
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Angle of point 1 and position of caster - 45
Angle of point 1 and position of caster + 45

?

EDIT:
  • Unit - Order (Your Dummy Unit) to (Your Spell) ((Position of (Your Unit)) offset by ((Angle from (Position of (Your Unit)) to (Target point of issued order)) -/+ 45.00) towards 0.00 degrees)

Managed to leak six times in one line :/ (technically two lines)

JASS:
local real angle = GetUnitFacing(caster)
local real leftShot = angle + 45 * bj_DEGTORAD //bj_PI / 4
local real rightShot = angle - 45 * bj_DEGTORAD

local real firstShotX = GetUnitX(caster) + Cos(angle)
local real firstShotY = GetUnitY(caster) + Sin(angle)

local real leftShotX = GetUnitX(caster) + Cos(leftShot)
local real leftShotY = GetUnitY(caster) + Sin(leftShot)

local real rightShotX = GetUnitX(caster) + Cos(rightShot)
local real rightShotY = GetUnitY(caster) + Sin(rightShot)
 

sentrywiz

S

sentrywiz

Many thanks @Hera, @IcemanBo and @Arhowk.

I do know how to fix leaks, that wasn't my trigger, it was Hera's.

So its first time the original point, the second time is -45 degrees and third time is +45 degrees.

So what hera wrote but in the degrees part?
Mind someone making a dummy trigger just to show me?
With variables instead of just bluntly using the entire order unit to cast to point trigger
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Many thanks @Hera, @IcemanBo and @Arhowk.

I do know how to fix leaks, that wasn't my trigger, it was Hera's.

So its first time the original point, the second time is -45 degrees and third time is +45 degrees.

So what hera wrote but in the degrees part?
Mind someone making a dummy trigger just to show me?
With variables instead of just bluntly using the entire order unit to cast to point trigger

Check my trigger.. ;/
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
I made this very quickly in vJASS, I'll highlight the part that might interest you :
JASS:
scope Test
    //native UnitAlive takes unit u returns boolean
    
    globals
        private constant integer SPELL_ID = 'A000'
        private constant integer MISS_ID = 'M000'
        private constant real ANGLE /*In radian*/ = bj_PI/4
        private constant integer OFFSET = 200
        private constant real FPS = 0.0312500
        private constant real SPEED = 500.
        private constant real DISTANCE =500.
        private constant real AOE = 200.
        private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
        private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
    endglobals
    
    private constant function Damage takes integer level returns real
        return 60.*level
    endfunction
    
    private struct Dummy extends array
        unit targ
        real temp
        thistype prev
        thistype next
        static integer count
        static group g
        static timer period
        
        method destroy takes nothing returns nothing
            if this.next != 0 then
                set this.next.prev = this.prev
            endif
            set this.prev.next = this.next
            call GroupRemoveUnit(g, this.targ)
            set this.targ = null
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
            if thistype(0).next == 0 then
                call PauseTimer(period)
            endif
        endmethod
        
        static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next
            loop
                exitwhen this == 0
                set this.temp = this.temp - FPS
                if this.temp <= 0 then
                    call this.destroy()
                endif
                set this = this.next
            endloop
        endmethod
        
        static method is takes unit u returns boolean
            return IsUnitInGroup(u,g)
        endmethod
        
        static method add takes unit u, real r returns nothing
            local thistype this
            if thistype(0).prev == 0 then
                set count = count + 1
                set this = count
            else
                set this = thistype(0).prev
                set thistype(0).prev = thistype(0).prev.prev
            endif
            if thistype(0).next == 0 then
                call TimerStart(period, FPS, true, function thistype.periodic)
            else
                set thistype(0).next.prev = this
            endif
            set this.next = thistype(0).next
            set thistype(0).next = this
            set this.prev = thistype(0)
            set this.targ = u
            set this.temp = r
            call GroupAddUnit(g, u)
        endmethod
        
        static method onInit takes nothing returns nothing
            set count = 0
            set g = CreateGroup()
            set period = CreateTimer()
        endmethod
    endstruct
    
    private struct Core extends array
        unit missile
        unit caster
        real dmg
        real X
        real Y
        integer steps
        thistype prev
        thistype next
        static timer period
        static integer count
        static group g
        
        method destroy takes nothing returns nothing
            if this.next != 0 then
                set this.next.prev = this.prev
            endif
            set this.prev.next = this.next
            set this.missile = null
            set this.caster = null
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
            if thistype(0).next == 0 then
                call PauseTimer(period)
            endif
        endmethod
        
        static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next
            local unit u
            local real x
            local real y
            local player p
            loop
                exitwhen this == 0
                set x = GetUnitX(this.missile)+this.X
                set y = GetUnitY(this.missile)+this.Y
                call SetUnitX(this.missile, x)
                call SetUnitY(this.missile, y)
                set p = GetOwningPlayer(this.missile)
                call GroupEnumUnitsInRange(g, x, y, AOE, null)
                loop
                    set u = FirstOfGroup(g)
                    exitwhen u == null
                    call GroupRemoveUnit(g,u)
                    if IsUnitEnemy(u, p) and UnitAlive(u) then
                        call UnitDamageTarget(this.caster, u, this.dmg, true, false, A_TYPE, D_TYPE, null)
                        call Dummy.add(u,1)
                    endif
                endloop
                set this.steps = this.steps - 1
                if this.steps == 0 then
                    call this.destroy()
                endif
                set this = this.next
            endloop
            set p = null
        endmethod
        
        static method cond takes nothing returns boolean
            local thistype this
            local real x
            local real y
            local real tx
            local real ty
            local integer lvl
            local integer i
            local unit u
            local player p
            local real angle
            if GetSpellAbilityId() == SPELL_ID then
                set i = 0
                set u = GetTriggerUnit()
                set x = GetUnitX(u)
                set y = GetUnitY(u)
                set tx = GetSpellTargetX()
                set ty = GetSpellTargetY()
                set angle = Atan2(ty-y, tx-x) - ANGLE
                set lvl = GetUnitAbilityLevel(u, SPELL_ID)
                set p = GetOwningPlayer(u)
                loop
                    exitwhen i>3
                    if thistype(0).prev == 0 then
                        set count = count + 1
                        set this = count
                    else
                        set this = thistype(0).prev
                        set thistype(0).prev = thistype(0).prev.prev
                    endif
                    if thistype(0).next == 0 then
                        call TimerStart(period, FPS, true, function thistype.periodic)
                    else
                        set thistype(0).next.prev = this
                    endif
                    set this.next = thistype(0).next
                    set thistype(0).next = this
                    set this.prev = thistype(0)
                    set this.caster = u
                    set this.dmg = Damage(lvl)
                    set this.missile = CreateUnit(p, MISS_ID, x+OFFSET*Cos(angle), y+OFFSET*Sin(angle), angle)
                    set this.X = FPS*SPEED*Cos(angle)
                    set this.Y = FPS*SPEED*Sin(angle)
                    set this.steps = R2I(DISTANCE/SPEED/FPS)
                    set angle = angle + ANGLE
                    set i = i + 1
                endloop
                set u = null
                set p = null //Safety is costless
            endif
            return false
        endmethod
        
        static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.cond))
            set period = CreateTimer()
            set g = CreateGroup()
            set count = 0
            set t =null
        endmethod
    endstruct
endscope

JASS:
static method cond takes nothing returns boolean
            local thistype this
            local real x
            local real y
            local real tx
            local real ty
            local integer lvl
            local integer i
            local unit u
            local player p
            local real angle
            if GetSpellAbilityId() == SPELL_ID then
                set i = 0
                set u = GetTriggerUnit()
                set x = GetUnitX(u)
                set y = GetUnitY(u)
                set tx = GetSpellTargetX()
                set ty = GetSpellTargetY()
                set angle = Atan2(ty-y, tx-x) - ANGLE
                set lvl = GetUnitAbilityLevel(u, SPELL_ID)
                set p = GetOwningPlayer(u)
                loop
                    exitwhen i>3
                    // DONT TAKE CARE IT IS ALLOCATOR
                    /*
                    if thistype(0).prev == 0 then
                        set count = count + 1
                        set this = count
                    else
                        set this = thistype(0).prev
                        set thistype(0).prev = thistype(0).prev.prev
                    endif
                    if thistype(0).next == 0 then
                        call TimerStart(period, FPS, true, function thistype.periodic)
                    else
                        set thistype(0).next.prev = this
                    endif
                    set this.next = thistype(0).next
                    set thistype(0).next = this
                    set this.prev = thistype(0)*/
                    set this.caster = u
                    set this.dmg = Damage(lvl)
                    set this.missile = CreateUnit(p, MISS_ID, x+OFFSET*Cos(angle), y+OFFSET*Sin(angle), angle)
                    set this.X = FPS*SPEED*Cos(angle)
                    set this.Y = FPS*SPEED*Sin(angle)
                    set this.steps = R2I(DISTANCE/SPEED/FPS)
                    set angle = angle + ANGLE
                    set i = i + 1
                endloop
                set u = null
                set p = null //Safety is costless
            endif
            return false
        endmethod
 

sentrywiz

S

sentrywiz

Guys this is JASS.

I don't do JASS. GUI only please.

I'm not asking you to do my entire spell, just show me how are
to find the three points where the missiles are supposed to go to.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Guys this is JASS.

I don't do JASS. GUI only please.

I'm not asking you to do my entire spell, just show me how are
to find the three points where the missiles are supposed to go to.

My snip showed how to find the x/y of each individual missile. Hera's showed how to find the point of each individual missile. What more do you desire?
 

sentrywiz

S

sentrywiz

My snip showed how to find the x/y of each individual missile. Hera's showed how to find the point of each individual missile. What more do you desire?

Hera didn't get the trigger right imo.
You did show me jass in a way I can understand it.
Only I didn't understand "bj_DEGTORAD"? What is it?
Because the formulae is:

local real angle = GetUnitFacing(caster)
local real leftShot = angle + 45 * bj_DEGTORAD //bj_PI / 4
local real rightShot = angle - 45 * bj_DEGTORAD

Since in GUI I don't need the X and Y of the point, the rest of your jass
code isn't working for me. However this part is -- when I understand what bj_DEGTORAD is.

Sorry made it from scratch didn't think about GUI nor JASS.

Anyway the formulas for the cone are right there and easier to understand when written

Thank you for your spell. If only I could understand it :D
Still thanks.
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
The problem is that in GUI you use location which is a bit boring and leaky ....

So the matter is this (see picture):

You have S(x;y) which is the position of the caster.
Admitting that the caster casts the spell at the position B(x';y').
To get A and C :
First we get the angle between S and B : set angle = Atan2(y'-y,x'-x) or in GUI it is called Angle Between Points.

A = (x+distance*Cos(angle+45degrees);y+distance*Sin(angle+45degrees))
C = (x+distance*Cos(angle-45degrees);y+distance*Sin(angle-45degrees))

I maybe did a mistake if someone found so tell me ^^
 

Attachments

  • Powerful art.png
    Powerful art.png
    6.8 KB · Views: 59
Level 19
Joined
Aug 8, 2007
Messages
2,765
Managed to leak six times in one line :/ (technically two lines)

JASS:
local real angle = GetUnitFacing(caster) * bj_DEGTORAD
local real leftShot = angle + 45 * bj_DEGTORAD //bj_PI / 4
local real rightShot = angle - 45 * bj_DEGTORAD

local real firstShotX = GetUnitX(caster) + Cos(angle)
local real firstShotY = GetUnitY(caster) + Sin(angle)

local real leftShotX = GetUnitX(caster) + Cos(leftShot)
local real leftShotY = GetUnitY(caster) + Sin(leftShot)

local real rightShotX = GetUnitX(caster) + Cos(rightShot)
local real rightShotY = GetUnitY(caster) + Sin(rightShot)

Hera didn't get the trigger right imo.
You did show me jass in a way I can understand it.
Only I didn't understand "bj_DEGTORAD"? What is it?
Because the formulae is:

local real angle = GetUnitFacing(caster)
local real leftShot = angle + 45 * bj_DEGTORAD //bj_PI / 4
local real rightShot = angle - 45 * bj_DEGTORAD

Since in GUI I don't need the X and Y of the point, the rest of your jass
code isn't working for me. However this part is -- when I understand what bj_DEGTORAD is.


Thank you for your spell. If only I could understand it :D
Still thanks.

sorry i made a mistake in the local real angle line. bj_DEGTORAD is the mathematical constant pi/180, which converts a degree angle measure into a radian angle measure. (I thought using degrees instead of radians would make the code a bit more obvious) If you can't figure out how to convert my code into GUI, you could just copy paste the lines as custom script, change the names to udg_Your_Variable_Name_In_Gui, than make a new location at (Your Variable Name In Gui,whatever2)
 
Status
Not open for further replies.
Top