• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[JASS] Gas Grenade

Status
Not open for further replies.
Hi guys, Well, I was searching for maps in the spells section and I found a Gas Grenada that is just what I need. However, the spell leaks, and I believe I can make it more efficient. So I decided to start doing so, removing all BJ's, and stuff like that.

However I have a problem ... My grenade does not kill the enemy units !!
I will post the code I did here:

[jass=Gas Grenade, my version]
function Trig_Poison_Gas_Grenade_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00Q'
endfunction
//==========================================================
function Trig_Poison_Gas_Grenade_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit() //casting unit
local player owner = GetOwningPlayer(caster) //owner of casting unit
local location l = GetSpellTargetLoc() //target location
local effect e //this will be used to store the cloud effect
local integer duration = 0 //this variable will be used as a counter
local group g = CreateGroup() //it will store units arround the target locations
local unit picked

local real dx = GetLocationX(l) - GetUnitX(caster) //distance between CasterX and targetlocX
local real dy = GetLocationY(l) - GetUnitY(caster) //distance between CasterY and targetlocY
local real dAB = SquareRoot(dx * dx + dy * dy) //transforms the coordinates into a vector AB with lenght

local unit dummy = CreateUnit(owner, 'e003', GetUnitX(caster), GetUnitY(caster), 270.0) //Creates the dummy that will launch the grenade

call IssuePointOrderLoc(dummy, "attackground", l) //Orders dummy to launch grenade to targetloc
call UnitApplyTimedLife(dummy, 'BTLF', 0.90) //kills unit after it launches grenade (takes +/- 0.90 secs to launch it)
call TriggerSleepAction(dAB / 800.0) // this uses a law of physics ( velocity = distance / time). Here I wait until the projectile arrives its destination

set e = AddSpecialEffectLoc("war3mapImported\\Radioactivecloud.mdx", l) //creates the Cloud effect in the target loc

//Unil this comment, everything works in perfection
//after this comment, I need help, I make no idea how to do this

//I want to select all enemy, non-structure units arround the targetloc
//so then I can kill them, or do anything.
//the problem is in creating to group to do this.

call GroupEnumUnitsInRange( g, GetLocationX( l ), GetLocationY( l ), 250, Filter(null) )//Picks all units in a 250 AoE arround targetloc

loop
exitwhen(duration == 10)
set picked = FirstOfGroup(g)

if IsUnitEnemy(picked, owner) and IsUnitType(picked, UNIT_TYPE_MAGIC_IMMUNE) == false and GetUnitState(picked, UNIT_STATE_LIFE) > 0 and IsUnitType(picked, UNIT_TYPE_STRUCTURE) == false then
call KillUnit(picked)
endif
call GroupRemoveUnit(g,picked)
call TriggerSleepAction(1.0)
set duration = duration + 1
endloop

//Now after this comment, stuff is ok too
call DestroyEffect(e)
call DestroyGroup(g)
call RemoveLocation(l)

set e = null
set g = null
set l = null
set caster = null
set dummy = null
set owner = null
set picked = null
endfunction
//=========================================================
function InitTrig_Poison_Gas_Grenade takes nothing returns nothing
set gg_trg_Poison_Gas_Grenade = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Poison_Gas_Grenade, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Poison_Gas_Grenade, Condition( function Trig_Poison_Gas_Grenade_Conditions ) )
call TriggerAddAction( gg_trg_Poison_Gas_Grenade, function Trig_Poison_Gas_Grenade_Actions )
endfunction[/code]

This is what I did. I am also commenting it, so you guys can understand the complexity of the spell.

Now, here is the original spell ... as you can see, it was clearly made of GUI, and then converted.

[jass=GUI converted original version]
function Trig_Poison_Gas_Grenade_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A00Q' ) ) then
return false
endif
return true
endfunction

//Poisen Gas Grenade temporary Unitgroup actions

function PGGgroupActions takes nothing returns nothing
call UnitDamageTargetBJ( GetTriggerUnit(), GetEnumUnit(), ( 45.00 * I2R(GetUnitAbilityLevelSwapped('A00Q', GetTriggerUnit())) ), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
call AddSpecialEffectTargetUnitBJ( "chest", GetEnumUnit(), "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl" )
call DestroyEffectBJ( GetLastCreatedEffectBJ() )
call CreateTextTagUnitBJ( ( I2S(( 45 * GetUnitAbilityLevelSwapped('A00Q', GetTriggerUnit()) )) + "!" ), GetEnumUnit(), 0, 10, 0.00, 100, 0.00, 0 )
call SetTextTagVelocityBJ( GetLastCreatedTextTag(), 40.00, 90 )
call SetTextTagPermanentBJ( GetLastCreatedTextTag(), false )
call SetTextTagLifespanBJ( GetLastCreatedTextTag(), 3.00 )
endfunction

//Poisen Gas Grenade temporary Conditions actions

function PGGgroupW takes nothing returns boolean
return ( IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) == true )
endfunction

function PGGgroupQ takes nothing returns boolean
return ( GetUnitStateSwap(UNIT_STATE_LIFE, GetFilterUnit()) > 0.00 )
endfunction

function PGGCondition takes nothing returns boolean
return GetBooleanAnd( PGGgroupW(), PGGgroupQ() )
endfunction

//Poisen Gas Grenade Trigger

