Tutorial Creating Realistic Projectiles With The Particle System (W.I.P.)

1

1337D00D

Guest
The Particle System

Table of Contents:
What is it?
Requirements and installation
Basic functions
Creating a grenade
Creating a bullet
[del]More fun uses[/del]

I apologize for not linking, but anchor tags are removed.

What is it?
The Particle System, created by iNfraNe, is for moving units as if they were particles. It uses Anitarf's Vector System, which is pretty much the base to the Particle System. The Particle System is basically a simpler way to use the Vector System (All the heavy math....) ;) .

Requirements and Installation

Requires:
-iNfraNe's Particle System
-Moderate knowledge of JASS
-Wc3
-A map editor
-Computer
-Brain

Installation:


-Copy ALL stuff in the Map Header into your map's Map Header
-Copy the triggers in the Particle System folder.
-With "Automatically create unknown variables when pasting in the Trigger Editor" ticked in preferences, copy and paste the GUI Variables trigger into your map. You can then delete it.
-Save your map.

You're done!


The Basic Functions

Here's a list of functions you can use, along with what they do.

Natives List:
Chief Speedy Turtle
Running Bear
Swift Fox
Giant Boar

Haha, I'm funny. :p

Functions:

CreateParticle(...) Takes player p, integer utype, real x, real y, real facing returns unit. This function creates a unit as a particle.

ParticleSetSpeed(...) Takes unit u, real x, real y, real z returns nothing. This function sets the x, y, and z target points of a particle. If x != 0 and y=0 and z=0, the particle will move to the right. To make a particle move towards a point, use the formula (GetLocationX(fromposition)-GetLocationX(toposition)). Replace the X with Y or Z for other values.

ParticleLinkConditionTrigger2Func(...) Takes unit u, trigger t, string s returns nothing. This links a condition and an action to be taken, to a unit. When trigger t returns true, the function with the name of string s will be called. See below for pre-made actions and conditions.

ParticleUnlinkCondition(...) Takes unit u, trigger t returns nothing. Undoes the function above.

ParticleAddForce(...) Takes unit u, integer vector returns nothing. Adds a force like gravity or wind. Use G() for gravity and Wind() for wind (these are the integers). You can also add your own.

ParticleRemoveForce(...) Takes unit u, integer vector returns nothing. Undoes the above function.

Linkable Conditions

ParticleGroundHit() Checks when the particle collides with the ground. Including cliffs.

ParticleDeath() Checks when the particle dies.

Linkable Actions

Death_Remove - Removes the particle. Designed for use with ParticleDeath()

GroundHit_Bounce - Makes the particle bounce depending on its speed, the terrain angle, and the force of gravity. Desined for use with ParticleGroundHit()


Creating A Grenade


Now it's time to have some fun. Here's a guide that can help you make your own realistic grenade.

First, you'll need a dummy unit. It can look like whatever you want. Give it a -1 regeneration rate, and about 4 hp so it will detonate on its own. Also make an AoE damage upon death and give it that, too. Then, make an ability to throw the grenade. I based mine off of Far Sight, only with no reveal and a range of 1000.

Now for coding part.

Here we have our function.

Code:
function Trig_ThrowGrenade_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function Trig_ThrowGrenade_Actions takes nothing returns nothing
endfunction

//===========================================================================
function InitTrig_ThrowGrenade takes nothing returns nothing
    set gg_trg_ThrowGrenade = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_ThrowGrenade, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_ThrowGrenade, Condition( function Trig_ThrowGrenade_Conditions ) )
    call TriggerAddAction( gg_trg_ThrowGrenade, function Trig_ThrowGrenade_Actions )
endfunction

It has the event "Unit starts the effect of an ability." You will probably have to change the ability raw code in the condition.

Next, let's look at our actions.

Code:
function Trig_ThrowGrenade_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetSpellAbilityUnit())
local location topos = GetSpellTargetLoc()
local unit u
endfunction

First things first. We need to create local variables for our two locations, and one for our unit. The unit will be our grenade.

Next, we will use CreateParticle(...) to create the grenade.

Code:
function Trig_ThrowGrenade_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetSpellAbilityUnit())
local location topos = GetSpellTargetLoc()
local unit u = CreateParticle(GetOwningPlayer(GetSpellAbilityUnit()),'h001',GetLocationX(casterpos),GetLocationY(casterpos),GetUnitFacing(GetSpellAbilityUnit()))
endfunction

My grenade dummy's ID is 'h001'. Yours might be different. You will need to change it. There is now a grenade at the position of our caster.

Now we need to make it move.

Code:
function Trig_ThrowGrenade_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetSpellAbilityUnit())
local location topos = GetSpellTargetLoc()
local unit u = CreateParticle(GetOwningPlayer(GetSpellAbilityUnit()),'h001',GetLocationX(casterpos),GetLocationY(casterpos),GetUnitFacing(GetSpellAbilityUnit()))
call ParticleSetSpeed(u,GetLocationX(topos)-GetLocationX(casterpos),GetLocationY(topos)-GetLocationY(casterpos),1200)
endfunction

Remember the formula to set the particle's speed to move towards a point? If you didn't, just copy what I did. My z speed is 1200, but it can be whatever you want it to be.

Now to add the conditions, and to apply gravity.

Code:
function Trig_ThrowGrenade_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetSpellAbilityUnit())
local location topos = GetSpellTargetLoc()
local unit u = CreateParticle(GetOwningPlayer(GetSpellAbilityUnit()),'h001',GetLocationX(casterpos),GetLocationY(casterpos),GetUnitFacing(GetSpellAbilityUnit()))
call ParticleSetSpeed(u,GetLocationX(topos)-GetLocationX(casterpos),GetLocationY(topos)-GetLocationY(casterpos),1200)
call ParticleLinkConditionTrigger2Func(u, ParticleGroundHit(), "GroundHit_Bounce")
call ParticleLinkConditionTrigger2Func(u, ParticleDeath(), "Death_Remove")
call ParticleAddForce(u, G())
endfunction

Now our grenade will bounce when it hits the ground, and it will be removed when it dies. The grenade will also be affected by gravity. You can change the force of gravity in the G() function, found in the trigger Particle Supplement Functions.

