• 🏆 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!

Snake Curve & DNA Wave

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
This is a spell that twists around like a snake, basicly creating units with polar projections with a hard angle formula which I made.
The spells are MUI , at the cost of slowly unit creation due to TriggerSleepAction.
Creatin a second trigger that performs the actions every 0.04 seconds will require a global integer and the base angle making this spell not MUI and theres no way to avoid that.
JASS:
function Trig_SnakeWaveSingle_Conditions takes nothing returns boolean

    if ( GetSpellAbilityId() == 'A001' ) then

        return true

    endif

    return false

endfunction

function Trig_SnakeWaveSingle_Actions takes nothing returns nothing

     local unit a = GetSpellAbilityUnit()

     local real r = GetUnitFacing(a) // caster angle facing

     local real x = GetUnitX(a)

     local real y = GetUnitY(a) // caster possition

     local real x1 = 0 

     local real y1 = 0  //the possition of new unit

     local real d = 75  // distance 

     local real r2 = r  // angle for polar projection

     local integer k = 0 // number of times

     local unit L  //the unit that is goint to be created

     loop

          call TriggerSleepAction(0.0001) // the price for MUI... Its not slower than you think!

          set x1 = x + d*Cos(r2 * bj_DEGTORAD) //calculates the possition of new unit(PolarProjection)

          set y1 = y + d*Sin(r2 * bj_DEGTORAD)

          set L = CreateUnit(GetOwningPlayer(a),'e000',x1,y1,bj_UNIT_FACING)//unit creation

          call UnitApplyTimedLife(L,'BTLF',1.15)//duration

          set x = x1

          set y = y1  // saves and stores prevous coordiantes

          set k = k +1 // number of times , also used in the angle calculation

          set r2 = r + 40*Cos(45-12*k) // the key for making it curve , special formula made from scratch

     exitwhen (k==40)

     endloop

endfunction

//===========================================================================

function InitTrig_SnakeWaveSingle takes nothing returns nothing

    set gg_trg_SnakeWaveSingle = CreateTrigger(  )

    call TriggerRegisterAnyUnitEventBJ( gg_trg_SnakeWaveSingle, EVENT_PLAYER_UNIT_SPELL_EFFECT )

    call TriggerAddCondition( gg_trg_SnakeWaveSingle, Condition( function Trig_SnakeWaveSingle_Conditions ) )

    call TriggerAddAction( gg_trg_SnakeWaveSingle, function Trig_SnakeWaveSingle_Actions )

endfunction

JASS:
function Trig_DNAWave_Conditions takes nothing returns boolean

    if ( GetSpellAbilityId() == 'A002' ) then

        return true

    endif

    return false

endfunction

function Trig_DNAWave_Actions takes nothing returns nothing

     local unit a = GetSpellAbilityUnit()

     local real r = GetUnitFacing(a) //angle that will be used

     local real x = GetUnitX(a)

     local real y = GetUnitY(a)  //caster location

     local real xP = x

     local real yP = y   //storage for prevous unit pos 2nd type

     local real x1 = 0

     local real y1 = 0   //the possition of new unit 1st

     local real x2 = 0  

     local real y2 = 0  // the possition of new unit 2nd

     local real d  = 75 //distance between units , increasing this will make it longer

     local real r2 = r  // angle for polar projection 1st unit

     local real r3 = r  // the constant angle used for r4 ,USELESS.

     local real r4 = r // angle for polar projection for the 2nd unit

     local integer n = 12 //increasing this will change the shape of elipse

     local integer k = 0 // the number of times

     local unit L  // units

     local unit L2 // units at the other side

     loop

        call TriggerSleepAction(0.0001) // the price for MUI ... 

        set x1 = x + d*Cos(r2 * bj_DEGTORAD) //calculates the possition of new unit 1st

        set y1 = y + d*Sin(r2 * bj_DEGTORAD)

        set x2 = xP + d*Cos(r4 * bj_DEGTORAD)//calculates the possition of new unit 2nd

        set y2 = yP + d*Sin(r4 * bj_DEGTORAD)

        set L = CreateUnit(GetOwningPlayer(a),'e000',x1,y1,bj_UNIT_FACING)//unit creation

        call UnitApplyTimedLife(L,'BTLF',1.15) //unit duration

        set L2 = CreateUnit(GetOwningPlayer(a),'e000',x2,y2,bj_UNIT_FACING)//2nd unit creation

        call UnitApplyTimedLife(L2,'BTLF',1.15)

        set x = x1 // saves and stores the prevous possition to be used to calculate new

        set y = y1

        set xP = x2 //saves and stores.... for 2nd unit

        set yP = y2

        set k = k +1 // number of times counter

        set r2 = r + 40*Cos(45+n*k) // the key to making curve,  

        set r4 = r3 +40*Cos(180+n*k) // why 180? yes i want to know that too,but works

     exitwhen (k==40)

     endloop