function Trig_Poison_Gas_Grenade_Actions takes nothing returns nothing
local location PGGlocA = GetUnitLoc(GetTriggerUnit())
local location PGGlocB = GetSpellTargetLoc()
local group PGGgroupA
local integer IntegerPGG
local effect EffPGG
call CreateNUnitsAtLoc( 1, 'e003', GetOwningPlayer(GetTriggerUnit()), PGGlocA, AngleBetweenPoints(PGGlocA, PGGlocB) )
call IssuePointOrderLocBJ( GetLastCreatedUnit(), "attackground", PGGlocB )
call SetUnitPathing( GetLastCreatedUnit(), false )
call UnitApplyTimedLifeBJ( 0.90, 'BTLF', GetLastCreatedUnit() )
call TriggerSleepAction( ( DistanceBetweenPoints(PGGlocA, PGGlocB) / 800.00 ) )
call AddSpecialEffectLocBJ( PGGlocB, "war3mapImported\\Radioactivecloud.mdx" )
set EffPGG = GetLastCreatedEffectBJ()
set IntegerPGG = 1
loop
exitwhen IntegerPGG > 10
set PGGgroupA = GetUnitsInRangeOfLocMatching(220.00, PGGlocB, Condition(function PGGCondition))
call ForGroupBJ( PGGgroupA, function PGGgroupActions )
call TriggerSleepAction(1.00 )
set IntegerPGG = IntegerPGG + 1
endloop
call DestroyEffectBJ( EffPGG )
call RemoveLocation(PGGlocA)
call RemoveLocation(PGGlocB)
call DestroyGroup(PGGgroupA)
set PGGlocA = null
set PGGlocB = null
set PGGgroupA = null
set EffPGG = null
set IntegerPGG = 0
endfunction

//===========================================================================
function InitTrig_Poison_Gas_Grenade takes nothing returns nothing
set gg_trg_Poison_Gas_Grenade = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Poison_Gas_Grenade, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Poison_Gas_Grenade, Condition( function Trig_Poison_Gas_Grenade_Conditions ) )
call TriggerAddAction( gg_trg_Poison_Gas_Grenade, function Trig_Poison_Gas_Grenade_Actions )
endfunction

[/code]

To simplify my code, I replaced the real effect with "call KillUnit(whichUnit)".
But the point will still be the same.

My real problem is in the loop.
Help plz =S
 
Mmmm, well, I will post here the original map, from where I took this spell.
It is a spellpack map, not approved (last time I checked) made by orkofmordor.

The point here, is to select all units inside the cloud, and then kill them.
The variable duration is the time the spell will last (it lasts for 10 seconds).
Meanwhile, all units within the cloud, or that enter the cloud, will be damaged (killed in my trigger).

I am posting here the original map. Hope the testing of it can actually help you out.

It is actually on of the best spell packs I've ever seen, to bad it is not optimized or either approved. So I decided to optimize it myself =)
 

Attachments

  • 13 Random Spells by orkofmordor.w3x
    99.6 KB · Views: 112
Level 29
Joined
Jul 29, 2007
Messages
5,174
I didn't look at the original code but yours simply can't do that.

You pick ONCE all the units in that area and then you start a loop of 10 loops that will kill each time the first of the group.

For what you want, you need a loop inside a loop.
The first one to pick the units every 0.5/second/whatever you want, and the second one to kill them.


And of course it won't be approved, the code is crappy :p
 
Level 19
Joined
Aug 24, 2007
Messages
2,888
YOU AGAIN !!! :D

