Missle Collision, boolexpr filter help needed.

S

SixDemonBag

Guest
So, i just got the Jass NewGen Pack and decided to make a simple missle ability.
Problem is, i have no clue how to set the boolexpr filter of the collision detection to NOT detect the caster of the ability. I tried using GetTriggerUnit() but it didnt work at all. Right now it only effects Neutral Hostile units, but i want it to effect(or affect?) units who are enemys of the caster.
Also, the "pickedgroup" is a global variable, and thus there may be some mui problems with the spell.
Heres the code for the spell.
JASS:

globals
group pickedgroup = CreateGroup()
endglobals

struct spell
      unit missle
      unit caster
      location end
      real angle
endstruct

function Trig_Missle_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A000' ) ) then
        return false
    endif
    return true
endfunction

function True takes nothing returns boolean
    return ( GetOwningPlayer(GetFilterUnit()) == Player(PLAYER_NEUTRAL_AGGRESSIVE) )
endfunction

function collision takes nothing returns nothing
    if ( not ( IsUnitInGroup(GetEnumUnit(), pickedgroup) == true) ) then
        call GroupAddUnit(pickedgroup,GetEnumUnit())
        call AddSpecialEffect("Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl" ,GetUnitX(GetEnumUnit()),GetUnitY(GetEnumUnit()))
    else
    endif
endfunction

function Missle_Move takes nothing returns nothing
local timer t = GetExpiredTimer()
local spell data = GetHandleInt(t, "data")
local group collisiongroup = CreateGroup()

if (DistanceBetweenPoints(GetUnitLoc(data.missle),data.end)) > 10.00 then
    call SetUnitFacing(data.missle, data.angle)
    call SetUnitPosition(data.missle,GetUnitX(data.missle)+Cos(Deg2Rad(GetUnitFacing(data.missle)))*15,GetUnitY(data.missle)+Sin(Deg2Rad(GetUnitFacing(data.missle)))*15)
    call GroupEnumUnitsInRange(collisiongroup,GetUnitX(data.missle),GetUnitY(data.missle),150.00, Filter(function True))
    call ForGroup(collisiongroup,function collision)

else
    call GroupClear(pickedgroup)
    set collisiongroup = null
    call DestroyGroup(collisiongroup)
    call RemoveUnit(data.missle)
    call PauseTimer(t)
    call DestroyTimer(t)
    call data.destroy()
    call FlushHandleLocals(t)
endif
endfunction

function Trig_Missle_Actions takes nothing returns nothing
local spell data = spell.create()
local timer t = CreateTimer()
set data.caster = GetTriggerUnit()
set data.missle = CreateUnit(GetOwningPlayer(data.caster),'h002',GetUnitX(data.caster),GetUnitY(data.caster),GetUnitFacing(data.caster))
call SetUnitFlyHeight(data.missle, 100.00, 800.00)
set data.end = GetSpellTargetLoc()
set data.angle = AngleBetweenPoints(GetUnitLoc(data.caster),data.end)
call SetHandleInt(t, "data", data)
call TimerStart(t, 0.03, true, function Missle_Move)

endfunction

//===========================================================================
function InitTrig_Missle takes nothing returns nothing
    set gg_trg_Missle = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Missle, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Missle, Condition( function Trig_Missle_Conditions ) )
    call TriggerAddAction( gg_trg_Missle, function Trig_Missle_Actions )
endfunction

Help would be apreciated :)
 

AceLegend90

New Member
Reaction score
6
Use something like:

JASS:
function True takes nothing returns boolean
    if IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) then
        return false
    elseif GetWidgetLife(GetFilterUnit()) <= 0. then
        return false
    elseif IsUnitAlly(GetFilterUnit(), GetTriggerPlayer()) then
        return false
    elseif IsUnitInvisible(GetFilterUnit(), GetTriggerPlayer()) then
        return false
    elseif IsUnitInGroup(GetFilterUnit(), pickedgroup) then
        return false
    endif
    return true
endfunction


This checks if the filter unit is a structure, dead, an ally, or invisible and returns false if either one of those are true. If the filtering unit is neither a structure, dead, an ally, or invisible, it puts it into 'collisiongroup'.

However, I would use 'Condition(function True)' instead of 'Filter(function True)'.