endfunction

//===========================================================================

function InitTrig_DNAWave takes nothing returns nothing

    set gg_trg_DNAWave = CreateTrigger(  )

    call TriggerRegisterAnyUnitEventBJ( gg_trg_DNAWave, EVENT_PLAYER_UNIT_SPELL_EFFECT )

    call TriggerAddCondition( gg_trg_DNAWave, Condition( function Trig_DNAWave_Conditions ) )

    call TriggerAddAction( gg_trg_DNAWave, function Trig_DNAWave_Actions )

endfunction


Keywords:
curve snake wave DNA spiral
Contents

SnakeWave (Map)

Reviews
12th Dec 2015 IcemanBo: For long time as NeedsFix. Rejected. Bribe: These waits need to be removed as 1) their wait period is random and never less than 0.26 2) it could occur with different intervals in replays 3) on battle.net a wait...

Moderator

M

Moderator

12th Dec 2015
IcemanBo: For long time as NeedsFix. Rejected.

Bribe:

These waits need to be removed as

1) their wait period is random and never less than 0.26
2) it could occur with different intervals in replays
3) on battle.net a wait could under some conditions desync

Using a Timer to do this job will yield far better results.
 
Level 10
Joined
Apr 25, 2009
Messages
296
Good spell. Its fully MUI and performs well.

Don't use immolation for damage, as the caster doesn't get credit for kills, and doesn't 'pull' units.

You use alot of dummy units, perhaps you could use special effects?
Its a mere suggestion.

Perhaps a damage splat/special effect? It was hard to see what units were taking damage.
 

instead of loops using TriggerSleepAction, you might want to use timer loops... since TSA is pretty inaccurate... and it really does not go below .27 seconds...

its pretty easy to make it MUI with timed loops, you just need to learn how to use hashtables or recycling dynamic indexing...

and oh, most spells that deal through time uses timed loops...


also you can put the actions into the conditions for faster execution... and also your condition block ryt now was pretty long and is clearly converted directly from GUI... (oh, the whole trigger was converted GUI, and then added some locals and changed things to natives)

also save the Owning player into a variable as you call it over and over...

and instead of bj_Unitfacing just use a real value...

and instead of Facing angle of the caster (which actually returns limited values), you might want to use the angle between the target point and the caster position...

and your spell's configurability is bad... it won't even support custom damage formulas (like those using hero attributes to calc damage)

also I suggest you learn how to use a single dummy unit, using dummy.mdx, as most resources use that, and just attach the effect model to it via triggers, to lessen object data, and it also makes it easier for the users...


For now, it really needs a lot of fixes for optimization and configurability... (if the Vote buttons was still there, I would have voted for rejection)
 
A few suggestions:

JASS:
function InitTrig_SnakeWaveSingle takes nothing returns nothing

    set gg_trg_SnakeWaveSingle = CreateTrigger(  )

    call TriggerRegisterAnyUnitEventBJ( gg_trg_SnakeWaveSingle, EVENT_PLAYER_UNIT_SPELL_EFFECT )

    call TriggerAddCondition( gg_trg_SnakeWaveSingle, Condition( function Trig_SnakeWaveSingle_Conditions ) )

    call TriggerAddAction( gg_trg_SnakeWaveSingle, function Trig_SnakeWaveSingle_Actions )