repleace "Filter(null)" with "null"
Yes you need 2 loops
one for killing units
one for time increasing
set ChosenOnes = CreateGroup
loop
exitwhen duration == 10
call GroupThemAllTo(ChosenOnes
.. loop
.. set picked = firstOfGroup(ChosenOnes)
.. exitwhen picked == null
.. call PWNtehPICKEDone
.. call GroupRemoveUnit(you know
.. endloop
set duration = duration +1
Wait(1.)
endloop

I think members of group gets repleaced when
GroupEnumUnits
if it makes a problem (I dont think it will)
Clear group after pwning
 
Level 11
Joined
Aug 25, 2006
Messages
971
I would suggest the use of one loop and a ForGroup function. You can pass local variables through globals. I just like the way it works opposed to setting up a loop.
 
MMM, about the ForGroup function, it is slower and will create more lag in the game rit ??
That's why I am trying to optimize this spell. To avoid huge lag in my map.
If you download my spell map, you will see that the Incendiary bombs spell already creates a lot of lag (due the effects), I don't want the same to happen here, that's all.

I am working on the loop, more news once I did something (or not because I was not able to lol)
 
Level 6
Joined
Jun 30, 2006
Messages
230
If I remember correctly, Vexorian did some tests and determined ForGroup was actually faster than looping. I'll try to find the source, someone set us both straight if I am wrong.
 
Thx, that would be great to know.

Btw, Guys about the loop, I tried this, but it also doesn't work:
[jass=why?]
local group g = CreateGroup() //it will store units arround the target locations
loop
exitwhen(duration == 10)
call GroupEnumUnitsInRange( g, GetLocationX( l ), GetLocationY( l ), 250, Filter(null) )//Picks all units in a 250 AoE arround targetloc
set picked = FirstOfGroup(g)
loop
exitwhen ( picked == null)
if IsUnitEnemy(picked, owner) and GetUnitState(picked, UNIT_STATE_LIFE) > 0 then
call KillUnit(picked)
endif
call GroupRemoveUnit(g, picked)
endloop
call TriggerSleepAction(1.0)
set duration = duration + 1
endloop[/code]

Btw, Blue_Jeans, can you show me those tests after ? It would be awesome, and it would be worthy of + rep =P
 
Level 6
Joined
Jun 30, 2006
Messages
230
http://www.wc3campaigns.net/showthread.php?t=85392

You'll note in my code that I actually use a loop. This is because of the way I code things. You can't call a method in a ForGroup, you HAVE to do a function. So in this case I am using a loop.

Also, I wouldn't use TriggerSleepAction unless I had to, I'd use timers. I'm not completely done with the code, but I've been redoing it 'properly' with structs and such. You may not want to use this as it requires Cohadar's ABC and vJASS, but it will work when I'm done. I'll update this as I go:
JASS:
scope PoisonGasGrenade

globals
    integer AID_POISON_GAS_GRENADE='A00Q'
endglobals

struct PGG
    unit caster=GetTriggerUnit()
    unit target
    unit dummy
    timer t=CreateTimer()
    location casterloc=GetUnitLoc(.caster)
    location targetloc=GetSpellTargetLoc()
    group g=CreateGroup()
    integer i=0
    texttag tt
    
    private method onDestroy takes nothing returns nothing
        call ClearTimerStructA(.t)
        call PauseTimer(.t)
        call DestroyTimer(.t)
        call RemoveLocation(.casterloc)
        call RemoveLocation(.targetloc)
        call DestroyGroup(.g)
    endmethod
    private method textTag takes real dmg returns nothing
        call SetTextTagText(.tt,I2S(R2I(dmg))+"!",0.024)
        call SetTextTagPos(.tt,GetUnitX(.target),GetUnitY(.target),0)
        call SetTextTagColor(.tt,0,100,0,255)
        call SetTextTagVelocity(.tt,0,0.04)
        call SetTextTagFadepoint(.tt,1.2)
        call SetTextTagLifespan(.tt,3.00)
        call SetTextTagPermanent(.tt,false)
        call SetTextTagVisibility(.tt,true)
    endmethod
	public method Init takes string fx returns nothing
	    call CreateUnitAtLoc(GetOwningPlayer(.caster),'e003',.casterloc,AngleBetweenPoints(.casterloc,.targetloc))
	    set .dummy=GetLastCreatedUnit()
	    call IssuePointOrderLoc(.dummy,"attackground",.targetloc)
	    call SetUnitPathing(.dummy,false)
	    call UnitApplyTimedLife(.dummy,'BTLF',.90)
	    //call TriggerSleepAction((DistanceBetweenPoints(.casterloc,.targetloc)/ 800.00))
	    call AddSpecialEffectLoc(fx,.targetloc)
	endmethod
    public method Damage takes integer reps,real dmg,integer radius,string fx returns nothing
        set .i=.i+1
        call GroupEnumUnitsInRangeOfLoc(.g,.targetloc,radius,null)
        loop
            set .target=FirstOfGroup(.g)
            exitwhen .target==null
            if (IsUnitEnemy(.target,GetOwningPlayer(.caster))==true and GetUnitStateSwap(UNIT_STATE_LIFE,GetFilterUnit())> 0.405 and IsUnitType(.target,UNIT_TYPE_STRUCTURE)==false) then
                call DestroyEffect(AddSpecialEffectTarget(fx,.target,"chest"))
                call UnitDamageTarget(.caster,.target,dmg ,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC,null)
                set .tt=CreateTextTag()
                call this.textTag(dmg)
            endif
            call GroupRemoveUnit(.g,.target)
        endloop
        if(.i==reps)then
            call this.destroy()
        endif
    endmethod
endstruct

function Conditions takes nothing returns boolean
    return GetSpellAbilityId()==AID_POISON_GAS_GRENADE
endfunction

function Cast takes nothing returns nothing
    local PGG data=GetTimerStructA(GetExpiredTimer())
    local real dmg=45.00 * I2R(GetUnitAbilityLevelSwapped(AID_POISON_GAS_GRENADE, data.caster))
    call data.Damage(2,dmg,220,"Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl")
endfunction

function Actions takes nothing returns nothing
    local PGG data=PGG.create()
	call DisplayTextToPlayer(GetLocalPlayer(),0,0,"I fire0!")
	call data.Init("war3mapImported\\Radioactivecloud.mdx")
    call SetTimerStructA(data.t,data)
    call TimerStart(data.t,1,true,function Cast)
endfunction 

function InitTrig takes nothing returns nothing 
    local trigger trig=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
endfunction 

endscope



Edit: about your specific code, try this:
JASS:
local group g = CreateGroup()
//it will store units arround the target locations  
loop
    exitwhen(duration == 10)
    call GroupEnumUnitsInRange( g, GetLocationX( l ), GetLocationY( l ), 250, null )
    //Picks all units in a 250 AoE arround targetloc
    loop
        set picked = FirstOfGroup(g)
        exitwhen ( picked == null)
        if IsUnitEnemy(picked, owner) and GetUnitState(picked, UNIT_STATE_LIFE) > 0.405 then
            call KillUnit(picked)
        endif
        call GroupRemoveUnit(g, picked)
    endloop
    call TriggerSleepAction(1.0)
    set duration = duration + 1
endloop
 
Last edited:
So it means that loops are better that
JASS:
ForGroup
rit ?.. As i though ...
Ok, thx for your help +rep.

However, I am sorry to announce you, because I don't know about Katana's system, vJass, timers, or stucts, I can't use your code.

I've searching long for a decent tutorial, but that doesn't seem to exist. They just give you some stupid piece of code and the say: "Here is the code, the rest is your problem", and I always end up learning nothing.

So I won't use your code =S, Although I will try your loop optimization (you just changed the life state rit ?).
I think it won't work, but I will try.
About timers, well, I just have to wait 1 second, so my percentage of error can be actually a little big, precision is not a priority here.

Btw, if you guys know of a decent tutorial about timers (people are always talking about them), I would like to see them ...

EDIT

GUYS !!! i was searching here, and I found an excelent tutorial about katana's handle system !!!
I think I am ready to start using it (with some easy examples, I don't want to complicate things that much for mow).

So, if you guys think that's Katana's system is the solution you are free to use it, as long as you explain to me who it works after ! (lol)

Btw, yes, it seems that ForGroup is way faster then anything. I will try to use from now on, it also seems to be less complicated to use =)
 
Last edited:
Level 19
Joined
Aug 24, 2007
Messages
2,888
ForGroup is cool but
I think it can be faster without ForGroup
because we dont recreate group for many times
We have a group and we just repleace members in it
no delete/create
 
ABC !?, No1 is using ABC. I am not using ABC. Blue Jeans is, not me.
Anyway, today was a great day for me, as I have learned a lot (keep in mind that it is 12:31 pm, so I still have a long day ahead lol).

Anyway, Here is My gas Bomb !!

[jass=Gas Grenade]
function Trig_Poison_Gas_Grenade_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00Q'
endfunction
//==========================================================
function Trig_Poison_Gas_Grenade_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit() //casting unit
local player owner = GetOwningPlayer(caster) //owner of casting unit
local location l = GetSpellTargetLoc() //target location
local effect e //this will be used to store the cloud effect
local integer duration = 0 //this variable will be used as a counter
local group g = CreateGroup()//it will store units arround the target locations
local unit picked // this var will be used to store a uni from group g

local real dx = GetLocationX(l) - GetUnitX(caster) //distance between CasterX and targetlocX
local real dy = GetLocationY(l) - GetUnitY(caster) //distance between CasterY and targetlocY
local real dAB = SquareRoot(dx * dx + dy * dy) //transforms the coordinates into a vector AB with lenght

local unit dummy = CreateUnit(owner, 'e003', GetUnitX(caster), GetUnitY(caster), 270.0) //Creates the dummy that will launch the grenade

call IssuePointOrderLoc(dummy, "attackground", l) //Orders dummy to launch grenade to targetloc
call UnitApplyTimedLife(dummy, 'BTLF', 0.90) //kills unit after it launches grenade (takes +/- 0.90 secs to launch it)
call TriggerSleepAction(dAB / 800.0) // this uses a law of physics ( velocity = distance / time). Here I wait until the projectile arrives its destination

set e = AddSpecialEffectLoc("war3mapImported\\Radioactivecloud.mdx", l) //creates the Cloud effect in the target loc

loop
exitwhen(duration == 10) // this will exit when Duration == 10, which means 10 secs have passed
call GroupEnumUnitsInRange( g, GetLocationX( l ), GetLocationY( l ), 250, null )
//Picks all units in a 250 AoE arround targetloc
loop
set picked = FirstOfGroup(g)
exitwhen ( picked == null) //When all units were picked
if IsUnitEnemy(picked, owner) and GetUnitState(picked, UNIT_STATE_LIFE) > 0.405 and IsUnitType(picked, UNIT_TYPE_STRUCTURE) == false then
call KillUnit(picked)
//I really don't know what to do here, SO I am opened to suggestions (lol)
//About the effects the gas
endif
//if "picked" unit is enemy, alive and non structure then it will die, or suffer from something
call GroupRemoveUnit(g, picked) //removes picked Unit from Group g, so other Unit can take its place
endloop
call TriggerSleepAction(1.0) //waits 1 second
set duration = duration + 1 //increases this var after waiting 1 sec
endloop

//Now after this comment, stuff is ok too
call DestroyEffect(e)
call DestroyGroup(g)
call RemoveLocation(l)

set e = null
set g = null
set l = null
set caster = null
set dummy = null
set owner = null
endfunction
//=========================================================
function InitTrig_Poison_Gas_Grenade takes nothing returns nothing
set gg_trg_Poison_Gas_Grenade = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Poison_Gas_Grenade, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Poison_Gas_Grenade, Condition( function Trig_Poison_Gas_Grenade_Conditions ) )
call TriggerAddAction( gg_trg_Poison_Gas_Grenade, function Trig_Poison_Gas_Grenade_Actions )
endfunction[/code]

I am still opened to suggestion.
Also, if you have a good idea for the effect, go ahead and say it! =P, you will ofc be credited for it.
 
Level 19
Joined
Aug 24, 2007
Messages
2,888
I said it to blue jeans...
Anyway
want to store struct in timer ?
JASS:
globals
  private integer array STORE
endglobals
//
function H2I takes handle h returns integer
  return h
return 0
endfunction
//
function SetTimerStruct takes timer t, integer i returns nothing
  set STORE[H2I(t)-0x100000] = i
endfunction
//
function GetTimerStruct takes timer t, integer i returns nothing
   return STORE[H2I(t)-0x100000]
endfunction
This supports 8100(0) (I forgot to actual number) handles
I have this with
STORE1 STORE2 STORE3
that supports 24300(0) which you can never reach
 
Guys, Well, the loop is not working again ... why ?? No idea ... No damn idea ...
To make things worse, the cloud stays in the map for ever, it doesn't die... which means (probably) that the loop isn't working ... infinite loop ??
Here is the code I am using:
JASS:
function Trig_GasBombs_Actions takes nothing returns nothing
    local unit bomb = GetDyingUnit()
    local integer bombID = GetUnitTypeId(bomb)
    local player p = GetOwningPlayer(bomb)
    local unit array dummy
    local effect e
    local integer duration = 0
    local group g
    local unit picked
    if bombID == 'h000' then
        set e = AddSpecialEffect("war3mapImported\\Radioactivecloud.mdx", GetUnitX(bomb), GetUnitY(bomb)) //creates the Cloud effect in the target loc
        loop
            exitwhen(duration == 10) // this will exit when Duration == 10, which means 10 secs have passed
            call GroupEnumUnitsInRange( g, GetUnitX( bomb ), GetUnitY( bomb ), 250, null )
            //Picks all units in a 250 AoE arround targetloc
            loop
                set picked = FirstOfGroup(g)
                exitwhen ( picked == null) //When all units were picked
                if IsUnitEnemy(picked, p) and GetUnitState(picked, UNIT_STATE_LIFE) > 0.405 and IsUnitType(picked, UNIT_TYPE_STRUCTURE) == false then
                    set dummy[0] = CreateUnit(p, 'h001', GetUnitX(bomb), GetUnitY(bomb), 0.0)
                    set dummy[1] = CreateUnit(p, 'h001', GetUnitX(bomb), GetUnitY(bomb), 0.0)
                    call UnitAddAbility(dummy[0], 'A002')
                    call UnitAddAbility(dummy[1], 'A004')
                    call IssueTargetOrder(dummy[0], "curse", picked)
                    call IssueTargetOrder(dummy[1], "slow", picked)
                    call UnitApplyTimedLife(dummy[0], 'BTLF', 1)
                    call UnitApplyTimedLife(dummy[1], 'BTLF', 1)
                endif
                //if "picked" unit is enemy, alive and non structure then it will die, or suffer from something
                call GroupRemoveUnit(g, picked) //removes picked  Unit from Group g, so other Unit can take its place
            endloop
            call TriggerSleepAction(1.0) //waits 1 second
            set duration = duration + 1 //increases this var after waiting 1 sec
        endloop
        call DestroyEffect(e)
        call DestroyGroup(g)
    endif
    set g = null
    set e = null
    set bomb = null
    set p = null
    set dummy[0] = null
    set dummy[1] = null
endfunction
//===========================================================================
function InitTrig_Gas_Bombs takes nothing returns nothing
    set gg_trg_Gas_Bombs = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Gas_Bombs, EVENT_PLAYER_UNIT_DEATH )
    call TriggerAddAction( gg_trg_Gas_Bombs, function Trig_GasBombs_Actions )
