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

[vJass] (system) Missile

I have worked on this missle engine for 2 months now and start the first official beta today.

Please post feedback, critism, pros, cons, bugs, etc.
Thanks all for your patience!

And thanks for downloading.
Preview image by Furby. Thanks a lot!

Edit:
I've updated the testmap and added a second spell.
There is a lot of improvements in version 0.1.7 and I plan to make it even faster and even more modular. I also plan to create an easy to understand API.

Used librarys:


Changed all constants (TRUE, FALSE) to true/false
Changed interval to 0.03125
Fixed object leaks
Performance improvements on MissileMovement: Less object generation
Merged MissileLocHelpers to Missile<type>Target
Removed HomingMissile wrapper
Added second spell (Rain of Fire)
Removed Libraries from Modules



Changed name to Missile.
Completely remade in modules, supports now a lot of optional stuff.
Added SpellHelper, fixed a lot of problems, made the Miranas Arrow example WAY more powerful to show what this system is able to be capable of.


Keywords:
Missile, Projectile, xe, xemissile, xecollider, projectile, collider, awesome, anachron, collide, colliding, vJass
Contents

CustomMissile 0.1.7 (Map)

Reviews
BPower: 11:02, 25th Feb 2016 Reason for re-review: Nowadays the spell section is packed full of missile systems from different authors, therefore a more qualified moderator comment than "this is neat stuff" is required. There is keen...
I will add x/y and zOffset to the target anyway, you will be able to change it at any time, so the missile could actually have your own arc or you can make it so that an ability increases the perfection of the flight and removes the offset from the not precise shot.

