//******************************************************
// 1 - Basic functionality and changeables
//******************************************************
//Reset unit data (not recommended to be changed)
function OETForGroupEnd takes nothing returns nothing
call FlushCache4Handle(GetEnumUnit())
endfunction
//The filter conditions for picking units. Be careful when changing, "sfx" must stay, "bj_ghoul[0]" shall not be overwritten.
function OETFilter takes nothing returns boolean
local integer sfx=bj_cineModeSavedSeed
if GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0 then
if IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING)==false then
if IsUnitAlly(GetFilterUnit(),GetOwningPlayer(bj_ghoul[0])) or (GetOwningPlayer(GetFilterUnit())==GetOwningPlayer(bj_ghoul[0])) then
return IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false and (GetFilterUnit()!=bj_ghoul[0]) and not LoadBoolean(udg_Cache,GetX(GetFilterUnit()),sfx)
endif
endif
endif
return false
endfunction
//The dummy unittype that represents the beam
constant function OETDummy takes nothing returns integer
return 'u000'
endfunction
//The radius, in which units are being picked up
constant function OETPickingRange takes nothing returns real
return 550.0
endfunction
//The size of the target area that beamed units will be ported into
constant function OETPlacingRange takes nothing returns real
return 150.0
endfunction
//Minimum size of the beam
constant function OETMinSize takes nothing returns real
return 100.0
endfunction
//Maximum size of the beam
constant function OETMaxSize takes nothing returns real
return 300.0
endfunction
//Steps you need to be beamed. Each step is 0.1 seconds. When changing them, you will also have to check when and where to place the special effects
//if you wish to keep them.
constant function OETSteps takes nothing returns integer
return 10
endfunction
//Determines the rate at which the beam will move towards his targets
constant function OETSearchSpeed takes nothing returns real
return 20.
endfunction
//Determines the rate at which the beam will move back to his starting point
constant function OETReturnSpeed takes nothing returns real
return 25.
endfunction
//**************Grafics**************
//Dummyscale calculation: Basic scale+ X*radius
//Basic dummy scale
constant function OETScaleBase takes nothing returns real
return 1.0
endfunction
//Scale*radius
constant function OETScaleRadius takes nothing returns real
return .008
endfunction
//The Z scale of the dummy, may be useful when using beams...
constant function OETScaleZ takes nothing returns real
return 10.
endfunction
//The animation speed of the dummy
constant function OETAnimSpeed takes nothing returns real
return 5.
endfunction
//******************************************************
// 2 - Moving functions
//******************************************************
//******************************************************
// I-Getting a target
//******************************************************
function OETGetTarget takes integer sfx returns unit
local unit u=null
local unit target=null
local unit caster=GetU(sfx,1)
local real x=GetR(sfx,1)
local real y=GetR(sfx,2)
//Initialize the searching for the weakest unit
call GroupClear(udg_Tempgroup)
set bj_ghoul[0]=caster
set bj_cineModeSavedSeed =sfx
call GroupEnumUnitsInRange(udg_Tempgroup,x,y,OETPickingRange(),Filter(function OETFilter))
set target=FirstOfGroup(udg_Tempgroup)
//Now search
loop
set u=FirstOfGroup(udg_Tempgroup)
exitwhen u==null
call GroupRemoveUnit(udg_Tempgroup,u)
if GetUnitState(u,UNIT_STATE_LIFE)<GetUnitState(target,UNIT_STATE_LIFE) then
set target=u
endif
endloop
//target contains the weakest unit now or NULL if there was none found.
return target
endfunction
//******************************************************
// II-Moving towards target
//******************************************************
function OETBeamMoving takes integer sfx returns boolean
local real x
local real y
local unit dummy=GetU(sfx,2)
local real dx=GetUnitX(dummy)
local real dy=GetUnitY(dummy)
local unit target=GetU(sfx,3)
if (GetR(sfx,1)-dx)*(GetR(sfx,1)-dx)+(GetR(sfx,2)-dy)*(GetR(sfx,2)-dy) >= (OETPickingRange()+50)*(OETPickingRange()+50) then //Out of range
set target= OETGetTarget(sfx)
call SaveU(target,sfx,3)
endif
set x=GetUnitX(target)
set y=GetUnitY(target)
if (x-dx)*(x-dx)+(y-dy)*(y-dy) <=OETSearchSpeed() then //In range of 50
call SetUnitX(dummy,x)
call SetUnitY(dummy,y)
return true
endif
if x>dx then
if RealDiff(x,dx)<OETSearchSpeed() then
call SetUnitX(dummy,x)
else
call SetUnitX(dummy,dx+OETSearchSpeed())
endif
elseif x<dx then
if RealDiff(x,dx)<OETSearchSpeed() then
call SetUnitX(dummy,x)
else
call SetUnitX(dummy,dx-OETSearchSpeed())
endif
endif
if y>dy then
if RealDiff(y,dy)<OETSearchSpeed() then
call SetUnitY(dummy,y)
else
call SetUnitY(dummy,dy+OETSearchSpeed())
endif
elseif y<dy then
if RealDiff(y,dy)<OETSearchSpeed() then
call SetUnitY(dummy,y)
else
call SetUnitY(dummy,dy-OETSearchSpeed())
endif
endif
return false //Go on moving, too far away
endfunction
//******************************************************
// III-Moving back to starting point
//******************************************************
function OETBeamBackMoving takes integer sfx returns boolean
local unit dummy=GetU(sfx,2)
local real dx=GetUnitX(dummy)
local real dy=GetUnitY(dummy)
if (GetR(sfx,1)-dx)*(GetR(sfx,1)-dx)+(GetR(sfx,2)-dy)*(GetR(sfx,2)-dy) <=2500 then //In range of 50
call SetUnitX(dummy,GetR(sfx,1))
call SetUnitY(dummy,GetR(sfx,2))
return true
endif
if GetR(sfx,1)>dx then
if RealDiff(GetR(sfx,1),dx)<OETReturnSpeed() then
call SetUnitX(dummy,GetR(sfx,1))
else
call SetUnitX(dummy,dx+OETReturnSpeed())
endif
elseif GetR(sfx,1)<dx then
if RealDiff(GetR(sfx,1),dx)<OETReturnSpeed() then
call SetUnitX(dummy,GetR(sfx,1))
else
call SetUnitX(dummy,dx-OETReturnSpeed())
endif
endif
if GetR(sfx,2)>dy then
if RealDiff(GetR(sfx,2),dy)<OETReturnSpeed() then
call SetUnitY(dummy,GetR(sfx,2))
else
call SetUnitY(dummy,dy+OETReturnSpeed())
endif
elseif GetR(sfx,2)<dy then
if RealDiff(GetR(sfx,2),dy)<OETReturnSpeed() then
call SetUnitY(dummy,GetR(sfx,2))
else
call SetUnitY(dummy,dy-OETReturnSpeed())
endif
endif
return false //Go on moving, not yet in the middle
endfunction
//******************************************************
// 3 - Beaming functions
//******************************************************
//******************************************************
// I- Calculating beaming range
//******************************************************
function OETCheckSize takes integer sfx returns real
local unit dummy=GetU(sfx,2)
local real array a
local real array b
local integer pointer=0
local integer i=0
local unit u=null
local integer max=0
local integer count=0
local real dist
local real x=GetUnitX(GetU(sfx,2))
local real y=GetUnitY(GetU(sfx,2))
//First get all distances of units in range
call GroupClear(udg_Tempgroup)
set bj_ghoul[0]=GetU(sfx,1)
call GroupEnumUnitsInRange(udg_Tempgroup,x,y,OETMaxSize(),Filter(function OETFilter))
if FirstOfGroup(udg_Tempgroup)!=null then
loop
set u=FirstOfGroup(udg_Tempgroup)
exitwhen u==null
call GroupRemoveUnit(udg_Tempgroup,u)
set a[pointer]=SquareRoot((GetUnitX(u)-x)*(GetUnitX(u)-x) + (GetUnitY(u)-y)*(GetUnitY(u)-y))
set pointer=pointer+1
endloop
set count=pointer
//Bubblesort style
loop
exitwhen pointer<0
//First get the biggest number
set max=0
set i=0
loop
exitwhen i>=pointer
if a[i]>=a[max] then
set max=i
endif
set i=i+1
endloop
//Save it
set b[pointer]=a[max]
//Then delete it and move the other numbers afterwards
loop
exitwhen max>pointer
set max=max+1
set a[max-1]=a[max]
endloop
set pointer=pointer-1
endloop
//Ranges shall be sorted now
//Check where to set the limits
set i=0
loop
exitwhen b[i]+75>OETMinSize() or i>=count
set i=i+1
endloop
loop
exitwhen count==1
exitwhen b[0]+75>OETMinSize() and b[0]+75<b[1] //just the first units in range of about 100+
exitwhen b[i]+75>OETMaxSize() or i>=count //Maximum range/all units checked
exitwhen b[i]+75<b[i+1] //Cutplace
set i=i+1
endloop
//Now let's see whether it skipped it's actions because of the limit or found a distance to cut in.
set dist=b[i]+75
if dist>OETMaxSize() then
//Found nothing to cut in, go for max range
set dist=OETMaxSize()
endif
//Show the increased range
call SetUnitScale(dummy,OETScaleBase()+dist*OETScaleRadius(),OETScaleBase()+dist*OETScaleRadius(),OETScaleZ())
return dist //Return the distance we found
else
return OETMaxSize()
endif
endfunction
//******************************************************
// III- Actions for units in beaming range (ForGroup)
//******************************************************
function OETForGroupBeam takes nothing returns nothing
//Currently untouched by teleporters
local unit u=null
local integer sfx=bj_cineModeSavedSeed
local real x
local real y
local real ox
local real oy
local integer c
local unit caster=GetU(sfx,1)
local integer usfx
local location rp=null
//Unitcount in group
if GetX(GetEnumUnit())==0 then
call SetX(GetEnumUnit())
call IncX()
endif
set usfx=GetX(GetEnumUnit())
if LoadBoolean(udg_Cache,usfx,sfx) then
return //Has been already targeted, stop all actions
else
set bj_forceCountPlayers=bj_forceCountPlayers+1 //Count if the target is ok.
endif
if IsUnitInGroup(GetEnumUnit(),udg_OETGroups[sfx])==false then
//Came into range
call GroupAddUnit(udg_OETGroups[sfx],GetEnumUnit())
call SaveR(GetUnitX(GetEnumUnit()),usfx,1)
call SaveR(GetUnitY(GetEnumUnit()),usfx,2)
if GetI(usfx,1)==0 then
call SaveI(OETSteps(),usfx,1) //Has to be OETSteps() times in range to be beamed. OETSteps * 0.1 seconds= 1 second for a teleport
endif
endif
//Is in group now
//Effects
if GetI(usfx,1)==2 then
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl",GetEnumUnit(),"overhead"))
elseif GetI(usfx,1)==4 then
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl",GetEnumUnit(),"head"))
elseif GetI(usfx,1)==6 then
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl",GetEnumUnit(),"chest"))
elseif GetI(usfx,1)==8 then
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl",GetEnumUnit(),"origin"))
endif
set x=GetUnitX(GetEnumUnit())
set y=GetUnitY(GetEnumUnit())
set ox=GetR(usfx,1)
set oy=GetR(usfx,2)
set c=GetI(usfx,1)-1
if (ox-x)*(ox-x)+(oy-y)*(oy-y)>=25 then
//Unit moved, having at least 25 Wu/sec speed, do not decrease c. Wu= Warcraft units.
set c=c+1
if (ox-x)*(ox-x)+(oy-y)*(oy-y)>=400 then
//Unit moved, having at least 100 Wu/sec speed, increase c if it's not already 10.
if c<OETSteps() then
set c=c+1
endif
endif
endif
call SaveI(c,usfx,1)
call SaveR(GetUnitX(GetEnumUnit()),usfx,1)
call SaveR(GetUnitY(GetEnumUnit()),usfx,2)
if c<=0 then
//*********************Teleport to caster********************\\
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl",GetUnitX(GetEnumUnit()),GetUnitY(GetEnumUnit())))
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\Flare\\FlareCaster.mdl",GetUnitX(GetEnumUnit()),GetUnitY(GetEnumUnit())))
set rp=GetUnitRallyPoint(caster)
if rp==null then
call SetUnitPosition(GetEnumUnit(),GetUnitX(caster)+GetRandomReal(0,OETPlacingRange()),GetUnitY(caster)+GetRandomReal(0,OETPlacingRange()))
else
call SetUnitPosition(GetEnumUnit(),GetLocationX(rp)+GetRandomReal(0,OETPlacingRange()),GetLocationY(rp)+GetRandomReal(0,OETPlacingRange()))
call RemoveLocation(rp)
set rp=null
endif
call SaveBoolean(udg_Cache,usfx,sfx,true)//Has been ported by this beam now, do not port again
endif
endfunction
//******************************************************
// II- Actions for units in beaming range (Basic)
//******************************************************
function OETBeamActions takes integer sfx returns boolean
if udg_OETGroups[sfx]==null then
set udg_OETGroups[sfx]=CreateGroup()
endif
call GroupClear(udg_Tempgroup)
set bj_ghoul[0]=GetU(sfx,1)
call GroupEnumUnitsInRange(udg_Tempgroup,GetUnitX(GetU(sfx,2)),GetUnitY(GetU(sfx,2)),GetR(sfx,3),Filter(function OETFilter))
set bj_cineModeSavedSeed=sfx
set bj_forceCountPlayers=0
call ForGroup(udg_Tempgroup,function OETForGroupBeam)
return bj_forceCountPlayers==0 //Skip when there are no units left
endfunction
//******************************************************
// 3 - Basic function that calls the previous functions (splitter)
//******************************************************
function OETSplit takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer sfx=GetX(t)
local real x=GetR(sfx,1)
local real y=GetR(sfx,2)
local unit target=GetU(sfx,3)
local boolean swap=false
local integer i=GetI(sfx,1)
if i==0 then
//0=Moving mode
if target==null then
set target=OETGetTarget(sfx)
endif
if target!=null then
//Only go on if there are any targets.
call SaveU(target,sfx,3)
//**********************************************
set swap=OETBeamMoving(sfx)
//**********************************************
if swap then
//Within 50 range, change mode to beaming
call SaveI(1,sfx,1)
call SaveR(0,sfx,3)
endif
//**********************************************
call TimerStart(t,0.04,false,function OETSplit)
//**********************************************
else
//**********************************************
//No targets found, ending spell...
call DisplayTextToPlayer(GetOwningPlayer(GetU(sfx,1)),0,0,"|cffff0000No targets found.|r")
call KillUnit(GetU(sfx,2))
set target=CreateUnit(Player(15),'espv',x,y,0)
call SetUnitPathing(target,false)
call SetUnitPosition(target,x,y)
call PauseUnit(target,true)
call KillUnit(target)
call ForGroup(udg_OETGroups[sfx],function OETForGroupEnd)//Clear data
call DestroyGroup(udg_OETGroups[sfx])
set udg_OETGroups[sfx]=null
call FreeTimer(t)
set target=null
//**********************************************
endif
elseif i==1 then
//1=Beaming mode
if GetR(sfx,3)==0 then
//No distance calculated by now
call SaveR(OETCheckSize(sfx),sfx,3)
endif
//Distance must have been calculated by now
//**********************************************
set swap=OETBeamActions(sfx)
//**********************************************
if swap then
//Finished beaming. Swap mode to mid moving.
call SaveU(null,sfx,3)
call SaveI(2,sfx,1)
//Reset Dummy
call SetUnitScale(GetU(sfx,2),OETScaleBase(),OETScaleBase(),OETScaleZ())
//**********************************************
call TimerStart(t,0.3,false,function OETSplit)
//**********************************************
else
//**********************************************
call TimerStart(t,0.1,false,function OETSplit)
//**********************************************
endif
else
//i=2, Backmoving to the middle
//**********************************************
set swap= OETBeamBackMoving(sfx)
//**********************************************
if swap then
//In the middle again, change mode to searching
call SaveI(0,sfx,1)
call TimerStart(t,0.0,false,function OETSplit)
else
//**********************************************
call TimerStart(t,0.04,false,function OETSplit)
//**********************************************
endif
endif
set target=null
endfunction
//******************************************************
// 5 - Function to get started
//******************************************************
function OrbitalEmergencyTransportStart takes unit caster, location l returns nothing
local timer t=GetTimer()
local integer sfx=udg_zz_index
local real x=GetLocationX(l)
local real y=GetLocationY(l)
call RemoveLocation(l)
set l=null
call SetX(t)
call IncX()
//Unit saves
call SaveU(caster,sfx,1)//Caster=>1
//Create Dummy
call SaveU(CreateUnit(GetOwningPlayer(caster),OETDummy(),x,y,0),sfx,2)//Beam=>2
call SetUnitAnimation(GetU(sfx,2),"birth")
call SetUnitScale(GetU(sfx,2),OETScaleBase(),OETScaleBase(),OETScaleZ())
call SetUnitTimeScale(GetU(sfx,2),OETAnimSpeed())
call SaveU(null,sfx,3) //Clear space for beaming targets=>3
//Coordinates
call SaveR(x,sfx,1) //Target X
call SaveR(y,sfx,2) //Target Y
call SaveR(0,sfx,3) //Clear space for beam's range
//0=Move, 1=Beam, 2=Back to middle
call SaveI(0,sfx,1)
//Timer starts
call TimerStart(t,1.0,false, function OETSplit)
endfunction