endfunction

Now, you guys wonder why all those dummy units. I really don't know ... I just want it to work ...

Anyway I decided to make the following change:
JASS:
function Trig_GasBombs_Actions takes nothing returns nothing
    local unit bomb = GetDyingUnit()
    local integer bombID = GetUnitTypeId(bomb)
    local player p = GetOwningPlayer(bomb)
    local unit array dummy
    local effect e
    local integer duration = 0
    local group g
    local unit picked
    if bombID == 'h000' then
        set e = AddSpecialEffect("war3mapImported\\Radioactivecloud.mdx", GetUnitX(bomb), GetUnitY(bomb)) //creates the Cloud effect in the target loc
        loop
            exitwhen(duration == 10) // this will exit when Duration == 10, which means 10 secs have passed
            call GroupEnumUnitsInRange( g, GetUnitX( bomb ), GetUnitY( bomb ), 250, null )
            //Picks all units in a 250 AoE arround targetloc
            loop
                set picked = FirstOfGroup(g)
                exitwhen ( picked == null) //When all units were picked
                if IsUnitEnemy(picked, p) and GetUnitState(picked, UNIT_STATE_LIFE) > 0.405 and IsUnitType(picked, UNIT_TYPE_STRUCTURE) == false then
                    call KillUnit(picked)
                endif
                //if "picked" unit is enemy, alive and non structure then it will die, or suffer from something
                call GroupRemoveUnit(g, picked) //removes picked  Unit from Group g, so other Unit can take its place
            endloop
            call TriggerSleepAction(1.0) //waits 1 second
            set duration = duration + 1 //increases this var after waiting 1 sec
        endloop
        call DestroyEffect(e)
        call DestroyGroup(g)
    endif
    set g = null
    set e = null
    set bomb = null
    set p = null
    set dummy[0] = null
    set dummy[1] = null