EDIT: Bleh! I found the reason why it didn't work.
 
S

SixDemonBag

Guest
Thanks for the reply :)
Hmmm, i imput'd exactly that which you stated, however it still targets the caster and his allies. I do believe GetTriggerUnit() isnt working.
As a side note, i used a blademaster with windwalk and he was put into the group.
But buildings wernt, however.
I really dont know what would be wrong with
JASS:
    elseif IsUnitAlly(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) then
        return false

Unless it cant get the triggering unit or somthing.
The other ones work fine however (structure / dead unit)

EDIT: What would the differance between Filter and Condition be, anways?
 

AceLegend90

New Member
Reaction score
6
Here's the code you should use:

JASS:
globals
    group pickedgroup = CreateGroup()
    unit tempUnit
endglobals

struct spell
      unit missle
      unit caster
      location end
      real angle
endstruct

function Trig_Missle_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function True takes nothing returns boolean
    if IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) then
        return false
    elseif GetWidgetLife(GetFilterUnit()) <= 0. then
        return false
    elseif IsUnitAlly(GetFilterUnit(), GetOwningPlayer(tempUnit)) then
        return false
    elseif IsUnitInvisible(GetFilterUnit(), GetOwningPlayer(tempUnit)) then
        return false
    elseif IsUnitInGroup(GetFilterUnit(), pickedgroup) then
        return false
    endif
    return true
endfunction

function collision takes nothing returns nothing
    local unit pick = GetEnumUnit()

    call GroupAddUnit(pickedgroup, pick)
    call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl", GetUnitX(pick), GetUnitY(pick)))
endfunction

function Missle_Move takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local spell data = GetHandleInt(t, "data")
    local location missleLoc = GetUnitLoc(data.missle)
    local group collisiongroup = CreateGroup()

    if (DistanceBetweenPoints(missleLoc, data.end)) > 10.00 then
        call SetUnitFacing(data.missle, data.angle)
        call SetUnitPosition(data.missle, GetUnitX(data.missle) + Cos(Deg2Rad(GetUnitFacing(data.missle))) * 15, GetUnitY(data.missle) + Sin(Deg2Rad(GetUnitFacing(data.missle))) * 15)
        set tempUnit = data.caster
        call GroupEnumUnitsInRange(collisiongroup, GetUnitX(data.missle), GetUnitY(data.missle), 150.00, Condition(function True))
        call ForGroup(collisiongroup,function collision)
    else
        call GroupClear(pickedgroup)
        call RemoveUnit(data.missle)
        call PauseTimer(t)
        call DestroyTimer(t)
        call data.destroy()
        call FlushHandleLocals(t)
    endif

    call RemoveLocation(missleLoc)
    call DestroyGroup(collisiongroup)
    set missleLoc = null
    set collisiongroup = null
endfunction

function Trig_Missle_Actions takes nothing returns nothing
    local spell data = spell.create()
    local timer t = CreateTimer()
    set data.caster = GetTriggerUnit()
    set data.missle = CreateUnit(GetOwningPlayer(data.caster),'h002',GetUnitX(data.caster),GetUnitY(data.caster),GetUnitFacing(data.caster))
    call SetUnitFlyHeight(data.missle, 100.00, 800.00)
    set data.end = GetSpellTargetLoc()
    set data.angle = AngleBetweenPoints(GetUnitLoc(data.caster),data.end)
    call SetHandleInt(t, "data", data)
    call TimerStart(t, 0.03, true, function Missle_Move)
endfunction

//===========================================================================
function InitTrig_Missle takes nothing returns nothing
    set gg_trg_Missle = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Missle, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Missle, Condition(function Trig_Missle_Conditions))
    call TriggerAddAction(gg_trg_Missle, function Trig_Missle_Actions)
endfunction


Changes:

(1) Added 'tempUnit' to represent 'data.caster' because you cannot use functions like 'GetTriggerUnit()' in timer functions.
(2) Optimized 'Trig_Missle_Conditions'.
(3) Changed function 'True' to work as intended using 'tempUnit' that was set in 'Missle_Move'.
(4) Removed the leaks caused by 'collisiongroup' and 'GetUnitLoc(data.missle)'. You need to destroy your 'collisiongroup' every time since you create it every 0.03 seconds. The code you had before would only destroy the last 'collisiongroup' created.
 
