• 🏆 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] 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:
Level 40
Joined
Dec 14, 2005
Messages
10,532
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.
 
Level 4
Joined
Apr 2, 2006
Messages
32
>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 ^^
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
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.
Top