endfunction
//===========================================================================
function InitTrig_Gas_Bombs takes nothing returns nothing
    set gg_trg_Gas_Bombs = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Gas_Bombs, EVENT_PLAYER_UNIT_DEATH )
    call TriggerAddAction( gg_trg_Gas_Bombs, function Trig_GasBombs_Actions )
endfunction

But the code does NOT work yet ... and I don't know why ... help ?
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
You didn't create the group - "local group g".

Also, its not suggested to not put the ID condition as a trigger condition because every time a unit dies it will create variables and destroy them for no reason.

You can also put a filter instead of that If/Then.

The end code would look like this:

JASS:
function Trig_GasBombs_Conditions takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == 'h000' 
endfunction
function GroupConditions takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) == true and GetWidgetLife(GetFilterUnit()) > 0
endfunction
function Trig_GasBombs_Actions takes nothing returns nothing
    local unit bomb = GetTriggerUnit()
    local effect e = AddSpecialEffect("war3mapImported\\Radioactivecloud.mdx", GetUnitX(bomb), GetUnitY(bomb))
    local integer duration = 0
    local group g = CreateGroup()
    local unit picked
    loop
        exitwhen duration == 10
        call GroupEnumUnitsInRange( g, GetUnitX( bomb ), GetUnitY( bomb ), 250, Condition(function GroupConditions))
            loop
                set picked = FirstOfGroup(g)
                exitwhen picked == null
                call GroupRemoveUnit(g, picked)
                call KillUnit(picked)
            endloop
            call TriggerSleepAction(1.0)
            set duration = duration + 1
        endloop
    call DestroyEffect(e)
    call DestroyGroup(g)
    set g = null
    set e = null
    set bomb = null