S

SixDemonBag

Guest
Ah, now it works perfectly (However, I am unsure if it is MUI or not now)
Also, thanks for pointing out those leaks.
Gotta check and see if its MUI though =/
+ rep :thup:
 

AceLegend90

New Member
Reaction score
6
Ah, now it works perfectly (However, I am unsure if it is MUI or not now)
Also, thanks for pointing out those leaks.
Gotta check and see if its MUI though =/
+ rep :thup:

Currently, it isn't MUI because 'pickedgroup' is global, therefore would have too many units in it if two missiles are being casted.

Back up your old code and try this code to make it MUI:

JASS:
globals
    unit tempUnit
endglobals

struct spell
    unit missle
    unit caster
    location end
    real angle
    group picked = CreateGroup()
endstruct

function Trig_Missle_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function True takes nothing returns boolean
    if IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) then
        return false
    elseif GetWidgetLife(GetFilterUnit()) <= 0. then
        return false
    elseif IsUnitAlly(GetFilterUnit(), GetOwningPlayer(tempUnit)) then
        return false
    elseif IsUnitInvisible(GetFilterUnit(), GetOwningPlayer(tempUnit)) then
        return false
    endif
    return true
endfunction

function Missle_Move takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local spell data = GetHandleInt(t, "data")
    local location missleLoc = GetUnitLoc(data.missle)
    local group collisiongroup = CreateGroup()
    local unit pick

    if DistanceBetweenPoints(missleLoc, data.end) > 10.00 then
        call SetUnitFacing(data.missle, data.angle)
        call SetUnitPosition(data.missle, GetUnitX(data.missle) + Cos(Deg2Rad(GetUnitFacing(data.missle))) * 15, GetUnitY(data.missle) + Sin(Deg2Rad(GetUnitFacing(data.missle))) * 15)
        set tempUnit = data.caster
        call GroupEnumUnitsInRange(collisiongroup, GetUnitX(data.missle), GetUnitY(data.missle), 150.00, Condition(function True))
        loop
            set pick = FirstOfGroup(collisiongroup)
            exitwhen pick == null
            call GroupRemoveUnit(collisiongroup, pick)
            if not(IsUnitInGroup(pick, data.picked)) then
                call GroupAddUnit(data.picked, pick)
                call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl", GetUnitX(pick), GetUnitY(pick)))
            endif
        endloop
    else
        call DestroyGroup(data.picked)
        call RemoveUnit(data.missle)
        call PauseTimer(t)
        call DestroyTimer(t)
        call data.destroy()
        call FlushHandleLocals(t)
    endif

    call RemoveLocation(missleLoc)
    call DestroyGroup(collisiongroup)
    set missleLoc = null
    set collisiongroup = null
endfunction

function Trig_Missle_Actions takes nothing returns nothing
    local spell data = spell.create()
    local timer t = CreateTimer()
    set data.caster = GetTriggerUnit()
    set data.missle = CreateUnit(GetOwningPlayer(data.caster), 'h002', GetUnitX(data.caster), GetUnitY(data.caster), GetUnitFacing(data.caster))
    call SetUnitFlyHeight(data.missle, 100.00, 800.00)
    set data.end = GetSpellTargetLoc()
    set data.angle = AngleBetweenPoints(GetUnitLoc(data.caster),data.end)
    call SetHandleInt(t, "data", data)
    call TimerStart(t, 0.03, true, function Missle_Move)
endfunction

//===========================================================================
function InitTrig_Missle takes nothing returns nothing
    set gg_trg_Missle = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Missle, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Missle, Condition(function Trig_Missle_Conditions))
    call TriggerAddAction(gg_trg_Missle, function Trig_Missle_Actions)
endfunction


Changes:

(1) Instead of using a global 'pickedgroup', I substituted it with the group 'picked' in the struct 'Spell'. This way, every instance of the missile has its own picked group and would not interfere with each other. Of course, other parts of the code had to be changed around, such as adding a loop in 'Missle_Move' function to loop through 'collisiongroup' instead of using the 'ForGroup()' function.
 
S

SixDemonBag