There's one tiny problem: This grenade dosen't make a big boom. :(. So, we can fix that by creating our own function. What I did here is I copied the existing Death_Remove, renamed it, and added a special effect. If you use a custom one, remember to replace Death_Remove in the grenade trigger with the one you created.

Code:
function Death_RemoveBoom takes nothing returns nothing
  local location upos = GetUnitLoc(GetEnumUnit())
  local effect eff = AddSpecialEffectLocBJ(upos, "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl")  
  call DestroyEffect(eff)
  call RemoveParticle(GetEnumUnit(),true)
  call RemoveLocation(upos)
  set upos=null
endfunction

Ka-boom! :). But wait--we're still not done here. Our trigger leaks, and that's a bad thing. Let's clean those up.

Code:
function Trig_ThrowGrenade_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetSpellAbilityUnit())
local location topos = GetSpellTargetLoc()
local unit u = CreateParticle(GetOwningPlayer(GetSpellAbilityUnit()),'h001',GetLocationX(casterpos),GetLocationY(casterpos),GetUnitFacing(GetSpellAbilityUnit()))
call ParticleSetSpeed(u,GetLocationX(topos)-GetLocationX(casterpos),GetLocationY(topos)-GetLocationY(casterpos),1200)
call ParticleLinkConditionTrigger2Func(u, ParticleGroundHit(), "GroundHit_Bounce")
call ParticleLinkConditionTrigger2Func(u, ParticleDeath(), "Death_Remove")
call ParticleAddForce(u, G())
call RemoveLocation(casterpos)
call RemoveLocation(topos)
set casterpos=null
set topos=null
set u = null
endfunction

Tadaa! A grenade spell! Have fun blowing things up.

Code:
function Trig_ThrowGrenade_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function Trig_ThrowGrenade_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetSpellAbilityUnit())
local location topos = GetSpellTargetLoc()
local unit u = CreateParticle(GetOwningPlayer(GetSpellAbilityUnit()),'h001',GetLocationX(casterpos),GetLocationY(casterpos),GetUnitFacing(GetSpellAbilityUnit()))
call ParticleSetSpeed(u,GetLocationX(topos)-GetLocationX(casterpos),GetLocationY(topos)-GetLocationY(casterpos),1200)
call ParticleLinkConditionTrigger2Func(u, ParticleGroundHit(), "GroundHit_Bounce")
call ParticleLinkConditionTrigger2Func(u, ParticleDeath(), "Death_Remove")
call ParticleAddForce(u, G())
call RemoveLocation(casterpos)
call RemoveLocation(topos)
set casterpos=null
set topos=null
set u = null
endfunction

//===========================================================================
function InitTrig_ThrowGrenade takes nothing returns nothing
    set gg_trg_ThrowGrenade = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_ThrowGrenade, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_ThrowGrenade, Condition( function Trig_ThrowGrenade_Conditions ) )
    call TriggerAddAction( gg_trg_ThrowGrenade, function Trig_ThrowGrenade_Actions )
endfunction

Creating A Bullet


Creating a bullet is almost the same as creating a grenade, however with a bullet we don't want it to bounce off of the ground or be affected by gravity. We also want it to collide with units.

We can simply add these functions into the Particle Supplement Functions trigger to check for collision. Remember, this projectile can move in 3 dimensions. So we also need to check if the projectile is high or low enough to hit the unit. It checks that the unit is within a sphere with a radius of 60 degrees. You can change the radius of the sphere by editing the bold parts.

Code:
function ParticleCollisionCond takes nothing returns boolean
  local group g = CreateGroup()
  local unit u = GetEnumUnit()
  local unit f
  local integer p = udg_clsParticlePlace[GetUnitUserData(u)]
  local integer tv
  local location l
  call GroupEnumUnitsInRange(g, udg_vectorX[p], udg_vectorY[p], [B]60[/B], null)

  loop
    set f = FirstOfGroup(g)
    exitwhen f == null
    set l = GetUnitLoc(f)
    set tv = VectorCreate(GetLocationX(l), GetLocationY(l), GetLocationZ(l)+GetUnitFlyHeight(f))
    call RemoveLocation(l)

    if IsPointInSphere(tv, p, [B]60[/B]) then

      call VectorDestroy(tv)

      set udg_TUnit = f //This is a temp global to be used in the conditionfuncs
      if IsPlayerAlly(GetOwningPlayer(f),GetOwningPlayer(u))==false then
      set u = null
      set l = null
      set f = null

      return true

    
    
    endif
    endif
  call VectorDestroy(tv)
    call GroupRemoveUnit(g,f)
  endloop

  set u = null
  set l = null
  set f = null

  return false
endfunction

Code:
function ParticleCollision takes nothing returns trigger
  if udg_conditionCollision == null then
    set udg_conditionCollision = CreateEvalTrig(function ParticleCollisionCond)
  endif
  return udg_conditionCollision
endfunction

We will also need two global variables:
conditionCollision, which is a trigger variable, and
TUnit, which is a unit variable.

We can now link the condition ParticleCollision() to a particle!

Now all we need is a modified version of our grenade function.

Code:
function Trig_ShootMissile_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == [B]'A002'[/B]
endfunction

function Trig_ShootMissile_Actions takes nothing returns nothing
local location cpos = GetUnitLoc(GetSpellAbilityUnit())
local location tpos = GetSpellTargetLoc()
local location npos = PolarProjectionBJ(cpos,1000,AngleBetweenPoints(cpos,tpos))
local unit u = CreateParticle(GetOwningPlayer(GetSpellAbilityUnit()),[B]'h002'[/B],GetLocationX(cpos),GetLocationY(cpos),AngleBetweenPoints(cpos,tpos))
call ParticleSetSpeed(u,GetLocationX(npos)-GetLocationX(cpos),GetLocationY(npos)-GetLocationY(cpos),GetLocationZ(tpos)-GetLocationZ(cpos))
call ParticleLinkConditionTrigger2Func(u, ParticleGroundHit(), "Death_Remove")
call ParticleLinkConditionTrigger2Func(u, ParticleDeath(), "Death_Remove")
call ParticleLinkConditionTrigger2Func(u, ParticleCollision(), "Collision_Damage80")
call RemoveLocation(cpos)
call RemoveLocation(tpos)
call RemoveLocation(npos)
set cpos=null
set tpos=null
set npos=null
set u = null
endfunction