endfunction

Change this to:

JASS:
function InitTrig_SnakeWaveSingle takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(t, Condition( function Trig_SnakeWaveSingle_Conditions ) )
    call TriggerAddAction(t, function Trig_SnakeWaveSingle_Actions )
endfunction

I just think it would look better that way ;)

This exitwhen (k==40) could be changed to exitwhen k >= 40
It's safer that way :p

One more thing:
JASS:
function Trig_SnakeWaveSingle_Conditions takes nothing returns boolean

    if ( GetSpellAbilityId() == 'A001' ) then

        return true

    endif

    return false

endfunction

Can be easily changed to:

JASS:
function Trig_SnakeWaveSingle_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A001' then
endfunction

I hope this helped :)
Good luck ^^
 
Last edited:
Level 22
Joined
Nov 14, 2008
Messages
3,256
He can't put the actions in the conditions as long as he uses TSA as you cannot do that in the conditions (I think, pretty sure about it too).

All you need is a hashtable variable and maybe a timer recycler... My pounce spell is built that way if you need any inspiration.

im not a fan of getspellabilityunit, gettriggerunit is fine

getowningplayer could be a local player p = GetTriggerPlayer(), should be

wtf wait 0.0001? 1/10000? cool if you could prove that that value works
 
Level 4
Joined
Feb 27, 2011
Messages
22
Ok for damage splat/effect to determine which unit is hit , it will lag very badly if there we alot of units , I tried that.
@bassee 0.0001 in TSA , as it is proven TSA does not go under 0.27 , 0.0001 is faster than 0.27 , I dont know why
@Adiktuz yes i had in mine for bj unit facing , also this spell is instant no target so theres no target point and so no angle for points
For the damage configurability , first I need the units near the spell effect then Unitdamagetarget and after that a unit group to add the target so it does not get hit again becouse theyr are many dummy units.
 
Last edited:
yeah, and that's exactly how you should do it... learn how to add the units to a group specific to the unit...

for the effects, it will only lag if you used a very high poly thing or if you have so many units or, if each dummy would cause an effect on each unit, so the solution would be use a simple effect and only show it if the unit is hit, meaning you should do my 1st suggestion on this post...

using bj_unitfacing is kinda useless as it just returns a real value, so instead of using that bj, just use a real value directly...

for the angle, well you can't do anything now that its instant cast...


Learn how to:
-Do timed loops
-Add units to a group specific to the caster or the instance of the spell
-make your spells configurable
-remove useless bj variables


if you will be stubborn and keep this as it is, I don't see it will get approved...
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
function Trig_DNAWave_Conditions takes nothing returns boolean
if ( GetSpellAbilityId() == 'A002' ) then
return true
endif
return false
endfunction
Branching for this is stupid...
return GetSpellAbilityId() == 'A002'
returning the boolean product from the comparision is far neater and does not rely on flow control (easier for the CPU to handle).

GetOwningPlayer(a)
This value could be cached into a local to prevent it being recomputed.

Both r2 and r4 could be kept in radians thoughout the function to prevent the overhead of constant conversions.

Loading constants into locals is not a good idea idea as the locals have to be initialized each time the function runs. Rather use global constants as those could potentially be inlined for greater efficiency.

set r2 = r + 40*Cos(45+n*k) // the key to making curve,
set r4 = r3 +40*Cos(180+n*k) // why 180? yes i want to know that too,but works
As you should be aware by now, the trig functions work in radians and not degrees.
45 radians ~ 58 degrees
180 radians ~ 233 degrees
12 radians ~ 327 degrees or -32 degrees
Thus I have no idea what you are doing with your mathematics. I advise redesiging the solution, as it seems you may not have been aware of radians.
 
Bribe:

These waits need to be removed as

1) their wait period is random and never less than 0.26
2) it could occur with different intervals in replays
3) on battle.net a wait could under some conditions desync

Using a Timer to do this job will yield far better results.

You forgot to tell him that he has to null those leaking local variables :)
 
Top