• 🏆 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: 'Over Time' Effects

Status
Not open for further replies.
I'm coding a projectile system in jass and I've gotten a long way, but i want to be able for it to have the functionality of a fire ball that when it blows up the nearby ground catches on fire.

However I want it to be that with a few changes in the trigger (that uses the system) you can make it an ice field from a blizzard.

All this can be done except the AoE damaging/slowing overtime. The slowing part I can do, but I'm lost on making the basic 'deals x dmg over y seconds in z area' effect.

NOTE: this is just the core system, not the two helper function that clear/set a projectile.

JASS:
function Trig_PS_TargetFilter takes nothing returns boolean
    local unit u=GetFilterUnit()
    local boolean b=GetUnitState(u,UNIT_STATE_LIFE)>0and IsUnitEnemy(u,GetOwningPlayer(udg_PS_CurProjectile))==true and IsUnitInGroup(u,udg_PSG_Projectiles)==false
    set u=null
    return b
endfunction
function Trig_PS_Target takes nothing returns nothing
    call UnitDamageTarget(udg_PS_CurProjectile,GetEnumUnit(),udg_PS_Dmg,true,false,ATTACK_TYPE_MELEE,DAMAGE_TYPE_NORMAL,null)
endfunction
function Trig_PS_Loop takes nothing returns nothing
    local unit u=GetEnumUnit()
    local integer id=GetHandleId(u)
    local real array xy
    local boolean Boom=false
    local group g
    local location l
    local integer i
    local player p=GetOwningPlayer(u)
    local real an
    local unit U
    //Reals
    set udg_PS_Wiggle=LoadReal(udg_PSG_Hash,id,StringHash("Wiggle"))*udg_PSG_Rate
    set udg_PS_Turn=LoadReal(udg_PSG_Hash,id,StringHash("Turn"))*udg_PSG_Rate
    set udg_PS_Angle=LoadReal(udg_PSG_Hash,id,StringHash("Angle"))+udg_PS_Turn+GetRandomReal(-udg_PS_Wiggle,udg_PS_Wiggle)
    set udg_PS_Speed=LoadReal(udg_PSG_Hash,id,StringHash("Speed"))*udg_PSG_Rate
    set udg_PS_ColSize=LoadReal(udg_PSG_Hash,id,StringHash("ColSize"))
    set udg_PS_ColColSize=LoadReal(udg_PSG_Hash,id,StringHash("ColColSize"))
    set udg_PS_Dmg=LoadReal(udg_PSG_Hash,id,StringHash("Dmg"))
    set udg_PS_DmgAoE=LoadReal(udg_PSG_Hash,id,StringHash("DmgAoE"))
    set udg_PS_DmgDoT=LoadReal(udg_PSG_Hash,id,StringHash("DmgDot"))
    //Integers
    //Ids
    set udg_PS_TrailUnit=LoadInteger(udg_PSG_Hash,id,StringHash("TrailUnit"))
    set udg_PS_ColUnit=LoadInteger(udg_PSG_Hash,id,StringHash("ColUnit"))
    //Ints
    set udg_PS_TrailChance=LoadInteger(udg_PSG_Hash,id,StringHash("TrailChance"))
    set udg_PS_TrailNum=LoadInteger(udg_PSG_Hash,id,StringHash("TrailNum"))
    set udg_PS_Life=LoadInteger(udg_PSG_Hash,id,StringHash("Life"))-R2I(udg_PS_Speed)
    set udg_PS_ColNum=LoadInteger(udg_PSG_Hash,id,StringHash("ColNum"))
    set udg_PS_Custom=LoadInteger(udg_PSG_Hash,id,StringHash("Custom"))
    set udg_PS_Filter=LoadInteger(udg_PSG_Hash,id,StringHash("Filter"))
    //Booleans
    set udg_PS_ColDeath=LoadBoolean(udg_PSG_Hash,id,StringHash("ColDeath"))
    //Strings
    set udg_PS_TrailSFX=LoadStr(udg_PSG_Hash,id,StringHash("TrailSFX"))
    set udg_PS_ColSFX=LoadStr(udg_PSG_Hash,id,StringHash("ColSFX"))
    set udg_PS_AoESFX=LoadStr(udg_PSG_Hash,id,StringHash("AoESFX"))
    set udg_PS_DoTSFX=LoadStr(udg_PSG_Hash,id,StringHash("DoTSFX"))
    //System
    if udg_PS_Filter==0 then
        set udg_PS_Filter=1
    endif
    set udg_PS_CurProjectile=u
    set xy[0]=GetUnitX(udg_PS_CurProjectile)+udg_PS_Speed*Cos(udg_PS_Angle*.01745)
    set xy[1]=GetUnitY(udg_PS_CurProjectile)+udg_PS_Speed*Sin(udg_PS_Angle*.01745)
    call SetUnitX(udg_PS_CurProjectile,xy[0])
    call SetUnitY(udg_PS_CurProjectile,xy[1])
    call SetUnitFacing(udg_PS_CurProjectile,udg_PS_Angle)
    set l=Location(xy[0],xy[1])
    set g=GetUnitsInRangeOfLocMatching(udg_PS_ColSize,l,Condition(function Trig_PS_TargetFilter))
    call RemoveLocation(l)
    set l=null
    if CountUnitsInGroup(g)>0then
        set Boom=true
        call ForGroup(g,function Trig_PS_Target)
        if udg_PS_ColDeath then
            set udg_PS_Life=0
        endif
    endif
    call GroupClear(g)
    set g=null
    /////////////////////////
    //Trail SFX and units
    /////////////////////////
    call DestroyEffect(AddSpecialEffect(udg_PS_TrailSFX,xy[0],xy[1]))
    if udg_PS_TrailChance>0and udg_PS_TrailUnit!=0and udg_PS_TrailNum>0then
        if GetRandomInt(1,100)<=udg_PS_TrailChance then
            set i=0
            loop
                exitwhen i==udg_PS_TrailNum
                set i=i+1
                if udg_PS_TrailNum==1then
                    set an=GetRandomReal(0,360)
                else
                    set an=360/udg_PS_TrailNum*i
                endif
                set U=CreateUnit(p,udg_PS_TrailUnit,xy[0],xy[1],an)
                call SaveInteger(udg_PSG_Hash,GetHandleId(U),StringHash("Custom"),udg_PS_Custom)
                set U=null
            endloop
        endif
    endif
    /////////////////////////
    //Save the values we change
    /////////////////////////
    call SaveReal(udg_PSG_Hash,id,StringHash("Angle"),udg_PS_Angle)
    call SaveInteger(udg_PSG_Hash,id,StringHash("Life"),udg_PS_Life)
    /////////////////////////
    //If out of life or on Death Terrain->die
    /////////////////////////
    if GetTerrainType(xy[0],xy[1])==udg_PSG_Terrain or udg_PS_Life<=0 or IsTerrainPathable(xy[0],xy[1],PATHING_TYPE_WALKABILITY) or IsTerrainPathable(xy[0],xy[1],ConvertPathingType(udg_PS_Filter))or IsPathable(xy[0],xy[1],'I001') then
        set Boom=true
        call KillUnit(udg_PS_CurProjectile)
        call GroupRemoveUnit(udg_PSG_Projectiles,udg_PS_CurProjectile)
        call FlushChildHashtable(udg_PSG_Hash,id)
    endif
    /////////////////////////
    //If collide with unit or die->boom
    /////////////////////////
    if Boom then
        call DestroyEffect(AddSpecialEffect(udg_PS_ColSFX,xy[0],xy[1]))
        call UnitDamagePoint(udg_PS_CurProjectile,0,udg_PS_ColColSize,xy[0],xy[1],udg_PS_DmgAoE,true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
        if udg_PS_ColUnit!=0and udg_PS_ColNum>0then
            set i=0
            loop
                exitwhen i==udg_PS_ColNum
                set i=i+1
                if udg_PS_ColNum==1then
                    set an=GetRandomReal(0,360)
                else
                    set an=360/udg_PS_ColNum*i
                endif
                set U=CreateUnit(p,udg_PS_ColUnit,xy[0],xy[1],an)
                call SaveInteger(udg_PSG_Hash,GetHandleId(U),StringHash("Custom"),udg_PS_Custom)
                set U=null
            endloop
        endif
    endif
    //clear locals
    set p=null
    set u=null
    //reset globals
    call PS_Reset()
    set udg_PSG_Count=udg_PSG_Count+1
endfunction
function Trig_PS_Actions takes nothing returns nothing
    set udg_PSG_Count=0
    call ForGroup(udg_PSG_Projectiles,function Trig_PS_Loop)
    if udg_PSG_Count<1then
        call DisableTrigger(gg_trg_PS)
    endif
endfunction
function InitTrig_PS takes nothing returns nothing
    set gg_trg_PS=CreateTrigger()
    call DisableTrigger(gg_trg_PS)
    call TriggerRegisterTimerEvent(gg_trg_PS,0.04,true)
    call TriggerAddAction(gg_trg_PS,function Trig_PS_Actions)
endfunction
Explanation of variables:
JASS:
===========================================================================
	Explaination of variables
===========================================================================

Note: Col=Hitting a unit, running out of life, or hitting the 'Death' terrain type.
====================
'LOCAL' VARIABLES
====================
udg_PS_Angle
 - Real
 - Determines the angle that the projectile moves in.
 - NOTE: Saves after each iteration.
====================
udg_PS_AoESFX
 - String
 - <Not In Use>
====================
udg_PS_ColColSize
 - Real
 - Radius to damage units for udg_PS_DmgAoE when the projectile collides (aka explodes)
====================
udg_PS_ColDeath
 - Boolean
 - Whether or not the projectiles dies when it collides.
====================
udg_PS_ColNum
 - Integer
 - How many units to create when the projectile collides or dies.
 - WARNING: Use care with high numbers!
====================
usg_PS_ColSFX
 - String
 - The special effect to create when the projectile collides or dies.
 - WARNING: Try to use 'small' models if udg_PS_ColDeath = true.
====================
udg_PS_ColSize
 - Real
 - How far of a radius to check for colliding with units.
====================
udg_PS_ColUnit
 - Integer (unit type)
 - The unit type to create when the projectile collides or dies.
====================
udg_PS_CurProjectile
 - Unit
 - This is a temporary variable used internally, basically the EnumUnit in the loop.
====================
udg_PS_Custom
 - Integer
 - A custom value (like a unit's custom value) that can be used to pass some data along the projectile.
 - NPTE: This value is passed to all TrailUnits or ColUnits it creates.
 - NOTE: Not used in the system, but by the unser on a spell by spell basis.
====================
udg_PS_Dmg
 - Real
 - How much damage to deal to a unit it collides with.
====================
udg_PS_DmgAoE
 - Real
 - How much damage to deal to all units in udg_PS_ColColSize, stacks with udg_PS_Dmg.
====================
udg_PS_DmgDoT
 - Real
 - <Not In Use>
====================
udg_PS_DoTSFX
 - String
 - <Not In Use>
====================
udg_PS_Keep
 - Boolean
 - After calling PS_New() function if this is true you keep all the global variable values, rather thanr esetting them.
 - WARNING: Each iteration of the projectile system resets the values, so don't use waits.
 - NOTE: You have to set this to true after each call of PS_New() as that will always reset it to false.
====================
udg_PS_Life
 - Integer
 - How far (in distance) the projectile moves before dieing.
 - NOTE: Saves after each iteration.
====================
udg_PS_Speed
 - Real
 - How far the projectile moves.
====================
udg_PS_TrailChance
 - Integer
 - The chance (0-100) that the projectile will create udg_PS_TrailNum udg_PS_TrailUnit's.
 - WARNING: Use care with high chances!
====================
udg_PS_TrailNum
 - Integer
 - How many units to create when it creates a trail unit.
 - WARNING: Use care with high numbers!
====================
udg_PS_TrailSFX
 - String
 - The special effect to create each iteration.
 - WARNING: Try to use 'small' models.
====================
udg_PS_TrailUnit
 - Integer (unit type)
 - The unit type the projectile has a chance to make each iteration.
====================
udg_PS_Turn
 - Real
 - Is added to udg_PS_Angle.
====================
udg_PS_Wiggle
 - Real
 - Nudges udg_PS_Angle by this ammount, positive or negitive.
====================
'GLOBAL' VARIABLES
====================
udg_PSG_Count
 - Integer
 - Counter used internally, check if the looping trigger should be turned off.
====================
udg_PSG_Hash
 - Hashtable
 - Stores all projectile data in this.
====================
udg_PSG_Projectiles
 - Unit Group
 - Contains all projectiles to iterate through them.
====================
udg_PSG_Rate
 - Real
 - This is like the rate of time, and is defualted to 1.00, is put to 2.00 the projectiles move and turn twice as fast. if set to 0 they will freeze.
 - WARNING: Becareful of low values!
 - Note: High values are look worse (5+).
====================
udg_PSG_Terrain
 - Integer (Terrian Type)
 - A terrain type that will kill any touching projectile.
====================
REFERANCE LIST
====================
real		udg_PS_Angle
string		udg_PS_AoESFX
real		udg_PS_ColColSize
boolean		udg_PS_ColDeath
integer		udg_PS_ColNum
string		udg_PS_ColSFX
real		udg_PS_ColSize
unit-type	udg_PS_ColUnit
unit		udg_PS_CurProjectile
integer		udg_PS_Custom
real		udg_PS_Dmg
real		udg_PS_DmgAoE
real		udg_PS_DmgDoT
string		udg_PS_DoTSFX
boolean		udg_PS_Keep
integer		udg_PS_Life
real		udg_PS_Speed
integer		udg_PS_TrailChance
integer		udg_PS_TrailNum
string		udg_PS_TrailSFX
unit-type	udg_PS_TrailUnit
real		udg_PS_Turn
real		udg_PS_Wiggle
integer		udg_PSG_Count
hashtable	udg_PSG_Hash
unitgroup	udg_PSG_Projectiles
real		udg_PSG_Rate
terrain-type	udg_PSG_Terrain
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
You could add the damaging unit into a unit group and start a periodic timer. Save the coordinates into a hashtable. When the timer expires, pick all units near the coordinates and damage them. Update a time value for the unit so it knows when the time is over.

With correctly keyed coordinates, you can have multiple instances of the damage thingy going on for the same unit.

And instead of using this:
JASS:
GetUnitsInRangeOfLocMatching

you could use this:
JASS:
GroupEnumUnitsInRange

And isntead of CountUnitsInGroup you could use an integer value. Create a variable and increase it by 1 when a unit is added to the group, decrease it when a unit is removed from a group.
 
Status
Not open for further replies.
Top