//===========================================================================
function InitTrig_ShootMissile takes nothing returns nothing
    set gg_trg_ShootMissile = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_ShootMissile, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_ShootMissile, Condition( function Trig_ShootMissile_Conditions ) )
    call TriggerAddAction( gg_trg_ShootMissile, function Trig_ShootMissile_Actions )
endfunction

I'm using a missile as a projectile in this example. Be sure to change the spell raw code and the projectile raw code.

There are a few differences from the grenade function. In this function, the target position is a set point. The grenade function sets the target position to the target of the spell, thus making the grenade travel slower the closer the target is to the caster. Here, we set it to the caster's position offset by 1000. The only thing the player can choose is the direction of the missile.

The linked conditions are also different. The particle will be removed when it hits the ground or dies. There's also a third condition, ParticleCollision(), which is what you added in earlier. It checks for when it hits a unit.

You probably see a different action, too. Collision_Damage80 is a custom action that I made. You can create your own, too.

This is the one I used:

Code:
function Collision_Damage80 takes nothing returns nothing
  local unit u = GetEnumUnit()
  call UnitDamageTarget(u, udg_TUnit, 80, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
  call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\CannonTowerMissile\\CannonTowerMissile.mdl", udg_TUnit, "chest"))
  call KillUnit(u)
  call RemoveParticle(u,true)
  set u = null
endfunction

It also creates a special effect on the unit it damages. You can change both the damage and effect created.

And now you have a realistic projectile. Don't shoot your eye out.... :p



More stuff coming tomorrow, it's a Work In Progress!
 

chovynz

We are all noobs! in different states of Noobism!
Reaction score
130
I know this thread is a WIP, however the Grenade doesn't seem to work. I've done what you said and there are no errors, but there's no grenade either. I'll continue testing to see if there's something I've missed or done wrong.

I had the same thing happen on one of my tests (before I read this WIP:))
 

Chocobo

White-Flower
Reaction score
409
I'm quoting so I'm not using CODE

What is it?
The Particle System, created by iNfraNe, is for moving units as if they were particles. It uses Anitarf's Vector System, which is pretty much the base to the Particle System. The Particle System is basically a simpler way to use the Vector System (All the heavy math....) .

And uses Linked Lists.


Requires:
-iNfraNe's Particle System
-Moderate knowledge of JASS
-Wc3
-A map editor
-Computer
-Brain

Requires.. knowledge in JASS like you innove things. Because you must create your own functions. And also, you need to know how the Vector System works first..


-Copy ALL stuff in the Map Header into your map's Map Header
-Copy the triggers in the Particle System folder.
-With "Automatically create unknown variables when pasting in the Trigger Editor" ticked in preferences, copy and paste the GUI Variables trigger into your map. You can then delete it.
-Save your map.

You're done!

And the special dummy unit?


ParticleAddForce(...) Takes unit u, integer vector returns nothing. Adds a force like gravity or wind. Use G() for gravity and Wind() for wind (these are the integers). You can also add your own.

If the Force isn't constant, be sure to remove it to avoid to reach the vector limit.


Linkable Conditions

ParticleGroundHit() Checks when the particle collides with the ground. Including cliffs.

ParticleDeath() Checks when the particle dies.

Linkable Actions

Death_Remove - Removes the particle. Designed for use with ParticleDeath()

GroundHit_Bounce - Makes the particle bounce depending on its speed, the terrain angle, and the force of gravity. Desined for use with ParticleGroundHit()

Those are only demos. You can make your ones for more powerful abilities and behaviour.


ParticleSetSpeed(...) Takes unit u, real x, real y, real z returns nothing. This function sets the x, y, and z target points of a particle. If x != 0 and y=0 and z=0, the particle will move to the right. To make a particle move towards a point, use the formula (GetLocationX(fromposition)-GetLocationX(toposition)). Replace the X with Y or Z for other values.

You should explain how it exactly work. (speed every interval defined?)


function Trig_ThrowGrenade_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetSpellAbilityUnit())
local location topos = GetSpellTargetLoc()
local unit u
endfunction

Simply GetUnitLoc(GetTriggerUnit()).


function Trig_ThrowGrenade_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetSpellAbilityUnit())
local location topos = GetSpellTargetLoc()
local unit u = CreateParticle(GetOwningPlayer(GetSpellAbilityUnit()),'h001',GetLocationX(casterpos),GetLocationY(casterpos),GetUnitFacing(GetSpellAbilityUnit()))
call ParticleSetSpeed(u,GetLocationX(topos)-GetLocationX(casterpos),GetLocationY(topos)-GetLocationY(casterpos),1200)
call ParticleLinkConditionTrigger2Func(u, ParticleGroundHit(), "GroundHit_Bounce")
call ParticleLinkConditionTrigger2Func(u, ParticleDeath(), "Death_Remove")
call ParticleAddForce(u, G())
endfunction

Grenade doesn't work? (lets check) Lets say, the particle is created, it's speed is set to : (TargetX-CasterX),(TargetY-CasterY), at max height 1200.
The grenade is removed at it's death, the Vector G() (0,0,-2500) is applied.

