• 🏆 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] Is this more efficient?

Status
Not open for further replies.
hey may some of you have seen my missile system (Missile Sys) but as trigger hapy said the unit collision is very unefficient...

now i have reworked it and want to hear if it's now better.

JASS:
library UnitCollision initializer Init
    globals
        private hashtable           UC_Hash
        private constant integer    Sphere     = 1
        private constant integer    Cylinder   = 2
        private real                MaxCollSize = 0.
        private constant integer    DummyId    = 'h000' // your private dummy unit
    endglobals
    
    function GetUnitCollSizeSphere takes unit u returns real
        return LoadReal( UC_Hash, GetUnitTypeId(u), 1)
    endfunction
    
    function GetUnitRadCylinder takes unit u returns real
        return LoadReal( UC_Hash, GetUnitTypeId(u), 1)
    endfunction
    
    function GetUnitHeightCylinder takes unit u returns real
        return LoadReal( UC_Hash, GetUnitTypeId(u), 2)
    endfunction
    
    function GetUnitType takes unit u returns integer
        return LoadInteger(UC_Hash,GetUnitTypeId(u),0)
    endfunction
    
    function AddUnitCollisionSphere takes integer uID, real rad returns nothing
        call SaveInteger(UC_Hash, uID, 0, Sphere)
        call SaveReal(UC_Hash, uID, 1, rad)
        if rad >= MaxCollSize then
            set MaxCollSize =rad+.5
        endif
    endfunction
    
    function AddUnitCollisionCylinder takes integer uID, real rad, real height returns nothing
        local real x = SquareRoot((rad*rad)+(height*height))
        call SaveInteger(UC_Hash, uID, 0, Cylinder)
        call SaveReal(UC_Hash, uID, 1, rad)
        call SaveReal(UC_Hash, uID, 2, height)
        if x >= MaxCollSize then
            set MaxCollSize = x+.5
        endif
    endfunction
    
    function CheckForCollision takes real x, real y, real z, real size, player p returns boolean
        local group			g = CreateGroup()
        local unit			u = null
        local real array	r
        local boolean		b = false
        local location      p1
        local location      p2
        call GroupEnumUnitsInRange( g, x, y, MaxCollSize, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null or b == true
            if GetUnitTypeId(u)!= DummyId and GetUnitState(u,UNIT_STATE_LIFE) > 0.405 then
                if GetUnitType(u) == Sphere then
                    set r[0] = x - GetUnitX(u)
                    set r[1] = y - GetUnitY(u)
                    set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                    set p1    = GetUnitLoc(u)
                    set p2   = Location(x,y)
                    set r[3] = (GetUnitFlyHeight(u)+GetLocationZ(p1))-(z+GetLocationZ(p2))
                    set r[4] = SquareRoot(r[2] * r[2] + r[3] * r[3])
                    set b = ((r[4] <= GetUnitCollSizeSphere(u)+size) and GetOwningPlayer(u) != p)
                    call RemoveLocation(p1)
                    call RemoveLocation(p2)
                elseif GetUnitType(u) == Cylinder then
                    set r[0] = x - GetUnitX(u)
                    set r[1] = y - GetUnitY(u)
                    set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                    set p1   = GetUnitLoc(u)
                    set p2   = Location(x,y)
                    set r[3] = GetUnitFlyHeight(u)
                    set b = (r[2] <= GetUnitRadCylinder(u)+size and z+GetLocationZ(p2) > r[3]-size+GetLocationZ(p1) and z+GetLocationZ(p2) < r[3]+GetUnitHeightCylinder(u)+size+GetLocationZ(p1) and GetOwningPlayer(u) != p)
                    call RemoveLocation(p1)
                    call RemoveLocation(p2)
                endif
            endif
            call GroupRemoveUnit(g,u)
            set u = null
        endloop
        call DestroyGroup(g)
        set g 	= null
        set u 	= null
        return b
    endfunction
    
    // extra function to damage units in range with the unit collision system
    // (simpel edit from the check for collision function)
    function DamageUnitInRange takes real x, real y, real z, real damage, real rad, unit damagedealer returns nothing
        local group			g = CreateGroup()
        local unit			u = null
        local real array	r
        local location      p1
        local location      p2
        call GroupEnumUnitsInRange( g, x, y, MaxCollSize, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            if GetUnitTypeId(u)!= DummyId and GetUnitState(u,UNIT_STATE_LIFE) > 0.405 then
                if GetUnitType(u) == Sphere then
                    set r[0] = x - GetUnitX(u)
                    set r[1] = y - GetUnitY(u)
                    set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                    set p1   = GetUnitLoc(u)
                    set p2   = Location(x,y)
                    set r[3] = (GetUnitFlyHeight(u)+GetLocationZ(p1))-(z+GetLocationZ(p2))
                    set r[4] = SquareRoot(r[2] * r[2] + r[3] * r[3])
                    if (r[4] <= GetUnitCollSizeSphere(u)+rad) and GetOwningPlayer(u) != GetOwningPlayer(damagedealer) then
                        call UnitDamageTarget(damagedealer, u, damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                    endif
                    call RemoveLocation(p1)
                    call RemoveLocation(p2)
                elseif GetUnitType(u) == Cylinder then
                    set r[0] = x - GetUnitX(u)
                    set r[1] = y - GetUnitY(u)
                    set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                    set p1   = GetUnitLoc(u)
                    set p2   = Location(x,y)
                    set r[3] = GetUnitFlyHeight(u)
                    if r[2] <= GetUnitRadCylinder(u)+rad and z+GetLocationZ(p2) > r[3]-rad+GetLocationZ(p1) and z+GetLocationZ(p2) < r[3]+GetUnitHeightCylinder(u)+rad+GetLocationZ(p1) and GetOwningPlayer(u) != GetOwningPlayer(damagedealer) then
                        call UnitDamageTarget(damagedealer, u, damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                    endif
                    call RemoveLocation(p1)
                    call RemoveLocation(p2)
                endif
            endif
            call GroupRemoveUnit(g,u)
            set u = null
        endloop
        call DestroyGroup(g)
        set g 	= null
        set u 	= null
    endfunction

    private function Init takes nothing returns nothing
        set UC_Hash = InitHashtable()
        call AddUnitCollisionSphere('h004',100)
        call AddUnitCollisionSphere('h001',30)
        call AddUnitCollisionSphere('h005',50)
        call AddUnitCollisionSphere('h007',90)
        call AddUnitCollisionCylinder('h002',50,45)
        call AddUnitCollisionCylinder('h008',45,100)
        call AddUnitCollisionCylinder('h006',100,240)
        call AddUnitCollisionCylinder('h003',60,280)
        call AddUnitCollisionCylinder('h009',12.5,35)
        call AddUnitCollisionCylinder('h00A',14,35)
    endfunction
endlibrary

JASS:
library UnitCollision initializer Init
    globals
        //------------------ small Setup part ---------------------
        private constant integer    Sphere           = 1
        private constant integer    Cylinder         = 2
        private constant integer    Dummy_Id         = 'h000' // your private dummy unit
        //----------------- end of the settings -------------------
        private location            Point1           = Location(0,0)
        private location            Point2           = Location(0,0)
        private hashtable           UC_Hash
        private real                Max_CollSize     = 0.
		private group 				Picked_Group	 = CreateGroup()
		private boolean				Collision_Check	 = false
		//---------------- stored things for the Unit Collision --------------
		private real				Stored_X		 = 0.
		private real				Stored_Y		 = 0.
		private real				Stored_Z		 = 0.
		private real				Stored_Size		 = 0.
		private player				Stored_Player	 = null
		// ------------ stored things for the Damage Units in range function ---------
		private real				Stored_Damage	 = 0.
		private unit				Stored_Damagedealer = null
    endglobals
    
    function GetUnitCollSizeSphere takes unit u returns real
        return LoadReal( UC_Hash, GetUnitTypeId(u), 1)
    endfunction
    
    function GetUnitRadCylinder takes unit u returns real
        return LoadReal( UC_Hash, GetUnitTypeId(u), 1)
    endfunction
    
    function GetUnitHeightCylinder takes unit u returns real
        return LoadReal( UC_Hash, GetUnitTypeId(u), 2)
    endfunction
    
    function GetUnitType takes unit u returns integer
        return LoadInteger(UC_Hash,GetUnitTypeId(u),0)
    endfunction
    
    function AddUnitCollisionSphere takes integer uID, real rad returns nothing
        call SaveInteger(UC_Hash, uID, 0, Sphere)
        call SaveReal(UC_Hash, uID, 1, rad)
        //-------------------------------------
        if rad >= Max_CollSize then
            set Max_CollSize =rad+.5
        endif
    endfunction
    
    function AddUnitCollisionCylinder takes integer uID, real rad, real height returns nothing
        local real x = SquareRoot((rad*rad)+(height*height))
        //-------------------------------------
        call SaveInteger(UC_Hash, uID, 0, Cylinder)
        call SaveReal(UC_Hash, uID, 1, rad)
        call SaveReal(UC_Hash, uID, 2, height)
        //-------------------------------------
        if x >= Max_CollSize then
            set Max_CollSize = x+.5
        endif
    endfunction
	
	function CheckForCollisionAction takes nothing returns boolean
	    local real array	r
		local unit 			u	= GetFilterUnit()
        call MoveLocation(Point2,Stored_X,Stored_Y)
        call MoveLocation(Point1,GetUnitX(u),GetUnitY(u))
        //-------------------------------------------------------------------
		if Collision_Check == false then
			if GetUnitTypeId(u)!= Dummy_Id and GetWidgetLife(u) > 0.405 then
                if GetUnitType(u) == Sphere then
                    //--------------------------------------
                    set r[0] = Stored_X - GetUnitX(u)
                    set r[1] = Stored_Y - GetUnitY(u)
                    set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                    //--------------------------------------
                    set r[3] = (GetUnitFlyHeight(u)+GetLocationZ(Point1))-(Stored_Z+GetLocationZ(Point2))
                    set r[4] = SquareRoot(r[2] * r[2] + r[3] * r[3])
                    //--------------------------------------
                    set Collision_Check = ((r[4] <= GetUnitCollSizeSphere(u)+Stored_Size) and GetOwningPlayer(u) != Stored_Player)
                    //--------------------------------------
                elseif GetUnitType(u) == Cylinder then
                    //--------------------------------------
                    set r[0] = Stored_X - GetUnitX(u)
                    set r[1] = Stored_Y - GetUnitY(u)
                    set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                    //--------------------------------------
                    set r[3] = GetUnitFlyHeight(u)
                    //--------------------------------------
                    set Collision_Check = (r[2] <= GetUnitRadCylinder(u)+Stored_Size and Stored_Z+GetLocationZ(Point2) > r[3]-Stored_Size+GetLocationZ(Point1) and Stored_Z+GetLocationZ(Point2) < r[3]+GetUnitHeightCylinder(u)+Stored_Size+GetLocationZ(Point1) and GetOwningPlayer(u) != Stored_Player)
                    //--------------------------------------
                endif
            endif
		endif
        //--------------------------------------
		set u	= null
        return false
	endfunction
    
    function CheckForCollision takes real x, real y, real z, real size, player p returns boolean
        set Stored_Player   = p
        set Stored_X        = x
        set Stored_Y        = y
        set Stored_Z        = z
        set Stored_Size     = size
        //-----------------------------------------------------------------
        call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, Filter(function CheckForCollisionAction))
        //-----------------------------------------------------------------
        set Picked_Group 	= null
        //-----------------------------------------------------------------
        return Collision_Check
    endfunction
    
//  |==========================================================================|
//  |--------------------------------------------------------------------------|
//  |==========================================================================|
    
    function DamageUnitsInRangeAction takes nothing returns boolean
        local unit			u = GetFilterUnit()
        local real array	r
        call MoveLocation(Point2,Stored_X,Stored_Y)
        call MoveLocation(Point1,GetUnitX(u),GetUnitY(u))
        //-------------------------------------------------------------------
        if GetUnitTypeId(u)!= Dummy_Id and GetWidgetLife(u) > 0.405 then
            if GetUnitType(u) == Sphere then
                //------------------------------------------------
                set r[0] = Stored_X - GetUnitX(u)
                set r[1] = Stored_Y - GetUnitY(u)
                set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                //------------------------------------------------
                set r[3] = (GetUnitFlyHeight(u)+GetLocationZ(Point1))-(Stored_Z+GetLocationZ(Point2))
                set r[4] = SquareRoot(r[2] * r[2] + r[3] * r[3])
                //---------------------------------------------------------------------------------------------------------------------------
                if (r[4] <= GetUnitCollSizeSphere(u)+Stored_Size) and GetOwningPlayer(u) != GetOwningPlayer(Stored_Damagedealer) then
                    call UnitDamageTarget(Stored_Damagedealer, u, Stored_Damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                endif
                //---------------------------------------------------------------------------------------------------------------------------
            elseif GetUnitType(u) == Cylinder then
                //----------------------------------------------------
                set r[0] = Stored_X - GetUnitX(u)
                set r[1] = Stored_Y - GetUnitY(u)
                set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                //------------------------------------------------
                set r[3] = GetUnitFlyHeight(u)
                //----------------------------------------------------------------------------------------------------------------------------------------------------------------
                if r[2] <= GetUnitRadCylinder(u)+Stored_Size and Stored_Z+GetLocationZ(Point2) > r[3]-Stored_Size+GetLocationZ(Point1) and Stored_Z+GetLocationZ(Point2) < r[3]+GetUnitHeightCylinder(u)+Stored_Size+GetLocationZ(Point1) and GetOwningPlayer(u) != GetOwningPlayer(Stored_Damagedealer) then
                    call UnitDamageTarget(Stored_Damagedealer, u, Stored_Damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                endif
                //----------------------------------------------------------------------------------------------------------------------------------------------------------------
            endif
        endif
        set u   = null
        return false
    endfunction
    
    function DamageUnitsInRange takes real x, real y, real z, real damage, real rad, unit damagedealer returns nothing
        set Stored_Damagedealer = damagedealer
        set Stored_Y        = y
        set Stored_Z        = z
        set Stored_Size     = rad
        set Stored_Damage   = damage
        //-------------------------------------------------------------------
        call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, Filter(function DamageUnitsInRangeAction))
        //-------------------------------------------------------------------
        set Picked_Group        = null
        set Stored_Damagedealer = null
    endfunction

    private function Init takes nothing returns nothing
        set UC_Hash = InitHashtable()
        //---------------------------------------------------------
        // This is a good place to add a collision to a unit type
        //---------------------------------------------------------
        call AddUnitCollisionSphere('h004',100)
        call AddUnitCollisionSphere('h001',30)
        call AddUnitCollisionSphere('h005',50)
        call AddUnitCollisionSphere('h007',90)
        call AddUnitCollisionCylinder('h002',50,45)
        call AddUnitCollisionCylinder('h008',45,100)
        call AddUnitCollisionCylinder('h006',100,240)
        call AddUnitCollisionCylinder('h003',60,280)
        call AddUnitCollisionCylinder('h009',12.5,35)
        call AddUnitCollisionCylinder('h00A',14,35)
    endfunction
endlibrary
 
Last edited by a moderator:
Level 11
Joined
Apr 29, 2007
Messages
826
because i don't know how xD

Huh?

JASS:
call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, null)
Becomes
JASS:
call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, Filter(function DamageUnitsInRangeAction))

Now you've got to replace GetEnumUnit() within DamageUnitsInRangeAction with GetFilterUnit()

And finally make it return false at the end.

JASS:
function CheckForCollisionAction takes nothing returns boolean

JASS:
//Bla
set p1 = null
set p2 = null
set u = null

return false
endfunction

Btw, you don't have to null parameters.
 
here is the newest code: (doesn't include the filter)
JASS:
library UnitCollision initializer Init
    globals
        //------------------ small Setup part ---------------------
        private constant integer    Sphere           = 1
        private constant integer    Cylinder         = 2
        private constant integer    Dummy_Id         = 'h000' // your private dummy unit
        //----------------- end of the settings -------------------
        private location            Point1           = Location(0,0)
        private location            Point2           = Location(0,0)
        private hashtable           UC_Hash
        private real                Max_CollSize     = 0.
		private group 				Picked_Group	 = CreateGroup()
		private boolean				Collision_Check	 = false
		//---------------- stored things for the Unit Collision --------------
		private real				Stored_X		 = 0.
		private real				Stored_Y		 = 0.
		private real				Stored_Z		 = 0.
		private real				Stored_Size		 = 0.
		private player				Stored_Player	 = null
		// ------------ stored things for the Damage Units in range function ---------
		private real				Stored_Damage	 = 0.
		private unit				Stored_Damagedealer = null
    endglobals
    
    function GetUnitCollSizeSphere takes unit u returns real
        return LoadReal( UC_Hash, GetUnitTypeId(u), 1)
    endfunction
    
    function GetUnitRadCylinder takes unit u returns real
        return LoadReal( UC_Hash, GetUnitTypeId(u), 1)
    endfunction
    
    function GetUnitHeightCylinder takes unit u returns real
        return LoadReal( UC_Hash, GetUnitTypeId(u), 2)
    endfunction
    
    function GetUnitType takes unit u returns integer
        return LoadInteger(UC_Hash,GetUnitTypeId(u),0)
    endfunction
    
    function AddUnitCollisionSphere takes integer uID, real rad returns nothing
        call SaveInteger(UC_Hash, uID, 0, Sphere)
        call SaveReal(UC_Hash, uID, 1, rad)
        //-------------------------------------
        if rad >= Max_CollSize then
            set Max_CollSize =rad+.5
        endif
    endfunction
    
    function AddUnitCollisionCylinder takes integer uID, real rad, real height returns nothing
        local real x = SquareRoot((rad*rad)+(height*height))
        //-------------------------------------
        call SaveInteger(UC_Hash, uID, 0, Cylinder)
        call SaveReal(UC_Hash, uID, 1, rad)
        call SaveReal(UC_Hash, uID, 2, height)
        //-------------------------------------
        if x >= Max_CollSize then
            set Max_CollSize = x+.5
        endif
    endfunction
	
	function CheckForCollisionAction takes nothing returns nothing
	    local real array	r
		local unit 			u	= GetEnumUnit()
        call MoveLocation(Point2,Stored_X,Stored_Y)
        call MoveLocation(Point1,GetUnitX(u),GetUnitY(u))
        //-------------------------------------------------------------------
		if Collision_Check == false then
			if GetUnitTypeId(u)!= Dummy_Id and GetWidgetLife(u) > 0.405 then
                if GetUnitType(u) == Sphere then
                    //--------------------------------------
                    set r[0] = Stored_X - GetUnitX(u)
                    set r[1] = Stored_Y - GetUnitY(u)
                    set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                    //--------------------------------------
                    set r[3] = (GetUnitFlyHeight(u)+GetLocationZ(Point1))-(Stored_Z+GetLocationZ(Point2))
                    set r[4] = SquareRoot(r[2] * r[2] + r[3] * r[3])
                    //--------------------------------------
                    set Collision_Check = ((r[4] <= GetUnitCollSizeSphere(u)+Stored_Size) and GetOwningPlayer(u) != Stored_Player)
                    //--------------------------------------
                elseif GetUnitType(u) == Cylinder then
                    //--------------------------------------
                    set r[0] = Stored_X - GetUnitX(u)
                    set r[1] = Stored_Y - GetUnitY(u)
                    set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                    //--------------------------------------
                    set r[3] = GetUnitFlyHeight(u)
                    //--------------------------------------
                    set Collision_Check = (r[2] <= GetUnitRadCylinder(u)+Stored_Size and Stored_Z+GetLocationZ(Point2) > r[3]-Stored_Size+GetLocationZ(Point1) and Stored_Z+GetLocationZ(Point2) < r[3]+GetUnitHeightCylinder(u)+Stored_Size+GetLocationZ(Point1) and GetOwningPlayer(u) != Stored_Player)
                    //--------------------------------------
                endif
            endif
		endif
        //--------------------------------------
		set u	= null
	endfunction
    
    function CheckForCollision takes real x, real y, real z, real size, player p returns boolean
        set Stored_Player   = p
        set Stored_X        = x
        set Stored_Y        = y
        set Stored_Z        = z
        set Stored_Size     = size
        //-----------------------------------------------------------------
        call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, null)
		call ForGroup(Picked_Group, function CheckForCollisionAction)
        //-----------------------------------------------------------------
        set Picked_Group 	= null
        //-----------------------------------------------------------------
        return Collision_Check
    endfunction
    
//  |==========================================================================|
//  |--------------------------------------------------------------------------|
//  |==========================================================================|
    
    function DamageUnitsInRangeAction takes nothing returns nothing
        local unit			u = GetEnumUnit()
        local real array	r
        call MoveLocation(Point2,Stored_X,Stored_Y)
        call MoveLocation(Point1,GetUnitX(u),GetUnitY(u))
        //-------------------------------------------------------------------
        if GetUnitTypeId(u)!= Dummy_Id and GetWidgetLife(u) > 0.405 then
            if GetUnitType(u) == Sphere then
                //------------------------------------------------
                set r[0] = Stored_X - GetUnitX(u)
                set r[1] = Stored_Y - GetUnitY(u)
                set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                //------------------------------------------------
                set r[3] = (GetUnitFlyHeight(u)+GetLocationZ(Point1))-(Stored_Z+GetLocationZ(Point2))
                set r[4] = SquareRoot(r[2] * r[2] + r[3] * r[3])
                //---------------------------------------------------------------------------------------------------------------------------
                if (r[4] <= GetUnitCollSizeSphere(u)+Stored_Size) and GetOwningPlayer(u) != GetOwningPlayer(Stored_Damagedealer) then
                    call UnitDamageTarget(Stored_Damagedealer, u, Stored_Damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                endif
                //---------------------------------------------------------------------------------------------------------------------------
            elseif GetUnitType(u) == Cylinder then
                //----------------------------------------------------
                set r[0] = Stored_X - GetUnitX(u)
                set r[1] = Stored_Y - GetUnitY(u)
                set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                //------------------------------------------------
                set r[3] = GetUnitFlyHeight(u)
                //----------------------------------------------------------------------------------------------------------------------------------------------------------------
                if r[2] <= GetUnitRadCylinder(u)+Stored_Size and Stored_Z+GetLocationZ(Point2) > r[3]-Stored_Size+GetLocationZ(Point1) and Stored_Z+GetLocationZ(Point2) < r[3]+GetUnitHeightCylinder(u)+Stored_Size+GetLocationZ(Point1) and GetOwningPlayer(u) != GetOwningPlayer(Stored_Damagedealer) then
                    call UnitDamageTarget(Stored_Damagedealer, u, Stored_Damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                endif
                //----------------------------------------------------------------------------------------------------------------------------------------------------------------
            endif
        endif
        set u   = null
    endfunction
    
    function DamageUnitsInRange takes real x, real y, real z, real damage, real rad, unit damagedealer returns nothing
        set Stored_Damagedealer = damagedealer
        set Stored_Y        = y
        set Stored_Z        = z
        set Stored_Size     = rad
        set Stored_Damage   = damage
        //-------------------------------------------------------------------
        call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, null)
        call ForGroup(Picked_Group, function DamageUnitsInRangeAction)
        //-------------------------------------------------------------------
        set Picked_Group        = null
        set Stored_Damagedealer = null
    endfunction

    private function Init takes nothing returns nothing
        set UC_Hash = InitHashtable()
        //---------------------------------------------------------
        // This is a good place to add a collision to a unit type
        //---------------------------------------------------------
        call AddUnitCollisionSphere('h004',100)
        call AddUnitCollisionSphere('h001',30)
        call AddUnitCollisionSphere('h005',50)
        call AddUnitCollisionSphere('h007',90)
        call AddUnitCollisionCylinder('h002',50,45)
        call AddUnitCollisionCylinder('h008',45,100)
        call AddUnitCollisionCylinder('h006',100,240)
        call AddUnitCollisionCylinder('h003',60,280)
        call AddUnitCollisionCylinder('h009',12.5,35)
        call AddUnitCollisionCylinder('h00A',14,35)
    endfunction
endlibrary
 
Level 11
Joined
Apr 29, 2007
Messages
826
wtf?
i thought:
JASS:
call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, function CollisionCondition)

function CollisionCondition takes nothing returns boolean
          return ("condition")
endfunction

What?


EDIT: why i don't have to null locations? (they are locals)
You have to null locals, but not those who were given to the function.

Example:
JASS:
function foo takes unit bla returns nothing
    local unit x = bla

    //Whatever..

    set x = null
    //We don't have to null bla because it is a parameter. Don't ask me why, Warcraft just handles it fine.
endfunction
 
Level 11
Joined
Apr 29, 2007
Messages
826
JASS:
    function DamageUnitsInRangeAction takes nothing returns boolean
        local unit u = GetFilterUnit()
        local real array r
        call MoveLocation(Point2,Stored_X,Stored_Y)
        call MoveLocation(Point1,GetUnitX(u),GetUnitY(u))
        //-------------------------------------------------------------------
        if GetUnitTypeId(u)!= Dummy_Id and GetWidgetLife(u) > 0.405 then
            if GetUnitType(u) == Sphere then
                //------------------------------------------------
                set r[0] = Stored_X - GetUnitX(u)
                set r[1] = Stored_Y - GetUnitY(u)
                set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
                //------------------------------------------------
                set r[3] = (GetUnitFlyHeight(u)+GetLocationZ(Point1))-(Stored_Z+GetLocationZ(Point2))
                set r[4] = SquareRoot(r[2] * r[2] + r[3] * r[3])
                //---------------------------------------------------------------------------------------------------------------------------
                if (r[4] <= GetUnitCollSizeSphere(u)+Stored_Size) and GetOwningPlayer(u) != GetOwningPlayer(Stored_Damagedealer) then
                    call UnitDamageTarget(Stored_Damagedealer, u, Stored_Damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                endif
                //---------------------------------------------------------------------------------------------------------------------------
            elseif GetUnitType(u) == Cylinder then
                //----------------------------------------------------
                set r[0] = Stored_X - GetUnitX(u)
                set r[1] = Stored_Y - GetUnitY(u)
                set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
//------------------------------------------------
                set r[3] = GetUnitFlyHeight(u)
                //----------------------------------------------------------------------------------------------------------------------------------------------------------------
                if r[2] <= GetUnitRadCylinder(u)+Stored_Size and Stored_Z+GetLocationZ(Point2) > r[3]-Stored_Size+GetLocationZ(Point1) and Stored_Z+GetLocationZ(Point2) < r[3]+GetUnitHeightCylinder(u)+Stored_Size+GetLocationZ(Point1) and GetOwningPlayer(u) != GetOwningPlayer(Stored_Damagedealer) then
                    call UnitDamageTarget(Stored_Damagedealer, u, Stored_Damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                endif
                //----------------------------------------------------------------------------------------------------------------------------------------------------------------
            endif
        endif
        set u = null

        return false
    endfunction

    function DamageUnitsInRange takes real x, real y, real z, real damage, real rad, unit damagedealer returns nothing
        set Stored_Damagedealer = damagedealer
        set Stored_Y = y
        set Stored_Z = z
        set Stored_Size = rad
        set Stored_Damage = damage
        //-------------------------------------------------------------------
        call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, Filter(function DamageUnitsInRangeAction))
        //-------------------------------------------------------------------
        set Picked_Group = null
        set Stored_Damagedealer = null
    endfunction

That's all...
 
Last edited by a moderator:
JASS:
library MissileData
{
    public interface MissileData
    {
        /*
        These are event methods, called upon certain things happening to the missile
        
        For all of them, if you return false, the Missile is destroyed (or in the case
        of onDeath, which is called when the Missile is destroyed anyway, the dummy unit
        is killed instead)
        
        Returning true means the Missile/unit will remain intact.
        */
        
        //Called when the MissileData is assigned to a Missile
        method onAssign () -> boolean = true;
        //This will be called every MS_TIMER_INTERVAL seconds
        method onLoop () -> boolean = true;
        //Called when the Missile collides with a unit
        method onUnit (unit u) -> boolean = false;
        //Called when the Missile hits the ground
        method onGround () -> boolean = false;
        //Called when the Missile is destroyed
        method onDeath () -> boolean = false;
        
        /*
        The copy method should create a new MissileData of the same type with all the
        same data and return it. If no copy method is defined, you will not be able to
        use the same MissileData of this type in more than one Missile. Attempting to
        do so will result in the old Missile losing its data.
        */
        
        method copy () -> MissileData = 0;
        
        /*
        Variables
        */
        
        //Used to access the missile the actions are attached to
        Missile missile = 0;
        
        //The collision radius of the Missile
        real    rad         = 0.,
        
                xO          = 0., //the dummy unit's
                yO          = 0., //position will be modified by these values
                zO          = 0., //when rendering
                
                lifespan    = 0.; //how long the Missile lasts in seconds
                                  //after <lifespan> seconds, the Missile
                                  //is automatically destroyed
                                  //lifespan 0 means the Missile lasts
                                  //until it is manually destroyed
        
        //If this is true, the Missile will be able to collide with dead units
        boolean hitDead = false;
        
        //The model of the Missile. This can be changed dynamically.
        string  model   = "";
    }
}
JASS:
/*****************************************************
*         MissileSystem by Element of Water          *
******************************************************
* Credits:                                           *
* - Rising_Dusk -- GroupUtils                        *
* - Grim001     -- ListModule                        *
* - Grim001     -- AutoIndex                         *
******************************************************
* Visit [url]http://www.hiveworkshop.com[/url] for more systems *
* and spells                                         *
*****************************************************/

//! import vjass "ListModule.j"
//! import vjass "GroupUtils.j"
//! import vjass "AutoIndex.j"

//! import zinc "MissileData.zn"

library MissileSystem requires ListModule, GroupUtils, AutoIndex
{
    public constant real       MS_TIMER_INTERVAL  = 0.035;
    public constant integer    MS_DUMMY_ID        = 'msdm';
    
    public struct Missile
    {
        /*****************************************
        *        PUBLIC MEMBERS + METHODS        *
        *****************************************/
        
        real xP         = 0.,   //the current x/y/z
             yP         = 0.,   //coordinates of the
             zP         = 0.,   //missile
                    
             age        = 0.;   //the age in seconds
                                //(see lifespan in
                                //MissileData)
             
        private real v0 = 0.,   //the distance the
                     v1 = 0.,   //missile moves every 
                     v2 = 0.;   //second (use method
                                //operators below to
                                //access these as xV,
                                //yV and zV.
        
        unit dum        = null; //the dummy unit
        
        /*
        To set the missile's speed
        */
        
        //X = right/left
        method operator xV= (real nV)
        {
            v0 = nV * MS_TIMER_INTERVAL;
        }
        
        method operator xV () -> real
        {
            return v0 / MS_TIMER_INTERVAL;
        }
        
        //Y = forwards/backwards
        method operator yV= (real nV)
        {
            v1 = nV * MS_TIMER_INTERVAL;
        }
        
        method operator yV () -> real
        {
            return v1 / MS_TIMER_INTERVAL;
        }
        
        //Z = up/down
        method operator zV= (real nV)
        {
            v2 = nV * MS_TIMER_INTERVAL;
        }
        
        method operator zV () -> real
        {
            return v2 / MS_TIMER_INTERVAL;
        }
        
        /*
        To set the missile's data
        */
        private MissileData xdat = 0;
        
        method operator dat= (MissileData newDat)
        {
            MissileData d;
            if (newDat != 0)
            {
                if (newDat.missile !=0)
                {
                    d = newDat.copy();
                    if (d == 0)
                    {
                        debug BJDebugMsg(SCOPE_PREFIX + "WARNING: Assigning a MissileData instance without a copy method, which is already assigned to a Missile, to a different Missile. The old Missile will not retain its data or actions.");
                        newDat.missile.dat = 0;
                    }
                    newDat = d;
                }
                xdat = newDat;
                xdat.missile = this;
                
                model = xdat.model;
                
                if (!xdat.onAssign()) destroy();
            }
        }
        
        method operator dat () -> MissileData
        {
            return xdat;
        }
        
        /*
        To set the effect scale
        */
        
        private real size = 1.;
        
        method operator scale () -> real
        {
            return this.size;
        }
        
        method operator scale= (real newScale)
        {
            this.size = newScale;
            SetUnitScale(this.dum, newScale, 0., 0.);
        }
        
        /*
        To set the missile's position
        */
        
        method setCoords (real x, real y, real z)
        {
            this.xP = x; this.yP = y; this.zP = z;
        }
        
        /*
        To set the missile's velocity
        */
        
        method setVel (real x, real y, real z)
        {
            this.xV = x; this.yV = y; this.zV = z;
        }
        
        /*
        To set the missile's facing angle
        */
        
        private real xyA = 0;
        private real zA  = 0;
        
        method operator xyFacing= (real newAngle)
        {
            this.xyA = newAngle;
            SetUnitFacing(this.dum, newAngle);
        }
        
        method operator xyFacing () -> real
        {
            return this.xyA;
        }
        
        method operator zFacing= (real newAngle)
        {
            this.zA = newAngle;
            SetUnitAnimationByIndex(this.dum, 90 + R2I(newAngle));
        }
        
        method operator zFacing () -> real
        {
            return this.zA;
        }
        
        /*
        To move the missile towards a point
        */
        
        method projectToPoint (real x, real y, real z, real speed)
        {
            real dx = x - this.xP,
                 dy = y - this.yP,
                 dz = z - this.zP,
                 len = SquareRoot(dx * dx + dy * dy + dz * dz);
            
            xV = speed * (dx/len);
            yV = speed * (dy/len);
            zV = speed * (dz/len);
        }
        
        /*
        To make the missile home in on a target
        */
        
        private unit homeTarg = null;
        private Missile homeMiss = 0;
        private real homeSpeed = 0.;
        
        method followTarget (unit target, real speed)
        {
            this.homeTarg = target; this.homeMiss = 0; this.homeSpeed = speed;
        }
        
        method followMissile (Missile target, real speed)
        {
            this.homeTarg = null; this.homeMiss = target; this.homeSpeed = speed;
        }
        
        method stopFollow ()
        {
            this.homeTarg = null; this.homeMiss = 0;
        }
        
        /*
        Detects if the missile is at the specified coordinates
        
        Will return true if the coordinates are within the Missile's radius
        */
        
        method isAtCoords (real x, real y, real z) -> boolean
        {
            real dx = this.xP - x,
                 dy = this.yP - y,
                 dz = this.zP - z;
                    
            //use Pythagoras' theorem of a^2 + b^2 + c^2 = d^2
            //to determine if the coordinate is in range of the missile
            return (dx * dx + dy * dy + dz * dz < this.xdat.rad * this.xdat.rad);
        }
        
        /*****************************************
        *          CORE METHODS / MEMBERS        *
        *****************************************/
        module List;
        
        private static timer tim    = CreateTimer();
        private static location loc = Location(0, 0);
        
        private static Missile Current = 0;
        
        private group collGroup;
        private unit collided = null;
        
        private effect sfx = null;
        private string sfs = "";
        
        private method operator model= (string newModel)
        {
            if (newModel != sfs)
            {   
                sfs = newModel;
                if (sfx != null) DestroyEffect(sfx);
                if (dum != null && newModel != "") 
                    sfx = AddSpecialEffectTarget(newModel, dum, "origin");
            }
        }
        
        private static method onLoop()
        {
            real zh; //measures the height of the terrain
            boolean destroy = false; //if this becomes true, the missile will be destroyed at the end of its actions
            Missile d = Missile.getLast();
            
            real x, y, z;
            
            while (d != 0)
            {
                Missile.Current = d;
                
                destroy = !d.xdat.onLoop(); //run the onLoop actions, 
                                           //and if they return false, destroy the missile
                
                if (d.homeTarg != null)
                {
                    x = GetUnitX(d.homeTarg);
                    y = GetUnitY(d.homeTarg);
                    MoveLocation(Missile.loc, x, y); z = GetLocationZ(Missile.loc);
                    d.projectToPoint(x, y, zh, d.homeSpeed);
                }
                else if (d.homeMiss != 0) 
                    d.projectToPoint(d.homeMiss.xP, d.homeMiss.yP, d.homeMiss.zP, d.homeSpeed);
                
                d.xP = d.xP + d.v0; //move the missile
                d.yP = d.yP + d.v1;
                d.zP = d.zP + d.v2;
                
                //calculate the terrain height and use the information to move the dummy unit up/down
                MoveLocation(Missile.loc, d.xP, d.yP); zh = GetLocationZ(Missile.loc);
                if (d.zP < zh)
                {
                    //Run the ground collision actions if the z position is below the terrain height
                    d.zP = zh;
                    destroy = destroy || !d.xdat.onGround();
                }
                SetUnitFlyHeight(d.dum, d.zP - zh + d.xdat.zO, 0.);
                
                SetUnitX(d.dum, d.xP + d.xdat.xO); //move the dummy unit
                SetUnitY(d.dum, d.yP + d.xdat.yO); //across the x/y plane
                
                //I <3 anonymous functions!
                ForGroup(d.collGroup, static method ()
                {
                    Missile d = Missile.Current;
                    unit u = GetEnumUnit();
                    //if the unit is a missile, retrieve the missile
                    Missile d2 = getFromDummy(u);
                    //calculate the relative coordinates of the unit compared to the missile
                    real x,  y,  z,
                         dx, dy, dz;
                    
                    if (d2 == 0)
                    {
                        //if the unit isn't a missile, use the unit's coordinates
                        x = GetUnitX(u);
                        y = GetUnitY(u);
                        MoveLocation(loc, x, y);
                        z = GetUnitFlyHeight(u) - GetLocationZ(loc);
                        
                        dx = d.xP - x;
                        dy = d.yP - y;
                        dz = d.zP - z;
                    }
                    else
                    {
                        //if the unit is a missile, use the missile's coordinates
                        dx = d.xP - d2.xP;
                        dy = d.yP - d2.yP;
                        dz = d.zP - d2.zP;
                    }
                    
                    //use Pythagoras' theorem of a^2 + b^2 + c^2 = d^2
                    //to determine if the unit is out of range of the missile
                    //and remove it from the collided group if it is
                    if (dx * dx + dy * dy + dz * dz > d.xdat.rad * d.xdat.rad) GroupRemoveUnit(d.collGroup, u);
                });
                
                if (d.xdat.rad > 0.)
                {
                    //if the missile can collide, enumerate all the units in range
                    GroupEnumUnitsInRange(ENUM_GROUP, d.xP, d.yP, d.xdat.rad, static method() -> boolean
                    {
                        Missile d = Missile.Current;
                        unit u = GetFilterUnit();
                        //if the unit is a missile, retrieve the missile
                        Missile d2 = getFromDummy(u);
                        
                        //calculate the relative coordinates of the unit compared to the missile
                        real x,  y,  z,
                             dx, dy, dz;
                    
                        if (d2 == 0)
                        {
                            //if the unit isn't a missile, use the unit's coordinates
                            x = GetUnitX(u);
                            y = GetUnitY(u);
                            MoveLocation(loc, x, y);
                            z = GetUnitFlyHeight(u) - GetLocationZ(loc);
                            
                            dx = d.xP - x;
                            dy = d.yP - y;
                            dz = d.zP - z;
                        }
                        else
                        {
                            //if the unit is a missile, use the missile's coordinates
                            dx = d.xP - d2.xP;
                            dy = d.yP - d2.yP;
                            dz = d.zP - d2.zP;
                        }
                        
                        if (u != d.dum &&                       //the enumerated unit isn't the missile's dummy
                            (!IsUnitType(u, UNIT_TYPE_DEAD) ||  //the enumerated unit isn't dead
                            d.xdat.hitDead) &&
                            dx * dx + dy * dy + dz * dz <= d.xdat.rad * d.xdat.rad && //the unit is within
                                                                                      //the missile's radius
                            !IsUnitInGroup(u, d.collGroup))     //the unit isn't already colliding with the missile
                        {
                            d.collided = u;
                            GroupAddUnit(d.collGroup, u);
                        }
                        return false;
                    });
                    
                    if (d.collided != null) 
                    {
                        destroy = destroy || !d.xdat.onUnit(d.collided);
                        d.collided = null;
                    }
                }
                
                //Increase the missile's age, and destroy it if it reaches the end of its lifespan
                d.age += MS_TIMER_INTERVAL;
                destroy = destroy || d.xdat.lifespan > 0. && d.age >= d.xdat.lifespan;
                
                //Change the Missile's model if it has been changed in the MissileData
                if (d.sfs != d.xdat.model) d.model = d.xdat.model;
                
                //if the missile was allocated for destruction, destroy it now
                if (destroy) {destroy = false; d.destroy();}
                
                d = d.getPrev();
            }
        }
        
        private method onDestroy()
        {
            //run the missile death actions and kill the dummy if they return false
            if (!this.xdat.onDeath()) KillUnit(this.dum);
            //clear the data for the unit
            Missile.setMissileDummy(dum, 0);
            //remove the special effect
            this.model = "";
            //destroy the actions struct
            this.xdat.destroy();
            
            this.removeList();
            ReleaseGroup(this.collGroup);
        }
        
        /*****************************************
        *            CREATION METHODS            *
        *****************************************/
        
        static method create(real x, real y, real z, real xyFacing, real zFacing) -> Missile
        {
            Missile d = Missile.allocate();
            
            //set the coordinates of the missile
            d.xP = x; d.yP = y; d.zP = z;
            
            //create the dummy unit
            d.dum = CreateUnit(Player(15), MS_DUMMY_ID, x, y, xyFacing);
            //move the dummy up/down based of the terrain height
            MoveLocation(Missile.loc, x, y); SetUnitFlyHeight(d.dum, z - GetLocationZ(Missile.loc), 0);
            //Make the unit face the right z angle
            SetUnitAnimationByIndex(d.dum, 90 + R2I(zFacing));
            
            //set the facing angles of the missile
            d.xyA = xyFacing * bj_DEGTORAD; d.zA = zFacing * bj_DEGTORAD;
            
            //start the timer
            if (Missile.getLast() == 0) TimerStart(Missile.tim, MS_TIMER_INTERVAL, true, static method Missile.onLoop);
            d.addList();
            
            d.collGroup = NewGroup();
            
            Missile.setMissileDummy(d.dum, d);
            
            return d;
        }
        
        static method createFromUnit(unit u) -> Missile
        {
            Missile d = Missile.allocate();
            
            //set the dummy unit
            d.dum = u;
            //set the coordinates of the missile
            d.xP = GetUnitX(u); d.yP = GetUnitY(u);
            //find the absolute height of the unit
            MoveLocation(Missile.loc, d.xP, d.yP); d.zP = GetLocationZ(Missile.loc) + GetUnitFlyHeight(u);
            
            //set the facing angles of the missile
            d.xyA = GetUnitFacing(u); d.zA = 0.;
            
            //start the timer
            if (Missile.getLast() == 0) TimerStart(Missile.tim, MS_TIMER_INTERVAL, true, static method Missile.onLoop);
            d.addList();
            
            d.collGroup = NewGroup();
            
            Missile.setMissileDummy(d.dum, d);
            
            return d;
        }
        
        /*****************************************
        *        DUMMY -> MISSILE METHODS        *
        *****************************************/
        private static Missile DummyMissiles[];
        
        private static method setMissileDummy (unit u, Missile m)
        {
            DummyMissiles[GetUnitId(u)] = m;
        }
        
        static method getFromDummy (unit u) -> Missile
        {
            return DummyMissiles[GetUnitId(u)];
        }
        
        static method isUnitMissile (unit u) -> boolean
        {
            return DummyMissiles[GetUnitId(u)] != 0;
        }
    }
}
This is still in development, and has no documentation, but yeah. It beats yours by a long way (it's Zinc btw, if you can't understand it, not cJass).
 
Status
Not open for further replies.
Top