scope Bloodthirst initializer i
struct healingOrb
unit orb
unit target
real size
real dX
real dY
real dZ
effect model
endstruct
globals
private constant real ENUM_RAD = 600.
private constant real MULTIPLIER = .1
private constant real OVERFLOW_DURATION = 3.
private constant real CLOCK_PERIOD = 1./30.
private constant real INITIAL_ORB_VEL = 1000.
private constant real ACCELERATION = 50.
private constant real CHEST_HEIGHT = 50.
private constant real TOUCH_DISTANCE_SQUARED = 80.*80.
private constant real CHEAP_AIR_FRICTION = .6 //What fraction of the velocity is lost per second
private constant real HEAL_BUFFER_MULTIPLIER = 1.
private constant real HEAL_BUFFER_DURATION = 3.
private constant string BLOOD_MODEL = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl"
private constant string HEAL_EFFECT = "Abilities\\Spells\\Other\\HealingSpray\\HealBottleMissile.mdl"
private constant string BUFFER_FX = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl"
private constant string BUFFER_FX_POINT="overhead"
private group g = CreateGroup()
private timer time = CreateTimer()
private healingOrb array db
private integer dbIndex = -1
endglobals
private function p takes nothing returns nothing
local integer index = 0
local healingOrb tempOrb
local real xyDist2
local real xyzDist2
local real tX
local real tY
local real oX
local real oY
local real oZ
local real ang
local real zAng
loop
exitwhen index>dbIndex
set tempOrb=db[index]
// Simulate Orb Movement
set tX=GetUnitX(tempOrb.target)
set tY=GetUnitY(tempOrb.target)
set oX=GetUnitX(tempOrb.orb)
set oY=GetUnitY(tempOrb.orb)
set oZ=GetUnitFlyHeight(tempOrb.orb)
call SetUnitX(tempOrb.orb,oX+tempOrb.dX)
call SetUnitY(tempOrb.orb,oY+tempOrb.dY)
call SetUnitFlyHeight(tempOrb.orb,oZ+tempOrb.dZ,0.)
// Calculate new vector acceleration
set ang = Atan2(tY-oY,tX-oX)
set xyDist2 = (tX-oX)*(tX-oX) + (tY-oY)*(tY-oY)
set zAng= Atan2(CHEST_HEIGHT-oZ,SquareRoot(xyDist2))
set xyzDist2 = (tX-oX)*(tX-oX) + (tY-oY)*(tY-oY) + (CHEST_HEIGHT-oZ)*(CHEST_HEIGHT-oZ)
set tempOrb.dX=tempOrb.dX + ACCELERATION*Cos(ang)*Cos(zAng)*CLOCK_PERIOD
set tempOrb.dY=tempOrb.dY + ACCELERATION*Sin(ang)*Cos(zAng)*CLOCK_PERIOD
set tempOrb.dZ=tempOrb.dZ + ACCELERATION*Sin(zAng)*CLOCK_PERIOD
// Calculate cheap air friction
set tempOrb.dX = tempOrb.dX * (1.-CHEAP_AIR_FRICTION*CLOCK_PERIOD)
set tempOrb.dY = tempOrb.dY * (1.-CHEAP_AIR_FRICTION*CLOCK_PERIOD)
set tempOrb.dZ = tempOrb.dZ * (1.-CHEAP_AIR_FRICTION*CLOCK_PERIOD)
// Check for no target
if GetUnitTypeId(tempOrb.target)==0 or not UnitAlive(tempOrb.target) then
call DestroyEffect(tempOrb.model)
call DummyUnitStack.release(tempOrb.orb)
call tempOrb.destroy()
set db[index]=db[dbIndex]
set dbIndex=dbIndex-1
set index=index-1
if dbIndex==-1 then
call PauseTimer(time)
endif
//Check for touch
elseif xyzDist2<TOUCH_DISTANCE_SQUARED then
call DestroyEffect(AddSpecialEffectTarget(HEAL_EFFECT,tempOrb.target,"overhead"))
set oX=GetUnitState(tempOrb.target,UNIT_STATE_LIFE)
set oY=GetUnitState(tempOrb.target,UNIT_STATE_MAX_LIFE)
set tX=oY-oX
set tY=tX-tempOrb.size
if tY>0. then
call SetUnitState(tempOrb.target,UNIT_STATE_LIFE,oX+tempOrb.size)
else
call SetUnitState(tempOrb.target,UNIT_STATE_LIFE,oY)
call Shield.add(tempOrb.target,-1.*HEAL_BUFFER_MULTIPLIER*tY,HEAL_BUFFER_DURATION,BUFFER_FX,BUFFER_FX_POINT)
endif
call DestroyEffect(tempOrb.model)
call DummyUnitStack.release(tempOrb.orb)
call tempOrb.destroy()
set db[index]=db[dbIndex]
set dbIndex=dbIndex-1
set index=index-1
if dbIndex==-1 then
call PauseTimer(time)
endif
endif
set index=index+1
endloop
endfunction
private function c takes nothing returns boolean
local unit tU=GetTriggerUnit()
local unit FoG
local unit bestMatch=null
local real val = 1000000.
local real life
local real scale
local real tX=GetUnitX(tU)
local real tY=GetUnitY(tU)
local healingOrb orb
if GetUnitAbilityLevel(tU,'Aloc')<1 then
call GroupEnumUnitsInRange(g,tX,tY,ENUM_RAD,null)
loop
set FoG=FirstOfGroup(g)
exitwhen FoG==null
if GetUnitTypeId(FoG)==LIEUT_ID and UnitAlive(FoG) then
set life = GetUnitState(FoG,UNIT_STATE_LIFE)
if life<val then
set bestMatch = FoG
set val = life
endif
endif
call GroupRemoveUnit(g,FoG)
endloop
if bestMatch!=null then
set orb = healingOrb.create()
set orb.target=bestMatch
set orb.size=GetUnitState(tU,UNIT_STATE_MAX_LIFE)*MULTIPLIER
set orb.orb=DummyUnitStack.get()
set scale = .75 + Math.ln(orb.size)*.1
call SetUnitScale(orb.orb,scale,scale,scale)
set orb.model=AddSpecialEffectTarget(BLOOD_MODEL,orb.orb,"origin")
call SetUnitX(orb.orb,tX)
call SetUnitY(orb.orb,tY)
call SetUnitFlyHeight(orb.orb,75.,0.)
set orb.dX=0.
set orb.dY=0.
set orb.dZ=INITIAL_ORB_VEL*CLOCK_PERIOD
set dbIndex=dbIndex+1
set db[dbIndex]=orb
if dbIndex==0 then
call TimerStart(time,CLOCK_PERIOD,true,function p)
endif
endif
endif
set tU=null
return false
endfunction
private function i takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t,Condition(function c))
set t=null
endfunction
endscope