endfunction
//===========================================================================
function InitTrig_Gas_Bombs takes nothing returns nothing
    set gg_trg_Gas_Bombs = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Gas_Bombs, EVENT_PLAYER_UNIT_DEATH )
    call TriggerAddCondition( gg_trg_Gas_Bombs, Condition( function Trig_GasBombs_Conditions ))
    call TriggerAddAction( gg_trg_Gas_Bombs, function Trig_GasBombs_Actions )
endfunction


By the way, can I finaly write codes with timers ? :p
 
Ahhh Wolf, you re my hero in deed. I could spend all day looking at this code, and I would have never found the error.

About your post:

Also, its not suggested to not put the ID condition as a trigger condition because every time a unit dies it will create variables and destroy them for no reason.
hã ?! You are telling me to use a condion_function rit ??
Well, I am aware of that. However, the codes you are seeing are for the spells section. They are not the full cavalry.
In my map, I shall place all this little codes into only 2 massive triggers called "bombers" and "bombs". By creating the codes like this, I am saving work. I mean that by making the code like this I am helping myself in a nearby future.
So, no, I don't intent to change the codes.
However, if you guys really think it is important, I will change the functions and such.
What you make me do =S

You can also put a filter instead of that If/Then.
The filter .... Won't that actually make the function run slower !?
I mean, that's is why I am avoiding the filters ...

Ohh, and the spell doesn't work btw (shame on me, gave you guys a bad code). If a unit gets out of the cloud, and then enters it again, the code won't work ... So I have to do this all again =( .... and see what's wrong. Again...
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Ahhh Wolf, you re my hero in deed. I could spend all day looking at this code, and I would have never found the error.

I was writing "Couldn't really find any problem... etc. etc." and then suddenly noticed that lol :xxd:


The filter .... Won't that actually make the function run slower !?
I mean, that's is why I am avoiding the filters ...

Well, using the filter is exacly like using the conditions alone, just its more comftorable to use.

Ohh, and the spell doesn't work btw (shame on me, gave you guys a bad code). If a unit gets out of the cloud, and then enters it again, the code won't work ... So I have to do this all again =( .... and see what's wrong. Again...

Eh ? I don't see any reason why it won't work... :huh:
 
Mmm,

Well, using the filter is exacly like using the conditions alone, just its more comftorable to use.

So you are saying to me that using a function is exactly the same thing as using an "if/then/else" ??
I don't think you are correct. If I use a function, The computer will have to jump to the conditional function, see the conditions and return a value, and then jump again to the function where I was, so I can use the returned value.
With If then Else it will be harder to use (i know) but I think that it will be worth it.

Eh ? I don't see any reason why it won't work...
Me either ... I am sure of 1 thing .. it's human error and I gotta find it.
 
Level 6
Joined
Jun 30, 2006
Messages
230
I had a good reply, but I took too long and it logged me out, doh. Basically, I'll look at your code when I get the chance, but I'm busy at the moment.
 
Level 6
Joined
Jun 30, 2006
Messages
230
Do you want to do a damage-over-time (DoT) or do damage? or are you just leaving it at KillUnit()?
If you are not leaving it at simply killing the unit, I'd do it a bit differently than GhostWolf, but I'm sure that he would do it differently as well. Plus, you can add more effects, more efficiently if it is done another method. I can even avoid structs if you want ;)
 
Last edited:
Level 6
Joined
Jun 30, 2006
Messages
230
To be honest, I find Kattana's Handle Vars more confusing than structs + ABC, I should teach you sometime. Plus the NewGen editor gives you some basic features that are very nice for just basic JASS. Perhaps I'll write this spell using handle vars and then convert it piece by piece to structs and ABC/CSData to help you learn vJASS. We'll see how much time I end up having.
 
MMmm, learning vJass or ABC or whatever you are talking about could proof to be useful in the future... However, I just learned Katan's very recently, and I do not wish to complicate things even more.

Please keep it simple.

Also, about teaching me vJass, well, knowledge belongs to man kind by rit, if you feel like sharing it with some1, I will be most happy in adding you to create a mini-tutorial about it (if you want).


thx for help =)
 
Level 6
Joined
Jun 30, 2006
Messages
230
I have it nearly done with Handle Vars, but the trigger doesn't seem to be working as intended. The damage happens rapidly, all ten instances are done in less than a second. There is some cleanup to do as well, so I'll just edit this post when I'm done.
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Flame, I made it anew with structs (been reading about vJass so I see this like a good occasion to try and use it... not that its hard using 1 struct lol :xxd:).

