[jass=]
library CasterSystem initializer InitCasterSystem requires CSSafeCache, GroupUtils, TimerUtils
//***************************************************************************
//* *
//* Caster System 16.0 *
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
http://wc3campaigns.net/vexorian *
//* Requires: *
//* ¯¯¯¯¯¯¯¯¯ *
//* - Jasshelper / Newgen pack *
//* *
//* - The CSSafeCache Module *
//* - The CSData Module *
//* - The CSSafety Module *
//* *
//* - The caster unit from this map Can be found in this map's unit editor *
//* ( Custom Units\Neutral Passive\Units\Caster ) *
//* *
//* ( Update the cs_CasterUnitId constant next
*
//* *
//* - the war3mapImported\dummy.mdx imported file (find it in this map) *
//* *
//***************************************************************************
//====================================================================================================================================================================
// Caster System Configuration constants :
//
globals
//
// Caster Unit type rawcode (changes betwen maps, always use it inside '')
//
constant integer cs_CasterUnitId = 'e000'
// cs_TIMER_CYCLE : Cycle value for the projectile movement in seconds (Each 0.04 the projectiles get moved)
// 0.01 looks smooth but is lag friendly
// 0.025 looks smooth and probably matches wc3's frame rate (so in theory, lower values than it are not needed)
// 0.1 looks horrible but is not laggy
// 0.04 is decent for the human eye and very efficient.
// 0.035 is ... well, a little smoother than 0.04
// 0.05 would be an improvement in efficiency but probably doesn't look too well )
//
constant real cs_TIMER_CYCLE = 0.035
//
// The eat tree ability, don't need to change this rawcode unless you modiffied that ability in your map, in that case copy it, reset the copied one and use its rawcode here.
//
constant integer cs_DamageTreeDetectorId = 'Aeat'
//
// Medivh's Crow form ability, don't need to change this rawcode unless you
// modiffied that ability in your map, in that case copy it, reset the copied one and use its rawcode here:
//
constant integer cs_FlyingHeightHack = 'Amrf'
//
// This must point to an inventory ability with 6 slots that does not add bonuses, you don't need one unless
// the caster system item hiding functions are used in your map
//
constant integer cs_DummyInventory_Id = 'null'
//
//Maximum collision size in your map - Affects the caster system's area cast/damage functions
//
constant real cs_MaxUnitCollisionSize = 55.0
//
// Next are default attack and damage types for the old caster system functions or when using 0 as damageoptions
//
constant attacktype cs_DefaultAttackType = ATTACK_TYPE_CHAOS
constant damagetype cs_DefaultDamageType = DAMAGE_TYPE_UNIVERSAL
//
// cs_InitialCastersNumber: Number of casters to create on map init:
//
constant integer cs_InitialCastersNumber = 12
endglobals
//
//=================================================================================================
// Caster System script:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//=================================================================================================
// main Caster System global variables:
//
globals
//old ones (udg_ preffix forced for compat ( )
unit udg_currentcaster = null
real array udg_castervars
group udg_casters = null
integer udg_currentabi = 0
unit udg_currenthurter = null
real udg_delayhack = 0.
location udg_sourcehack = null
//--
integer array cs_missiles
integer cs_missilecount = 0
timer cs_movementtimer = CreateTimer()
boolean cs_movementtimer_active = false
endglobals
//=================================================================================================
function CS_CopyGroup takes group g returns group
set bj_groupAddGroupDest=NewGroup()
call ForGroup(g, function GroupAddGroupEnum)
return bj_groupAddGroupDest
endfunction
globals
constant real cs_RectLimitOffSet = 50.0
real cs_game_maxx
real cs_game_maxy
real cs_game_miny
real cs_game_minx
endglobals
function CS_SafeXY_Init takes nothing returns nothing
set cs_game_maxx=GetRectMaxX(bj_mapInitialPlayableArea)-cs_RectLimitOffSet
set cs_game_maxy=GetRectMaxY(bj_mapInitialPlayableArea)-cs_RectLimitOffSet
set cs_game_miny=GetRectMinY(bj_mapInitialPlayableArea)+cs_RectLimitOffSet
set cs_game_minx=GetRectMinX(bj_mapInitialPlayableArea)+cs_RectLimitOffSet
endfunction
function CS_SafeX takes real x returns real
if (x<cs_game_minx) then
return cs_game_minx
elseif (x>cs_game_maxx) then
return cs_game_maxx
endif
return(x)
endfunction
function CS_SafeY takes real y returns real
if (y<cs_game_miny) then
return cs_game_minx
elseif (y>cs_game_maxy) then
return cs_game_maxy
endif
return(y)
endfunction
//Deprecated, since patch 1.21 there is no crash anymore, it is possibly
// still mildly useful since it does bound checking.
function CS_MoveUnit takes unit u, real x, real y returns boolean
local boolean b=true
if (x<cs_game_minx) then
set b=false
elseif (x>cs_game_maxx) then
set b=false
elseif (y>cs_game_maxy) then
set b=false
elseif (y<cs_game_miny) then
set b=false
endif
if (b) then
call SetUnitX(u, x)
call SetUnitY(u, y)
endif
return b
endfunction
function CS_MoveUnitLoc takes unit u, location loc returns boolean
return CS_MoveUnit(u,GetLocationX(loc),GetLocationY(loc))
endfunction
//==================================================================================================
function CS_EnumUnitsInAOE_Filter takes nothing returns boolean
return IsUnitInRangeLoc(GetFilterUnit(), bj_enumDestructableCenter ,bj_enumDestructableRadius)
endfunction
//==================================================================================================
// Use this version when you only have coordinates of the point.
//
function CS_EnumUnitsInAOE takes group g, real x, real y, real area, boolexpr bx returns nothing
local boolexpr cond
local boolexpr aux=Condition(function CS_EnumUnitsInAOE_Filter)
if (bx==null) then
set cond=aux
else
set cond=And(aux,bx)
endif
set bj_enumDestructableCenter=Location(x,y)
set bj_enumDestructableRadius=area
call GroupEnumUnitsInRange(g,x,y,cs_MaxUnitCollisionSize+area,cond)
if (bx!=null) then
call DestroyBoolExpr(cond)
endif
call RemoveLocation(bj_enumDestructableCenter)
set aux=null
set cond=null
endfunction
//==================================================================================================
// Use this version whenever you already have a location for that point, to save some steps
//
function CS_EnumUnitsInAOELoc takes group g, location loc, real area, boolexpr bx returns nothing
local boolexpr cond
local boolexpr aux=Condition(function CS_EnumUnitsInAOE_Filter)
if (bx==null) then
set cond=aux
else
set cond=And(aux,bx)
endif
set bj_enumDestructableCenter=loc
set bj_enumDestructableRadius=area
call GroupEnumUnitsInRangeOfLoc(g,loc,cs_MaxUnitCollisionSize+area,cond)
call DestroyBoolExpr(cond)
if (bx!=null) then
call DestroyBoolExpr(aux)
endif
set aux=null
set cond=null
endfunction
//==================================================================================================
// Angle Calculations
//
// I decided to add them to the caster system, because I found myself using them everytime, I am
// trying to convert the caster system into a Spell Development Framework (hehe)
//
//=================================================================================================
// Returns the angle distance between angles a1 and a2 (For example: a1=30 , a2=60 , return= 30 )
//
function Angles_GetAngleDifference takes real a1, real a2 returns real
local real x
set a1=ModuloReal(a1,360)
set a2=ModuloReal(a2,360)
if a1>a2 then
set x=a1
set a1=a2
set a2=x
endif
set x=a2-360
if a2-a1 > a1-x then
set a2=x
endif
set x=a1-a2
if (x<0) then
return -x
endif
return x
endfunction
//=================================================================================================
// Returns the mid angle between a1 and a2 (For example: a1=30 , a2=60 , return= 45 )
//
function Angles_GetMidAngle takes real a1, real a2 returns real
local real x
set a1=ModuloReal(a1,360)
set a2=ModuloReal(a2,360)
if a1>a2 then
set x=a1
set a1=a2
set a2=x
endif
set x=a2-360
if a2-a1 > a1-x then
set a2=x
endif
return (a1+a2)/2
endfunction
//=================================================================================================
// Makes angle a1 advance i units towards angle a2 (For Example: a1=30, a2=60, i=10, return=40 )
//
function Angles_MoveAngleTowardsAngle takes real a1, real a2, real i returns real
local real x
set a1=ModuloReal(a1,360)
set a2=ModuloReal(a2,360)
if a1>a2 then
set x=a1-360
if a1-a2 > a2-x then
set a1=x
endif
else
set x=a2-360
if a2-a1 > a1-x then
set a2=x
endif
endif
if a1>a2 then
set x=a1-i
if x<=a2 then
return a2
endif
return x
endif
set x=a1+i
if x>=a2 then
return a2
endif
return x
endfunction
//=================================================================================================
// Returns true if the angle 'angle' is between 'angle1' and 'angle2'
//
function Angles_IsAngleBetweenAngles takes real angle, real angle1, real angle2 returns boolean
local real x
set angle=ModuloReal(angle,360)
set angle1=ModuloReal(angle1,360)
set angle2=ModuloReal(angle2,360)
if (angle1>angle2) then
set x=angle1
set angle1=angle2
set angle2=x
endif
if (angle2-angle1)>(angle1 - (angle2-360)) then
set angle2=angle2-360
if angle > 180 then
set angle=angle-360
endif
return angle>=angle2 and angle<=angle1
endif
return (angle>=angle1) and (angle<=angle2)
endfunction
//====================================================================================================================================================================
function CreateCaster takes real fac, real x , real y returns unit
local unit m
if (x!=0) then
set x=CS_SafeX(x)
endif
if (y!=0) then
set y=CS_SafeY(y)
endif
set m=CreateUnit( Player(15), cs_CasterUnitId, x ,y ,fac)
call UnitAddAbility(m, 'Aloc')
call UnitAddAbility(m, cs_FlyingHeightHack)
call UnitRemoveAbility(m, cs_FlyingHeightHack )
set udg_currentcaster=m
set m=null
return udg_currentcaster
endfunction
function AddCasterFacing takes real fac returns unit
return CreateCaster(fac,0,0)
endfunction
function AddCaster takes nothing returns unit
return CreateCaster(0,0,0)
endfunction
//====================================================================================================================================================================
function CreateCasters takes integer n returns nothing
local integer a=0
local unit c
loop
exitwhen a>=n
set c=CreateCaster(0,0,0)
call GroupAddUnit( udg_casters, c)
set a=a+1
endloop
set c=null
endfunction
private function InitCasterSystem takes nothing returns nothing
set udg_casters=NewGroup()
call CS_SafeXY_Init()
call CreateCasters(cs_InitialCastersNumber)
set udg_castervars[100]=-1
set udg_castervars[101]=-1
set udg_castervars[102]=-1
set udg_castervars[103]=-1
set udg_castervars[104]=-1
set cs_dmg_caster=CreateCaster(0.,0.,0.)
call UnitRemoveAbility(cs_dmg_caster,'Aloc') //Otherwise the units would flee like crazy
endfunction
//====================================================================================================================================================================
function GetACaster takes nothing returns unit
set udg_currentcaster=FirstOfGroup( udg_casters)
if udg_currentcaster == null then
set udg_currentcaster=CreateCaster(0,0,0)
endif
call GroupRemoveUnit( udg_casters,udg_currentcaster)
call SetUnitState( udg_currentcaster, UNIT_STATE_MANA, 1000)
return udg_currentcaster
endfunction
//====================================================================================================================================================================
function Caster_SetZAngle takes unit caster, real ang returns nothing
local real a=(ModuloReal(GetUnitFacing(caster),360)*bj_DEGTORAD)
local real x
set ang=ModuloReal(ang,360)
if ( ang == 90 ) then
set ang = 89
endif
if ( ang == 270 ) then
set ang = 271
endif
if (ang>90) and (ang<270) then
set x=-1
else
set x=1
endif
set ang=ang*bj_DEGTORAD
call SetUnitLookAt(caster,"Bone_Chest",caster, 10000.0*Cos(a)*Cos(ang), 10000.0*Sin(a)*Cos(ang), x*(10000.0*Tan(ang)+90.0) )
endfunction
//====================================================================================================================================================================
function Caster_SetZAngle2 takes unit caster, integer ang returns nothing
call SetUnitAnimationByIndex(caster,ang+90) //Thanks infrane!
endfunction
//====================================================================================================================================================================
function RecycleCaster takes unit caster returns nothing
if GetWidgetLife(caster)>=0.405 then
call ResetUnitLookAt(caster)
call SetUnitOwner( caster, Player(15), true)
call SetUnitVertexColor( caster, 255,255,255,255)
call SetUnitScale( caster, 1,1,1)
call SetUnitTimeScale( caster, 1)
call SetUnitMoveSpeed( caster, 522)
call SetUnitFlyHeight( caster, 0,0)
call UnitAddAbility(caster, 'Aloc')
call SetUnitTurnSpeed( caster, 0.6)
call GroupAddUnit( udg_casters, caster)
endif
endfunction
function RecycleCaster_Light takes unit caster returns nothing
if GetWidgetLife(caster)>=0.405 then
call SetUnitOwner( caster, Player(15), true)
call GroupAddUnit( udg_casters, caster)
endif
endfunction
function RecicleCaster takes unit caster returns nothing
call RecycleCaster(caster)
endfunction
function RecicleCaster_Light takes unit caster returns nothing
call RecycleCaster_Light(caster)
endfunction
private struct csrecy
unit caster
integer abil
endstruct
function CasterRecycleTimed_X takes nothing returns nothing
local timer t=GetExpiredTimer()
local csrecy k=GetCSData(t)
if (k.abil!=0) then
call UnitRemoveAbility(k.caster,k.abil)
endif
call RecycleCaster(k.caster)
call k.destroy()
call ReleaseTimer(t)
endfunction
function CasterRecycleTimed takes unit caster, integer abi, real delay returns nothing
local timer t=NewTimer()
local csrecy k= csrecy.create()
set k.caster=caster
set k.abil=abi
call SetCSData(t,k)
call TimerStart(t,delay,false,function CasterRecycleTimed_X)
endfunction
function CasterWaitForEndCast takes nothing returns nothing
local unit caster=udg_currentcaster
local integer abilid=udg_currentabi
local real delay=udg_castervars[0]
local boolean activeability=(udg_castervars[1]>0)
loop
exitwhen GetUnitCurrentOrder(caster) == 0
call TriggerSleepAction(0)
endloop
if (delay>0) then
if activeability then
call CasterRecycleTimed(caster,abilid,delay)
else
call UnitRemoveAbility( caster, abilid)
call CasterRecycleTimed(caster,0,delay)
endif
else
call UnitRemoveAbility( caster, abilid)
call RecycleCaster(caster)
endif
set caster=null
endfunction
function RecycleCasterAfterCastEx takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing
set udg_castervars[0]=delaytime
set udg_castervars[1]=IntegerTertiaryOp(activeability,1,0)
set udg_currentabi=abilid
set udg_currentcaster=caster
call ExecuteFunc("CasterWaitForEndCast" )
endfunction
function RecicleCasterAfterCastEx takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing
call RecycleCasterAfterCastEx(caster,delaytime,abilid,activeability)
endfunction
function CasterWaitForEndCast_Light takes nothing returns nothing
local unit caster=udg_currentcaster
local integer abilid=udg_currentabi
local real delay=udg_castervars[0]
local boolean activeability=(udg_castervars[1]>0)
loop
exitwhen GetUnitCurrentOrder(caster) == 0
call TriggerSleepAction(0)
endloop
if (delay>0) then
if activeability then
call CasterRecycleTimed(caster,abilid,delay)
else
call UnitRemoveAbility( caster, abilid)
call CasterRecycleTimed(caster,0,delay)
endif
else
call UnitRemoveAbility( caster, abilid)
call RecycleCaster_Light(caster)
endif
set caster=null
endfunction
function RecycleCasterAfterCastEx_Light takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing
set udg_castervars[0]=delaytime
set udg_castervars[1]=IntegerTertiaryOp(activeability,1,0)
set udg_currentabi=abilid
set udg_currentcaster=caster
call ExecuteFunc("CasterWaitForEndCast_Light" )
endfunction
function RecicleCasterAfterCastEx_Light takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing
call RecycleCasterAfterCastEx_Light(caster,delaytime,abilid,activeability)
endfunction
function RecicleCasterAfterCast takes unit caster, integer abilid returns nothing
call RecycleCasterAfterCastEx(caster,udg_delayhack,abilid,false)
endfunction
function RecycleCasterAfterCast takes unit caster, integer abilid returns nothing
call RecycleCasterAfterCastEx(caster,udg_delayhack,abilid,false)
endfunction
//====================================================================================================================================================================
function PreloadAbility takes integer abilid returns integer
local unit u=FirstOfGroup(udg_casters)
if u==null then
set u=GetACaster()
call UnitAddAbility(u, abilid)
call UnitRemoveAbility(u, abilid)
call RecycleCaster_Light( u)
else
call UnitAddAbility(u, abilid)
call UnitRemoveAbility(u, abilid)
endif
set u=null
return abilid
endfunction
//====================================================================================================================================================================
function CasterCastAbilityEx takes player owner, real x, real y, real z, integer abilid, integer level, string order, widget target, real delay returns unit
local unit caster=GetACaster()
local boolean done=false
call SetUnitOwner( caster, owner, false)
call UnitAddAbility( caster, abilid)
call SetUnitAbilityLevel(caster,abilid,level)
call SetUnitX(caster,x)
call SetUnitY(caster,y)
call SetUnitFlyHeight(caster,z,0)
if S2I(order) != 0 then
set done=IssueTargetOrderById( caster, S2I(order), target )
else
set done=IssueTargetOrder( caster, order, target )
endif
if (delay<=0) or not(done) then
call UnitRemoveAbility( caster, abilid)
call RecycleCaster_Light( caster)
else
call RecycleCasterAfterCastEx_Light(caster, delay, abilid, true)
endif
set udg_currentcaster=caster
set caster=null
return udg_currentcaster
endfunction
//====================================================================================================================================================================
function CasterCastAbilityExLoc takes player owner, location loc, real z, integer abilid, integer level, string order, widget target, real delay returns unit
return CasterCastAbilityEx(owner,GetLocationX(loc),GetLocationY(loc),z,abilid,level,order,target,delay)
endfunction
//====================================================================================================================================================================
function CasterCastAbilityLevel takes player owner, integer abilid, integer level, string order, widget target, boolean instant returns unit
local real x
local real y
local real d
if udg_sourcehack!=null then
set x=GetLocationX(udg_sourcehack)
set y=GetLocationY(udg_sourcehack)
else
set x=GetWidgetX(target)
set y=GetWidgetY(target)
endif
if not(instant) then
set d=udg_delayhack+0.01
else
set d=0
endif
return CasterCastAbilityEx(owner,x,y,0,abilid,level,order,target,d)
endfunction
//====================================================================================================================================================================
function CasterCastAbility takes player owner, integer abilid, string order, widget target, boolean instant returns unit
return CasterCastAbilityLevel( owner, abilid, 1, order, target, instant )
endfunction
//====================================================================================================================================================================
function CasterCastAbilityPointEx takes player owner, real x1, real y1, real z1, integer abilid, integer level, string order, real x2, real y2, real delay returns unit
local unit caster=GetACaster()
call SetUnitOwner( caster, owner, false)
call UnitAddAbility( caster, abilid)
call SetUnitAbilityLevel(caster,abilid,level)
call SetUnitX(caster,x1)
call SetUnitY(caster,y1)
call SetUnitFlyHeight(caster,z1,0)
if S2I(order) != 0 then
if not IssuePointOrderById( caster, S2I(order), x2,y2 ) then
call IssueImmediateOrderById( caster, S2I(order) )
endif
else
if not IssuePointOrder( caster, order, x2,y2 ) then
call IssueImmediateOrder( caster, order )
endif
endif
if (delay<=0) then
call UnitRemoveAbility( caster, abilid)
call RecycleCaster_Light( caster)
else
call RecicleCasterAfterCastEx_Light(caster, delay, abilid, true)
endif
set udg_currentcaster=caster
set caster=null
return udg_currentcaster
endfunction
//====================================================================================================================================================================
function CasterCastAbilityPointExLoc takes player owner, location loc1, real z1, integer abilid, integer level, string order, location loc2, real delay returns unit
return CasterCastAbilityPointEx(owner,GetLocationX(loc1),GetLocationY(loc1),z1,abilid,level,order,GetLocationX(loc2),GetLocationY(loc2),delay)
endfunction
//====================================================================================================================================================================
function CasterCastAbilityLevelPoint takes player owner, integer abilid, integer level, string order, real x, real y, boolean instant returns unit
local real sx
local real sy
local real d
if udg_sourcehack!=null then
set sx=GetLocationX(udg_sourcehack)
set sy=GetLocationY(udg_sourcehack)
else
set sx=x
set sy=y
endif
if instant then
set d=0
else
set d=udg_delayhack+0.01
endif
return CasterCastAbilityPointEx(owner,sx,sy,0,abilid,level,order,x,y,d)
endfunction
function CasterCastAbilityPoint takes player owner, integer abilid, string order, real x, real y, boolean instant returns unit
return CasterCastAbilityLevelPoint(owner,abilid,1,order,x,y,instant)
endfunction
function CasterCastAbilityPointLoc takes player owner, integer abilid, string order, location loc, boolean instant returns unit
return CasterCastAbilityLevelPoint( owner, abilid, 1,order, GetLocationX(loc), GetLocationY(loc), instant )
endfunction
function CasterCastAbilityLevelPointLoc takes player owner, integer abilid, integer level, string order, location loc, boolean instant returns unit
return CasterCastAbilityLevelPoint( owner, abilid, level,order, GetLocationX(loc), GetLocationY(loc), instant )
endfunction
//====================================================================================================================================================================
private struct cssabi
effect fx
unit caster
integer abil
endstruct
function CasterUseAbilityLevelStatic_Rec takes nothing returns nothing
local timer t=GetExpiredTimer()
local cssabi k=GetCSData(t)
call RecycleCaster(k.caster)
call k.destroy()
call ReleaseTimer(t)
endfunction
function CasterUseAbilityLevelStatic_X takes nothing returns nothing
local timer t=GetExpiredTimer()
local cssabi k=GetCSData(t)
call DestroyEffect(k.fx)
call UnitRemoveAbility( k.caster, k.abil)
call TimerStart(t,2,false, function CasterUseAbilityLevelStatic_Rec)
endfunction
function CasterUseAbilityLevelStatic takes player owner, string modelpath, integer abilityid, integer level, real duration, real x, real y returns unit
local timer t=NewTimer()
local unit c=GetACaster()
local cssabi k= cssabi.create()
call SetUnitPosition( c, x, y)
set k.fx= AddSpecialEffectTarget( modelpath, c,"origin" )
set k.caster = c
set k.abil=abilityid
call SetUnitOwner(c, owner, true)
call UnitAddAbility(c, abilityid)
call SetUnitAbilityLevel(c, abilityid, level)
call SetCSData(t,k)
call TimerStart(t,duration,false,function CasterUseAbilityLevelStatic_X)
set udg_currentcaster=c
set c=null
return udg_currentcaster
endfunction
function CasterUseAbilityStatic takes player owner, string modelpath, integer abilityid, real duration, real x, real y returns unit
return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,1,duration,x,y)
endfunction
function CasterUseAbilityStaticLoc takes player owner, string modelpath, integer abilityid, real duration, location loc returns unit
return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,1,duration, GetLocationX(loc), GetLocationY(loc))
endfunction
function CasterUseAbilityLevelStaticLoc takes player owner, string modelpath, integer abilityid, integer level,real duration, location loc returns unit
return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,level,duration, GetLocationX(loc), GetLocationY(loc))
endfunction
//====================================================================================================================================================================
function CasterCastAbilityLevelGroup takes player owner, integer abilid, integer level,string order, group targetgroup, boolean instant returns nothing
local group affected
local unit tempunit
local unit caster=null
if bj_wantDestroyGroup then
set bj_wantDestroyGroup=false
set affected=targetgroup
else
set affected=NewGroup()
call GroupAddGroup( targetgroup, affected)
endif
loop
set tempunit=FirstOfGroup(affected)
exitwhen tempunit == null
if instant then
if caster==null then
set caster=GetACaster()
call SetUnitOwner( caster, owner, false)
call UnitAddAbility( caster, abilid)
call SetUnitAbilityLevel( caster, abilid,level)
endif
if udg_sourcehack != null then
call SetUnitX(caster,GetLocationX(udg_sourcehack))
call SetUnitY(caster,GetLocationY(udg_sourcehack))
else
call SetUnitX(caster,GetUnitX(tempunit))
call SetUnitY(caster,GetUnitY(tempunit))
endif
if S2I(order) != 0 then
call IssueTargetOrderById( caster, S2I(order), tempunit )
else
call IssueTargetOrder( caster, order, tempunit )
endif
else
call CasterCastAbilityLevel( owner, abilid,level, order, tempunit, false)
endif
call GroupRemoveUnit(affected, tempunit)
endloop
if caster != null then
call UnitRemoveAbility( caster, abilid)
call RecycleCaster(caster)
endif
call ReleaseGroup(affected)
set affected=null
set tempunit=null
set caster=null
endfunction
function CasterCastAbilityGroup takes player owner, integer abilid, string order, group targetgroup, boolean instant returns nothing
call CasterCastAbilityLevelGroup(owner,abilid,1,order,targetgroup,instant)
endfunction
//====================================================================================================================================================================
function CasterAOE_IsFilterEnemy takes nothing returns boolean
return IsUnitEnemy( GetFilterUnit(), bj_groupEnumOwningPlayer ) and ( GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction
function CasterAOE_IsFilterAlly takes nothing returns boolean
return IsUnitAlly( GetFilterUnit(), bj_groupEnumOwningPlayer ) and ( GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction
//====================================================================================================================================================================
function CasterCastAbilityLevelAOE takes player owner, integer abilid, integer level, string order, real x, real y, real radius, boolean goodeffect, boolean instant returns nothing
local boolexpr b
local group aoe=NewGroup()
set bj_groupEnumOwningPlayer=owner
if goodeffect then
set b=Condition(function CasterAOE_IsFilterAlly)
else
set b=Condition(function CasterAOE_IsFilterEnemy)
endif
call CS_EnumUnitsInAOE(aoe, x,y, radius, b)
set bj_wantDestroyGroup=true
call CasterCastAbilityLevelGroup( owner, abilid, level, order, aoe, instant)
call DestroyBoolExpr(b)
set b=null
set aoe=null
endfunction
function CasterCastAbilityAOE takes player owner, integer abilid, string order, real x, real y, real radius, boolean goodeffect, boolean instant returns nothing
call CasterCastAbilityLevelAOE(owner,abilid,1,order,x,y,radius,goodeffect,instant)
endfunction
function CasterCastAbilityAOELoc takes player owner, integer abilid, string order, location center, real radius, boolean goodeffect, boolean instant returns nothing
call CasterCastAbilityLevelAOE(owner, abilid,1, order, GetLocationX(center), GetLocationY(center), radius, goodeffect, instant)
endfunction
function CasterCastAbilityLevelAOELoc takes player owner, integer abilid, integer level, string order, location center, real radius, boolean goodeffect, boolean instant returns nothing
call CasterCastAbilityLevelAOE(owner, abilid,level, order, GetLocationX(center), GetLocationY(center), radius, goodeffect, instant)
endfunction
//====================================================================================================================================================================
globals
timer cs_sourcehacktimer = CreateTimer()
timer cs_delayhacktimer = CreateTimer()
endglobals
function ResetSourceHack takes nothing returns nothing
if (udg_sourcehack!=null) then
call RemoveLocation(udg_sourcehack)
set udg_sourcehack=null
endif
endfunction
function CasterSetCastSource takes real x, real y returns nothing
if (udg_sourcehack==null) then
set udg_sourcehack=Location(x,y)
else
call MoveLocation(udg_sourcehack,x,y)
endif
call TimerStart(cs_sourcehacktimer,0.,false,function ResetSourceHack)
endfunction
function CasterSetCastSourceLoc takes location loc returns nothing
call CasterSetCastSource( GetLocationX(loc), GetLocationY(loc) )
endfunction
function ResetDelayHack takes nothing returns nothing
set udg_delayhack=0.
endfunction
function CasterSetRecycleDelay takes real Delay returns nothing
set udg_delayhack=Delay
call TimerStart(cs_delayhacktimer,0.,false,function ResetDelayHack)
endfunction
//====================================================================================================================================================================
//Super DamageOptions structure!
globals
attacktype cs_dopt_Atype = null
damagetype cs_dopt_Dtype = null
unittype cs_dopt_ExceptionUtype = null
real cs_dopt_ExceptionFct = 1.0
unittype cs_dopt_OnlyUtype = null
unittype cs_dopt_IgnoreUtype = null
integer cs_dopt_EnemyAlly = 0 //[ 0 = onlyenemies, 1= forceall, 2=onlyallies]
integer cs_dopt_dfab1 = 'null'
real cs_dopt_dfab1_fc = 1.0
integer cs_dopt_dfab2 = 'null'
real cs_dopt_dfab2_fc = 1.
integer cs_dopt_dfab3 = 'null'
real cs_dopt_dfab3_fc = 1.
real cs_dopt_Ally_fc = 1.
endglobals
function DamageTypes takes attacktype attT, damagetype dmgT returns integer
// set udg_castervars[100] = CS_H2I(attT)
// set udg_castervars[101] = CS_H2I(dmgT)
set cs_dopt_Atype=attT
set cs_dopt_Dtype=dmgT
return 1
endfunction
function DamageException takes unittype Exception, real ExceptionFactor returns integer
set cs_dopt_ExceptionUtype=Exception
set cs_dopt_ExceptionFct = ExceptionFactor
// set udg_castervars[102] = CS_H2I(Exception)
// set udg_castervars[103] = ExceptionFactor
return 2
endfunction
function DamageOnlyTo takes unittype ThisUnitType returns integer
set cs_dopt_OnlyUtype = ThisUnitType
// set udg_castervars[104] = CS_H2I(ThisUnitType)
return 4
endfunction
constant function DontDamageSelf takes nothing returns integer
return 8
endfunction
constant function DamageTrees takes nothing returns integer
return 16
endfunction
constant function DamageOnlyVisibles takes nothing returns integer
return 32
endfunction
function DamageOnlyEnemies takes nothing returns integer
set cs_dopt_EnemyAlly=0
// ouch, forgot what it was
return 64
endfunction
function ForceDamageAllies takes nothing returns integer
set cs_dopt_EnemyAlly=1
return 64
endfunction
function DamageOnlyAllies takes nothing returns integer
set cs_dopt_EnemyAlly=2
return 64
endfunction
function DamageFactorAbility1 takes integer spellid, real factor returns integer
set cs_dopt_dfab1=spellid
set cs_dopt_dfab1_fc=factor
return 128
endfunction
function DamageFactorAbility2 takes integer spellid, real factor returns integer
set cs_dopt_dfab2=spellid
set cs_dopt_dfab2_fc=factor
return 256
endfunction
function DamageFactorAbility3 takes integer spellid, real factor returns integer
set cs_dopt_dfab3=spellid
set cs_dopt_dfab3_fc=factor
return 512
endfunction
function DamageIgnore takes unittype ThisUnitType returns integer
set cs_dopt_IgnoreUtype = ThisUnitType
// set udg_castervars[112] = CS_H2I(ThisUnitType)
return 1024
endfunction
function DamageAlliedFactor takes real fct returns integer
set cs_dopt_Ally_fc = fct
// set udg_castervars[113] = fct
return 2048
endfunction
constant function ConsiderOnlyDeadUnits takes nothing returns integer
return 4096
endfunction
constant function IgnoreDeadState takes nothing returns integer
return 8192
endfunction
//===============================================================================================
function IsDamageOptionIncluded takes integer DamageOptions, integer whichDamageOption returns boolean
local integer i=8192
if (DamageOptions==0) then
return false
endif
loop
exitwhen (i<=whichDamageOption)
if (DamageOptions>=i) then
set DamageOptions=DamageOptions-i
endif
set i=i/2
endloop
return (DamageOptions>=whichDamageOption)
endfunction
//=================================================================================================
globals
unit cs_dmg_caster=null
endglobals
function GetDamageFactor takes unit u,attacktype a, damagetype d returns real
local real hp=GetWidgetLife(u)
local real mana=GetUnitState(u,UNIT_STATE_MANA)
local real r
//Since a unit is in that point, we don't need checks.
call SetUnitX(cs_dmg_caster,GetUnitX(u))
call SetUnitY(cs_dmg_caster,GetUnitY(u))
call SetUnitOwner(cs_dmg_caster,GetOwningPlayer(u),false)
set r=hp
if (hp<1) then
call SetWidgetLife(u,1)
set r=1
endif
call UnitDamageTarget(cs_dmg_caster,u,0.01,true,false,a,d,null)
call SetUnitOwner(cs_dmg_caster,Player(15),false)
if (mana>GetUnitState(u,UNIT_STATE_MANA)) then
//Unit had mana shield, return 1 and restore mana too.
call SetUnitState(u,UNIT_STATE_MANA,mana)
set r=1
else
set r= (r-GetWidgetLife(u))*100
endif
call SetWidgetLife(u,hp)
return r
endfunction
//======================================================================================================
// Fix for the unit type bugs from blizzard, amphibious units aren't considered ground for some reason
// so this considers any non flying unit as ground.
//
// Also heroes are resistant too, so in case UNIT_TYPE_RESISTANT is used it will return true in case the
// unit is a hero too.
//
function CS_IsUnitType takes unit u, unittype ut returns boolean
if (ut==UNIT_TYPE_GROUND) then
return not(IsUnitType(u,UNIT_TYPE_FLYING))
elseif (ut==UNIT_TYPE_RESISTANT) then
return IsUnitType(u,ut) or IsUnitType(u,UNIT_TYPE_HERO)
endif
return IsUnitType(u,ut)
endfunction
function GetDamageFactorByOptions takes unit hurter, unit target, integer d returns real
local real r=1
if (d>=8192) then
set d=d-8192
elseif (d>=4096) then
if (GetWidgetLife(target)>0.405) then
return 0.0
endif
set d=d-4096
elseif (GetWidgetLife(target)<=0.405) then
return 0.0
endif
if d>=2048 then
if IsUnitAlly(target,GetOwningPlayer(hurter)) then
set r=r* cs_dopt_Ally_fc
endif
set d=d-2048
endif
if d>=1024 then
if CS_IsUnitType(target, cs_dopt_IgnoreUtype ) then
return 0.0
endif
set d=d-1024
endif
if d>=512 then
if GetUnitAbilityLevel(target, cs_dopt_dfab1 )>0 then
set r=r*cs_dopt_dfab1_fc
endif
set d=d-512
endif
if d>=256 then
if GetUnitAbilityLevel(target, cs_dopt_dfab2 )>0 then
set r=r*cs_dopt_dfab2_fc
endif
set d=d-256
endif
if d>=128 then
if GetUnitAbilityLevel(target, cs_dopt_dfab3 )>0 then
set r=r*cs_dopt_dfab3_fc
endif
set d=d-128
endif
if d>=64 then
if (cs_dopt_EnemyAlly==0) and IsUnitAlly(target,GetOwningPlayer(hurter)) then
return 0.0
elseif (cs_dopt_EnemyAlly==2) and IsUnitEnemy(target,GetOwningPlayer(hurter)) then
return 0.0
endif
set d=d-64
endif
if d>=32 then
set d=d-32
if not IsUnitVisible(target,GetOwningPlayer(hurter)) then
return 0.0
endif
endif
if d>=16 then
set d=d-16
endif
if d>=8 then
set d=d-8
if hurter==target then
return 0.0
endif
endif
if d>=4 then
set d=d-4
if not CS_IsUnitType( target,cs_dopt_OnlyUtype) then
return 0.0
endif
endif
if d>=2 then
set d=d-2
if CS_IsUnitType( target, cs_dopt_ExceptionUtype ) then
set r=r* cs_dopt_ExceptionFct
endif
endif
if d>=1 then
set d=d-1
set r=r*GetDamageFactor(target,cs_dopt_Atype,cs_dopt_Dtype)
endif
return r
endfunction
//======================================================================================================================
// This used to be needed because in 1.17 UnitDamageTarget didn't consider the damagetype argument, this bug
// was fixed in 1.18, and we no longer need this function, left for compatibility.
//
function DamageUnitByTypes takes unit hurter, unit target, real dmg, attacktype attT, damagetype dmgT returns boolean
return UnitDamageTarget(hurter,target,dmg,true,false,attT,dmgT,null)
endfunction
//=============================================================================================================================
function DamageUnitByOptions takes unit hurter, unit target, real dmg, integer DamageOptions returns boolean
local real f=GetDamageFactorByOptions(hurter,target,DamageOptions)
if (f==0) then
return false
endif
return UnitDamageTarget(hurter,target,dmg*f,true,false,null,null,null)
endfunction
//=============================================================================================================================
function DamageUnit takes player hurter, real damage, unit victim returns boolean
call SetUnitX(cs_dmg_caster,GetUnitX(victim))
call SetUnitY(cs_dmg_caster,GetUnitY(victim))
call SetUnitOwner(cs_dmg_caster,hurter,false)
call DamageUnitByTypes(cs_dmg_caster,victim,damage,cs_DefaultAttackType,cs_DefaultDamageType)
call SetUnitOwner(cs_dmg_caster,Player(15),false)
return GetWidgetLife(victim)<=0 // I thought UnitDamageTarget returned true when it killed the unit, but nope, it returns true when it was able to do the damage.
endfunction
//====================================================================================================================================================================
function UnitDamageUnitTimed_Child takes nothing returns nothing
local real damage = udg_castervars[0]
local real damageperiod= udg_castervars[2]
local effect fx=bj_lastCreatedEffect
local timer t=NewTimer()
local unit hurter=udg_currenthurter
local real next=0
local integer i=0
local real c
local unit target=udg_currentcaster
local damagetype dmgT=ConvertDamageType(R2I(udg_castervars[4]))
local attacktype attT=ConvertAttackType(R2I(udg_castervars[3]))
call TimerStart(t, udg_castervars[1]-0.01, false,null)
loop
if TimerGetElapsed(t) >= next then
exitwhen not UnitDamageTarget(hurter, target, damage,true,false, attT, dmgT,null)
exitwhen GetWidgetLife(target)<=0.405
set i=i+1
set next=i*damageperiod
endif
exitwhen (TimerGetRemaining(t) <= 0) or GetWidgetLife(target)<=0.405
call TriggerSleepAction(0)
endloop
call DestroyEffect(fx)
call ReleaseTimer(t)
set fx=null
set dmgT=null
set attT=null
endfunction
function UnitDamageUnitTimed takes unit hurter, real damageps, real damageperiod, real duration, unit target, string modelpath, string attachPointName, attacktype attT, damagetype dmgT returns nothing
local unit c=udg_currentcaster
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, target,attachPointName )
set udg_currentcaster=target
set udg_castervars[0]=damageps
set udg_castervars[1]=duration
set udg_castervars[2]=damageperiod
set udg_castervars[3]=CS_H2I(attT)
set udg_castervars[4]=CS_H2I(dmgT)
set udg_currenthurter=hurter
call ExecuteFunc("UnitDamageUnitTimed_Child")
set udg_currentcaster=c
set c=null
endfunction
//=============================================================================================================
// Left for compatibility
//
function DamageUnitTimedEx_Child takes nothing returns nothing
local real damage = udg_castervars[0]
local real damageperiod= udg_castervars[2]
local effect fx=bj_lastCreatedEffect
local timer t=NewTimer()
local integer id=udg_currentabi
local real next=0
local integer i=0
local real c
local unit target=udg_currentcaster
call TimerStart(t, udg_castervars[1]-0.01, false,null)
loop
if TimerGetElapsed(t) >= next then
exitwhen DamageUnit( Player(id), damage, target)
set i=i+1
set next=i*damageperiod
endif
exitwhen (TimerGetRemaining(t) <= 0) or GetWidgetLife(target)<=0.405
call TriggerSleepAction(0)
endloop
call DestroyEffect(fx)
call ReleaseTimer(t)
set fx=null
endfunction
function DamageUnitTimedEx takes player owner, real damageps, real damageperiod, real duration, unit target, string modelpath, string attachPointName returns nothing
local unit c=udg_currentcaster
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, target,attachPointName )
set udg_currentcaster=target
set udg_castervars[0]=damageps
set udg_castervars[1]=duration
set udg_castervars[2]=damageperiod
set udg_currentabi=GetPlayerId( owner )
call ExecuteFunc("DamageUnitTimedEx_Child")
set udg_currentcaster=c
set c=null
endfunction
function DamageUnitTimed takes player owner, real damageps, real duration, unit target, string modelpath, string attachPointName returns nothing
call DamageUnitTimedEx(owner , damageps, 1, duration, target, modelpath, attachPointName )
endfunction
//[
private struct dostruct
integer value
attacktype attt
damagetype dmgt
unittype excp
real excf
unittype only
integer allied
integer dfab1
real dfab1_fc
integer dfab2
real dfab2_fc
integer dfab3
real dfab3_fc
unittype ign
real ally_fc
endstruct
// integer k used to point to a table in gamecache, this is the reason I am not using dostruct directly
// the evil backwards compatibility... You shall find out why OOP guys like encapsullation so much...
//
// It's fun, it was first an integer pointing to a mission in gamecache, then it was a dynamic array
// and now it is a struct... so much history.
function SetDamageOptions_i takes integer k, integer DamageOptions returns nothing
local integer d=DamageOptions
set dostruct(k).value=d
if (d>=8192) then
set d=d-8192
endif
if (d>=4096) then
set d=d-4096
endif
if d>=2048 then
set dostruct(k).ally_fc=cs_dopt_Ally_fc
set d=d-2048
endif
if d>=1024 then
set dostruct(k).ign = cs_dopt_IgnoreUtype
set d=d-1024
endif
if d>=512 then
set dostruct(k).dfab3=cs_dopt_dfab3
set dostruct(k).dfab3_fc=cs_dopt_dfab3_fc
set d=d-512
endif
if d>=256 then
set dostruct(k).dfab2=cs_dopt_dfab2
set dostruct(k).dfab2_fc=cs_dopt_dfab2_fc
set d=d-256
endif
if d>=128 then
set dostruct(k).dfab1=cs_dopt_dfab1
set dostruct(k).dfab1_fc=cs_dopt_dfab1_fc
set d=d-128
endif
//[0 integer value][1 integer attT][2 integer dmgT][3 integer excp][4 real excf][5 integer only]
//[6 integer allied][7 integer ab1][8 real fc1][9 integer ab2][10 real fc2][11 integer ab3][12 real fc3]
//[13 integer ign][14 real allf]
if d >= 64 then
set d=d-64
set dostruct(k).allied=cs_dopt_EnemyAlly //[6=allied]
endif
if d >= 32 then
set d=d-32
endif
if d >= 16 then
set d=d-16
endif
if d >= 8 then
set d=d-8
endif
if d >= 4 then
set dostruct(k).only=cs_dopt_OnlyUtype
set d=d-4
endif
if d >= 2 then
set dostruct(k).excp= cs_dopt_ExceptionUtype
set dostruct(k).excf= cs_dopt_ExceptionFct
set d=d-2
endif
if d >= 1 then
set dostruct(k).attt=cs_dopt_Atype
set dostruct(k).dmgt=cs_dopt_Dtype
endif
endfunction
// inline friendly
function SetDamageOptions takes integer id, integer DamageOptions returns nothing
call SetDamageOptions_i(id,DamageOptions)
endfunction
function CreateDamageOptions takes integer DamageOptions returns integer
local integer n =integer(dostruct.create())
call SetDamageOptions_i(n,DamageOptions)
return n
endfunction
function DestroyDamageOptions takes integer id returns nothing
call dostruct(id).destroy()
endfunction
function LoadDamageOptions takes integer id returns integer
local integer opt=dostruct(id).value
local integer v=opt
if v>=8192 then
set v=v-8192
endif
if v>=4096 then
set v=v-4096
endif
if v>=2048 then
set cs_dopt_Ally_fc = dostruct(id).ally_fc
set v=v-2028
endif
if v>=1024 then
set cs_dopt_IgnoreUtype = dostruct(id).ign
set v=v-1024
endif
if v>=512 then
set cs_dopt_dfab3 =dostruct(id).dfab3
set cs_dopt_dfab3_fc=dostruct(id).dfab3_fc
set v=v-512
endif
if v>=256 then
set cs_dopt_dfab2 =dostruct(id).dfab2
set cs_dopt_dfab2_fc=dostruct(id).dfab2_fc
set v=v-256
endif
if v>=128 then
set cs_dopt_dfab1 =dostruct(id).dfab1
set cs_dopt_dfab1_fc=dostruct(id).dfab1_fc
set v=v-128
endif
if v >= 64 then
set v=v-64
set cs_dopt_EnemyAlly= dostruct(id).allied
endif
if v >= 32 then
set v=v-32
endif
if v >= 16 then
set v=v-16
endif
if v >= 8 then
set v=v-8
endif
if v >= 4 then
set cs_dopt_OnlyUtype = dostruct(id).only
set v=v-4
endif
if v >= 2 then
set cs_dopt_ExceptionUtype= dostruct(id).excp
set cs_dopt_ExceptionFct= dostruct(id).excf
set v=v-2
endif
if v >= 1 then
set cs_dopt_Atype= dostruct(id).attt
set cs_dopt_Dtype= dostruct(id).dmgt
endif
return opt
endfunction
//==================================================================================================
function IsDestructableTree_withcs takes destructable d returns boolean
local boolean b
local boolean i=IsDestructableInvulnerable(d)
call SetUnitX(cs_dmg_caster,GetWidgetX(d))
call SetUnitY(cs_dmg_caster,GetWidgetY(d))
if i then
call SetDestructableInvulnerable(d,false)
endif
call UnitAddAbility(cs_dmg_caster,cs_DamageTreeDetectorId)
set b=(IssueTargetOrder(cs_dmg_caster,"eattree",d))
call UnitRemoveAbility(cs_dmg_caster,cs_DamageTreeDetectorId)
if i then
call SetDestructableInvulnerable(d,true)
endif
return b
endfunction
function IsDestructableTree takes destructable d returns boolean
local string k=I2S(GetDestructableTypeId(d))
local boolean b
if HaveStoredBoolean(cs_cache,"trees",k) then
set b=GetStoredBoolean(cs_cache,"trees",k)
return b
else
set b=IsDestructableTree_withcs(d)
call StoreBoolean(cs_cache,"trees",k,b)
endif
return b
endfunction
//===============================================================================================
function DamageDestructablesInCircleEnum takes nothing returns nothing
local destructable d=GetEnumDestructable()
local unit u=udg_currentcaster
if (GetWidgetLife(d)>0) and not(IsDestructableInvulnerable(d)) and ((Pow(GetDestructableX(d)-udg_castervars[200],2)+Pow(GetDestructableY(d)-udg_castervars[201],2)) <= udg_castervars[202]) then
call SetWidgetLife(d,GetWidgetLife(d)-udg_castervars[203])
endif
set udg_currentcaster=u
set u=null
set d=null
endfunction
function DamageDestructablesInCircle takes real x, real y, real radius, real dmg returns nothing
local rect r=Rect(x - radius,y - radius,x + radius,y + radius)
set udg_castervars[200]=x
set udg_castervars[201]=y
set udg_castervars[202]=radius*radius
set udg_castervars[203]=dmg
call EnumDestructablesInRect(r,null,function DamageDestructablesInCircleEnum)
call RemoveRect(r)
set r=null
endfunction
function DamageDestructablesInCircleLoc takes location loc, real radius, real dmg returns nothing
call DamageDestructablesInCircle(GetLocationX(loc),GetLocationY(loc),radius,dmg)
endfunction
function DamageTreesInCircleEnum takes nothing returns nothing
local destructable d=GetEnumDestructable()
if (GetWidgetLife(d)>0) and not(IsDestructableInvulnerable(d)) and ((Pow(GetDestructableX(d)-udg_castervars[200],2)+Pow(GetDestructableY(d)-udg_castervars[201],2)) <= udg_castervars[202]) and (IsDestructableTree(d)) then
call KillDestructable(d)
endif
set d=null
endfunction
function DamageTreesInCircle takes real x, real y, real radius returns nothing
local rect r=Rect(x - radius,y - radius,x + radius,y + radius)
set udg_castervars[200]=x
set udg_castervars[201]=y
set udg_castervars[202]=radius*radius
call EnumDestructablesInRect(r,null,function DamageTreesInCircleEnum)
call RemoveRect(r)
set r=null
endfunction
function DamageTreesInCircleLoc takes location loc, real radius returns nothing
call DamageTreesInCircle(GetLocationX(loc),GetLocationY(loc),radius)
endfunction
function DamageUnitGroupEx takes unit hurter, real damage, group targetgroup, integer DamageOptions returns nothing
local group affected
local unit p
if bj_wantDestroyGroup then
set bj_wantDestroyGroup=false
set affected=targetgroup
else
set affected=NewGroup()
call GroupAddGroup( targetgroup, affected)
endif
loop
set p=FirstOfGroup(affected)
exitwhen p==null
call DamageUnitByOptions(hurter,p,damage,DamageOptions)
call GroupRemoveUnit(affected,p)
endloop
call ReleaseGroup(affected)
set affected=null
set p=null
endfunction
function DamageUnitsInAOEEx takes unit hurter, real damage, real x, real y, real radius, boolean affectallied, integer DamageOptions returns nothing
local boolexpr b=null
local group aoe=NewGroup()
local integer d=DamageOptions
set bj_groupEnumOwningPlayer=GetOwningPlayer(hurter)
if d>=8192 then
set d=d-8192
endif
if d>=4096 then
set d=d-4096
endif
if d>=2048 then
set d=d-2048
endif
if d>=1024 then
set d=d-1024
endif
if d>=512 then
set d=d-512
endif
if d>=256 then
set d=d-256
endif
if d>=128 then
set d=d-128
endif
if d>=64 then
if (cs_dopt_EnemyAlly==2) then
set b=Condition(function CasterAOE_IsFilterAlly)
elseif (cs_dopt_EnemyAlly==1) then
else
set b=Condition(function CasterAOE_IsFilterEnemy)
endif
set d=d-64
elseif not(affectallied) then
set b=Condition(function CasterAOE_IsFilterEnemy)
endif
if d>=32 then
set d=d-32
endif
if d>=16 then
call DamageTreesInCircle(x,y,radius)
endif
call CS_EnumUnitsInAOE(aoe, x,y, radius, b)
set bj_wantDestroyGroup=true
call DamageUnitGroupEx( hurter, damage, aoe,DamageOptions)
//call DestroyBoolExpr(b)
set b=null
set aoe=null
endfunction
function DamageUnitsInAOEExLoc takes unit hurter, real damage, location loc, real radius, boolean affectallied, integer DamageOptions returns nothing
call DamageUnitsInAOEEx(hurter,damage, GetLocationX(loc), GetLocationY(loc), radius, affectallied,DamageOptions)
endfunction
function DamageUnitGroup takes player hurter, real damage, group targetgroup returns nothing
call SetUnitOwner(cs_dmg_caster,hurter,false)
call DamageUnitGroupEx(cs_dmg_caster,damage,targetgroup,0)
call SetUnitOwner(cs_dmg_caster,Player(15),false)
endfunction
//====================================================================================================================================================================
function DamageUnitsInAOE takes player hurter, real damage, real x, real y, real radius, boolean affectallied returns nothing
call SetUnitOwner(cs_dmg_caster,hurter,false)
call DamageUnitsInAOEEx(cs_dmg_caster,damage,x,y,radius,affectallied,0)
call SetUnitOwner(cs_dmg_caster,Player(15),false)
endfunction
function DamageUnitsInAOELoc takes player hurter, real damage, location loc, real radius, boolean affectallied returns nothing
call DamageUnitsInAOE( hurter, damage, GetLocationX(loc), GetLocationY(loc), radius, affectallied)
endfunction
//====================================================================================================================================================================
function AddAreaDamagerForUnit_Child takes nothing returns nothing
local real D
local real damageps = udg_castervars[0]
local real area = udg_castervars[2]
local real damageperiod = udg_castervars[3]
local real excd=udg_castervars[8]
local boolean affectallies = (udg_castervars[4]>=1)
local boolean onlyallies = (udg_castervars[4]==2)
local boolean self = (udg_castervars[5]==1)
local unit hurter=udg_currenthurter
local unit fire = udg_currentcaster
local player owner = GetOwningPlayer(fire)
local timer t = NewTimer()
local real next = 0
local integer a = 0
local group inrange = NewGroup()
local string c
local string art=bj_lastPlayedMusic
local string attach=""
local unit picked
local boolean recicled=false
local unittype only=null
local unittype ign=null
local unittype exce=null
local attacktype attT
local damagetype dmgT
local boolean trees=(udg_castervars[11]==1)
local boolean inv=(udg_castervars[12]==1)
local integer a1=0
local integer a2=0
local integer a3=0
local real f1=cs_dopt_dfab1_fc
local real f2=cs_dopt_dfab2_fc
local real f3=cs_dopt_dfab3_fc
local real allf=udg_castervars[113]
local effect array fx
local integer deadcond=R2I(udg_castervars[114])
local boolean deadeval=false
local integer fxn=0
set fx[0]=bj_lastCreatedEffect
if f1!=1 then
set a1=cs_dopt_dfab1
endif
if f2!=1 then
set a2=cs_dopt_dfab2
endif
if f3!=1 then
set a3=cs_dopt_dfab3
endif
if udg_castervars[112]!=-1 then
set ign=ConvertUnitType(R2I(udg_castervars[112]))
endif
if udg_castervars[6]!=-1 then
set only=ConvertUnitType(R2I(udg_castervars[6]))
endif
if udg_castervars[7]!=-1 then
set exce=ConvertUnitType(R2I(udg_castervars[7]))
endif
if udg_castervars[9]!=-1 then
set attT=ConvertAttackType(R2I(udg_castervars[9]))
else
set attT=cs_DefaultAttackType
endif
if udg_castervars[10]!=-1 then
set dmgT=ConvertDamageType(R2I(udg_castervars[10]))
else
set dmgT=cs_DefaultDamageType
endif
loop
set c=SubString(art,a,a+1)
exitwhen c=="!" or c==""
set attach=attach+c
set a=a+1
endloop
set art=SubString(art,a+1,10000)
call TimerStart(t, udg_castervars[1]-0.01, false,null)
set a=0
loop
loop
exitwhen fxn<=0
call DestroyEffect(fx[fxn])
set fx[fxn]=null
set fxn=fxn-1
endloop
if IsUnitInGroup( fire, udg_casters) then
set recicled=true
call GroupRemoveUnit( udg_casters,fire)
endif
exitwhen recicled
if TimerGetElapsed(t) >= next then
set a=a+1
set next=a*damageperiod
call CS_EnumUnitsInAOE(inrange, GetUnitX(fire), GetUnitY(fire), area, null )
if trees then
call DamageTreesInCircle(GetUnitX(fire), GetUnitY(fire), area)
endif
loop
set picked=FirstOfGroup(inrange)
exitwhen picked==null
if (deadcond==0) then
set deadeval=(GetWidgetLife(picked)>0.405)
elseif(deadcond==1)then
set deadeval=(GetWidgetLife(picked)<=0.405)
else
set deadeval=true
endif
if (self or picked!=hurter) and not(GetWidgetLife(picked)<=0.405) and ( ((affectallies or onlyallies) and IsUnitAlly(picked, owner)) or (not(onlyallies) and IsUnitEnemy(picked, owner)) ) and (only==null or CS_IsUnitType(picked,only)) and (ign==null or not(CS_IsUnitType(picked,ign))) then
set D=damageps
if (allf!=1) and IsUnitAlly(picked, owner) then
set D=D*allf
endif
if (exce!=null) and CS_IsUnitType(picked,exce) then
set D=D*excd
endif
if inv and not(IsUnitVisible(picked,owner)) then
set D=0
endif
if (a1!=0) and (GetUnitAbilityLevel(picked,a1)>0) then
set D=D*f1
endif
if (a2!=0) and (GetUnitAbilityLevel(picked,a2)>0) then
set D=D*f2
endif
if (a3!=0) and (GetUnitAbilityLevel(picked,a3)>0) then
set D=D*f3
endif
if D!=0 then
call DamageUnitByTypes(hurter,picked,D,attT,dmgT )
if (art!="") and (art!=null) then
set fxn=fxn+1
set fx[fxn]=AddSpecialEffectTarget(art,picked,attach)
endif
endif
endif
call GroupRemoveUnit(inrange,picked)
endloop
endif
exitwhen TimerGetRemaining(t)<=0
call TriggerSleepAction(0)
endloop
call ReleaseGroup(inrange)
call DestroyEffect(fx[0])
call TriggerSleepAction(2)
call RecicleCaster(fire)
call ReleaseTimer(t)
set inrange=null
set fire=null
set owner=null
set fx[0]=null
set picked=null
set hurter=null
set only=null
set ign=null
set exce=null
set attT=null
set dmgT=null
endfunction
function AddAreaDamagerForUnit takes unit hurter, string modelpath, string targetart, string targetattach, real x, real y, real damage , real damageperiod, real duration, real area, boolean affectallies, integer DamageOptions returns unit
local string s=bj_lastPlayedMusic
local integer v=DamageOptions
set bj_lastPlayedMusic=targetattach+"!"+targetart
set udg_currentcaster=GetACaster()
call SetUnitPosition( udg_currentcaster, x, y)
set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" )
set udg_castervars[0]=damage
set udg_castervars[1]=duration
set udg_castervars[2]=area
set udg_castervars[3]=damageperiod
if(v>=8192)then
set udg_castervars[114]=2
set v=v-8192
elseif (v>=4096)then
set udg_castervars[114]=1
set v=v-4096
else
set udg_castervars[114]=0
endif
if v>=2048 then
set v=v-2048
else
set udg_castervars[113]=1
endif
if v >= 1024 then
set v=v-1024
else
set udg_castervars[112]=-1
endif
if v >= 512 then
set v=v-512
else
set udg_castervars[111]=0
endif
if v >= 256 then
set v=v-256
else
set udg_castervars[109]=0
endif
if v >= 128 then
set v=v-128
else
set udg_castervars[107]=0
endif
if v >= 64 then
set v=v-64
set udg_castervars[4]=cs_dopt_EnemyAlly
else
set udg_castervars[4]=IntegerTertiaryOp(affectallies,1,0)
endif
if v >= 32 then
set udg_castervars[12]=1
set v=v-32
else
set udg_castervars[12]=0
endif
if v >= 16 then
set udg_castervars[11]=1
set v=v-16
else
set udg_castervars[11]=0
endif
if v >= 8 then
set udg_castervars[5]=0
set v=v-8
else
set udg_castervars[5]=1
endif
if v >= 4 then
set udg_castervars[6]=CS_H2I(cs_dopt_OnlyUtype)
set v=v-4
else
set udg_castervars[6]=-1
endif
if v >= 2 then
set udg_castervars[7]=CS_H2I(cs_dopt_ExceptionUtype)
set udg_castervars[8]=damage*cs_dopt_ExceptionFct
set v=v-2
else
set udg_castervars[7]=-1
set udg_castervars[8]=-1
endif
if v >= 1 then
set udg_castervars[9]= CS_H2I(cs_dopt_Atype)
set udg_castervars[10]= CS_H2I(cs_dopt_Dtype)
else
set udg_castervars[9]=-1
set udg_castervars[10]=-1
endif
set udg_currenthurter=hurter
call SetUnitOwner( udg_currentcaster, GetOwningPlayer(hurter), true)
call ExecuteFunc("AddAreaDamagerForUnit_Child")
set bj_lastPlayedMusic=s
return udg_currentcaster
endfunction
function AddAreaDamagerForUnitLoc takes unit hurter, string modelpath, string targetart, string targetattach, location loc, real damage , real damageperiod, real duration, real area, boolean affectallies, integer DamageOptions returns unit
return AddAreaDamagerForUnit(hurter,modelpath,targetart,targetattach,GetLocationX(loc),GetLocationY(loc), damage , damageperiod, duration, area,affectallies, DamageOptions)
endfunction
function AddDamagingEffectEx takes player owner, string modelpath, string targetart, string targetattach, real x, real y, real damage , real damageperiod, real duration, real area, boolean affectallies returns unit
local string s=bj_lastPlayedMusic
set bj_lastPlayedMusic=targetattach+"!"+targetart
set udg_currentcaster=GetACaster()
call SetUnitPosition( udg_currentcaster, x, y)
set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" )
set udg_castervars[0]=damage
set udg_castervars[1]=duration
set udg_castervars[2]=area
set udg_castervars[3]=damageperiod
set udg_castervars[4]=IntegerTertiaryOp(affectallies,1,0)
set udg_castervars[5]=1
set udg_castervars[6]=-1
set udg_castervars[7]=-1
set udg_castervars[8]=-1
set udg_castervars[9]=-1
set udg_castervars[10]=-1
set udg_castervars[107]=0
set udg_castervars[109]=0
set udg_castervars[111]=0
set udg_castervars[112]=-1
set udg_castervars[113]=1
set udg_currenthurter=udg_currentcaster
call SetUnitOwner( udg_currentcaster, owner, true)
call ExecuteFunc("AddAreaDamagerForUnit_Child")
set bj_lastPlayedMusic=s
return udg_currentcaster
endfunction
function AddDamagingEffectExLoc takes player owner, string modelpath, string targetart, string targetattach, location loc, real damage , real damageperiod, real duration, real area, boolean affectallies returns unit
return AddDamagingEffectEx( owner, modelpath, targetart, targetattach, GetLocationX(loc), GetLocationY(loc), damage , damageperiod, duration, area, affectallies )
endfunction
function AddDamagingEffect takes player owner, string modelpath, real x, real y, real damageps , real duration, real area, boolean affectallies returns unit
return AddDamagingEffectEx( owner, modelpath, "", "", x, y, damageps , 1, duration, area, affectallies )
endfunction
function AddDamagingEffectLoc takes player owner, string modelpath, location loc, real damageps , real duration, real area, boolean affectallies returns unit
return AddDamagingEffectEx( owner, modelpath, "", "", GetLocationX(loc), GetLocationY(loc), damageps ,1, duration, area, affectallies)
endfunction
//============================================================================================================
function UnitMoveToAsProjectileAnySpeed_Move takes unit m, csprojectile k returns boolean
local boolean tounit = k.tounit
local unit tg
local real x2
local real y2
local real z2
local real x1=GetUnitX(m)
local real y1=GetUnitY(m)
local real z1=GetUnitFlyHeight(m)
local real g
local real d
local real od
local real v
local real time
local integer n
local boolean done=false
local effect fx
if tounit then
set tg=k.target
if (GetWidgetLife(tg)<=0.405) then
set tounit=false
set k.tounit=false
else
set x2=GetUnitX(tg)
set y2=GetUnitY(tg)
set z2=GetUnitFlyHeight(tg)+k.z2o
set n=k.N
if (n==0) then
//Using the counter prevents us to save z2,x2,y2 too much times and saves speed
set k.z2=z2
set k.x2=x2 // Backup stuff just in case
set k.y2=y2
elseif (n==25) then
set n=0
else
set n=n+1
endif
set k.N=n
endif
set tg=null
endif
if not(tounit) then
set z2=k.z2
set x2=k.x2
set y2=k.y2
endif
set g=Atan2(y2-y1,x2-x1)
call SetUnitFacing(m,g*bj_RADTODEG)
set v=k.speed
set d= v * cs_TIMER_CYCLE
set od=SquareRoot(Pow(x1-x2,2) + Pow(y1-y2,2))
if( od <=d )then
call SetUnitX(m,x2)
call SetUnitY(m,y2)
set done=true
else
call SetUnitX(m,x1+d*Cos(g))
call SetUnitY(m,y1+d*Sin(g))
endif
set g=k.acel
set time= od / v
set d=v
set v=(z2-z1+0.5*g*time*time)/time //z speed
if (GetUnitTypeId(m)==cs_CasterUnitId) then
call SetUnitAnimationByIndex(m,R2I(Atan2(v,d)* bj_RADTODEG)+90) //Thanks infrane!
endif
call SetUnitFlyHeight(m,z1+v*cs_TIMER_CYCLE,0)
set d=( Pow(GetUnitX(m)-x2,2) + Pow(GetUnitY(m)-y2,2) )
if (done or (d<=400)) then //So the actual distance is less than or equal to 20
set done=true
set k.done=true
set fx=k.fx
if (fx!=null) then
call SetUnitAnimationByIndex(m,91)
call DestroyEffect(fx)
set fx=null
endif
endif
return done
endfunction
interface csmissile
integer mtype=0
unit m //the missile
endinterface
globals
constant integer cs_TYPE_COLLISIONMISSILE=2
constant integer cs_TYPE_PROJECTILE=1
endglobals
struct cscollisionmissile extends csmissile
integer state //state of the collision missile
trigger t
triggeraction ac
real collision
real speed
real aspeed //angle speed
real f //facing of collisionmissile
real maxd
integer ttype=0 //target type
static constant integer ttype_widget=2
static constant integer ttype_point=1
static constant integer ttype_none=0
real tx //homing target x
real ty //homing target y
widget tw //homing target widget
boolean pfx=false //periodic fx mode
real pfx_current //current pfx (timer)
real pfx_dur //duration of a periodic effect
string pfx_path //path for the periodix fx
boolean new //Was it a new collision missile or must be recycled?
effect fx
integer tag=0 //custom tag for the user.
endstruct
function CollisionMissile_Destroyer takes unit m, cscollisionmissile k, trigger T returns nothing
local trigger tr = T
local triggeraction ta = k.ac
if (k.fx!=null) then
call DestroyEffect(k.fx)
endif
if (k.new) then
call ExplodeUnitBJ(m)
else
call RecicleCasterAfterCastEx(m,4,0,true)
endif
call TriggerRemoveAction(tr,ta)
//call TriggerRemoveAction(T,GetArrayTriggerAction(k,18)) //[18=triggeraction]
call k.destroy()
//call Hostage(CS_H2I(tr))
call DestroyTrigger(tr)
//call CleanAttachedVars(T)
//call DestroyTrigger(T)
set tr = null
set ta = null
endfunction
function GetTriggerCollisionMissile takes nothing returns unit
return s__csmissile_m[GetCSData(GetTriggeringTrigger()) ]
endfunction
function CollisionMissile_Move takes unit m, cscollisionmissile k returns boolean
local integer state= k.state
local boolean done
local real d
local real F
local real asp
local real x
local real nx
local real y
local real ny
local integer tt
local widget wd
local trigger TTT
if (state==2) then
set TTT=k.t
call TriggerExecute(TTT)
set TTT=null
set k.state=3
return false
elseif (state==3) then
call CollisionMissile_Destroyer(m,k,k.t)
return true
else
if (state==1) then
call TriggerRegisterUnitInRange(k.t,m,k.collision,null)
set k.state=0
endif
set d=k.speed * cs_TIMER_CYCLE
set F=k.f
set asp=k.aspeed
set x=GetUnitX(m)
set y=GetUnitY(m)
if (asp!=0) then
set tt=k.ttype
if (tt==cscollisionmissile.ttype_point) or (tt==cscollisionmissile.ttype_widget ) then
if (tt==cscollisionmissile.ttype_point) then
set nx=k.tx
set ny=k.ty
set F=Angles_MoveAngleTowardsAngle(F,Atan2(ny-y,nx-x)*bj_RADTODEG, asp * cs_TIMER_CYCLE)
else
set wd=k.tw
if (GetWidgetLife(wd)<=0.405) then
set k.ttype=cscollisionmissile.ttype_none
set nx=x+0.001
set ny=y+0.001
set F=F+ asp * cs_TIMER_CYCLE
else
set nx=GetWidgetX(wd)
set ny=GetWidgetY(wd)
set F=Angles_MoveAngleTowardsAngle(F,Atan2(ny-y,nx-x)*bj_RADTODEG, asp * cs_TIMER_CYCLE)
endif
set wd=null
endif
else
set F=F+ asp * cs_TIMER_CYCLE
endif
set k.f=F
call SetUnitFacing(m,F)
endif
set F=F*bj_DEGTORAD
set nx=x+d*Cos(F)
set ny=y+d*Sin(F)
set d=k.maxd-d
set k.maxd=d
set done=(d<=0)
if (not done) then
if not(CS_MoveUnit(m,nx,ny)) then
set done=true
elseif (k.pfx) then
set F= k.pfx_current+cs_TIMER_CYCLE
if (F>=k.pfx_dur) then
call DestroyEffect(AddSpecialEffectTarget(k.pfx_path, m, "origin" ))
set k.pfx_current=0.
else
set k.pfx_current=F
endif
endif
endif
endif
if done then
call DisableTrigger(k.t)
call DestroyEffect(k.fx)
set k.fx=null
set k.state=2
return false
endif
return false
endfunction
function CasterSystemMovementTimer takes nothing returns nothing
local timer ti
local integer n=cs_missilecount
local integer i=1
local unit p
local csmissile k
loop
exitwhen (i>n)
set k=cs_missiles
if (k.mtype==cs_TYPE_COLLISIONMISSILE) then
set p=k.m
if not(CollisionMissile_Move(p,k)) then
set i=i+1
else
set cs_missiles=cs_missiles[n]
set n=n-1
endif
elseif (k.mtype==cs_TYPE_PROJECTILE) then
set p=k.m
if not(UnitMoveToAsProjectileAnySpeed_Move(p,k )) then
set i=i+1
else
set cs_missiles=cs_missiles[n]
set n=n-1
endif
else
set i=i+1
call BJDebugMsg("Caster System: Unexpected Error (1) Wrong Array:"+I2S(k)+" ; "+I2S(k.mtype))
endif
endloop
if (n==0) then
call PauseTimer(cs_movementtimer)
set cs_movementtimer_active=false
endif
set cs_missilecount=n
set p=null
endfunction
struct csprojectile extends csmissile
boolean tounit //Is it directed towards a unit?
unit target //if so, what target?
real z2
real x2
real y2
real speed
real acel
boolean done=false
effect fx
real z2o // offset for z2, useful for flyers
integer N=0
endstruct
function UnitMoveToAsProjectileAnySpeed_Effect takes unit m, effect fx, real speed, real arc, real x2, real y2, unit target, real z2 returns nothing
//
// The internal projectile system used by all the projectile functions
//
local timer t //=GetTableTimer("CasterSystem","MOVEMENT_TIMER")
local string km
local csprojectile k
set km=I2S(CS_H2I(m))
set k=GetTableInt("MOVEMENT_TABLES",km)
if (k>0) then
set k.done=true
endif
set k=csprojectile.create()
set k.m=m
call StoreInteger(cs_cache,"MOVEMENT_TABLES",km,k)
set cs_missilecount=cs_missilecount+1
set cs_missiles[cs_missilecount]=k
if (not cs_movementtimer_active) then
call TimerStart(cs_movementtimer,cs_TIMER_CYCLE,true,function CasterSystemMovementTimer)
set cs_movementtimer_active=true
endif
set k.mtype=cs_TYPE_PROJECTILE
if (target!=null) then
set k.tounit=true
set k.target=target
set k.x2=GetUnitX(target)
set k.y2=GetUnitY(target)
set k.z2o=z2
else
set k.tounit=false
set k.x2=x2
set k.y2=y2
endif
set k.z2=z2
set k.speed=speed
set k.acel=arc*8000
if (fx!=null) then
set k.fx=fx
set fx=null
endif
loop
exitwhen k.done
call TriggerSleepAction(0)
endloop
call FlushStoredInteger(cs_cache,"MOVEMENT_TABLES",km)
call k.destroy()
endfunction
function UnitMoveToAsProjectileAnySpeed takes unit m, real speed, real arc, real x2, real y2, unit target, real z2 returns nothing
//Left for compat
call UnitMoveToAsProjectileAnySpeed_Effect(m,null,speed,arc,x2,y2,target,z2)
endfunction
//========================================================================================================================
function UnitMoveToAsProjectileGen takes unit m, real arc, real x2, real y2, unit target, real z2 returns nothing
//
// The internal projectile system used by all the projectile functions
//
local real x1=GetUnitX(m)
local real y1=GetUnitY(m)
local real acel=arc*1600
local real speed=GetUnitMoveSpeed(m)
local real z1=GetUnitFlyHeight(m)
local real d
local real d1
local real d2
local real t
local real vel
local real dif=0
local boolean tounit= (target!=null)
local boolean b=false
local boolean mode=false
if tounit then
set x2=GetUnitX(target)
set y2=GetUnitY(target)
set z2=GetUnitFlyHeight(target)+z2
endif
set mode=(z2>z1)
set d=SquareRoot(Pow(x2-x1,2)+Pow(y2-y1,2))
set d1=1000000
set d2=0
set t=d/speed
if t==0 then
set t=0.001
endif
set vel=(z2-z1+0.5*acel*t*t)/t
call SetUnitFacing( m, Atan2BJ(y2 - y1, x2 - x2) )
call IssuePointOrder( m, "move", x2,y2)
set t=0
loop
set d2=d1
if tounit then
if (GetWidgetLife(target)<=0.405) then
set tounit=false
else
set x2=GetUnitX(target)
set y2=GetUnitY(target)
endif
endif
set d1=SquareRoot(Pow(x2-GetUnitX(m),2)+Pow(y2-GetUnitY(m),2))
exitwhen b or d1==0
set b=(d1<=speed*(t-dif))
exitwhen (mode and b) or (GetUnitCurrentOrder(m) != OrderId("move"))
if tounit then
call IssuePointOrder( m, "move", x2,y2)
endif
set dif=t
if dif==0.001 then
set t=0.1
else
set t= (d-d1)/speed
endif
set t= 2*t-dif
call SetUnitFlyHeight( m, z1+(vel*t-0.5*acel*t*t), RAbsBJ( vel-acel*(t+dif)/2) )
set t=(t+dif)/2
call TriggerSleepAction(0)
endloop
if tounit then
set x2=GetUnitX(target)
set y2=GetUnitY(target)
endif
call SetUnitFlyHeight( m,z2,0)
call SetUnitX(m,x2)
call SetUnitY(m,y2)
endfunction
function UnitMoveToAsProjectile takes unit m, real arc, real x2, real y2, real z2 returns nothing
call UnitMoveToAsProjectileGen(m, arc,x2,y2,null,z2)
endfunction
//============================================================================================================
function ProjectileLaunchEx takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc,real x1, real y1, real z1, real x2, real y2, real z2 returns nothing
local unit m=CreateCaster( Atan2BJ(y2 - y1, x2 - x1),x1,y1 )
local effect fx=null
call SetUnitScale( m, scale, scale, scale)
call SetUnitVertexColor(m, red, green, blue, alpha)
call SetUnitFlyHeight( m, z1, 0)
set fx= AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, owner, true)
if (speed<=522) then
call SetUnitMoveSpeed(m, speed)
call UnitMoveToAsProjectile(m, arc, x2, y2, z2)
call DestroyEffect(fx)
else
call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed,arc,x2,y2,null,z2)
endif
call ExplodeUnitBJ(m)
set owner=null
set fx=null
set m=null
endfunction
function ProjectileLaunchExLoc takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, location loc1, real z1, location loc2, real z2 returns nothing
call ProjectileLaunchEx( owner, modelpath, scale, red, green, blue, alpha, speed, arc,GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2)
endfunction
[/code]