HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Unit path prediction - what do you think?

11-03-2006, 01:12 AM#1
crazedcougar
Mainly because of a question from a friend, I've spent the last couple days making a system that will have an artillery attack the spot where a unit will be when the projectile lands. (supposing that the unit walks in a straight line.)

This tool takes in to account:
- Projectile and unit speed.
- Firing Delay.
- Rotation speed.
- Projectile window.

In what I hope is a bugfree version, I can kill every target with a 25 diameter attack ground anywhere from 100-1000 units away. The timing is off by less that 0.1 seconds every time.

Heres the code!
Collapse JASS:
function convert takes real input returns real //this fixes a bug where the angle between two units can return a negative value.
    if (input < 0 ) then 
    return (input + 360)
    else
    return input 
    endif
endfunction

function check2 takes real input returns real
    if (input < 0 ) then
    return 0
    else
    return input
    endif
endfunction

function check1 takes real input returns real
    if (input > 180) then
    return (360 - input)
    else
    return input
    endif
endfunction

function Trig_atk_prediction_Actions takes nothing returns nothing
    local location attackedLoc = GetUnitLoc(GetTriggerUnit())
    local location attackedLocV = GetUnitLoc(GetTriggerUnit())
    local location attackerLoc = GetUnitLoc(GetAttacker())
    local real attackerA = GetUnitFacing(GetAttacker())
    local real attackedA = GetUnitFacing(GetTriggerUnit())
    local real timeTilHit
    local real travelAngle
    local integer i = 0

    call IssueImmediateOrderBJ( gg_unit_ebal_0000, "stop" )

    loop
    set i = i+1
    set travelAngle = check2( check1((RAbsBJ(attackerA - convert(AngleBetweenPoints(attackerLoc, attackedLocV))))) -GetUnitPropWindowBJ(GetAttacker()) )
    set timeTilHit = ( (DistanceBetweenPoints(attackedLocV, attackerLoc) / 1000.00 ) + (0.25) + (0.30) + ( travelAngle * (GetUnitTurnSpeed(GetAttacker()) / 360.00) )) 
     //1000 is projectile speed, 0.25 is fire delay, and 0.30 is an arbitrary constant.
    set attackedLocV = PolarProjectionBJ(attackedLoc, GetUnitMoveSpeed(GetTriggerUnit()) * timeTilHit, attackedA)
    call AddSpecialEffectLocBJ( attackedLocV, "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl" )
    exitwhen (i==4)
    endloop
    call DisplayTextToForce(GetPlayersAll(), "rotation needed: " + R2S(travelAngle))  //this is often 0 because of the 30 degree propulsion window.
    call StartTimerBJ( udg_tempTimer, false, 30 )
   
    if (DistanceBetweenPoints(attackedLocV, attackerLoc) < 1151 ) then  //dont atk if not in range
    call TriggerSleepAction( 0.01 )  //needed to make the thing actually fire
    call IssuePointOrderLocBJ( gg_unit_ebal_0000, "attackground", attackedLocV )
    endif

    call TriggerRegisterUnitEvent( gg_trg_find_lista_delay_2, GetAttackedUnitBJ(), EVENT_UNIT_DAMAGED ) //detect projectile impact time
    set udg_flightTime = timeTilHit //for comparison in other trigger
    call TriggerSleepAction( 0.40 )
    call IssueImmediateOrderBJ( gg_unit_ebal_0000, "stop" )
    call RemoveLocation(attackedLoc)
    call RemoveLocation(attackedLocV)
    call RemoveLocation(attackerLoc)
endfunction

Does it leak? I am considering submitting it to the demo maps section. Is there anything to change first? I hope someone can dream up a use for this.
Attached Images
File type: jpgcatapultDoom.jpg (58.7 KB)
11-03-2006, 02:12 AM#2
The_AwaKening
You have some leaks in there; such as a special effect not destroyed. You should also learn to indent your code for easier reading.