Anyway, I got a bit confused at the actions part.

Do you want the units damaged ?
Do you want the units to be slowed/cursed ?
Are this two diffrent bombs ?
Who are the targets ?

Please answer to all this questions :p

Anyway, just incase you wanna see it - here is the code.

JASS:
struct gas
    real x
    real y
    unit bomb
    effect e
endstruct

//===========================================================================
function GasBombsConditions takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == 'h000'
endfunction

//===========================================================================
function GasTimer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer i = GetHandleInt(t, "i") // getting our "clock"
    local gas s = GetHandleInt(t, "gas") // getting all the info in "s"
    local group g = CreateGroup()
    call GroupEnumUnitsInRange(g, s.x, s.y, 250, null)
//******************//
    // actions
//******************//
    if i == 20 then // when i = 20 the time that passed is 10 seconds
        call s.destroy()
        call FlushHandleLocals(t)
        call DestroyTimer(t)
    endif
    call SetHandleInt(t, "i", i + 1)
    set t = null
    call DestroyGroup(g)
    set g = null
endfunction
function GasBombsActions takes nothing returns nothing
    local timer t = CreateTimer()
    local integer i = 0
    local gas s = gas.create()
    set s.bomb = GetTriggerUnit()
    set s.x = GetUnitX(s.bomb)
    set s.y = GetUnitY(s.bomb)
    set s.e = AddSpecialEffect("some\\model.mdx", s.x, s.y)
    call SetHandleInt(t, "gas", s) // attaching all the info in "s" to the timer
    call SetHandleInt(t, "i", i) // attaching our "clock" to the timer
    call TimerStart(t, .5, true, function GasTimer)
    set t = null
endfunction

//===========================================================================
function InitTrig_Gas_Bombs takes nothing returns nothing
    set gg_trg_Gas_Bombs = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Gas_Bombs, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(gg_trg_Gas_Bombs, Condition(function GasBombsConditions))
    call TriggerAddAction( gg_trg_Gas_Bombs, function GasBombsActions )
endfunction


Now also I have one question, Jeans (I guess you'll know the answer), will putting "i" into the struct and then each time the timer ends setting the new value with all the rest of them (which can be considerd as constants in the timer actions) be faster then making "i" a diffrent variable ?

Also, im not really sure as if the unit/effect in the struct leak when I destroy it. Wasn't written in the tut lol :p
 
OMG !! guys plz don't use structs, I understand nothing of them !!!plz keep it simple.

Also, Wolf what was wrong with your code ?? did you find it out ?
This is what I want; if a unit is inside the cloud it shall:
1 - be slowed
2 - be cursed with miss
3 - take 25 damage per sec.
While inside that cloud. If the unit leaves the cloud everything goes back to normal

Two different bombs !? No! Just make it MUI. The idea of the code is to run every time a gas bomb dies.

About the targets, there is no specific unit. Just pick all units in a 250 range that are enemy, alive, not structure or mechanical and not magic immune, and damage them by 25 points per sec

Oh, and Blue, You can post your code with a new post =)
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
OMG !! guys plz don't use structs, I understand nothing of them !!!plz keep it simple.

