Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- library Knockback3D initializer i requires IsTerrainWalkable
- private struct knockDat
- unit u
- real xOffs
- real yOffs
- real zOffs
- endstruct
- globals
- private constant boolean USE_MOVESPEED_MODIFIERS=true //This defines whether or not units should have their movespeed set to 0 and then back to "default" speed (Using GetUnitDefaultMoveSpeed()). If false, units in mid air can still fully control themselves.
- private constant integer CROW_ID='Arav'
- private constant real FIDELITY=1./30. //How often the periodic trigger fires. A value of (1./30.) represents 30 frames per second.
- private constant real BOUNCE_COEFFICIENT=.4 //How much momentum is retained when a unit bounces. A value of .4 means 40% of the z velocity is retained.
- private constant real FRICTION=.15 //What percentage of momentum is lost while a unit is sliding. A value of .15 means that 85% of the unit's speed is retained with each slide iteration.
- private constant real GRAVITY=FIDELITY*41.25 //The downward acceleration of all units in the stack. A value of FIDELITY*41.25 means they accelerate downwards by 41.25 game units per second.
- private constant real MAX_Z_VELOCITY_TO_BOUNCE=FIDELITY*-300. //This represents a minimum fall-speed for a unit to bounce. For a value of (-10.), units have to have a negative zVelocity of at least 10, or they won't bounce.
- private constant real MIN_FLY_HEIGHT=5. //This is the minimum height a unit can be at to be considered "sliding" (friction is applied to it)
- private constant real MIN_FOR_KNOCKBACK=FIDELITY*30. //This is the minimum horizontal velocity a unit can be sliding at before it is removed from the stack.
- private constant real MIN_FRICTION_FOR_EFFECT=FIDELITY*180. //While a sliding unit's horizontal velocity is higher than this number, a "friction" effect is spawned.
- private constant real MIN_Z_VELOCITY_TO_BECOME_AIRBORNE=FIDELITY*150. //This is the minimum z-velocity of a unit to actually have it's flying height changed. Otherwise, it just slides.
- private constant real DESTRUCTABLE_ENUM_RADIUS=130. //This is the distance from the center of a sliding unit to a nearby destructable for it to be destroyed. Note that the radius is coverted to a square and therefor the user must consider this value *Sqrt(2).
- private constant real MIN_VEL_DESTROY_DESTRUCTABLE=FIDELITY*300. //This is the minimum horizontal velocity a unit must have to destroy a destructable. You can set this to a very high number to disable the feature.
- private constant real DESTROY_DESTRUCTABLE_MOMENTUM_CONSERVED=BOUNCE_COEFFICIENT //This is the percentage of momentum to conserve if a sliding unit destroys a destructable. Default value is the same as BOUNCE_COEFFICIENT
- private constant real MAX_HEIGHT_DESTROY_DESTRUCTABLE=150. //This is the height below which a unit in the stack is elligible to destroy a destructable. Ideally it should be the average height of your destructables.
- private constant string FRICTION_MODEL="Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl" //This is the model to spawn when a unit's horizontal velocity > MIN_FRICTION_FOR_EFFECT
- private boolean hitDestructable
- private effect fx
- private integer dbIndex=-1
- private knockDat array knockDB
- private location zLoc=Location(0.,0.)
- private real minX
- private real maxX
- private real minY
- private real maxY
- private rect rct
- private timer time=CreateTimer()
- endglobals
- private function getZ takes real x, real y returns real
- call MoveLocation(zLoc,x,y)
- return GetLocationZ(zLoc)
- endfunction
- private function d takes nothing returns nothing
- local destructable des=GetEnumDestructable()
- if GetDestructableLife(des)>0. then
- call KillDestructable(des)
- set hitDestructable=true
- endif
- set des=null
- endfunction
- private function p takes nothing returns nothing
- local boolean newInMap
- local integer index=0
- local real flyHeight
- local real unitX
- local real unitY
- local real heightDifference
- local real newX
- local real newY
- local real vel2d
- local knockDat tempDat
- loop
- exitwhen index>dbIndex
- set tempDat=knockDB[index]
- set unitX=GetUnitX(tempDat.u)
- set unitY=GetUnitY(tempDat.u)
- set newX=unitX+tempDat.xOffs
- set newY=unitY+tempDat.yOffs
- set newInMap=newX>minX and newX<maxX and newY>minY and newY<maxY
- set flyHeight=GetUnitFlyHeight(tempDat.u)
- set vel2d=(tempDat.xOffs*tempDat.xOffs+tempDat.yOffs*tempDat.yOffs)
- if flyHeight<MIN_FLY_HEIGHT then
- if IsTerrainWalkable(newX,newY) and newInMap then
- call SetUnitX(tempDat.u,unitX+tempDat.xOffs)
- call SetUnitY(tempDat.u,unitY+tempDat.yOffs)
- set tempDat.xOffs=tempDat.xOffs*(1.-FRICTION)
- set tempDat.yOffs=tempDat.yOffs*(1.-FRICTION)
- static if USE_MOVESPEED_MODIFIERS then
- call SetUnitMoveSpeed(tempDat.u,GetUnitDefaultMoveSpeed(tempDat.u))
- endif
- if vel2d>MIN_FRICTION_FOR_EFFECT then
- set fx=AddSpecialEffect(FRICTION_MODEL,unitX,unitY)
- call DestroyEffect(fx)
- endif
- else
- set tempDat.xOffs=0
- set tempDat.yOffs=0
- endif
- if tempDat.zOffs<MAX_Z_VELOCITY_TO_BOUNCE then
- set tempDat.zOffs=tempDat.zOffs*-1.*BOUNCE_COEFFICIENT
- endif
- if tempDat.zOffs>MIN_Z_VELOCITY_TO_BECOME_AIRBORNE then
- call SetUnitFlyHeight(tempDat.u,flyHeight+tempDat.zOffs,0)
- set tempDat.zOffs=tempDat.zOffs-GRAVITY
- endif
- elseif newInMap then
- set tempDat.zOffs=tempDat.zOffs-GRAVITY
- set heightDifference=getZ(newX,newY)-getZ(unitX,unitY)
- call SetUnitFlyHeight(tempDat.u,flyHeight+tempDat.zOffs-heightDifference,0)
- call SetUnitX(tempDat.u,newX)
- call SetUnitY(tempDat.u,newY)
- static if USE_MOVESPEED_MODIFIERS then
- call SetUnitMoveSpeed(tempDat.u,0)
- endif
- endif
- if vel2d<MIN_FOR_KNOCKBACK and tempDat.zOffs>MAX_Z_VELOCITY_TO_BOUNCE and tempDat.zOffs<-1*MAX_Z_VELOCITY_TO_BOUNCE and flyHeight<MIN_FLY_HEIGHT then
- set knockDB[index]=knockDB[dbIndex]
- set dbIndex=dbIndex-1
- call SetUnitFlyHeight(tempDat.u,0,0)
- static if USE_MOVESPEED_MODIFIERS then
- call SetUnitMoveSpeed(tempDat.u,GetUnitDefaultMoveSpeed(tempDat.u))
- endif
- call tempDat.destroy()
- set index=index-1
- if dbIndex<0 then
- call PauseTimer(time)
- endif
- endif
- if vel2d>MIN_VEL_DESTROY_DESTRUCTABLE and flyHeight<MAX_HEIGHT_DESTROY_DESTRUCTABLE then
- set hitDestructable=false
- call MoveRectTo(rct,newX,newY)
- call EnumDestructablesInRect(rct,null,function d)
- if hitDestructable then
- set tempDat.xOffs=tempDat.xOffs*DESTROY_DESTRUCTABLE_MOMENTUM_CONSERVED
- set tempDat.yOffs=tempDat.yOffs*DESTROY_DESTRUCTABLE_MOMENTUM_CONSERVED
- endif
- endif
- set index=index+1
- endloop
- endfunction
- private function getUnitIndexFromStack takes unit u returns integer
- local integer index=0
- local integer returner=-1
- local knockDat tempDat
- loop
- exitwhen index>dbIndex or returner!=-1
- set tempDat=knockDB[index]
- if tempDat.u==u then
- set returner=index
- endif
- set index=index+1
- endloop
- return returner
- endfunction
- public function add takes unit u, real velocity, real angleInRads, real zAngleInRads returns nothing //make sure setVel matches this!
- local integer index=getUnitIndexFromStack(u)
- local knockDat tempDat
- local real instVel=velocity*FIDELITY
- if index==-1 then
- set tempDat=knockDat.create()
- set tempDat.u=u
- set tempDat.xOffs=instVel*Cos(angleInRads)*Cos(zAngleInRads) //Warning! Don't send angles in degrees to these functions if you value your life!
- set tempDat.yOffs=instVel*Sin(angleInRads)*Cos(zAngleInRads)
- set tempDat.zOffs=instVel*Sin(zAngleInRads)
- set dbIndex=dbIndex+1
- set knockDB[dbIndex]=tempDat
- if UnitAddAbility(tempDat.u,CROW_ID) then
- call UnitRemoveAbility(tempDat.u,CROW_ID)
- endif
- if dbIndex==0 then
- call TimerStart(time,FIDELITY,true,function p)
- endif
- else
- set tempDat=knockDB[index]
- set tempDat.xOffs=tempDat.xOffs+instVel*Cos(angleInRads)*Cos(zAngleInRads)
- set tempDat.yOffs=tempDat.yOffs+instVel*Sin(angleInRads)*Cos(zAngleInRads)
- set tempDat.zOffs=tempDat.zOffs+instVel*Sin(zAngleInRads)
- endif
- endfunction
- public function setVel takes unit u, real velocity, real angleInRads, real zAngleInRads returns nothing //make sure this matches add!
- local integer index=getUnitIndexFromStack(u)
- local knockDat tempDat
- local real instVel=velocity*FIDELITY
- if index==-1 then
- set tempDat=knockDat.create()
- set tempDat.u=u
- set tempDat.xOffs=instVel*Cos(angleInRads)*Cos(zAngleInRads)
- set tempDat.yOffs=instVel*Sin(angleInRads)*Cos(zAngleInRads)
- set tempDat.zOffs=instVel*Sin(zAngleInRads)
- set dbIndex=dbIndex+1
- set knockDB[dbIndex]=tempDat
- if UnitAddAbility(tempDat.u,CROW_ID) then
- call UnitRemoveAbility(tempDat.u,CROW_ID)
- endif
- if dbIndex==0 then
- call TimerStart(time,FIDELITY,true,function p)
- endif
- else
- set tempDat=knockDB[index]
- set tempDat.xOffs=instVel*Cos(angleInRads)*Cos(zAngleInRads)
- set tempDat.yOffs=instVel*Sin(angleInRads)*Cos(zAngleInRads)
- set tempDat.zOffs=instVel*Sin(zAngleInRads)
- endif
- endfunction
- public function updateMapArea takes rect rct returns nothing
- set minX=GetRectMinX(rct)
- set minY=GetRectMinY(rct)
- set maxX=GetRectMaxX(rct)
- set maxY=GetRectMaxY(rct)
- endfunction
- private function i takes nothing returns nothing
- set rct=Rect(-1*DESTRUCTABLE_ENUM_RADIUS,-1*DESTRUCTABLE_ENUM_RADIUS,DESTRUCTABLE_ENUM_RADIUS,DESTRUCTABLE_ENUM_RADIUS)
- set minX=GetRectMinX(bj_mapInitialPlayableArea)
- set maxX=GetRectMaxX(bj_mapInitialPlayableArea)
- set minY=GetRectMinY(bj_mapInitialPlayableArea)
- set maxY=GetRectMaxY(bj_mapInitialPlayableArea)
- endfunction
- endlibrary
Advertisement
Add Comment
Please, Sign In to add comment