Guest
Just tried what you said, works really well as multiple missles may effect the same unit.
I think i tried doing somthing like that before, but it didnt work out so well :(

There's just one last "problem" i can think of, which is that the caster variable would change if an enemy unit casted the spell right after your unit casted it, making your missle only affect enemys of your enemys (you) which seems pretty problematic..
I could be wrong however.
Anyways, i dont think you can transfer variables to function True so i am unsure how you could get around that =/
I'd + rep you again, but i cant right now :)

Edit: Going to bed, ill check any reply's tomorrow.
 

AceLegend90

New Member
Reaction score
6
Just tried what you said, works really well as multiple missles may effect the same unit.
I think i tried doing somthing like that before, but it didnt work out so well :(

There's just one last "problem" i can think of, which is that the caster variable would change if an enemy unit casted the spell right after your unit casted it, making your missle only affect enemys of your enemys (you) which seems pretty problematic..
I could be wrong however.
Anyways, i dont think you can transfer variables to function True so i am unsure how you could get around that =/
I'd + rep you again, but i cant right now :)

Edit: Going to bed, ill check any reply's tomorrow.

No, it wouldn't affect you because you set 'tempUnit' every time you need it. Since the global is instantaneously used, it should never work the way you described.

So, for example, you and your enemy cast a missile right at each other. The 'tempUnit' global will be switching from you and your enemy, depending on which missile is using the variable. When your missile hits your enemy, 'tempUnit' will be set to you and vice versa.
 

Viikuna

No Marlo no game.
Reaction score
265
You dont need those elseifs in True function, this works too:
JASS:
function True takes nothing returns boolean
    return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and GetWidgetLife(GetFilterUnit()) <= 0. and IsUnitAlly(GetFilterUnit(), GetOwningPlayer(tempUnit)) == false and IsUnitInvisible(GetFilterUnit(), GetOwningPlayer(tempUnit)) == false
endfunction


You should also use global group instead of local collinsiongroup

JASS:
globals
    private group TempG = CreateGroup()
endglobals


It is MUI, if you dont have any waits inside your loop. This saves you from creating&destroying a new group every 0.03sec.

JASS:
        call GroupEnumUnitsInRange(TempG, GetUnitX(data.missle), GetUnitY(data.missle), 150.00, Condition(function True))
        loop
            set pick = FirstOfGroup(TempG)
            exitwhen pick == null
            call GroupRemoveUnit(TempG, pick)
            if IsUnitInGroup(pick, data.picked) == false then
                call GroupAddUnit(data.picked, pick)
                call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl", GetUnitX(pick), GetUnitY(pick)))
            endif
        endloop
 
S

SixDemonBag

Guest
No, it wouldn't affect you because you set 'tempUnit' every time you need it. Since the global is instantaneously used, it should never work the way you described.

So, for example, you and your enemy cast a missile right at each other. The 'tempUnit' global will be switching from you and your enemy, depending on which missile is using the variable. When your missile hits your enemy, 'tempUnit' will be set to you and vice versa.

Thats neat.

You dont need those elseifs in True function, this works too:
JASS:
function True takes nothing returns boolean
    return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and GetWidgetLife(GetFilterUnit()) <= 0. and IsUnitAlly(GetFilterUnit(), GetOwningPlayer(tempUnit)) == false and IsUnitInvisible(GetFilterUnit(), GetOwningPlayer(tempUnit)) == false
endfunction


You should also use global group instead of local collinsiongroup

JASS:
globals
    private group TempG = CreateGroup()
endglobals


It is MUI, if you dont have any waits inside your loop. This saves you from creating&destroying a new group every 0.03sec.

JASS:
        call GroupEnumUnitsInRange(TempG, GetUnitX(data.missle), GetUnitY(data.missle), 150.00, Condition(function True))
        loop
            set pick = FirstOfGroup(TempG)
            exitwhen pick == null
            call GroupRemoveUnit(TempG, pick)
            if IsUnitInGroup(pick, data.picked) == false then
                call GroupAddUnit(data.picked, pick)
                call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl", GetUnitX(pick), GetUnitY(pick)))
            endif
        endloop

Optimization is key :) replaced collisiongroup with a global and it works fine, i clear when the missle reachs its destination and it seems to work great.
Thanks to both of you, problem solved. I learned a bunch in the process too.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top