LOL, this works just fine:
JASS:
local real realhigh = GetUnitFlyHeight(.getEffUnit())
now i can put my headshot system to work (and the projectiles that goes above the target won't hit him never (unless he jumps but datz gonna be stupid)).

thanks, sorry for all this mess xD
No problem, glad I could help you finding out.
 
Level 12
Joined
Sep 4, 2007
Messages
407
you mean a "standart" ZOffset? Like it's gonna be automatic the "unit's height" measure check? I tell ya, most units have an 80. height.

also, Offsets in my camera view are very usefull cuz you'd have to always target the units feet to the projectile to hit it's location; with this i can make an interactive offset that measures the distance from the target and can simulate the "z" so you can target the chest.
 
Level 12
Joined
Sep 4, 2007
Messages
407
you should create a function that takes one string (effect's path) and three real (x,y,z) parameters to create a special effect at the exact location and also a function to clean it. =)

that function might even using a unit with a special effect attached to it, i think thats the easy way, it's better than using destructable. also because you'll be able to use vexorians color system in it.

that way you can make missiles with trails using onLoop.

(i want check my missiles trageotories and also make easy special effects)
 
Level 12
Joined
Sep 4, 2007
Messages
407
if you just use a function with those 4 parameters instead of just the string path, you'll be able to put speciall effects ANYWHERE ANYHEIGHT in the map, get it? that gives you liberty to put it on the missile or to put it on the target or in the caster or both at the same time. (and if are greedy you can put a forth real parameter "timer" for it to die, so you won't need cleaning it artificially, calling something. but i don't think thats really necessary, though usefull))
 
if you just use a function with those 4 parameters instead of just the string path, you'll be able to put speciall effects ANYWHERE ANYHEIGHT in the map, get it? that gives you liberty to put it on the missile or to put it on the target or in the caster or both at the same time. (and if are greedy you can put a forth real parameter "timer" for it to die, so you won't need cleaning it artificially, calling something. but i don't think thats really necessary, though usefull))
You didn't understand.

I will add the function
CreateSpecialEffectOnLoc takes real x, real y, real z, string eff returns effect

to the CustomEffect library.

Into the CustomMissile library I will add a new function like
addEffect takes string s returns effect. (This calls the CreateSpecialEffectOnLoc function with the current x, y and z parameters of the missile)
 
Level 12
Joined
Sep 4, 2007
Messages
407
oh, it would be interesting if the missile system had a remake of the collision (.hitrange) system. hitrange does not detect pathing but the "unit point" location of the widget, so even if the destructable has a big pathing map or the unit have a big collision size, the missile will only hit it if the widget gets within the .hitrange radius of the missile.

Here's a graphic telling why only having .hitrange as "collision" detection parameter is a problem:
138643-albums3204-picture27905.jpg


this can be solved by making the Missile System able detect pathing around its projectiles, this way it can hit units by its collision size, buildings n' destructibles by it's pathing and other missiles by the .hitrange system (since the missile's collision size = 0.00).

is it possible to detect pathing n' apply this "method"???


=======
....If it isn't (since you are storing units in a group created by trigger) you might consider creating several extra hitrange detecter functions, those taking two parameters, the first,a text macro stating the kind of widget desired.the second, the range used to detect it's center.

Examples:

call hitrange[1]( UNIT_TYPE_HERO, 32.00) ----> stupid example: if unittype of the unitpicket on the hitrange group = hero, the arrow will detect it at range 32.00
call hitrange[2]( UNIT_TYPE_STRUCTURE, 120.00) ---> if unittype of the unitpicket on the hitrange group = building, the arrow will detect it at range 120.00 (large to simulate the pathing)
call hitrange[3]( UNIT_TYPE_POLYMORPHED , 16.00) ---> polimorphed units are smaller, so the projectile detects it with more difficulty
call hitrange[4]( WIDGET_TYPE_LARGEDEST, 50.00) ----> tree that is larger than a unit (btw, you gonna have to generate some customisable textmacros, or teach how to do it, this one could detect a destructable and filter it by it's typeid or even by it's life (supposing that bigger destructables have bigger lifes) )
call hitrange[5](WIDGET_TYPE_SMALLTREE, 20.00) same as before, but smaller.

you might even be more specific like:

set .hitrange.unit = 32.
set .hitrange.dest1 = 40.
set .hitrange.dest2 = 120.

but thats gonna take a LOT of time to make a library (i can help you doing the massive work if you choose to do this)

Here's a graphic how the .hitrange becomes after this kind of change
138643-albums3204-picture27906.jpg


obviously this kinda makes the system somehow slower, so it might be an optional module or optional feature (like .hitwalls) having multiple projectiles with this sytems (filtering 5 or 6 types of widget) might affect performance. One way to get pass that is to always put the maximum .hitrange and always check the distance between the widget and the projectile, if the distance is equal o smaller than the required for that kind of widget, the projectile "touches" the widget. (gosh this is complicated)


unfortunatly this system will not detect exotic shapes, since is all based on hitrange radius, it will always be a "round" "pathing".

_____________________________________________________________________________________________________________________________________________

other thing (just to take doubt out of my head), how many times per second onLoop is runned? (it's a lot according to my experiments with your system)

Edit: forget it, I did this:
JASS:
method onCreate takes nothing returns nothing
      set .decay = 1.
endmethod

method onLoop takes nothing returns nothing
       set .loopshow = .loopshow + 1 
endmethod

method onEnd takes nothing returns nothing
       call BJDebugMsg(I2S(.loopshow))
endmethod

the result is 32. Every second onLoop is runned 32 times o_O

______________________________________________________________________________________________________________________________________________

oh, and i also made a sample spell for your map, i'll put the coding here later, if you want. It's a Flame Splash: a phoenix missile projectile with 1500 max range that deals 100 area damage (area 150) on unithit, on wallnit,on desthit,on reachtarget. also, when this damage is dealt, 20 small flame drops come out of the projectile (that is already dead with flashy effects) simulating a "flame splash". those drops deal 25 damage to any unit it hits. The whole thing is very flashy looks very realistic (not that liquid fire exists...)
 
Last edited:
JASS:
//|=======================================================|
//|              this system is made by The_Witcher       |
//|            all credits for this system goes to him    |
//|=======================================================|

library CollisionSystem initializer Init
globals
    private integer array class
    private real array xx
    private real array yy
    private real array zz
    private integer total = 0
    private hashtable h = InitHashtable()
    private real maxR = 0
    private group g = CreateGroup()
    private boolean Free = true
    private real X
    private real Y
    private real Z
endglobals

function AddEnvironmentCollision takes integer rcode, real SizeX, real SizeY, real SizeZ returns nothing
    if LoadInteger(h,rcode,0) == 0 then
        set total = total + 1
        set xx[total] = SizeX / 2
        set yy[total] = SizeY / 2
        set zz[total] = SizeZ
        set class[total] = rcode
        call SaveInteger(h, rcode, 0, total)
        if SizeX > maxR then
            set maxR = SizeX
        endif
        if SizeY > maxR then
            set maxR = SizeY
        endif
    endif
endfunction

private function GetRectFromCircle takes real x, real y, real radius returns rect
    return Rect(x - radius, y - radius, x + radius, y + radius)
endfunction

private function Destrloop takes nothing returns nothing
    local integer i = LoadInteger(h,GetDestructableTypeId(GetEnumDestructable()),0)
    local real x = GetDestructableX(GetEnumDestructable())
    local real y = GetDestructableY(GetEnumDestructable())
    if Free then
        if i != 0 then
            if (X > x - xx[i] and X < x + xx[i]) and (Y > y - yy[i] and Y < y + yy[i]) and (Z >= 0 and Z < zz[i]) then
                set Free = false
            endif
        endif
    endif
endfunction

private function AliveFilter takes nothing returns boolean
    return not (IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) or GetUnitTypeId(GetFilterUnit()) == 0 )
endfunction

function IsWayFree takes real x, real y, real z returns boolean
    local location p = Location(x,y)
    local unit u
    local integer i
    local real xxx
    local real yyy
    local real zzz
    set X = x
    set Y = y
    set Z = z
    set Free = true
    call EnumDestructablesInCircleBJ(maxR,p,function Destrloop)
    if Free then
        call GroupEnumUnitsInRange(g,x,y,maxR,Condition(function AliveFilter))
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null or not Free
            set i = LoadInteger(h,GetUnitTypeId(u),0)
            if i != 0 then
                set xxx = GetUnitX(u)
                set yyy = GetUnitY(u)
                set zzz = GetUnitFlyHeight(u)
                set Free = (X > xxx - xx[i] and X < xxx + xx[i]) and (Y > yyy - yy[i] and Y < yyy + yy[i]) and(Z >= zzz and Z < zzz+ zz[i])
                set Free = not Free
            endif
            call GroupRemoveUnit(g,u)
        endloop
    endif
    return Free
endfunction

function IsWayFreeLoc takes location p, real z returns boolean
    return IsWayFree(GetLocationX(p),GetLocationY(p),z)
endfunction

private function Init takes nothing returns nothing
    //call AddEnvironmentCollision(
endfunction
endlibrary

i requested this sys some time ago
may it's usefull (my unit collision sys still bugs -.-')
 
hmm
my unit collision doesn't have this problem
i post it here but don't use it becasue it doesn't work
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
 
Level 12
Joined
Sep 4, 2007
Messages
407
we are getting off topic xD the focus here is anacrhons system.

Edit: anadron, i'm trying to use grouputils but my spell scope does not reconizes NewGroup() as function. why does that happens? can you fix the system so it can reconize? Weird thing since it reconizes ReleaseGroup(group) and the other functions

JASS:
    private struct spellMissile extends CustomMissile
        private group targetgroup = NewGroup()

it does not work, the WE does not let me do this

Plz help me with that because i need a group for the spell to work and while i can't solve this, 'im creating and destroing groups everytime the spell is casted.
 
Last edited:
lelyanra said:
Right now I am really busy with reallife, so sorry, I am checking this idea later.

it does not work, the WE does not let me do this

Plz help me with that because i need a group for the spell to work and while i can't solve this, 'im creating and destroing groups everytime the spell is casted.
You can't do this, just do that on the onCreate method.

Edit:
I will NOT add CreateEffectOnLoc because that's the purpose of the CustomEffect.

Edit2:
I will also not change the collision system. It's fine as it is now. The other stuff will just explode the range of this system and it will be a lot slower.
 
Last edited:
Level 12
Joined
Sep 4, 2007
Messages
407
dunno, i'm new to vJASS, most i know is because of your system. still did not get the idea of struct, method those stuff. just learning how to use it.

since you don't want to set the missile detection slower you can generate a custom pathing radius based on the unit's life or collision size or whatever. the missile will detect the units radius when both custom collision and hitrange radius cross.(life for destructibles, custom value for units). that way your system does not get slower and this system will become just a module. you will just generate like eight points (or more if the radius is too big) around the widget to "simulate" the radius (it will be actually a octogon but i think you got my point).those points might be dummy units that are bounded to the Main unit. You only need to create one extra function in the system to make subordinate units (the points) lead to the main unit.(or even less than if you make an Optional to the library AutoIndex (you know AutoIndex right?))

i think autoindex even lets you make extra values to store in the unit so each unit type might have different colliding radius, zheights (you may use this for other things in your system!), all you need to do is to make those values be stored at the unit creation xD

anyway just some ideas.

plzzzzzzz i really need pathing difference for units and destructibles in my map.
 
Level 12
Joined
Sep 4, 2007
Messages
407
Is it better to use onTouchUnit and make the .hitrange equal to the maximum custom pathing radius possible? onUnittouch will check the storied custom radius and check if the missile is close enought to perform a "hiting" action.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
I don't know what the exact aim of the system is, but typically projectiles aren't going to need a whole whack-load of collision detection. If there is such a requirement for very specific collision, then you should really be using a physics engine.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
It seems though like it would almost be easier to only handle X/Y collision detection, and let the user handle the height modifications themselves. In my system (probably similar in this one) you can reference the x/y/z of a projectile and the collision interface-method includes a unit variable, so you would be able to gather the x/y/z coordinates of the unit as well (and be able to accomplish the same thing, but leave more open to the user).

I still don't know though, Anachron, what are your thoughts?

By the way, Anachron, how can projectiles be enumerated in this?
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
That's because you can't declare private variables inside a function/method, only local variables. Try using:

JASS:
local group targetGroup = NewGroup()

You shouldn't ever really need local groups, though, since a single global group variable can be used to do all the necessary process requirements of any single function. For example:

JASS:
globals
    private group enumGlobal = CreateGroup()
endglobals

...

method onCreate takes nothing returns nothing
    call GroupEnumUnitsInRange(enumGlobal, ...)

    // Be sure to clear the group (not destroy it) at the end, so that
    // there are no units remaining.
    call GroupClear(enumGlobal)
endmethod
 
Level 12
Joined
Sep 4, 2007
Messages
407
That's because you can't declare private variables inside a function/method, only local variables. Try using:

JASS:
local group targetGroup = NewGroup()

You shouldn't ever really need local groups, though, since a single global group variable can be used to do all the necessary process requirements of any single function. For example:

JASS:
globals
    private group enumGlobal = CreateGroup()
endglobals

...

method onCreate takes nothing returns nothing
    call GroupEnumUnitsInRange(enumGlobal, ...)

    // Be sure to clear the group (not destroy it) at the end, so that
    // there are no units remaining.
    call GroupClear(enumGlobal)
endmethod


so i can't just pick a group from the grouputils stack?

i can't have a global group because it would make the spell not MUI (if two people cast it at the same time, the target won't be targeted by both, the group avoids the same spell hitting the unit twice.)

sry for the double post
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Well if Anachron has his struct setup properly then you should be able to extend the CustomMissile struct and add certain properties to it (such as your group), which would give something like:

JASS:
struct yourMissile extends CustomMissile
    private group enumGroup = null

    method onDestroy takes nothing returns nothing
        // You should make sure you release the group.
        call ReleaseGroup(enumGroup)
    endmethod

    method onCreate takes nothing returns nothing
        set enumGroup=NewGroup()
    endmethod
endstruct
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Well it really doesn't matter where you create the group, as long as you create it before you use it, and destroy/release it when you are done using it.

And yes, this will pick a group from the "GroupUtils" stack because I am assigning the group to NewGroup.

I suggest you read the vJass Manual that's included in the jasshelper folder of your JNGP download.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
I think there is some sort of problem with groups being created/destroyed, which is why GroupUtils is so commonly used. If you only need a group for instant unit enumerations (like for area of effect damage, where units are not needed for any more than an instant) you can use a global group because you will not be needing to create/destroy it.
 
Level 12
Joined
Sep 4, 2007
Messages
407
JASS:
        private spell   spellInst = 0

what is this, why the 0? i have to make a new number for each spell?

since you are not creating that function (CreateEffectLocZ) could you at least teach me how to do it?
 
Last edited:
Level 12
Joined
Sep 4, 2007
Messages
407
it's a function that takes 3 real parameters (x,y,z) and a sfx parameter to create a special effect using them. it creates a special effect unit, set's its flaying height to x,y n z and then attach a special effect at its origin using the sfx parameter. I'd love to do this, but i dunno how to clean it later so it wont leak o_O

I tried to make a way to create spell effects a the EXACT location the spell hits.
here's what i did, tell me if that leaks or have some problem:

JASS:
scope ShortBow initializer init
    private keyword spell
    
    private struct spellMissile extends CustomMissile
        private spell   spellInst = 0
        
        private unit source = null


          //these are private methods to create a effect unit at the extact location i want the "blood" effect it lives only for the amount of seconds i want.
        private method CreateInstantZUnit takes real x, real y, real z, real a returns unit
            local unit instantUnit = CreateUnit(.owner, 'CExx', x, y, a)
            call SetUnitFlyHeight(instantUnit, z - GetLocZ(x, y), 0.)
            return instantUnit    
        endmethod

//in this space you would find a public static method to make the spell have target, method onCreate blah blah blah
//blah blah
//blah blah

        method onUnitTouch takes nothing returns nothing
            local unit effectunit = CreateInstantZUnit(.x,.y,.z,0.)
            call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl", effectunit, "origin"))
            set .hitunits = false
            set .hitwalls = false
            set .hitdests = false
            set .alive = false
            call BJDebugMsg("HIT!!!")
            set effectunit = null
        endmethod
endstruct

is there a better way to do this? this actually works but it is destroied toooo soon, it does not even play the effect entirelly.
 
Last edited:
Level 18
Joined
Jan 21, 2006
Messages
2,552
I see endstruct but I don't see endscope haha.

Other than that it looks fine, though you do not null instantUnit in CreateInstantZUnit which will cause a memory leak. To fix this use a global variable instead of declaring a local variable. It would look something like:

JASS:
globals
    private unit tempUnit = null
endglobals

...
          //these are private methods to create a effect unit at the extact location i want the "blood" effect it lives only for the amount of seconds i want.
        private method CreateInstantZUnit takes real x, real y, real z, real a returns unit
            set tempUnit = CreateUnit(.owner, 'CExx', x, y, a)
            call SetUnitFlyHeight(instantUnit, z - GetLocZ(x, y), 0.)
            return tempUnit
        endmethod
 
What the hell are you guys doing?

I tried to make a way to create spell effects a the EXACT location the spell hits.
here's what i did, tell me if that leaks or have some problem
JASS:
method onUnitTouch takes unit theUnit returns nothing
    local real x = GetUnitX(theUnit)
    local real y = GetUnitY(theUnit)
    local real z = GetLocZ(x, y) + GetUnitFlyHeight(theUnit)
    local CustomEffect e = CreateEffect(x, y, z, GetUnitFacing(theUnit))
    set e.sfx = "Effect\\Path.mdl"
    call e.destroy()
endmethod
 
Top