Warcraft III resources & community, 2003–2006 · archived

Bounce Pushback Effect

38 posts
#1

Bounce Pushback Effect

spend more then 3 hours making such trigger in GUI and all i could come up with was givind a unit an aura and if under the effect of the buff the unit will be randomly pushed to a side. But that would include that i have to check every 0.5 sec of the gametime if any of ALL units in playable map area has a sertain buff. And that could cause some lagg, even without memory leaks, when combined with other time triggers.
So i wonder if there anyone who could help me making such a trigger in JASS.
(the problem in gui is that it doesnt see custom variables in EVENT editor)
Should look something like this:
If a unit, classification mechanicle come in range 100 of an other organicle (not a building, not mechanicle) unit and the triggering unit speed current is higher than 200 then take that victem, take 20 damage, play death animation, make victem face the mech unit and Move the victem instantly of its position offset by 9.00 towards Facing itself - 180.00 degrees (move it few times to create a kickback effect)
So that is about it, it would realy mean world to me if someone helps
#2
I am on it.
The main function is already done. Pretty easy work.

What may take some more time, is to write my own function to get the point, to which your "victim" shall be pushed.
I have to get a location out of an angle, it's current location and a range...

My way only works for the first quarter of a two dimensional matrix yet...

c = angle between "victim" and "roller"
x1 = X-coordinate of "victim"
y1 = Y-coordinate of "victim"
x2 = X-coordinate of the new point
y2 = Y-coordinate of the new point
s = range between old and new location

x2 = (tan(c) + x1) * s
y2 = y1 (+ or -) square root(y1² + s² - ((tan(c) + x1) * s - x1)² - y1²)

... As it can easily be seen, something is wrong with y2 - there should not be two possiblities.
#3
Got it in another, much easier way:

xA = x-coordinate of the "roller"
yA = y-coordinate of the "roller"
xB = x-coordinate of the "victim"
yB = y-coordinate of the "victim"
s = range to push the "victim" back at once

x = s * (xB - xA) / square root((xA - xB)² + (yA - yB)²)
y = s * (yB - yA) / square root((xA - xB)² + (yA - yB)²)

Tomorrow the whole thing will be done.

Postscript:

Here is the "prototype". It is still untested.

Create a trigger, name it "Ueberfahrt", convert it into custom code.
Delete the first two lines of code and copy this onto their former place:

function Trig_Ueberfahrt_Einheitenfilter takes nothing returns boolean
  return IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL)
endfunction

function Trig_Ueberfahrt_Zielsuche_Einheitenfilter takes nothing returns boolean
  return IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and not IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL) and not IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)
endfunction

function Trig_Ueberfahrt_Zielsuche_Berechnung takes real xA,real yA,real xB,real yB,real strecke returns location
  local real x = strecke * (xB-xA) / SquareRoot((xA - xB) * (xA - xB) + (yA - yB) * (yA - yB))
  local real y = strecke * (yB-yA) / SquareRoot((xA - xB) * (xA - xB) + (yA - yB) * (yA - yB))
  return Location(x,y)
endfunction

function Trig_Ueberfahrt_Zielsuche takes nothing returns nothing
  local filterfunc infanterie = Filter(function Trig_Ueberfahrt_Zielsuche_Einheitenfilter)
  local group ziele = CreateGroup()
  local real zeit
  local timer ruhezeit = CreateTimer()
  local unit fahrzeug = GetTriggerUnit()
  local unit ziel
  loop
    set zeit = 0
    if GetUnitCurrentOrder(fahrzeug) != OrderId("stop") then
      call GroupEnumUnitsInRange(ziele,GetUnitX(fahrzeug),GetUnitY(fahrzeug),100,infanterie)
      loop
        set ziel = FirstOfGroup(ziele)
        call GroupRemoveUnit(ziele,ziel)
        call SetUnitExploded(ziel,true)
        call SetUnitState(ziel,UNIT_STATE_LIFE,RMaxBJ(0,GetUnitState(ziel,UNIT_STATE_LIFE) - 20))
        if GetUnitState(ziel,UNIT_STATE_LIFE) <= 0 then
          call KillUnit(ziel)
        endif
        call SetUnitFacing(ziel,bj_RADTODEG * Atan2(GetUnitY(ziel) - GetUnitY(fahrzeug),GetUnitX(ziel) - GetUnitX(fahrzeug)))
        call SetUnitAnimation(ziel,"Death")
        call TimerStart(ruhezeit,1,false,null)
        loop
          set zeit = zeit + 0.2
          call SetUnitPositionLoc(ziel,Trig_Ueberfahrt_Zielsuche_Berechnung(GetUnitX(fahrzeug),GetUnitY(fahrzeug),GetUnitX(ziel),GetUnitY(ziel),5))
          call TriggerSleepAction(0.01)
          exitwhen TimerGetRemaining(ruhezeit) <= 1 - zeit
        endloop
        call SetUnitAnimation(ziel,"Stand")
        call SetUnitExploded(ziel,false)
        exitwhen FirstOfGroup(ziele) == null
      endloop
    endif
    call TimerStart(ruhezeit,0.5,false,null)
    loop
      call TriggerSleepAction(0.01)
      exitwhen TimerGetRemaining(ruhezeit) <= 0
    endloop
    exitwhen GetUnitState(fahrzeug,UNIT_STATE_LIFE) <= 0
  endloop
  call DestroyFilter(infanterie)
  call DestroyGroup(ziele)
  call DestroyTimer(ruhezeit)
  set infanterie = null
  set ziele = null
  set ruhezeit = null
