• Check out the results of the Techtree Contest #19!
  • 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 void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!

[JASS] Spell Problem With Coords

Status
Not open for further replies.
Level 4
Joined
Apr 2, 2006
Messages
32
JASS:
constant function CF_Ability_ID takes nothing returns integer 
  return  'A000'
endfunction

constant function CF_Dummy_Ability_ID takes nothing returns integer 
  return  'A001'
endfunction

constant function CF_Frost_Ball_ID takes nothing returns integer 
  return  'u001'
endfunction

constant function CF_Dummy_Caster_ID takes nothing returns integer 
  return  'u000'
endfunction

constant function CF_Timer_Interval takes nothing returns real 
  return  0.03
endfunction

constant function CF_AoE takes real r returns real 
  return  500.0 + r * 15.0
endfunction

constant function CF_Frost_Ball_Offset takes nothing returns real
    return  16.0
endfunction

constant function CF_Frost_Ball_Detect_Range takes nothing returns real
    return  100.0
endfunction

constant function CF_Jumps takes integer lvl returns integer
    return  1 + lvl * 2
endfunction

function Chain_Frost_Filter takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) != true and IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) != true and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetHandleUnit(GetExpiredTimer(), "d"))) and (GetFilterUnit() != GetHandleUnit(GetExpiredTimer(), "t"))
endfunction

function Chain_Frost_Actions_2 takes nothing returns nothing
    local timer tt   = GetExpiredTimer()
    local unit t     = GetHandleUnit(tt, "t")
    local unit d     = GetHandleUnit(tt, "d")
    local real r     = GetHandleReal(tt, "r")
    local real AoE   = GetHandleReal(tt, "AoE")
    local real X1    = GetUnitX(d)
    local real Y1    = GetUnitY(d)
    local real X2    = GetUnitY(t)
    local real Y2    = GetUnitY(t)
    local real ang   = Atan2(Y1-Y2,X1-X2)
    local real X3    = X1 + CF_Frost_Ball_Offset() * Cos(ang)
    local real Y3    = Y1 + CF_Frost_Ball_Offset() * Sin(ang)
    local real dist  = SquareRoot((X2-X1) * (X2-X1) + (Y2-Y1) * (Y2-Y1))
    local boolexpr b = Condition(function Chain_Frost_Filter)
    local unit dd
    local unit p
    local group g

    if dist > CF_Frost_Ball_Detect_Range() then
        call SetUnitPosition(d, X3, Y3)
        call SetUnitFacing(d, ang * bj_RADTODEG)
    else
        call SetUnitPosition(d, X2, Y2)        
        set dd = CreateUnit(GetOwningPlayer(d), CF_Dummy_Caster_ID(), X2, Y2, 0)
        call SetUnitAbilityLevel(dd, CF_Dummy_Ability_ID(), R2I(r))
        call IssueTargetOrder(dd, "frostnova", t)
        call SetHandleReal(tt, "jumps", GetHandleReal(tt, "jumps") - 1)
        set g = CreateGroup()
        call GroupEnumUnitsInRange(g, GetUnitX(d), GetUnitY(d), AoE, b)

        if CountUnitsInGroup(g) > 0 and GetHandleReal(tt, "jumps") > 0 then
            set p = GroupPickRandomUnit(g)
            call SetHandleHandle(tt, "t", p)
        else
            call RemoveUnit(d)
            call FlushHandleLocals(tt)
            call PauseTimer(tt) 
            call DestroyTimer(tt)
        endif

       call DestroyGroup(g)
    endif

    call DestroyBoolExpr(b)
    
    set tt = null
    set t = null
    set d = null
    set b = null
    set dd = null
    set p = null
    set g = null
endfunction

function Chain_Frost_Actions takes nothing returns nothing
    local unit u     = GetTriggerUnit()
    local unit t     = GetSpellTargetUnit()
    local timer tt   = CreateTimer()
    local real r     = GetUnitAbilityLevel(u, CF_Ability_ID())
    local real AoE   = CF_AoE(r)
    local real jumps = CF_Jumps(R2I(r))
    local real X1    = GetUnitX(u)
    local real Y1    = GetUnitY(u)
    local real X2    = GetUnitX(t)
    local real Y2    = GetUnitY(t)
    local real ang   = Atan2(Y2-Y1,X2-X1)
    local unit d     = CreateUnit(GetOwningPlayer(u), CF_Frost_Ball_ID(), X1, Y1, ang * bj_RADTODEG)

    call SetHandleHandle(tt, "t", t)
    call SetHandleHandle(tt, "d", d)
    call SetHandleReal(tt, "r", r)
    call SetHandleReal(tt, "AoE", AoE)
    call SetHandleReal(tt, "jumps", jumps)
    call TimerStart(tt, CF_Timer_Interval(), true, function Chain_Frost_Actions_2)

    set u = null
    set t = null
    set tt = null
    set d = null
endfunction

function Chain_Frost_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == CF_Ability_ID() 
endfunction

function InitTrig_Chain_Frost takes nothing returns nothing
    set gg_trg_Chain_Frost = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Chain_Frost, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Chain_Frost, Condition( function Chain_Frost_Conditions ) )
    call TriggerAddAction( gg_trg_Chain_Frost, function Chain_Frost_Actions )
endfunction
The objective of the spell is to send a ball of frost that launches itself to a number of targets, which are random after the initial one has been damaged.

I aimed to make this spell the same as DotA's Chain Frost.
But, the frost ball doesn't move properly - it travels at a completely different angle to that between the ball and the current target (d & t) and doesn't look like it's going anywhere specific - just back and fourth, not really close at all to the t unit.

I tried using PolarProjections, instead - worked perfectly, but, I'd like to use X & Ys instead and I don't see any reason why it shouldn't be working the way as is.
The X & Ys are definately the problem, though I've never had one this "weird" before.

Thanks in advance.

EDIT: Figured out the problem - it was this line:
local real X2 = GetUnitY(t)... It should've been, GetUnitX(t).


So now I have 2 new questions:

1. Am I overwriting the handle "t" correctly, in this line: call SetHandleHandle(tt, "t", p), in the timer-callback function?
2. Sometimes it only damages the inital "t" unit, and then doesn't "chain".
What could be the problem?
 
Last edited:
If it doesn't chain, that's odd.

Yes, it's overwriting the "t" slot correctly.

Also, you should store "jumps" in an integer, subtract one from it, and use it again later; it's really inefficient to load something from a gamecache (especially with I2S(H2I()) thrown in to boot), and even loading it twice is a bad idea.
 
>I would use 'not bleh' instead of 'bleh != true', but that's a matter of preference

You mean like this:
not(GetFilterUnit() == GetHandleUnit(GetExpiredTimer(), "t"))
?

>I have this pet peeve with people who use .405 instead of 0 for the dead life check

I've heard that it's apparently faster than 0.
Probably rubbish, but I use .405 anyway ^^
 
not necessarily as a function, not is an operator like and/or (slightly different functionally, but same syntax)

I've heard that it's apparently faster than 0.
Probably rubbish, but I use .405 anyway ^^
I really really really highly doubt a floating point number is faster than an integer.

Most people say that it's because that units die at .405, but it doesn't matter anyways, 0 works. (And for an added bonus, it saves 3 bytes from your map size every time you use it :P)
 
Status
Not open for further replies.
Back
Top