If you are planning on submitting this map, I would also get rid of all the blizzard.j calls and use the natives. You have tons of them that are really easily removed such as GetAttackedUnitBJ(), which just translates to GetTriggerUnit(). There are also plenty more of them.

Get the blizzard.j file and search for anything in your code that has BJ in it first. You can see what a lot of these codes are calling.
11-03-2006, 02:25 AM#3
Vexorian
you have a lot of location leaks.
11-03-2006, 02:26 AM#4
crazedcougar
Collapse JASS:
function convert takes real input returns real //this fixes a bug where the angle between two units can return a negative value.
    if (input < 0 ) then 
    return (input + 360)
    else
    return input 
    endif
endfunction

function check2 takes real input returns real
    if (input < 0 ) then
    return 0
    else
    return input
    endif
endfunction

function check1 takes real input returns real
    if (input > 180) then
    return (360 - input)
    else
    return input
    endif
endfunction

function Trig_atk_prediction_Actions takes nothing returns nothing
    local location attackedLoc = GetUnitLoc(GetTriggerUnit())
    local location attackedLocV = GetUnitLoc(GetTriggerUnit())
    local location attackerLoc = GetUnitLoc(GetAttacker())
    local real attackerA = GetUnitFacing(GetAttacker())
    local real attackedA = GetUnitFacing(GetTriggerUnit())
    local real timeTilHit
    local real travelAngle
    local integer i = 0

    call IssueImmediateOrder( gg_unit_ebal_0000, "stop" )

    loop
    set i = i+1
    set travelAngle = check2( check1((RAbsBJ(attackerA - convert(AngleBetweenPoints(attackerLoc, attackedLocV))))) -GetUnitPropWindowBJ(GetAttacker()) )
    set timeTilHit = ( (DistanceBetweenPoints(attackedLocV, attackerLoc) / 1000.00 ) + (0.25) + (0.30) + ( travelAngle * (GetUnitTurnSpeed(GetAttacker()) / 360.00) ))
    set attackedLocV = PolarProjectionBJ(attackedLoc, GetUnitMoveSpeed(GetTriggerUnit()) * timeTilHit, attackedA)
    call AddSpecialEffectLocBJ( attackedLocV, "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl" )
    call DestroyEffect( bj_lastCreatedEffect )
    exitwhen (i==4)
    endloop
    call DisplayTextToForce(GetPlayersAll(), "rotation needed: " + R2S(travelAngle))  //this is often 0 because of the 30 degree propulsion window.
    call StartTimerBJ( udg_tempTimer, false, 30 )
   
    if (DistanceBetweenPoints(attackedLocV, attackerLoc) < 1151 ) then  //dont atk if not in range
    call TriggerSleepAction( 0.01 )  //needed to make the thing actually fire
    call IssuePointOrderLoc( gg_unit_ebal_0000, "attackground", attackedLocV )
    endif

    call TriggerRegisterUnitEvent( gg_trg_find_lista_delay_2, GetTriggerUnit(), EVENT_UNIT_DAMAGED ) //detect projectile impact time
    set udg_flightTime = timeTilHit //for comparison in other trigger
    call TriggerSleepAction( 0.40 )
    call IssueImmediateOrder( gg_unit_ebal_0000, "stop" )
    call RemoveLocation(attackedLoc)
    call RemoveLocation(attackedLocV)
    call RemoveLocation(attackerLoc)
    set attackedLoc = null
    set attackedLocV = null
    set attackerLoc = null
endfunction

function InitTrig_atk_prediction takes nothing returns nothing
    set gg_trg_atk_prediction = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_atk_prediction, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddAction( gg_trg_atk_prediction, function Trig_atk_prediction_Actions )
endfunction
I've removed all the useless BJs, the ones doing absolutely nothing. Its better to replicate what the 'useful' BJs are doing instead of letting them just do their thing?

fixed location leaks (I think.)
Thanks to this post by PipeDream
11-03-2006, 02:32 AM#5
[VDM]Amn
i remember having done a spell like that.
the spell had a 100% chance to hit the target, very precisely ahahah.
yes it was.