Currently I just used the struct so instead of attaching to the timer the X value, then the Y value, then the Unit value, then the Effect value, I just do it all in one thing.
If you want ill turn it back to normal but its not really using something special.
(read any vJass struct tut and you'll understand it in less then 2 minutes I assure you).

About the targets, there is no specific unit. Just pick all units in a 250 range that are enemy, alive, not structure or mechanical and not magic immune, and damage them by 25 points per sec


This ARE the targets ^^
 
Currently I just used the struct so instead of attaching to the timer the X value, then the Y value, then the Unit value, then the Effect value, I just do it all in one thing.
If you want ill turn it back to normal but its not really using something special.
(read any vJass struct tut and you'll understand it in less then 2 minutes I assure you).

ABout tuts, well, 1st i dunno where to find them and second, i still need time to cement that Katana's thingy. Just give time to time =Pl


This ARE the targets ^^

Well, About the targets, I could change that myself with an "if" statement you know =P, anyway I am glad I could help =) (LOOOOOOOOOL)

Plz keep me informed on your progress =S and Jeans too ! =P
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Its really weird.
Doesn't matter what values I change, the timer only works 5 times :razz:
It all works beside that weird bug and I can't seem to find anything (no real places for mistakes in this short code anyway).

Oh and a side note - im not sure you want to make them slowed/cursed only when they are in the gas because it means you will create a lot of dummies every 0.5 (or every 1 second, depends what value you put).

If you want that changed, add a If/Then statment that will say "If i == 1" before the dummies part (I put there a comment so you'll see where it is).

Can anyone check why this weird bug accurs ?

[Edit] Ok it just become even weirder.

I added a effect (forgot to check if it works lol) and the effect DOES get removed at the right time (after 10 seconds).
The damage however stops after 2.5 seconds. :nw::razz:

JASS:
struct gas
    real x
    real y
    unit bomb
    effect e
endstruct

//===========================================================================
function GasBombsConditions takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == 'h000'
endfunction

//===========================================================================
function groupConditions takes nothing returns boolean
    // all your conditions... long list :P
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) == true and IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
function GasTimer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer i = GetHandleInt(t, "i")
    local gas s = GetHandleInt(t, "gas")
    local group g = CreateGroup()
    local unit u
    local unit dummyOne
    local unit dummyTwo
    call GroupEnumUnitsInRange(g, s.x, s.y, 250, Condition(function groupConditions))
//******************//
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        call GroupRemoveUnit(g, u)
        call UnitDamageTarget(s.bomb, u, 12.5, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
        // **** dummies part ****
        set dummyOne = CreateUnit(GetOwningPlayer(s.bomb), 'h001', s.x, s.y, 0)
        set dummyTwo = CreateUnit(GetOwningPlayer(s.bomb), 'h001', s.x, s.y, 0)
        call IssueTargetOrder(dummyOne, "curse", u)
        call IssueTargetOrder(dummyTwo, "slow", u)
        call UnitApplyTimedLife(dummyOne, 'BTLF', .8)
        call UnitApplyTimedLife(dummyTwo, 'BTLF', .8)
        set dummyOne = null
        set dummyTwo = null
        // **** end dummies part ****
    endloop
//******************//
    if i == 20 then // when i = 20 the time that passed is 10 seconds
        call DestroyEffect(s.e)
        call s.destroy()
        call FlushHandleLocals(t)
        call DestroyTimer(t)
    endif
    call SetHandleInt(t, "i", i + 1)
    set t = null
    call DestroyGroup(g)
    set g = null
endfunction
function GasBombsActions takes nothing returns nothing
    local timer t = CreateTimer()
    local integer i = 0
    local gas s = gas.create()
    set s.bomb = GetTriggerUnit()
    set s.x = GetUnitX(s.bomb)
    set s.y = GetUnitY(s.bomb)
    set s.e = AddSpecialEffect("some\\model.mdx", s.x, s.y)
    call SetHandleInt(t, "gas", s)
    call SetHandleInt(t, "i", i)
    call TimerStart(t, 0.5, true, function GasTimer)
    set t = null
endfunction

//===========================================================================
function InitTrig_Gas_Bombs takes nothing returns nothing
    set gg_trg_Gas_Bombs = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Gas_Bombs, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(gg_trg_Gas_Bombs, Condition(function GasBombsConditions))
    call TriggerAddAction( gg_trg_Gas_Bombs, function GasBombsActions )
endfunction
 
Level 6
Joined
Jun 30, 2006
Messages
230
Hmm... I was nearly finished when my WE crashed and now it will no longer save the map. I don't know how long this will take to sort out, but it's very untimely!

Edit: I still can't get my WE working, and it isn't NewGen's fault. I may have to reinstall warcraft. Sorry for the delay!
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Ok here it is without the struct.

By the way, how can I store a effect with Handlevars ? there isn't a function for it but it still did it when it was inside the struct.

JASS:
function GasBombsConditions takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == 'h000'
endfunction

//===========================================================================
function GasTimer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer i = GetHandleInt(t, "i")
    local unit bomb = GetHandleUnit(t, "bomb")
    local real x = GetHandleReal(t, "x")
    local real y = GetHandleReal(t, "y")
    local group g = CreateGroup()
    local unit u
    local unit dummyOne
    local unit dummyTwo
    call GroupEnumUnitsInRange(g, x, y, 250, null)
//******************//
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        call GroupRemoveUnit(g, u)
        if IsUnitEnemy(u, GetOwningPlayer(bomb)) == true and IsUnitType(u, UNIT_TYPE_MECHANICAL) == false and IsUnitType(u, UNIT_TYPE_STRUCTURE) == false and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) == false then
            call UnitDamageTarget(bomb, u, 12.5, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
            // **** dummies part ****
            set dummyOne = CreateUnit(GetOwningPlayer(bomb), 'h001', x, y, 0)
            set dummyTwo = CreateUnit(GetOwningPlayer(bomb), 'h001', x, y, 0)
            call IssueTargetOrder(dummyOne, "curse", u)
            call IssueTargetOrder(dummyTwo, "slow", u)
            call UnitApplyTimedLife(dummyOne, 'BTLF', .5)
            call UnitApplyTimedLife(dummyTwo, 'BTLF', .5)
            set dummyOne = null
            set dummyTwo = null
            // **** end dummies part ****
        endif
    endloop
//******************//
    if i == 20 then // when i = 20 the time that passed is 10 seconds
        call FlushHandleLocals(t)
        call DestroyTimer(t)
    endif
    call SetHandleInt(t, "i", i + 1)
    set t = null
    call DestroyGroup(g)
    set g = null
    set bomb = null
endfunction
function GasBombsActions takes nothing returns nothing
    local timer t = CreateTimer()
    local integer i = 0
    local unit bomb = GetTriggerUnit()
    local real x = GetUnitX(bomb)
    local real y = GetUnitY(bomb)
    local effect e = AddSpecialEffect("some\\effect.mdl", x, y)
    call SetHandleHandle(t, "bomb", bomb)
    call SetHandleReal(t, "x", x)
    call SetHandleReal(t, "y", y)
    call SetHandleInt(t, "i", i)
    call TimerStart(t, 0.5, true, function GasTimer)
    call TriggerSleepAction(10)
    call DestroyEffect(e)
    set bomb = null
    set e = null
    set t = null
endfunction

//===========================================================================
function InitTrig_Gas_Bombs takes nothing returns nothing
    set gg_trg_Gas_Bombs = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Gas_Bombs, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(gg_trg_Gas_Bombs, Condition(function GasBombsConditions))
    call TriggerAddAction( gg_trg_Gas_Bombs, function GasBombsActions )
endfunction
 
Status
Not open for further replies.
Top