endfunction


Finally, delete everything between these lines:
function InitTrig_Ueberfahrt takes nothing returns nothing

endfunction

Then, copy this into this space:

  set gg_trg_Ueberfahrt = CreateTrigger()
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(0),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(1),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(2),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(3),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(4),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(5),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(6),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(7),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(8),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(9),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(10),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(11),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
//neutral players - let them out for an advantage of speed
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(12),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(13),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(14),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(15),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
  call TriggerAddAction(gg_trg_Ueberfahrt,function Trig_Ueberfahrt_Zielsuche)


I am sorry for the german names, but I am just a little short on time.
If appropriated, I will change that next day.

... And if an error occurs, do not hesitate to tell me.
#4
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(0),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(1),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(2),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(3),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(4),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(5),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(6),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(7),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(8),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(9),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(10),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(11),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
//neutral players - let them out for an advantage of speed
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(12),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(13),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(14),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(15),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)


replace all that code with
call TriggerRegisterAnyUnitEventBJ( gg_trg_Ueberfahrt, EVENT_PLAYER_UNIT_TRAIN_FINISH )


though, if you hate BJs, even though this one is good, this is the best solution ( assuming u need fahrzeug use this one )

local integer i = 0
loop
    exitwhen i == 16
    call TriggerRegisterPlayerUnitEvent(gg_trg_Ueberfahrt,Player(i),EVENT_PLAYER_UNIT_TRAIN_FINISH,fahrzeug)
    set i = i + 1
endloop
#5
However you want it. ^^
It is just a question of being formal.

Okay, some little faults have been cleared.
This code is tested and works.

function Trig_DriveOver_Unitfilter takes nothing returns boolean
  return IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL)
endfunction

function Trig_DriveOver_SearchForTarget_Unitfilter takes nothing returns boolean
  return IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and not IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL) and not IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)
endfunction

function Trig_DriveOver_SearchForTarget takes unit fahrzeug returns nothing
  local filterfunc infantry = Filter(function Trig_DriveOver_SearchForTarget_Unitfilter)
  local group targets = CreateGroup()
  local timer sleepingTime = CreateTimer()
  local real xV
  local real yV
  local real xT
  local real yT
  local unit vessel = GetTriggerUnit()
  local unit target
  loop
    if GetUnitCurrentOrder(vessel) != OrderId("stop") then
      call GroupEnumUnitsInRange(targets,GetUnitX(vessel),GetUnitY(vessel),150,infantry)
      loop
        set ziel = FirstOfGroup(targets)
        exitwhen ziel == null
        call GroupRemoveUnit(targets,target)
        call SetUnitExploded(target,true)
        call SetUnitState(target,UNIT_STATE_LIFE,RMaxBJ(0,GetUnitState(target,UNIT_STATE_LIFE) - 20))
        if GetUnitState(target,UNIT_STATE_LIFE) <= 0 then
          call KillUnit(target)
        endif
        set xV = GetUnitX(vessel)
        set yV = GetUnitY(vessel)
        call SetUnitFacing(target,bj_RADTODEG * Atan2(GetUnitY(target) - yV,GetUnitX(target) - xV))
        call SetUnitAnimation(target,"Death")
        call TimerStart(sleepingTime,2,false,null)
        loop
          set xT = GetUnitX(target)
          set yT = GetUnitY(target)
          call SetUnitPosition(ziel,xT + 7.5 * (xT - xV) / SquareRoot((xV - xT) * (xV - xT) + (yV - yT) * (yV - yT)),yT + 7.5 * (yT - yV) / SquareRoot((xV - xT) * (xV - xT) + (yV - yT) * (yV - yT)))
          call TriggerSleepAction(0.01)
          exitwhen TimerGetRemaining(sleepingTime) <= 0
        endloop
        call SetUnitAnimation(target,"Stand")
        call SetUnitExploded(target,false)
        exitwhen FirstOfGroup(targets) == null
      endloop
      set target = null
    endif
    call TimerStart(sleepingTime,0.5,false,null)
    loop
      call TriggerSleepAction(0.01)
      exitwhen TimerGetRemaining(sleepingTime) <= 0
    endloop
    exitwhen GetUnitState(vessel,UNIT_STATE_LIFE) <= 0
  endloop
  call DestroyFilter(infantry)
  call DestroyGroup(targets)
  call DestroyTimer(sleepingTime)
  set infantry = null
  set targets = null
  set sleepingTime = null
