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

Spell Help - Advanced JASSers

Status
Not open for further replies.
Level 13
Joined
Nov 22, 2006
Messages
1,260
I don't usually ask this much, but I've been working on a spell that creates lightning orbs around the caster that rotate, if they hit a unit, they knockback it. I want someone to look at my code (this is maybe a bit complicated) Here's what doesn't work: I want the orbs to accelerate when rotating, so when they reach LightningOrbs_MaxSpeed they explode (lifespan of a lightning orb is LightningOrbs_Duration), but they don't accelerate, they don't rotate at all. Everything else works, they knockback a unit if they hit it etc.

There's the problem about the angle, it doesn't change, but when the caster moves, lightning orbs move with him, so SetUnitX/SetUnitY works, the angle just won't change......

JASS:
constant function LightningOrbs_SpellId takes nothing returns integer
    return 'A000'
endfunction

constant function LightningOrbs_OrbId takes nothing returns integer
    return 'h000'
endfunction

constant function LightningOrbs_OrbCount takes integer level returns integer
    return 4 + 2 * level
endfunction

constant function LightningOrbs_Duration takes nothing returns real
    return 20.0
endfunction

constant function LightningOrbs_KnockbackDist takes real level returns real
    return 200.0 + 100.0 * level
endfunction

constant function LightningOrbs_Damage takes real level returns real
    return 50.0 + 50.0 * level
endfunction

constant function LightningOrbs_Distance takes nothing returns real
    return 300.0
endfunction

constant function LightningOrbs_Height takes nothing returns real
    return 100.0
endfunction

constant function LightningOrbs_OrbCollision takes nothing returns real
    return 70.0
endfunction

constant function LightningOrbs_MaxSpeed takes nothing returns real
    return 15.0
endfunction

constant function LightningOrbs_CastSFX takes nothing returns string
    return "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
endfunction

constant function LightningOrbs_LightningSFX takes nothing returns string
    return "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
endfunction

//===========================================================================