the map was the fight between Sargeras and Aegwyn, u know, from warcraft history... wow, it was a really good map i dunno why i stopped making it.

-----------
edit:
i opened the map, here's the trigger;
convert to jass if u need to.
Trigger:
Sargeras Impale
Events
Conditions
Collapse Actions
Sound - Play SacrificeUnit <gen>
Cinematic - Apply a filter over 4.00 seconds using Normal blending on texture Dream, starting with color (100.00%, 0.00%, 0.00%) and 1.00% transparency and ending with color (100.00%, 0.00%, 0.00%) and 100.00% transparency
Unit - Order Sargeras 0000 <gen> to Undead Crypt Lord - Impale ((Position of Guardian 0029 <gen>) offset by ((Distance between (Position of Guardian 0029 <gen>) and (Position of Sargeras 0000 <gen>)) / 2.50) towards (Facing of Guardian 0029 <gen>) degrees)
Wait 1.00 seconds
Camera - Shake the camera for Player 1 (Red) with magnitude 6.00
Wait 4.00 seconds
Camera - Stop swaying/shaking the camera for Player 1 (Red)
-------- Sargeras May Be Ordered Another Thing Now --------
Set Sargeras_Busy = False
Set Sargeras_GO = True

ok. what matters is the third action, where Sargeras ir ordered to cast Impale at a point.

Those values ( position / 2.5 ) were set considering the target unit's move speed, it was at max (522).
This action will surely help u in your spell.

btw, if u wanna know, every random time between 10 and 25 seconds Sargeras was ordered to cast a random spell, he had 3. One of them was this one, based on Impale.

So? well.. it happened that this stupid sargeras used to "lose his will to fight" i dunno, but he just used to scape from the attackers.
So i had to add a periodic event (every 4 seconds, not too much) to order him to attack-ground to his position of something.

BUT! that last trigger started to cancel his spells. Then those ugly booleans had to appear inside the triggers to avoid this to happen.

One more thing :) the first two actions in the trigger was just something to warn the player that sargeras was about to cast that shit. the skill had a short delay between impale's explotions, so it could be dodged.

good luck.
Amn.-
11-03-2006, 02:59 AM#6
zen87
there are still many useless bj

Collapse JASS:
    call AddSpecialEffectLocBJ( attackedLocV, "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl" )
    call DestroyEffect( bj_lastCreatedEffect )

replace with

Collapse JASS:
    call DestroyEffect(AddSpecialEffectLoc("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl",attackedLocV))

and
Collapse JASS:
    call StartTimerBJ( udg_tempTimer, false, 30 )
to
Collapse JASS:
    call TimerStart( udg_tempTimer, 30, false, null)

and
Collapse JASS:
    call TriggerSleepAction( 0.01 )  //needed to make the thing actually fire
this will atctually wait for > 0.1 sec, but i guess no big deal here, if you really want to get the shortest time possible, use timer with 0 sec timeout
11-03-2006, 04:01 AM#7
The_AwaKening
TriggerSleepAction is a native and for a .01 wait does not need to be accurate at all. I wouldn't use a timer for something like that.
11-04-2006, 12:33 AM#8
crazedcougar
Thanks. Will fix the above BJs.
Collapse JASS:
    call DestroyEffect(AddSpecialEffectLoc("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl",attackedLocV))
will that remove every thunder clap on the map? Or the last created one?

Best option would the wait would be to find out why I need it. Comment out that line, the ballista will just face the target, not shooting anything.
11-04-2006, 12:58 AM#9
zen87
basically it creates a thunderclap effect and instantly destroy it at the certain location so only its death animation are played, i did this alot untill i'm tired to typing it over and over again and make a function for it lol

Collapse JASS:
function CreateEffectEx takes string e, real x, real y returns nothing
    call DestroyEffect(AddSpecialEffect(e,x,y))
endfunction

function CreateEffectExLoc takes string e, location l returns nothing
    call CreateEffectEx(e,GetLocationX(l),GetLocationY(l))
endfunction