endfunction


  local filterfunc vessel = Filter(function Trig_DriveOver_Unitfilter)
 set gg_trg_DriveOver = CreateTrigger() 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(0),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel)
  call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(1),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(2),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(3),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(4),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(5),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(6),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(7),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(8),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(9),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(10),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(11),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
//neutral players - let them out for an advantage of speed 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(12),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(13),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(14),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(15),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel) 
call TriggerAddAction(gg_trg_DriveOver,function Trig_DriveOver_SearchForTarget)
  set vessel = null


OR

  local integer counter = 0
  local filterfunc vessel = Filter(function Trig_DriveOver_Unitfilter)
  set gg_trg_DriveOver = CreateTrigger()
  loop
    call TriggerRegisterPlayerUnitEvent(gg_trg_DriveOver,Player(counter),EVENT_PLAYER_UNIT_TRAIN_FINISH,vessel)
    set counter = counter + 1
    exitwhen counter >= 16
  endloop
  call TriggerAddAction(gg_trg_DriveOver,function Trig_DriveOver_SearchForTarget)
  set vessel = null


Preparation for usage remains the same - only your trigger should now be named "DriveOver" for identification purposes.
#6
ForGroup
is 2 times faster than Group Loop, so I would recommand that.
#7
... ForGroup blows :P
#9
though ForGroup cant get the variables from it parent function...
#10
You can, using HandleVars.
Also, I don't see any variables in your loop anyway besides the "FirstOfGroup" itself.
#11
Indeed. That was annoying and I became tired of thinking about working around.
So I used this way.

... And there is something else about "ForGroup", which is as serious:
It does not wait until the code is done for each group member.
So, the calling function's execution goes on, while the "ForGroup"-function is not finished.

Mostly, that does not cause problems, but sometimes...
I found such a case, while writing an automatical mating/breeding-script.

postscript:
Argh! UnMi, you were a little too fast in answering. ^^

... And by the way, there is still something wrong.
Just because I altered my code while testing, as I did not want to produce the unit before.

This
local unit vessel = GetTriggerUnit()

has to be replaced with this
local unit vessel = GetTrainedUnit()


The variable to get is vessel.
Sure, I could get it via "GetTrainedUnit()".
But what if two or three times the if-structure is skipped and while these 0.15 seconds passed another unit has been produced?
#12
We are not in GUI, the unit is saved in the local variable and won't be changed unless you change it.
#13
still, handle vars should be avoided as much as possible, as they arent exactly fast either...
#14
Well, yes, but normally you won't need any other values expect for the unit itself while group looping.
The point is to use ForGroup as much as possible, but if you need a lot extern variables, you will have to stick to group looping.
#15
We are not in GUI, the unit is saved in the local variable and won't be changed unless you change it.

And as we are not in GUI, will this local - this LOCAL variable be aviable in the called function?
No.

Ether I would have to use a global or the game cache to carry it's value over.
The global forbids the whole thing to be multiinstanceable, the cache...

Well, I would have to write an algorithm, which creates a unique key for each time the function is called and the creation,
storage and recycling of used keys would obviously take any speed bonus, I won by avoiding the iteration.