function LightningOrbs_OrbHit takes nothing returns nothing
    local trigger t = GetTriggeringTrigger()
    local unit c = GetTriggerUnit()
    local unit u = GetHandleUnit(t, "u")
    local real x1 = GetUnitX(c)
    local real y1 = GetUnitY(c)
    local real x2 = GetUnitX(u)
    local real y2 = GetUnitY(u)
    local integer lvl = GetHandleInt(t, "lvl")
    local real dmg = LightningOrbs_Damage(I2R(lvl))
    local real d = LightningOrbs_KnockbackDist(I2R(lvl))
    local real a = Atan2(y1 - y2, x1 - x2)
    local player p = GetOwningPlayer(u)
    call UnitDamageTarget(u, c, dmg, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
    call KillUnit(u)
    call Knockback(c, d, a, 1, 0, null, LightningOrbs_LightningSFX())
    call DestroyTrigger(t)
    set t = null
    set c = null
    set u = null
    set p = null
endfunction

//===========================================================================

function Trig_Lightning_Orbs_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == LightningOrbs_SpellId()
endfunction

function LightningOrbs_TimerDestroy takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer n = GetHandleInt(t, "n")
    local integer i = 1
    local trigger array trig
    loop
        exitwhen i > n
        set trig[i] = GetHandleTrigger(t, "trig" + I2S(i))
        call DestroyTrigger(trig[i])
        set trig[i] = null
    endloop
    call FlushHandleLocals(t)
    call DestroyTimer(t)
    set t = null
endfunction

function LightningOrbs_Rotate takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit c = GetHandleUnit(t, "c")
    local group g = GetHandleGroup(t, "g")
    local integer i = GetHandleInt(t, "i")
    local group g2 = CreateGroup()
    local real x = GetUnitX(c)
    local real y = GetUnitY(c)
    local integer q = R2I(LightningOrbs_Duration()/Frequency())
    local real a = 10 * bj_DEGTORAD
    local real a1
    local unit u
    local real x1
    local real y1
    call GroupAddGroup(g, g2)
    loop
        set u = FirstOfGroup(g2)
        exitwhen u == null
        call GroupRemoveUnit(g2, u)
        set a1 = GetHandleReal(u, "a") + a
        set x1 = x + LightningOrbs_Distance() * Cos(a1)
        set y1 = y + LightningOrbs_Distance() * Sin(a1)
        call SetUnitX(u, x1)
        call SetUnitY(u, y1)
        call SetHandleReal(u, "a", a1)
    endloop
    if i >= q then
        call FlushHandleLocals(t)
        call DestroyTimer(t)
    else
        call SetHandleInt(t, "i", i + 1)
    endif
    call DestroyGroup(g2)
    set t = null
    set c = null
    set g = null
    set g2 = null
endfunction

function Trig_Lightning_Orbs_Actions takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local unit u
    local real x = GetUnitX(c)
    local real y = GetUnitY(c)
    local real x1
    local real y1
    local integer lvl = GetUnitAbilityLevel(c, LightningOrbs_SpellId())
    local integer n = LightningOrbs_OrbCount(lvl)
    local integer i = 1
    local real a = (360/I2R(n)) * bj_DEGTORAD
    local player p = GetOwningPlayer(c)
    local trigger array trig
    local timer t = CreateTimer()
    local timer v = CreateTimer()
    local group g = CreateGroup()
    call SetHandleInt(t, "n", n)
    loop
        exitwhen i > n
        set trig[i] = CreateTrigger()
        set x1 = x + LightningOrbs_Distance() * Cos(a*i)
        set y1 = y + LightningOrbs_Distance() * Sin(a*i)
        set u = CreateUnit(p, LightningOrbs_OrbId(), x1, y1, 0)
        call GroupAddUnit(g, u)
        call SetHandleReal(u, "a", a*i)
        call SetUnitFlyHeight(u, LightningOrbs_Height(), 0)
        call UnitApplyTimedLife(u, 'BTLF', LightningOrbs_Duration())
        call SetHandleHandle(trig[i], "u", u)
        call SetHandleInt(trig[i], "lvl", lvl)
        call TriggerRegisterUnitInRange(trig[i], u, LightningOrbs_OrbCollision(), null)
        call TriggerAddAction(trig[i], function LightningOrbs_OrbHit)
        call SetHandleHandle(t, "trig" + I2S(i), trig[i])
        set trig[i] = null
        set i = i + 1
    endloop
    call TimerStart(t, LightningOrbs_Duration(), false, function LightningOrbs_TimerDestroy)
    call SetHandleHandle(v, "g", g)
    call SetHandleHandle(v, "c", c)
    call TimerStart(v, Frequency(), true, function LightningOrbs_Rotate)
    set t = null
    set c = null
    set u = null
    set p = null
endfunction

//===========================================================================
function InitTrig_Lightning_Orbs takes nothing returns nothing
    local integer i = 0
    set gg_trg_Lightning_Orbs = CreateTrigger(  )
    loop
        call TriggerRegisterPlayerUnitEvent(gg_trg_Lightning_Orbs, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition( gg_trg_Lightning_Orbs, Condition( function Trig_Lightning_Orbs_Conditions ) )
    call TriggerAddAction( gg_trg_Lightning_Orbs, function Trig_Lightning_Orbs_Actions )
endfunction

Knockback is a function I made, it works, don't worry about that. Frequency function is in my map header and it goes like this:

JASS:
constant function Frequency takes nothing returns real
    return 0.035
endfunction

Thanks in advance, I'll give +rep to the one who solves the problem, because only the experienced ones can follow the code (at least I have a hard time following it)
 
Last edited:
Level 15
Joined
Feb 15, 2006
Messages
851
I've had serious problems with the atan2 function and I think this is the problem.

I suggest to implement your own Atan2 function based in this information: http://en.wikipedia.org/wiki/Atan2

I'd use this formula to develop a Atan3:

d00b70e07e17dfede3023203e9a92416.png

I hope it solves your problem.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
I've never had any problems with Atan2, moyack. I wouldn't be surprised if what you showed there IS exactly what warcraft does, and custom functions are hellishly slow.

By the way, you don't need to use an Array of triggers. Just null the variable outside the loop, and reuse it every loop iteration.

EDIT: Note; Atan2 returns radians, Silvenon. You seem to be trying to convert it to radians from radians.
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Yeah I know, that's what I said up there :) The more bj_DEGTORAD I use, the smaller the number gets (and more screwy), right? I updated the code, and made the movement linear, not accelerative. It seems to move normally, but sometimes it knockbacks more than one unit on a single orb. The problem here is that NewGenPack says "Hit op limit in function Trig_Lightning_Orbs_Actions" (that's why I PMd you Pooty). It seems like I'm using a massive loop?

Please explain your suggestion about the trigger array, I really want to improve that, but I'm not sure what you mean.
 
Level 15
Joined
Feb 15, 2006
Messages
851
Atan2 doesn't have issues with the values. The problem is with the concept of measuring angles respect what point. If you have one unit with coordinates (10, 10) and other unit with coordinate (20, 20), if you measure the angle respect the first unit, you will obtain 45º, and if you do that respect to the second unit, OMG... 45º too... when it should be 225º.

That's what I mean.
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Oh, I didn't know that, thanks :) Hey Pooty, I think I know why it said "Hit op limit in function Trig_Lightning_Orbs_Actions", maybe because I didn't cleaned attached variables and it reached the gamecache limit?

And please explain your trigger suggestion (not being an array)

EDIT: Actually it says "Hit op limit in function LightningOrbs_TimerDestroy", does that change anything?
 
Last edited:
Level 40
Joined
Dec 14, 2005
Messages
10,532
Err... moyack... it should be 45 either way.
Code:
             (20,20)
             /
           /
         /
        (10,10)
      /
    /
|_

(bad ASCII art ftw)


heheh, silv, you forgot to set i = i + 1 in LightingOrbs_TimerDestroy

Also, as for the trigger array...

Instead of doing something like

JASS:
local trigger array trig
local integer i = 0
loop
    exitwhen i > asdf
    set trig[i] = CreateTrigger()
    //do something to trig[i]
    set trig[i] = null
    set i = i + 1
endloop

You can do..

JASS:
local trigger trig
local integer i = 0
loop
    exitwhen i > asdf
    set trig = CreateTrigger()
    //do something to trig
    set i = i + 1
endloop
set trig = null
 
Status
Not open for further replies.
Top