Ex :
- casterpos = Location(154.00,360.00)
- topos = Location(-103.50,-980.00)
(distance is quite big, I don't think someone can launch a grenade 1300 far :p)
154-(-103.5) = 257.5
360-(-980) = 1340

Quite weird.

I would use this instead :

PHP:
function MakeUnitFlyable takes unit u returns nothing
call UnitAddAbility(u,'Amrf')
call UnitRemoveAbility(u,'Amrf')
endfunction

function DestroyEffectTimed takes effect eff,real duration returns nothing
call PolledWait(duration)
call DestroyEffect(eff)
endfunction

function DamageArea takes unit source,real maxdmg,integer damageV,real radius returns nothing
local integer i=0
local integer originV
local real array r
local group g=CreateGroup()
local unit c
call GroupEnumUnitsInRange(g,udg_vectorX[damageV],udg_vectorY[damageV],radius,null)
loop
set c=FirstOfGroup(g)
exitwhen c==null
if GetUnitState(c,UNIT_STATE_LIFE)>0 then
set r[0]=GetUnitX(c)
set r[1]=GetUnitY(c)
set r[2]=GetZ(r[0],r[1])
set originV=VectorCreate(r[0],r[1],r[2])
if IsPointInSphere(originV,damageV,radius) then
call VectorSubtract(originV,damageV)
set r[5]=(radius-VectorGetLength(originV))/radius*maxdmg
call UnitDamageTarget(source,c,r[5],true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
endif
call VectorDestroy(originV)
endif
call GroupRemoveUnit(g,c)
endloop
call DestroyGroup(g)
set g=null
set c=null
endfunction

function CreateExplosion takes player p,string path,real x,real y,real z,real facing,real size,real time returns nothing
local unit u=CreateUnit(p,'e001',x,y,facing)
local effect e
call SetUnitX(u,x)
call SetUnitY(u,y)
call MakeUnitFlyable(u)
call SetUnitAnimationByIndex(u,90)
call SetUnitScale(u,size,size,size)
call SetUnitFlyHeight(u,z-GetZ(x,y),0)
if time==0 then
call DestroyEffect(AddSpecialEffectTarget(path,u,"origin"))
else
set e=AddSpecialEffectTarget(path,u,"origin")
endif
call KillUnit(u)
set u=null
if time>0 then
call DestroyEffectTimed(e,time)
endif
set e=null
endfunction

function Death_ExplodeNade takes nothing returns nothing
local unit u=GetEnumUnit()
local integer p=udg_clsParticlePlace[GetUnitUserData(u)]
call CreateExplosion(GetOwningPlayer(u),"Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",udg_vectorX[p],udg_vectorY[p],udg_vectorZ[p],GetRandomReal(0,360),1.,5.)
call CreateExplosion(GetOwningPlayer(u),"Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl",udg_vectorX[p],udg_vectorY[p],udg_vectorZ[p],GetRandomReal(0,360),3.,0)
call DamageArea(u,275,p,256.)
call RemoveParticle(u,true)
set u=null
endfunction

function Trig_Grenade_Conditions takes nothing returns boolean
return GetSpellAbilityId()=='A001'
endfunction
function Trig_Grenade_Actions takes nothing returns nothing
local unit h=GetSpellAbilityUnit()
local location l=GetSpellTargetLoc()
local real x=GetLocationX(l)-GetUnitX(h)
local real y=GetLocationY(l)-GetUnitY(h)
local real a=Atan2BJ(y,x)
local real aoa
local unit u=CreateParticle(GetOwningPlayer(h),'e000',GetUnitX(h),GetUnitY(h),a)
local real array r
local integer i=udg_clsParticlePlace[GetUnitUserData(u)]
set udg_vectorX[i]=udg_vectorX[i]-udg_vectorX[SpawnPlaceOffset()]*CosBJ(a)
set udg_vectorY[i]=udg_vectorY[i]-udg_vectorY[SpawnPlaceOffset()]*SinBJ(a)
set udg_vectorZ[i]=udg_vectorZ[i]-udg_vectorZ[SpawnPlaceOffset()]+1
set r[2]=750
set r[0]=RMinBJ(r[2],SquareRoot(x*x+y*y))
set r[1]=SquareRoot(r[2]*VectorGetLength(G()))
set aoa=(bj_PI/2)-(Asin((r[0]*VectorGetLength(G()))/(r[1]*r[1]))/2)
call SetUnitTimeScalePercent(u,10.00)
call ParticleSetSpeed(u,Cos(aoa)*CosBJ(a)*r[1],Cos(aoa)*SinBJ(a)*r[1],r[1]*Sin(aoa))
call ParticleAddForce(u,G())
call ParticleLinkConditionTrigger2Func(u,ParticleGroundHit(),"GroundHit_Bounce")
call ParticleLinkConditionTrigger2Func(u,ParticleDeath(),"Death_ExplodeNade")
call UnitApplyTimedLife(u,'BTLF',2.)
set l=null
set h=null
set u=null
endfunction

But well, it's a bit long :p

Who can't read the colorful text, then read this :

Code:
function MakeUnitFlyable takes unit u returns nothing
call UnitAddAbility(u,'Amrf')
call UnitRemoveAbility(u,'Amrf')
endfunction

function DestroyEffectTimed takes effect eff,real duration returns nothing
call PolledWait(duration)
call DestroyEffect(eff)
endfunction

function DamageArea takes unit source,real maxdmg,integer damageV,real radius returns nothing
local integer i=0
local integer originV
local real array r
local group g=CreateGroup()
local unit c
call GroupEnumUnitsInRange(g,udg_vectorX[damageV],udg_vectorY[damageV],radius,null)
loop
set c=FirstOfGroup(g)
exitwhen c==null
if GetUnitState(c,UNIT_STATE_LIFE)>0 then
set r[0]=GetUnitX(c)
set r[1]=GetUnitY(c)
set r[2]=GetZ(r[0],r[1])
set originV=VectorCreate(r[0],r[1],r[2])
if IsPointInSphere(originV,damageV,radius) then
call VectorSubtract(originV,damageV)
set r[5]=(radius-VectorGetLength(originV))/radius*maxdmg
call UnitDamageTarget(source,c,r[5],true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
endif
call VectorDestroy(originV)
endif
call GroupRemoveUnit(g,c)
endloop
call DestroyGroup(g)
set g=null
set c=null
endfunction

function CreateExplosion takes player p,string path,real x,real y,real z,real facing,real size,real time returns nothing
local unit u=CreateUnit(p,'e001',x,y,facing)
local effect e
call SetUnitX(u,x)
call SetUnitY(u,y)
call MakeUnitFlyable(u)
call SetUnitAnimationByIndex(u,90)
call SetUnitScale(u,size,size,size)
call SetUnitFlyHeight(u,z-GetZ(x,y),0)
if time==0 then
call DestroyEffect(AddSpecialEffectTarget(path,u,"origin"))
else
set e=AddSpecialEffectTarget(path,u,"origin")
endif
call KillUnit(u)
set u=null
if time>0 then
call DestroyEffectTimed(e,time)
endif
set e=null
endfunction

function Death_ExplodeNade takes nothing returns nothing
local unit u=GetEnumUnit()
local integer p=udg_clsParticlePlace[GetUnitUserData(u)]
call CreateExplosion(GetOwningPlayer(u),"Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",udg_vectorX[p],udg_vectorY[p],udg_vectorZ[p],GetRandomReal(0,360),1.,5.)
call CreateExplosion(GetOwningPlayer(u),"Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl",udg_vectorX[p],udg_vectorY[p],udg_vectorZ[p],GetRandomReal(0,360),3.,0)
call DamageArea(u,275,p,256.)
call RemoveParticle(u,true)
set u=null
endfunction

function Trig_Grenade_Conditions takes nothing returns boolean
return GetSpellAbilityId()=='A001'
endfunction
function Trig_Grenade_Actions takes nothing returns nothing
local unit h=GetSpellAbilityUnit()
local location l=GetSpellTargetLoc()
local real x=GetLocationX(l)-GetUnitX(h)
local real y=GetLocationY(l)-GetUnitY(h)
local real a=Atan2BJ(y,x)
local real aoa
local unit u=CreateParticle(GetOwningPlayer(h),'e000',GetUnitX(h),GetUnitY(h),a)
local real array r
local integer i=udg_clsParticlePlace[GetUnitUserData(u)]
set udg_vectorX[i]=udg_vectorX[i]-udg_vectorX[SpawnPlaceOffset()]*CosBJ(a)
set udg_vectorY[i]=udg_vectorY[i]-udg_vectorY[SpawnPlaceOffset()]*SinBJ(a)
set udg_vectorZ[i]=udg_vectorZ[i]-udg_vectorZ[SpawnPlaceOffset()]+1
set r[2]=750
set r[0]=RMinBJ(r[2],SquareRoot(x*x+y*y))
set r[1]=SquareRoot(r[2]*VectorGetLength(G()))
set aoa=(bj_PI/2)-(Asin((r[0]*VectorGetLength(G()))/(r[1]*r[1]))/2)
call SetUnitTimeScalePercent(u,10.00)
call ParticleSetSpeed(u,Cos(aoa)*CosBJ(a)*r[1],Cos(aoa)*SinBJ(a)*r[1],r[1]*Sin(aoa))
call ParticleAddForce(u,G())
call ParticleLinkConditionTrigger2Func(u,ParticleGroundHit(),"GroundHit_Bounce")
call ParticleLinkConditionTrigger2Func(u,ParticleDeath(),"Death_ExplodeNade")
call UnitApplyTimedLife(u,'BTLF',2.)
set l=null
set h=null
set u=null
endfunction

From Elimination Tournament 1.2. (I modified a bit the functions)
 
1

1337D00D

Guest
You changed the spell and unit raw codes in the ability, right?
 

substance

New Member
Reaction score
34
Sweet, I've been waiting for something like this. I can see that the particle system is really powerfull.

I'll give it a shot (even though im a JASS noob) and report back in this reply.

**Hah, I can't beleive it but I actually got it to work! This system is quite easy, I may have been able to do it without reading the JASS tutorials earlier.

Chocobo pointed out most of the obvious stuff and you should probably edit your main post to address those issues. Oh yeh and you might want to add that you have to change your WE settings in order to give feilds a negative value.

Chocobo your version of the spell seems a bit more complex (and customizable!) and I probably wont attempt to figure it out yet (untill I get more of the basics of the particle system down) but you should probably elaborate more on what the functions do(atleast the supplement functions) for other readers. It seems very solid!

Anyway good job 1337D00D, cant wait to see you finish this out!
 
1

1337D00D

Guest
Sure.

And I added how to make a bullet type projectile.

BTW, the special dummy unit isn't required for use.
 

Chocobo

White-Flower
Reaction score
409
Sweet, I've been waiting for something like this. I can see that the particle system is really powerfull.

I'll give it a shot (even though im a JASS noob) and report back in this reply.

**Hah, I can't beleive it but I actually got it to work! This system is quite easy, I may have been able to do it without reading the JASS tutorials earlier.

Chocobo pointed out most of the obvious stuff and you should probably edit your main post to address those issues. Oh yeh and you might want to add that you have to change your WE settings in order to give feilds a negative value.

Chocobo your version of the spell seems a bit more complex (and customizable!) and I probably wont attempt to figure it out yet (untill I get more of the basics of the particle system down) but you should probably elaborate more on what the functions do(atleast the supplement functions) for other readers. It seems very solid!

Anyway good job 1337D00D, cant wait to see you finish this out!

Sure.

And I added how to make a bullet type projectile.

BTW, the special dummy unit isn't required for use.

I can create some Extra Func packs if people need it and if I have TIME :p


Code:
  call GroupEnumUnitsInRange(g, udg_vectorX[p], udg_vectorY[p], 60, null)
    if IsPointInSphere(tv, p, 60) then

Just to people who don't know what's that, the first line generates a group from all units around Location(udg_VectorX[p],udg_VectorY[p]) at a range of 60 w/o any boolexpr (boolean expression, meaning Condition).
The second line is to check if the point tv from p is a range of 60 is in the Sphere (this works with Z, whereas groups only works with X and Y).

The last func requires Anitarf's Vector System.
 

Sooda

Diversity enchants
Reaction score
318
Because it is made by him from native functions. Remember kids everyone can do their own functions (Even H2I function is made by people and in reallity it dosn' t exict. I think it' s so.). That "particle" actualy is a dummy unit with locust what is moved on map. So to use these functions we have to use game chace (Otherwise it isn' t possible, exeption is when you use global variables to hold locals data. Or it has already examples how to transfer locals from function to function ?

// Offtopic
Still it is (Who created these functions.) huge work and I couldn' t do better for now (Will I ever can' t promise.). Is it using vectors (Rolf it does why I even ask it ?), because I saw one test map where "ball" bounced on small map (Vector System Test Map. I think it was his.) but that ball got from bounce more trust (Lol it should be reversed if it had even some kind of force what made it moving. It should never gain new speed from bounce [Argh if it isn' t elastic material what could give it but everything is a bit.]. So it should stopped at some point but it didn' t.).

// Ontopic
Anyway good work and it sure speeds up work progress but you have to know a bit JASS too.

EDIT: Ok now I read it and all who know JASS could do the same things but someone made your life easier and already made functions for us with (optimized) JASS natives.
You could tell that people need to paste that system to Map Header because all functions what are called need to be before function what calls them (All the "System" consist of human made functions really. There isn't nothing "out of space" what YOU couldn' t do. Read Daelin and Vexorian JASS tutorials.). The core thing of all is to explane people how to tranfer locals from function to function (Luckily Emjlr3 did a tutorial some days ago about it.).
Speed of "bullet" depends on distance because it uses instead of location (In GUI point) location' s x, y maybe even z cordinates (What are faster) thats why you can' t change missile speed for "bullet" (This method should be explaned in one of Daelin' s tutorials about JASS.).
Check Chocobo suggestions about using GetTriggerUnit(). The fancy name for dummy unit in that "system" is "particle", how cute.
If this tutorial was for JASS users they should figure it out what functions do and how to set them up. If it was for GUI users (Or who mix GUI with custom scripts) you should explaine all the "mystery" what particle really is and that functions what are being used aren' t some uber task to create yourself.
> All the heavy math....
It isn' t so hard to understand it.
For conclusion that "system" uses natives what can be used by anyone. Just learn yourself JASS and you will see how easy it is. JASS isn' t hard to learn and don' t afraid to start learning it. But it isn' t wise to start inventing wheel again so use that tutorial and system (functions).
 

substance

New Member
Reaction score
34
I've been spending a few days working with the particle system now and I'm pretty familiar with the functions. Got a question though, is there any way to reference the triggering unit from the actions functions in a different function (ie. the Death_Remove function)?

I've been working on a EMP grenade and I had to use a global variable to get the right triggering unit.. but I think my method makes the ability no longer MUI :

Code:
function Trig_EMP_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetTriggerUnit())
local location topos = GetSpellTargetLoc()
local unit u = CreateParticle(GetOwningPlayer(GetSpellAbilityUnit()),'e00I',GetLocationX(casterpos),GetLocationY(casterpos),GetUnitFacing(GetSpellAbilityUnit()))

set udg_EMP_Caster = GetTriggerUnit() 

call ParticleSetSpeed(u,GetLocationX(topos)-GetLocationX(casterpos),GetLocationY(topos)-GetLocationY(casterpos),1200)
call ParticleLinkConditionTrigger2Func(u, ParticleGroundHit(), "GroundHit_Bounce")
call ParticleLinkConditionTrigger2Func(u, ParticleDeath(), [U]"Death_RemoveEMPBoom"[/U])
call ParticleAddForce(u, G())

call RemoveLocation(casterpos)
call RemoveLocation(topos)
set casterpos=null
set topos=null
set u = null
endfunction

PHP:
function Death_RemoveEMPBoom takes nothing returns nothing 
local unit caster = udg_EMP_Caster
local unit nade = GetEnumUnit()
local location upos = GetUnitLoc(nade) 
local effect eff = AddSpecialEffectLocBJ(upos, "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl")
local group g = GetUnitsInRangeOfLocMatching(350.00,upos,null)
local player cowner =  GetOwningPlayer(caster)
local unit f 

local unit dum
local location floc

loop 
      set f = FirstOfGroup(g)
      exitwhen f==null
      set floc = GetUnitLoc(f)  
      if IsUnitEnemy(f,cowner) then 
      set dum=CreateUnitAtLoc(cowner,'e00C',floc,0) 
      call UnitApplyTimedLife(dum,'BTLF',1) 
      call UnitAddAbility(dum,'A013') 
      call UnitAddAbility(dum,'A06W') 
      call SetUnitAbilityLevel(dum,'A013',GetUnitAbilityLevel(caster,'A04Q')) 
      call SetUnitAbilityLevel(dum,'A06W',GetUnitAbilityLevel(caster,'A04Q'))
      call IssueTargetOrder(dum,"purge", f) 
      if IsUnitType(f,UNIT_TYPE_MECHANICAL) then 
      call IssueTargetOrder(dum,"thunderbolt",f) 
      endif 
      endif 
      call GroupRemoveUnit(g,f)
      call RemoveLocation(floc)
      set floc = null   
      set dum = null 
endloop 

call DestroyGroup(g) 
call DestroyEffect (eff)
call RemoveParticle(GetEnumUnit(),true) 
call RemoveLocation(upos)
set udg_EMP_Caster = null 
set upos = null
set cowner = null 
set g = null 
set f = null 
set caster = null
set nade = null  
set eff = null 
endfunction

Is there a better way to get the right triggering unit?

BTW, 1337D00D these tuts have been awesome, I hope you keep updating (i'd like to see a shotgun or something with random math)
 

Chocobo

White-Flower
Reaction score
409
Is there a better way to get the right triggering unit?

BTW, 1337D00D these tuts have been awesome, I hope you keep updating (i'd like to see a shotgun or something with random math)

Use Linked Lists from Particle System?
Use a unit array with an reference from the integer vector?

Each vector is an integer, so..

..you may use the long way (the whole function instead of CreateParticle) to get access to the integer used by the vector you need.

I mean :

local integer vector = CreateVector(blabla)
//whatever
set udg_EMP_Caster[vector] = GetTriggerUnit()
 

substance

New Member
Reaction score
34
Use Linked Lists from Particle System?
Use a unit array with an reference from the integer vector?

Each vector is an integer, so..

..you may use the long way (the whole function instead of CreateParticle) to get access to the integer used by the vector you need.

I mean :

local integer vector = CreateVector(blabla)
//whatever
set udg_EMP_Caster[vector] = GetTriggerUnit()

I'm familiar with using a unti array, but that still requires a UDG. I dont know how to create my own linked list... but I guess I could see how it would work. Could you go into detail on this?

I'm always up for learning the most efficient way of doing something, instead of the easiest way.
 

Chocobo

White-Flower
Reaction score
409
I'm familiar with using a unti array, but that still requires a UDG. I dont know how to create my own linked list... but I guess I could see how it would work. Could you go into detail on this?

I'm always up for learning the most efficient way of doing something, instead of the easiest way.

CreateParticle from Particle System :

Code:
function CreateParticle takes player p, integer utype, real x, real y, real facing returns unit
  local unit u = CreateUnit(p, utype, x, y, facing)
  set x = x+CosBJ(facing)*VectorGetX(SpawnPlaceOffset())+SinBJ(facing)*VectorGetY(SpawnPlaceOffset())
  set y = y+SinBJ(facing)*VectorGetX(SpawnPlaceOffset())+CosBJ(facing)*VectorGetY(SpawnPlaceOffset())
  call SetUnitX(u, x)
  call SetUnitY(u, y)
  if not clsParticleCreate(u) then
    call BJDebugMsg("|cffff0000Error:|r could not initialize particle class in function |cffffcc00CreateParticle|r, see the documentation for help.")
    call RemoveUnit(u)
    return null
  endif
  call MakeUnitFlyable(u)
  call GroupAddUnit(udg_particleGroup, u)
  return u
endfunction

Just modify it a bit, and to create a particle :

Code:
  local unit u = [B]CreateUnit(p, utype, x, y, facing)[/B]
  local real x = x+CosBJ(facing)*VectorGetX(SpawnPlaceOffset())+SinBJ(facing)*VectorGetY(SpawnPlaceOffset())
  local real y = y+SinBJ(facing)*VectorGetX(SpawnPlaceOffset())+CosBJ(facing)*VectorGetY(SpawnPlaceOffset())
  call SetUnitX([B]u[/B], x)
  call SetUnitY([B]u[/B], y)
  if not clsParticleCreate([B]u[/B]) then
    call BJDebugMsg("|cffff0000Error:|r could not initialize particle class in function |cffffcc00CreateParticle|r, see the documentation for help.")
    call RemoveUnit([B]u[/B])
    return null
  endif
  call MakeUnitFlyable([B]u[/B])
  call GroupAddUnit(udg_particleGroup, [B]u[/B])

Anf also, more anti :

Code:
  local integer i = 0
  local integer j = -1
  local unit u = [B]CreateUnit(p, utype, x, y, facing)[/B]
  local real x = x+CosBJ(facing)*VectorGetX(SpawnPlaceOffset())+SinBJ(facing)*VectorGetY(SpawnPlaceOffset())
  local real y = y+SinBJ(facing)*VectorGetX(SpawnPlaceOffset())+CosBJ(facing)*VectorGetY(SpawnPlaceOffset())
  call SetUnitX([B]u[/B], x)
  call SetUnitY([B]u[/B], y)
  if not clsParticleCreate([B]u[/B]) then
    call BJDebugMsg("|cffff0000Error:|r could not initialize particle class in function |cffffcc00CreateParticle|r, see the documentation for help.")
    call RemoveUnit([B]u[/B])
  endif
  call MakeUnitFlyable([B]u[/B])
  call GroupAddUnit(udg_particleGroup, [B]u[/B])
  loop
    exitwhen i > 8191
    if not udg_clsParticleTaken[i] then
      set j = i
      set i = 8192
    endif
    set i = i + 1
  endloop
  set udg_clsParticleTaken[j] = true
  set udg_clsParticlePlace[j] = VectorCreate(GetUnitX(u), GetUnitY(u), GetZ(GetUnitX(u), GetUnitY(u)) + VectorGetZ(SpawnPlaceOffset()))
  set udg_clsParticleSpeed[j] = VectorCreate(0,0,0)
  set udg_clsParticleForces[j] = LL_NewList(0)
  set udg_clsParticleConditions[j] = LL_NewList(0)
  set udg_clsParticleConditionStrings[j] = LL_NewList(0)
[B]  call SetUnitUserData(u,j)[/B]

The last line may be interesting. With some arrays, you may access freely to the number of the index in an another array :

Globals :
- udg_WhateverUnit : Unit Array

Pretty simple. To access it :

Code:
set udg_WhateverUnit[GetUnitUserData([B]<some unit>[/B])] = [B]<some unit>[/B]

More better? Structs. But I won't talk of it, if you are starting.

Lets take your trigger, and make a MUI Demo.

Your trigger :

Code:
function Death_RemoveEMPBoom takes nothing returns nothing 
[B]local unit caster = udg_EMP_Caster[/B]
local unit nade = GetEnumUnit()
local location upos = GetUnitLoc(nade) 
local effect eff = AddSpecialEffectLocBJ(upos, "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl")
local group g = GetUnitsInRangeOfLocMatching(350.00,upos,null)
local player cowner =  GetOwningPlayer(caster)
local unit f 

local unit dum
local location floc

loop 
      set f = FirstOfGroup(g)
      exitwhen f==null
      set floc = GetUnitLoc(f)  
      if IsUnitEnemy(f,cowner) then 
      set dum=CreateUnitAtLoc(cowner,'e00C',floc,0) 
      call UnitApplyTimedLife(dum,'BTLF',1) 
      call UnitAddAbility(dum,'A013') 
      call UnitAddAbility(dum,'A06W') 
      call SetUnitAbilityLevel(dum,'A013',GetUnitAbilityLevel(caster,'A04Q')) 
      call SetUnitAbilityLevel(dum,'A06W',GetUnitAbilityLevel(caster,'A04Q'))
      call IssueTargetOrder(dum,"purge", f) 
      if IsUnitType(f,UNIT_TYPE_MECHANICAL) then 
      call IssueTargetOrder(dum,"thunderbolt",f) 
      endif 
      endif 
      call GroupRemoveUnit(g,f)
      call RemoveLocation(floc)
      set floc = null   
      set dum = null 
endloop 

call DestroyGroup(g) 
call DestroyEffect (eff)
call RemoveParticle(GetEnumUnit(),true) 
call RemoveLocation(upos)
set udg_EMP_Caster = null 
set upos = null
set cowner = null 
set g = null 
set f = null 
set caster = null
set nade = null  
set eff = null 
endfunction

function Trig_EMP_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetTriggerUnit())
local location topos = GetSpellTargetLoc()
[B]local unit u = CreateParticle(GetOwningPlayer(GetSpellAbilityUnit()),'e00I',GetLocationX(casterpos),GetLocationY(casterpos),GetUnitFacing(GetSpellAbilityUnit()))[/B]

[B]set udg_EMP_Caster = GetTriggerUnit() [/B]

call ParticleSetSpeed(u,GetLocationX(topos)-GetLocationX(casterpos),GetLocationY(topos)-GetLocationY(casterpos),1200)
call ParticleLinkConditionTrigger2Func(u, ParticleGroundHit(), "GroundHit_Bounce")
call ParticleLinkConditionTrigger2Func(u, ParticleDeath(), "Death_RemoveEMPBoom")
call ParticleAddForce(u, G())

call RemoveLocation(casterpos)
call RemoveLocation(topos)
set casterpos=null
set topos=null
set u = null
endfunction


What we need to fix? The bolded parts. And also get rid of CreateParticle Function. For that, we will use what I wrote before.


Code:
function Death_RemoveEMPBoom takes nothing returns nothing 
[B]local unit caster = udg_EMP_Caster[GetUnitUserData(GetEnumUnit())][/B]
local unit nade = GetEnumUnit()
local location upos = GetUnitLoc(nade) 
local effect eff = AddSpecialEffectLocBJ(upos, "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl")
local group g = GetUnitsInRangeOfLocMatching(350.00,upos,null)
local player cowner =  GetOwningPlayer(caster)
local unit f 

local unit dum
local location floc

loop 
      set f = FirstOfGroup(g)
      exitwhen f==null
      set floc = GetUnitLoc(f)  
      if IsUnitEnemy(f,cowner) then 
      set dum=CreateUnitAtLoc(cowner,'e00C',floc,0) 
      call UnitApplyTimedLife(dum,'BTLF',1) 
      call UnitAddAbility(dum,'A013') 
      call UnitAddAbility(dum,'A06W') 
      call SetUnitAbilityLevel(dum,'A013',GetUnitAbilityLevel(caster,'A04Q')) 
      call SetUnitAbilityLevel(dum,'A06W',GetUnitAbilityLevel(caster,'A04Q'))
      call IssueTargetOrder(dum,"purge", f) 
      if IsUnitType(f,UNIT_TYPE_MECHANICAL) then 
      call IssueTargetOrder(dum,"thunderbolt",f) 
      endif 
      endif 
      call GroupRemoveUnit(g,f)
      call RemoveLocation(floc)
      set floc = null   
      set dum = null 
endloop 

call DestroyGroup(g) 
call DestroyEffect (eff)
call RemoveParticle(GetEnumUnit(),true) 
call RemoveLocation(upos)
set udg_EMP_Caster = null 
set upos = null
set cowner = null 
set g = null 
set f = null 
set caster = null
set nade = null  
set eff = null 
endfunction

function Trig_EMP_Actions takes nothing returns nothing
local location casterpos = GetUnitLoc(GetTriggerUnit())
local location topos = GetSpellTargetLoc()
  local integer i = 0
  local integer j = -1
  local unit u = [B]CreateUnit(GetOwningPlayer(), 'e001', GetLocationX(casterpos), GetLocationY(casterpos), GetUnitFacing(GetTriggerUnit())[/B]
  local real x = x+CosBJ(GetUnitFacing(GetTriggerUnit()))*VectorGetX(SpawnPlaceOffset())+SinBJ(GetUnitFacing(GetTriggerUnit()))*VectorGetY(SpawnPlaceOffset())
  local real y = y+SinBJ(GetUnitFacing(GetTriggerUnit()))*VectorGetX(SpawnPlaceOffset())+CosBJ(GetUnitFacing(GetTriggerUnit()))*VectorGetY(SpawnPlaceOffset())
  call SetUnitX([B]u[/B], x)
  call SetUnitY([B]u[/B], y)
  if not clsParticleCreate([B]u[/B]) then
    call BJDebugMsg("|cffff0000Error:|r could not initialize particle class in function |cffffcc00CreateParticle|r, see the documentation for help.")
    call RemoveUnit([B]u[/B])
  endif
  call MakeUnitFlyable([B]u[/B])
  call GroupAddUnit(udg_particleGroup, [B]u[/B])
  loop
    exitwhen i > 8191
    if not udg_clsParticleTaken[i] then
      set j = i
      set i = 8192
    endif
    set i = i + 1
  endloop
  set udg_clsParticleTaken[j] = true
  set udg_clsParticlePlace[j] = VectorCreate(GetUnitX(u), GetUnitY(u), GetZ(GetUnitX(u), GetUnitY(u)) + VectorGetZ(SpawnPlaceOffset()))
  set udg_clsParticleSpeed[j] = VectorCreate(0,0,0)
  set udg_clsParticleForces[j] = LL_NewList(0)
  set udg_clsParticleConditions[j] = LL_NewList(0)
  set udg_clsParticleConditionStrings[j] = LL_NewList(0)
[B]  call SetUnitUserData(u,j)[/B]

[B]set udg_EMP_Caster[GetUnitUserData(u)] = GetTriggerUnit() [/B]

call ParticleSetSpeed(u,GetLocationX(topos)-GetLocationX(casterpos),GetLocationY(topos)-GetLocationY(casterpos),1200)
call ParticleLinkConditionTrigger2Func(u, ParticleGroundHit(), "GroundHit_Bounce")
call ParticleLinkConditionTrigger2Func(u, ParticleDeath(), "Death_RemoveEMPBoom")
call ParticleAddForce(u, G())

call RemoveLocation(casterpos)
call RemoveLocation(topos)
set casterpos=null
set topos=null
set u = null
endfunction

Errors while saving? It's normal, I didn't check the code. Sorry for.
 

Rheias

New Helper (I got over 2000 posts)
Reaction score
232
Do you mind explaining in further detail what is does wind and gravity do?
 
1

1337D00D

Guest
Wind and gravity are "forces". Adding gravity to an object makes it fall down. Adding wind to an object makes it move to the side as if it was being blown.
 

Rheias

New Helper (I got over 2000 posts)
Reaction score
232
Yes I understood that, however how will I edit the values efficently?

Say I put G(#) what will the number present? Same goes to wind.

Thanks.
 
A

appz_hunter

Guest
This is a nice tutorial, but where can i get an unprotected example map of this? Submit one to either wc3campaigns.net or the hive workshop (or any wc3 map site) and link me there. I'd prefer one with an example of the bullet and grenade, with no memory leaks and full multi-user instanceability. I'd really appreciate it.
 

Chocobo

White-Flower
Reaction score
409
This is a nice tutorial, but where can i get an unprotected example map of this? Submit one to either wc3campaigns.net or the hive workshop (or any wc3 map site) and link me there. I'd prefer one with an example of the bullet and grenade, with no memory leaks and full multi-user instanceability. I'd really appreciate it.

The main objective is to create yours, this tutorial is more aimed to create your own projectile/bullet.

You can also just simply copy and paste, then create the required units..
 
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