//##Start##
//====================================================================================================================================================================
constant function Caster_UnitId takes nothing returns integer
return 'e00M' //// Caster Unit type rawcode (changes betwen maps, always use it inside '')
endfunction
constant function Caster_DefaultAttackType takes nothing returns attacktype
return ATTACK_TYPE_CHAOS // Default attack type used by the old functions and when you use 0 as DamageOptions
endfunction
constant function Caster_DefaultDamageType takes nothing returns damagetype
return DAMAGE_TYPE_UNIVERSAL // Default damage type used by the old functions and when you use 0 as DamageOptions
endfunction
constant function DamageTreeDetectorId takes nothing returns integer
return 'Aeat' /// 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.
endfunction
constant function ChangeableFlyingHeightAllowerId takes nothing returns integer
return 'Amrf' /// 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.
endfunction
constant function CS_Cycle takes nothing returns real
return 0.04 // Cycle value for the projectile movement in seconds (Each 0.04 the projectiles get moved)
// 0.01 looks smooth but is lag friendly
//0.1 looks horrible but is not laggy
// 0.04 is decent for the human eye and quite efficient.
// 0.05 would be an improvement in efficiency but probably doesn't look too well
endfunction
//=================================================================================================
function CS_H2I takes handle h returns integer
return h
return 0
endfunction
//=================================================================================================
function CSCache takes nothing returns gamecache
if udg_cscache==null then
set udg_castervars[500]=0
call FlushGameCache(InitGameCache("CasterSystem.vx"))
set udg_cscache=InitGameCache("CasterSystem.vx")
endif
return udg_cscache
endfunction
function CS_Rawcode2Real takes integer i returns real
return i
return 0.
endfunction
function CS_LoadRawcodeFromReal takes integer n returns integer
return udg_castervars[n]
return 0
endfunction
//==================================================================================================
function AttachInt takes handle h, string label, integer x returns nothing
local string k=I2S(CS_H2I(h))
if x==0 then
call FlushStoredInteger(CSCache(),k,label)
else
call StoreInteger(CSCache(),k,label,x)
endif
endfunction
function AttachReal takes handle h, string label, real x returns nothing
local string k=I2S(CS_H2I(h))
if x==0 then
call FlushStoredReal(CSCache(),k,label)
else
call StoreReal(CSCache(),k,label,x)
endif
endfunction
function AttachBoolean takes handle h, string label, boolean x returns nothing
local string k=I2S(CS_H2I(h))
if not x then
call FlushStoredBoolean(CSCache(),k,label)
else
call StoreBoolean(CSCache(),k,label,x)
endif
endfunction
function AttachString takes handle h, string label, string x returns nothing
local string k=I2S(CS_H2I(h))
if x=="" then
call FlushStoredString(CSCache(),k,label)
else
call StoreString(CSCache(),k,label,x)
endif
endfunction
function AttachObject takes handle h, string label, handle x returns nothing
call AttachInt( h, label, CS_H2I(x) )
endfunction
//==================================================================================================
function GetAttachedInt takes handle h, string label returns integer
local real r=udg_castervars[500]
local integer i
local integer L
local string c
local string num
if (r>0) then
if SubString(label,0,1)=="#" then
set udg_castervars[500]=r-1
set i=0
set num=""
loop
set i=i+1
set c=SubString(label,i,i+1)
exitwhen (c==";") or (c=="")
set num=num+c
endloop
if c==";" then
return GetStoredInteger(CSCache(),I2S(CS_H2I(h))+";"+SubString(label,i+1,StringLength(label)+1),num)
endif
endif
endif
return GetStoredInteger(CSCache(), I2S(CS_H2I(h)), label)
endfunction
function GetAttachedReal takes handle h, string label returns real
return GetStoredReal(CSCache(),I2S(CS_H2I(h)),label)
endfunction
function GetAttachedString takes handle h, string label returns string
return GetStoredString(CSCache(),I2S(CS_H2I(h)),label)
endfunction
function GetAttachedBoolean takes handle h, string label returns boolean
return GetStoredBoolean(CSCache(),I2S(CS_H2I(h)),label)
endfunction
function GetAttachedObject takes handle h, string label returns handle
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedUnit takes handle h, string label returns unit
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedItem takes handle h, string label returns item
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedEffect takes handle h, string label returns effect
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedDestructable takes handle h, string label returns destructable
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedTrigger takes handle h, string label returns trigger
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedTimer takes handle h, string label returns timer
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedGroup takes handle h, string label returns group
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedTriggerAction takes handle h, string label returns triggeraction
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedLightning takes handle h, string label returns lightning
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedImage takes handle h, string label returns image
return GetAttachedInt(h,label)
return null
endfunction
function GetAttachedUbersplat takes handle h, string label returns ubersplat
return GetAttachedInt(h,label)
return null
endfunction
//============================================================================================================
// Attached Sets:
//
function FromSetElement takes string setn, integer index returns string
set udg_castervars[500]=udg_castervars[500]+1
return "#"+I2S(index)+";"+setn
endfunction
//============================================================================================================
function AttachedSetAddInt takes handle h, string setn, integer int returns nothing
local gamecache g=CSCache()
local string k=I2S(CS_H2I(h))
local integer n
local integer x=GetStoredInteger(g,k,"#setnumberof;"+setn)
local integer y
if x==0 then
set y=GetStoredInteger(g,k,"#totalsets")+1
call StoreInteger(g,k,"#totalsets",y)
call StoreInteger(g,k,"#setnumberof;"+setn,y)
call StoreString(g,k,"#setName;"+I2S(y),setn)
endif
set k=k+";"+setn
if not HaveStoredInteger(g,k,"Pos"+I2S(int)) then
set n=GetStoredInteger(g,k,"n")+1
call StoreInteger(g,k,"n",n)
call StoreInteger(g,k,I2S(n),int)
call StoreInteger(g,k,"Pos"+I2S(int),n)
endif
set g=null
endfunction
function AttachedSetAddObject takes handle h, string setn, handle val returns nothing
call AttachedSetAddInt(h,setn,CS_H2I(val))
endfunction
//============================================================================================================
function AttachedSetHasInt takes handle h, string setn, integer int returns boolean
return HaveStoredInteger(CSCache(),I2S(CS_H2I(h))+";"+setn,"Pos"+I2S(int))
endfunction
//============================================================================================================
function AttachedSetHasObject takes handle h, string setn, handle val returns boolean
return AttachedSetHasInt(h,setn,CS_H2I(val))
endfunction
//============================================================================================================
function GetAttachedSetSize takes handle h, string setn returns integer
return GetStoredInteger(CSCache(),I2S(CS_H2I(h))+";"+setn,"n")
endfunction
//============================================================================================================
function AttachedSetRemInt takes handle h, string setn, integer int returns nothing
local gamecache g=CSCache()
local string k=I2S(CS_H2I(h))+";"+setn
local integer n
local integer x
local integer y
if HaveStoredInteger(g,k,"Pos"+I2S(int)) then
set x=GetStoredInteger(g,k,"Pos"+I2S(int))
set n=GetStoredInteger(g,k,"n")
if x!=n then
set y=GetStoredInteger(g,k,I2S(n))
call StoreInteger(g,k,I2S(x),y)
call StoreInteger(g,k,"Pos"+I2S(y),x)
endif
call FlushStoredInteger(g,k,"Pos"+I2S(int))
call FlushStoredInteger(g,k,I2S(n))
call StoreInteger(g,k,"n",n-1)
endif
set g=null
endfunction
function AttachedSetRemObject takes handle h, string setn, handle val returns nothing
call AttachedSetRemInt(h,setn,CS_H2I(val))
endfunction
//============================================================================================================
function ClearAttachedSet takes handle h, string setn returns nothing
call FlushStoredMission(CSCache(),I2S(CS_H2I(h))+";"+setn)
endfunction
//==================================================================================================
function CleanAttachedVars takes handle h returns nothing
local gamecache g=CSCache()
local string k=I2S(CS_H2I(h))
local integer n=GetStoredInteger(g,k,"#totalsets")
local integer i=1
loop
exitwhen i>n
call FlushStoredMission(g,k+";"+GetStoredString(g,k,"#setName;"+I2S(i)))
set i=i+1
endloop
call FlushStoredMission(g, k )
set g=null
endfunction
//====================================================================================================================================================================
// Left For compatibility
//
function SpellEffectModelPath takes integer abilityid, effecttype t returns string
return GetAbilityEffectById(abilityid,t, 0)
endfunction
//====================================================================================================================================================================
function AddCasterFacing takes real fac returns unit
local unit m=CreateUnit( Player(15), Caster_UnitId(), 0 ,0 ,fac)
call UnitAddAbility(m, 'Aloc')
call UnitAddAbility(m, ChangeableFlyingHeightAllowerId())
call UnitRemoveAbility(m, ChangeableFlyingHeightAllowerId())
set udg_currentcaster=m
set m=null
return udg_currentcaster
endfunction
function AddCaster takes nothing returns unit
return AddCasterFacing(0)
endfunction
//====================================================================================================================================================================
function CreateCasters takes integer n returns nothing
local integer a=0
local unit c
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
loop
exitwhen a>=n
set c=AddCaster()
call GroupAddUnit( udg_casters, c)
set a=a+1
endloop
set c=null
call RemoveLocation(udg_sourcehack)
set udg_sourcehack=null
endfunction
//====================================================================================================================================================================
function GetACaster takes nothing returns unit
set udg_currentcaster=FirstOfGroup( udg_casters)
if udg_currentcaster == null then
set udg_currentcaster=AddCaster()
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 RecicleCaster takes unit caster returns nothing
if not IsUnitDeadBJ(caster) 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 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 activeability then
call PolledWait(delay)
call UnitRemoveAbility( caster, abilid)
else
call UnitRemoveAbility( caster, abilid)
call PolledWait(delay)
endif
call RecicleCaster( caster)
set caster=null
endfunction
function RecicleCasterAfterCastEx 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 RecicleCasterAfterCast takes unit caster, integer abilid returns nothing
call RecicleCasterAfterCastEx(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 RecicleCaster( 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 SetUnitPosition( caster, x,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 RecicleCaster( caster)
else
call RecicleCasterAfterCastEx(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 SetUnitPosition( caster, x1, 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 RecicleCaster( caster)
else
call RecicleCasterAfterCastEx(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
//====================================================================================================================================================================
function CasterUseAbilityStatic_Child takes nothing returns nothing
local unit caster=udg_currentcaster
local effect fx=bj_lastCreatedEffect
local integer abilid=udg_currentabi
call PolledWait( udg_castervars[1])
call DestroyEffect(fx)
call UnitRemoveAbility(caster,abilid)
call TriggerSleepAction(2)
call RecicleCaster(caster)
set fx=null
set caster=null
endfunction
function CasterUseAbilityLevelStatic takes player owner, string modelpath, integer abilityid, integer level, real duration, real x, real y returns unit
set udg_currentcaster=GetACaster()
call SetUnitPosition( udg_currentcaster, x, y)
set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" )
set udg_castervars[1]=duration
call SetUnitOwner( udg_currentcaster, owner, true)
call UnitAddAbility( udg_currentcaster, abilityid)
call SetUnitAbilityLevel( udg_currentcaster, abilityid, level)
set udg_currentabi=abilityid
call ExecuteFunc("CasterUseAbilityStatic_Child")
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=CreateGroup()
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 SetUnitPositionLoc( caster, udg_sourcehack)
else
call SetUnitPosition( caster, GetUnitX(tempunit), 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 RecicleCaster(caster)
endif
call DestroyGroup(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 not(IsUnitDeadBJ(GetFilterUnit()))
endfunction
function CasterAOE_IsFilterAlly takes nothing returns boolean
return IsUnitAlly( GetFilterUnit(), bj_groupEnumOwningPlayer ) and not(IsUnitDeadBJ(GetFilterUnit()))
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=CreateGroup()
set bj_groupEnumOwningPlayer=owner
if goodeffect then
set b=Condition(function CasterAOE_IsFilterAlly)
else
set b=Condition(function CasterAOE_IsFilterEnemy)
endif
call GroupEnumUnitsInRange(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
//====================================================================================================================================================================
function ResetSourceHack takes nothing returns nothing
call RemoveLocation(udg_sourcehack)
set udg_sourcehack=null
call DestroyTimer(GetExpiredTimer() )
endfunction
function CasterSetCastSource takes real x, real y returns nothing
set udg_sourcehack=Location(x,y)
call TimerStart(CreateTimer(),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
call DestroyTimer(GetExpiredTimer() )
endfunction
//====================================================================================================================================================================
function CasterSetRecycleDelay takes real Delay returns nothing
set udg_delayhack=Delay
call TimerStart(CreateTimer(),0,false,function ResetDelayHack)
endfunction
//====================================================================================================================================================================
function DamageTypes takes attacktype attT, damagetype dmgT returns integer
set udg_castervars[100] = CS_H2I(attT)
set udg_castervars[101] = CS_H2I(dmgT)
return 1
endfunction
function DamageException takes unittype Exception, real ExceptionFactor returns integer
set udg_castervars[102] = CS_H2I(Exception)
set udg_castervars[103] = ExceptionFactor
return 2
endfunction
function DamageOnlyTo takes unittype ThisUnitType returns integer
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 udg_castervars[105]=0
return 64
endfunction
function ForceDamageAllies takes nothing returns integer
set udg_castervars[105]=1
return 64
endfunction
function DamageOnlyAllies takes nothing returns integer
set udg_castervars[105]=2
return 64
endfunction
function DamageFactorAbility1 takes integer spellid, real factor returns integer
set udg_castervars[106]=CS_Rawcode2Real(spellid)
set udg_castervars[107]=factor
return 128
endfunction
function DamageFactorAbility2 takes integer spellid, real factor returns integer
set udg_castervars[108]=CS_Rawcode2Real(spellid)
set udg_castervars[109]=factor
return 256
endfunction
function DamageFactorAbility3 takes integer spellid, real factor returns integer
set udg_castervars[110]=CS_Rawcode2Real(spellid)
set udg_castervars[111]=factor
return 512
endfunction
function DamageIgnore takes unittype ThisUnitType returns integer
set udg_castervars[112] = CS_H2I(ThisUnitType)
return 1024
endfunction
function DamageAlliedFactor takes real fct returns integer
set udg_castervars[113] = fct
return 2048
endfunction
//===============================================================================================
function CS_IsUnitVisible takes unit u, player p returns boolean
return IsUnitVisible(u,Player(bj_PLAYER_NEUTRAL_VICTIM)) or IsUnitVisible(u,p)
endfunction
//=================================================================================================
function GetDamageFactor takes unit u,attacktype a, damagetype d returns real
local real hp=GetWidgetLife(u)
local real r
local unit caster=GetACaster()
call UnitRemoveAbility(caster,'Aloc') //Otherwise the units would flee like crazy
call SetUnitPosition(caster,GetUnitX(u),GetUnitY(u))
call SetUnitOwner(caster,GetOwningPlayer(u),false)
call UnitDamageTarget(caster,u,0.01,true,false,a,d,null)
call RecicleCaster(caster)
set r= (hp-GetWidgetLife(u))*100
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 DamageOptions returns real
local real r=1
local integer d=DamageOptions
if (GetWidgetLife(target)<1) then
return 0.0
endif
if d>=2048 then
if IsUnitAlly(target,GetOwningPlayer(hurter)) then
set r=r*udg_castervars[113]
endif
set d=d-2048
endif
if d>=1024 then
if CS_IsUnitType(target, ConvertUnitType(R2I(udg_castervars[112])) ) then
return 0.0
endif
set d=d-1024
endif
if d>=512 then
if GetUnitAbilityLevel(target,CS_LoadRawcodeFromReal(110))>0 then
set r=r*udg_castervars[111]
endif
set d=d-512
endif
if d>=256 then
if GetUnitAbilityLevel(target,CS_LoadRawcodeFromReal(108))>0 then
set r=r*udg_castervars[109]
endif
set d=d-256
endif
if d>=128 then
if GetUnitAbilityLevel(target,CS_LoadRawcodeFromReal(106))>0 then
set r=r*udg_castervars[107]
endif
set d=d-128
endif
if d>=64 then
if (udg_castervars[105]==0) and IsUnitAlly(target,GetOwningPlayer(hurter)) then
return 0.0
elseif (udg_castervars[105]==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 CS_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, ConvertUnitType(R2I(udg_castervars[104])) ) then
return 0.0
endif
endif
if d>=2 then
set d=d-2
if CS_IsUnitType( target, ConvertUnitType(R2I(udg_castervars[102])) ) then
set r=r*udg_castervars[103]
endif
endif
if d>=1 then
set d=d-1
set r=r*GetDamageFactor(target,ConvertAttackType(R2I(udg_castervars[100])),ConvertDamageType(R2I(udg_castervars[101])))
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
local unit caster=GetACaster()
call UnitRemoveAbility(caster,'Aloc') //Otherwise the units would flee like crazy
call SetUnitPosition(caster,GetUnitX(victim),GetUnitY(victim))
call SetUnitOwner(caster,hurter,false)
call DamageUnitByTypes(caster,victim,damage,Caster_DefaultAttackType(),Caster_DefaultDamageType())
call RecicleCaster(caster)
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=CreateTimer()
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 IsUnitDeadBJ(target)
set i=i+1
set next=i*damageperiod
endif
exitwhen (TimerGetRemaining(t) <= 0) or IsUnitDeadBJ(target)
call TriggerSleepAction(0)
endloop
call DestroyEffect(fx)
call DestroyTimer(t)
set t=null
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=CreateTimer()
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 IsUnitDeadBJ(target)
call TriggerSleepAction(0)
endloop
call DestroyEffect(fx)
call DestroyTimer(t)
set t=null
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
function SetDamageOptions_i takes gamecache g, integer n, integer DamageOptions returns nothing
local string key="DOPT"+I2S(n)
local integer d=DamageOptions
call StoreInteger(g,key,"value",d)
if d>=2048 then
call StoreReal(g,key,"allf",udg_castervars[113])
set d=d-2048
endif
if d>=1024 then
call StoreInteger(g,key,"ign",R2I(udg_castervars[112]))
set d=d-1024
endif
if d>=512 then
call StoreInteger(g,key,"ab3",CS_LoadRawcodeFromReal(110))
call StoreReal(g,key,"fc3",udg_castervars[111])
set d=d-512
endif
if d>=256 then
call StoreInteger(g,key,"ab2",CS_LoadRawcodeFromReal(108))
call StoreReal(g,key,"fc2",udg_castervars[109])
set d=d-256
endif
if d>=128 then
call StoreInteger(g,key,"ab1",CS_LoadRawcodeFromReal(106))
call StoreReal(g,key,"fc1",udg_castervars[107])
set d=d-128
endif
if d >= 64 then
set d=d-64
call StoreInteger(g,key,"allied",R2I(udg_castervars[105]))
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
call StoreInteger(g,key,"only",R2I(udg_castervars[104]))
set d=d-4
endif
if d >= 2 then
call StoreInteger(g,key,"excp",R2I(udg_castervars[102]))
call StoreReal(g,key,"excf",udg_castervars[103])
set d=d-2
endif
if d >= 1 then
call StoreInteger(g,key,"attT",R2I(udg_castervars[100]))
call StoreInteger(g,key,"dmgT",R2I(udg_castervars[101]))
endif
endfunction
function SetDamageOptions takes integer id, integer DamageOptions returns nothing
call SetDamageOptions_i(CSCache(),id,DamageOptions)
endfunction
function CreateDamageOptions takes integer DamageOptions returns integer
local gamecache g=CSCache()
local integer n=GetStoredInteger(g,"misc","DOPTn")+1
call StoreInteger(g,"misc","DOPTn",n)
call SetDamageOptions_i(g,n,DamageOptions)
set g=null
return n
endfunction
function DestroyDamageOptions takes integer id returns nothing
call FlushStoredMission(CSCache(),"DOPT"+I2S(id))
endfunction
function LoadDamageOptions takes integer id returns integer
local gamecache g=CSCache()
local string key="DOPT"+I2S(id)
local integer opt=GetStoredInteger(g,key,"value")
local integer v=opt
if v>=2048 then
set udg_castervars[113]=GetStoredReal(g,key,"allf")
set v=v-2028
endif
if v>=1024 then
set udg_castervars[112]= GetStoredInteger(g,key,"ign")
set v=v-1024
endif
if v>=512 then
set udg_castervars[110]=CS_Rawcode2Real(GetStoredInteger(g,key,"ab3"))
set udg_castervars[111]=GetStoredReal(g,key,"fc3")
set v=v-512
endif
if v>=256 then
set udg_castervars[108]=CS_Rawcode2Real(GetStoredInteger(g,key,"ab2"))
set udg_castervars[109]=GetStoredReal(g,key,"fc2")
set v=v-256
endif
if v>=128 then
set udg_castervars[106]=CS_Rawcode2Real(GetStoredInteger(g,key,"ab1"))
set udg_castervars[107]=GetStoredReal(g,key,"fc1")
set v=v-128
endif
if v >= 64 then
set v=v-64
set udg_castervars[105]= GetStoredInteger(g,key,"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 udg_castervars[104]=GetStoredInteger(g,key,"only")
set v=v-4
endif
if v >= 2 then
set udg_castervars[102]=GetStoredInteger(g,key,"excp")
set udg_castervars[103]=GetStoredReal(g,key,"excf")
set v=v-2
endif
if v >= 1 then
set udg_castervars[100]=GetStoredInteger(g,key,"attT")
set udg_castervars[101]=GetStoredInteger(g,key,"dmgT")
endif
set g=null
return opt
endfunction
//==================================================================================================
function IsDestructableTree_withcs takes destructable d returns boolean
local unit c=GetACaster()
local boolean b
local boolean i=IsDestructableInvulnerable(d)
local integer s=DamageTreeDetectorId()
if i then
call SetDestructableInvulnerable(d,false)
endif
call UnitAddAbility(c,s)
call SetUnitPosition(c,GetWidgetX(d),GetWidgetY(d))
set b=(IssueTargetOrder(c,"eattree",d))
call UnitRemoveAbility(c,s)
call RecicleCaster(c)
set c=null
if i then
call SetDestructableInvulnerable(d,true)
endif
return b
endfunction
function IsDestructableTree takes destructable d returns boolean
local gamecache g=CSCache()
local string k=I2S(GetDestructableTypeId(d))
local boolean b
if HaveStoredBoolean(g,"trees",k) then
set b=GetStoredBoolean(g,"trees",k)
set g=null
return b
else
set b=IsDestructableTree_withcs(d)
call StoreBoolean(g,"trees",k,b)
endif
set g=null
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 (SquareRoot(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
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 (SquareRoot(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
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=CreateGroup()
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 DestroyGroup(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=CreateGroup()
local integer d=DamageOptions
set bj_groupEnumOwningPlayer=GetOwningPlayer(hurter)
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 (udg_castervars[105]==2) then
set b=Condition(function CasterAOE_IsFilterAlly)
elseif (udg_castervars[105]==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 GroupEnumUnitsInRange(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
local unit caster=GetACaster()
call UnitRemoveAbility(caster,'Aloc') //Otherwise the units would flee like crazy
call SetUnitOwner(caster,hurter,false)
call DamageUnitGroupEx(caster,damage,targetgroup,0)
call RecicleCaster(caster)
set caster=null
endfunction
//====================================================================================================================================================================
function DamageUnitsInAOE takes player hurter, real damage, real x, real y, real radius, boolean affectallied returns nothing
local unit caster=GetACaster()
call UnitRemoveAbility(caster,'Aloc') //Otherwise the units would flee like crazy
call SetUnitOwner(caster,hurter,false)
call DamageUnitsInAOEEx(caster,damage,x,y,radius,affectallied,0)
call RecicleCaster(caster)
set caster=null
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 = CreateTimer()
local real next = 0
local integer a = 0
local group inrange = CreateGroup()
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=udg_castervars[107]
local real f2=udg_castervars[109]
local real f3=udg_castervars[111]
local real allf=udg_castervars[113]
local effect array fx
local integer fxn=0
set fx[0]=bj_lastCreatedEffect
if f1!=1 then
set a1=CS_LoadRawcodeFromReal(106)
endif
if f2!=1 then
set a2=CS_LoadRawcodeFromReal(108)
endif
if f3!=1 then
set a3=CS_LoadRawcodeFromReal(110)
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=Caster_DefaultAttackType()
endif
if udg_castervars[10]!=-1 then
set dmgT=ConvertDamageType(R2I(udg_castervars[10]))
else
set dmgT=Caster_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 GroupEnumUnitsInRange(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 (self or picked!=hurter) and not(IsUnitDeadBJ(picked)) 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(CS_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 DestroyGroup(inrange)
call DestroyEffect(fx[0])
call TriggerSleepAction(2)
call RecicleCaster(fire)
call DestroyTimer(t)
set inrange=null
set fire=null
set t=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>=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]=udg_castervars[105]
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]=udg_castervars[104]
set v=v-4
else
set udg_castervars[6]=-1
endif
if v >= 2 then
set udg_castervars[7]=udg_castervars[102]
set udg_castervars[8]=damage*udg_castervars[103]
set v=v-2
else
set udg_castervars[7]=-1
set udg_castervars[8]=-1
endif
if v >= 1 then
set udg_castervars[9]=udg_castervars[100]
set udg_castervars[10]=udg_castervars[101]
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, timer t returns boolean
local boolean tounit = GetAttachedBoolean(t,"unit")
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 v
local real time
local integer n
local boolean done=false
if tounit then
set tg=GetAttachedUnit(t,"tg")
if (GetWidgetLife(tg)<1) then
set tounit=false
call AttachBoolean(t,"unit",false)
else
set x2=GetUnitX(tg)
set y2=GetUnitY(tg)
set z2=GetUnitFlyHeight(tg)+GetAttachedReal(t,"z2o")
set n=GetAttachedInt(t,"N")
if (n>=25) then
//I have the tilt writing on gamecache is slower than reading, in that case I prevent writting
// these 3 reals, but use a counter so each second they are backuped.
// They are needed because if the unit dies or is removed, they would otherwise go to the
// center of the map, and that is not something nice.
call AttachReal(t,"z2",z2)
call AttachReal(t,"x2",x2) // Backup stuff just in case
call AttachReal(t,"y2",y2)
set n=0
endif
call AttachInt(t,"N",n)
endif
set tg=null
endif
if not(tounit) then
set z2=GetAttachedReal(t,"z2")
set x2=GetAttachedReal(t,"x2")
set y2=GetAttachedReal(t,"y2")
endif
set g=Atan2(y2-y1,x2-x1)
call SetUnitFacing(m,g*bj_RADTODEG)
set v=GetAttachedReal(t,"speed") //xy speed
set d= CS_Cycle() * v
call SetUnitPosition(m , x1+d*Cos(g), y1+d*Sin(g) )
set g=GetAttachedReal(t,"acel")
set time= SquareRoot( Pow(x1-x2,2) + Pow(y1-y2,2) ) / v
set v=(z2-z1+0.5*g*time*time)/time //z speed
call SetUnitFlyHeight(m,z1+v*CS_Cycle(),0)
set d=SquareRoot( Pow(GetUnitX(m)-x2,2) + Pow(GetUnitY(m)-y2,2) )
if (d<=20) then
set done=true
call AttachBoolean(t,"done",true)
endif
return done
endfunction
function CollisionMissile_Destroyer takes unit m, timer t returns nothing
local trigger T=GetAttachedTrigger(t,"T")
call TriggerExecute(T)
call DestroyEffect(GetAttachedEffect(t,"fx"))
call TriggerRemoveAction(T,GetAttachedTriggerAction(T,"ac"))
call DestroyTrigger(T)
call CleanAttachedVars(T)
call AttachObject(m,"CasterSystem_Timer",null)
call CleanAttachedVars(m)
if GetAttachedBoolean(t,"new") then
call ExplodeUnitBJ(m)
else
call RecicleCasterAfterCastEx(m,4,0,true)
endif
call CleanAttachedVars(t)
call DestroyTimer(t)
set T=null
endfunction
function GetTriggerCollisionMissile takes nothing returns unit
return GetAttachedObject(GetTriggeringTrigger(),"m")
endfunction
function CollisionMissile_Move takes unit m, timer t returns boolean
local boolean done=false
local real d=GetAttachedReal(t,"speed") * CS_Cycle()
local real F=GetAttachedReal(t,"F")
local real asp=GetAttachedReal(t,"aspeed")
local real x=GetUnitX(m)
local real nx
local real y=GetUnitY(m)
local real ny
if (asp!=0) then
set F=F+ asp * CS_Cycle()
call AttachReal(t,"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=GetAttachedReal(t,"maxd")-d
call AttachReal(t,"maxd",d)
set done=(d<=0)
call SetUnitPosition(m,nx,ny)
if (SquareRoot(Pow(nx-GetUnitX(m),2)+Pow(ny-GetUnitY(m),2))>10) then
call SetUnitPosition(m,x,y)
set done=true
endif
if done then
call CollisionMissile_Destroyer(m,t)
endif
return done
endfunction
function CasterSystemMovementTimer takes nothing returns nothing
local timer t=GetExpiredTimer()
local timer T=GetExpiredTimer()
local group g=GetAttachedGroup(t,"G")
local group x=CreateGroup()
local unit p
loop
set p=FirstOfGroup(g)
exitwhen (p==null)
call GroupRemoveUnit(g,p)
set T=GetAttachedTimer(p,"CasterSystem_Timer")
if GetAttachedBoolean(T,"IsCollisionMissile") then
if not(CollisionMissile_Move(p,T)) then
call GroupAddUnit(x,p)
endif
else
if not(UnitMoveToAsProjectileAnySpeed_Move(p,T)) then
call GroupAddUnit(x,p)
endif
endif
endloop
if (FirstOfGroup(x)==null) then
call AttachObject(null,"CS_PROJECTILE_TIMER",null)
call CleanAttachedVars(t)
call DestroyTimer(t)
call DestroyGroup(x)
else
call AttachObject(t,"G",x)
endif
call DestroyGroup(g)
set T=null
set p=null
set x=null
set g=null
set t=null
endfunction
function UnitMoveToAsProjectileAnySpeed takes unit m, 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=GetAttachedTimer(null,"CS_PROJECTILE_TIMER")
local group g
if (t==null) then
set t=CreateTimer()
set g=CreateGroup()
call AttachObject(t,"G",g)
call TimerStart(t,CS_Cycle(),true,function CasterSystemMovementTimer)
else
set g=GetAttachedGroup(t,"G")
endif
set t=GetAttachedTimer(m,"CasterSystem_Timer")
if (t!=null) then
call AttachBoolean(t,"done",true)
endif
set t=CreateTimer()
call AttachObject(m,"CasterSystem_Timer",t)
call GroupAddUnit(g,m)
if (target!=null) then
call AttachBoolean(t,"unit",true)
call AttachObject(t,"tg",target)
call AttachReal(t,"x2",GetUnitX(target))
call AttachReal(t,"y2",GetUnitY(target))
call AttachReal(t,"z2o",z2)
else
call AttachReal(t,"x2",x2)
call AttachReal(t,"y2",y2)
endif
call AttachReal(t,"z2",z2)
call AttachReal(t,"speed",speed)
call AttachReal(t,"acel",arc*8000)
loop
exitwhen GetAttachedBoolean(t,"done")
call TriggerSleepAction(0)
endloop
call AttachObject(m,"CasterSystem_Timer",null)
call CleanAttachedVars(t)
call DestroyTimer(t)
set t=null
set g=null
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 IsUnitDeadBJ(target) 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 SetUnitPosition(m,x2,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=AddCasterFacing( Atan2BJ(y2 - y1, x2 - x1) )
local effect fx=null
call SetUnitPosition( m, x1,y1)
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)
else
call UnitMoveToAsProjectileAnySpeed(m,speed,arc,x2,y2,null,z2)
endif
call DestroyEffect(fx)
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
//============================================================================================================
function ProjectileLaunch takes string modelpath, real speed, real arc,real x1, real y1, real z1, real x2, real y2, real z2 returns nothing
call ProjectileLaunchEx( Player(15), modelpath, 1, 255, 255, 255, 255, speed, arc,x1,y1,z1,x2,y2,z2)
endfunction
function ProjectileLaunchLoc takes string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2 returns nothing
call ProjectileLaunchExLoc( Player(15), modelpath, 1,255,255,255,255,speed,arc,loc1,z1,loc2,z2)
endfunction
//============================================================================================================
function DamagingProjectileLaunchAOE_Child takes nothing returns nothing
local unit m=udg_currentcaster
local effect fx=bj_lastCreatedEffect
local real x2=udg_castervars[0]
local real y2=udg_castervars[1]
local real aoeradius=udg_castervars[3]
local real damage=udg_castervars[4]
local boolean affectallied=bj_isUnitGroupInRectResult
local integer V=CreateDamageOptions(R2I(udg_castervars[5]))
local unit hurter=udg_currenthurter
local real speed=udg_castervars[6]
if (speed<=522) then
call SetUnitMoveSpeed(m, speed)
call UnitMoveToAsProjectile(m, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], udg_castervars[2])
else
call UnitMoveToAsProjectileAnySpeed(m,speed,bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1],null, udg_castervars[2])
endif
call DestroyEffect(fx)
call DamageUnitsInAOEEx(hurter,damage,x2,y2,aoeradius,affectallied,LoadDamageOptions(V))
call DestroyDamageOptions(V)
call ExplodeUnitBJ(m)
set m=null
set fx=null
endfunction
function DamagingProjectileLaunchAOE takes unit hurter, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2, real aoeradius, real damage, boolean affectallied, integer DamageOptions returns unit
local unit m=AddCasterFacing( Atan2BJ(y2 - y1, x2 - x1) )
call SetUnitPosition(m, x1,y1)
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, GetOwningPlayer(hurter), true)
set bj_meleeNearestMineDist = arc
set udg_castervars[0] = x2
set udg_castervars[1] = y2
set udg_castervars[2] = z2
set udg_castervars[3] =aoeradius
set udg_castervars[4] =damage
set udg_castervars[5] =DamageOptions
set udg_castervars[6] =speed
set udg_currenthurter=hurter
call ExecuteFunc("DamagingProjectileLaunchAOE_Child")
set m=null
return udg_currentcaster
endfunction
function DamagingProjectileLaunchAOELoc takes unit hurter, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2, real aoeradius, real damage, boolean affectallied, integer DamageOptions returns unit
return DamagingProjectileLaunchAOE(hurter,modelpath,speed,arc,GetLocationX(loc1),GetLocationY(loc1),z1,GetLocationX(loc2),GetLocationY(loc2),z2, aoeradius, damage, affectallied, DamageOptions )
endfunction
function ProjectileLaunchDamage takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2, real aoeradius, real damage, boolean affectallied returns unit
local unit m=AddCasterFacing( Atan2BJ(y2 - y1, x2 - x1) )
call SetUnitPosition(m, x1,y1)
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, owner, true)
set bj_meleeNearestMineDist = arc
set udg_castervars[0] = x2
set udg_castervars[1] = y2
set udg_castervars[2] = z2
set udg_castervars[3] =aoeradius
set udg_castervars[4] =damage
set udg_castervars[5] =0
set udg_castervars[6]= speed
set bj_isUnitGroupInRectResult=affectallied
set udg_currenthurter=m
call ExecuteFunc("DamagingProjectileLaunchAOE_Child")
set m=null
return udg_currentcaster
endfunction
function ProjectileLaunchDamageLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2, real aoeradius, real damage, boolean affectallied returns unit
return ProjectileLaunchDamage( owner, modelpath, speed, arc, GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2, aoeradius, damage, affectallied)
endfunction
//============================================================================================================
function ProjectileLaunchKill_Child takes nothing returns nothing
local unit m=udg_currentcaster
local effect fx=bj_lastCreatedEffect
local real x2=udg_castervars[0]
local real y2=udg_castervars[1]
local real speed=udg_castervars[3]
if (speed<=522) then
call SetUnitMoveSpeed( m, speed)
call UnitMoveToAsProjectile(m, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], udg_castervars[2])
else
call UnitMoveToAsProjectileAnySpeed(m,speed, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], null, udg_castervars[2])
endif
call ExplodeUnitBJ(m)
call DestroyEffect( fx)
set m=null
set fx=null
endfunction
function ProjectileLaunchKill takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2 returns unit
local unit m=AddCasterFacing( Atan2BJ(y2 - y1, x2 - x1) )
call SetUnitPosition(m, x1,y1)
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, owner, true)
set bj_meleeNearestMineDist = arc
set udg_castervars[0] = x2
set udg_castervars[1] = y2
set udg_castervars[2] = z2
set udg_castervars[3] = speed
call ExecuteFunc("ProjectileLaunchKill_Child")
set m=null
return udg_currentcaster
endfunction
function ProjectileLaunchKillLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2 returns unit
return ProjectileLaunchKill( owner, modelpath, speed, arc, GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2)
endfunction
//====================================================================================================================================================================
function UnitMoveToUnitAsProjectile takes unit m, real arc, unit target, real zoffset returns nothing
call UnitMoveToAsProjectileGen(m, arc,0,0,target,zoffset)
endfunction
//====================================================================================================================================================================
function ProjectileLaunchToUnitEx 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, unit target, real zoffset returns nothing
local unit m=AddCasterFacing( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1) )
local effect fx=null
call SetUnitPosition( m, x1,y1)
call SetUnitFlyHeight( m, z1, 0)
call SetUnitScale( m, scale, scale, scale)
call SetUnitVertexColor(m, red, green, blue, alpha)
set fx=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m , owner, true)
if (speed<=522) then
call SetUnitMoveSpeed( m, speed)
call UnitMoveToUnitAsProjectile(m,arc,target, zoffset)
else
call UnitMoveToAsProjectileAnySpeed(m,speed, arc,0,0,target,zoffset)
endif
call DestroyEffect(fx)
call ExplodeUnitBJ(m)
set m=null
set fx=null
endfunction
function ProjectileLaunchToUnitExLoc takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, location loc1, real z1, unit target, real zoffset returns nothing
call ProjectileLaunchToUnitEx( owner, modelpath, scale, red, green, blue, alpha, speed, arc, GetLocationX(loc1),GetLocationY(loc1), z1, target, zoffset)
endfunction
function ProjectileLaunchToUnit takes string modelpath, real speed, real arc,real x1, real y1, real z1, unit target, real zoffset returns nothing
call ProjectileLaunchToUnitEx( Player(15), modelpath, 1, 255,255,255,255,speed,arc,x1,y1,z1,target,zoffset)
endfunction
function ProjectileLaunchToUnitLoc takes string modelpath, real speed, real arc, location loc1, real z1, unit target, real zoffset returns nothing
call ProjectileLaunchToUnitExLoc( Player(15), modelpath, 1, 255,255,255,255, speed, arc, loc1, z1, target,zoffset)
endfunction
//====================================================================================================================================================================
function DamagingProjectileLaunchTarget_Child takes nothing returns nothing
local unit m=udg_currentcaster
local unit target=bj_meleeNearestMine
local effect fx=bj_lastCreatedEffect
local real damage=udg_castervars[4]
local damagetype dmgT=ConvertDamageType(R2I(udg_castervars[6]))
local attacktype attT=ConvertAttackType(R2I(udg_castervars[5]))
local unit hurter=udg_currenthurter
local real speed=udg_castervars[7]
if (speed<=522) then
call SetUnitMoveSpeed( m, speed)
call UnitMoveToUnitAsProjectile(m, bj_meleeNearestMineDist, target, udg_castervars[2])
else
call UnitMoveToAsProjectileAnySpeed(m,speed, bj_meleeNearestMineDist,0,0,target,udg_castervars[2])
endif
call DestroyEffect( fx)
call DamageUnitByTypes(hurter,target,damage,attT,dmgT)
call ExplodeUnitBJ(m)
set m=null
set hurter=null
set target=null
set fx=null
set dmgT=null
set attT=null
endfunction
function DamagingProjectileLaunchTarget takes unit hurter, string modelpath, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset, real damage, attacktype attT, damagetype dmgT returns unit
local unit m=AddCasterFacing( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1) )
call SetUnitPosition(m, x1,y1)
set udg_castervars[7]=speed
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, GetOwningPlayer(hurter), true)
set bj_meleeNearestMineDist = arc
set udg_castervars[2]= zoffset
set bj_meleeNearestMine=target
set udg_castervars[4]=damage
set udg_castervars[5]=CS_H2I(attT)
set udg_castervars[6]=CS_H2I(dmgT)
set udg_currenthurter=hurter
call ExecuteFunc("DamagingProjectileLaunchTarget_Child")
set m=null
return udg_currentcaster
endfunction
function DamagingProjectileLaunchTargetLoc takes unit hurter, string modelpath, real speed, real arc, location loc, real z1, unit target, real zoffset, real damage, attacktype attT, damagetype dmgT returns unit
return DamagingProjectileLaunchTarget(hurter,modelpath,speed,arc,GetLocationX(loc),GetLocationY(loc), z1, target, zoffset, damage, attT, dmgT)
endfunction
function ProjectileLaunchToUnitDamage takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset, real damage returns unit
local unit m=AddCasterFacing( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1) )
call SetUnitPosition(m, x1,y1)
set udg_castervars[7]=speed
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, owner, true)
set bj_meleeNearestMineDist = arc
set udg_castervars[2]= zoffset
set bj_meleeNearestMine=target
set udg_castervars[4]=damage
set udg_castervars[5]=CS_H2I(Caster_DefaultAttackType())
set udg_castervars[6]=CS_H2I(Caster_DefaultDamageType())
set udg_currenthurter=m
call ExecuteFunc("DamagingProjectileLaunchTarget_Child")
set m=null
return udg_currentcaster
endfunction
function ProjectileLaunchToUnitDamageLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, unit target, real zoffset, real damage returns unit
return ProjectileLaunchToUnitDamage( owner, modelpath, speed, arc,GetLocationX(loc1),GetLocationY(loc1),z1,target,zoffset,damage)
endfunction
//==============================================================================================================================================================================
function CollisionMissile_Destroy takes unit m returns nothing
call GroupRemoveUnit( GetAttachedGroup(GetAttachedObject(null,"CS_PROJECTILE_TIMER"),"G"),m )
call CollisionMissile_Destroyer(m,GetAttachedTimer(m,"CasterSystem_Timer"))
endfunction
function CollisionMissile_Create takes string MissileModelPath, real x, real y, real dirangle, real speed, real AngleSpeed, real MaxDist, real height, boolean UseNewCaster, real Collision, code OnImpact returns unit
local timer t=GetAttachedTimer(null,"CS_PROJECTILE_TIMER")
local trigger R
local group g
local unit m
if (t==null) then
set t=CreateTimer()
set g=CreateGroup()
call AttachObject(t,"G",g)
call TimerStart(t,CS_Cycle(),true,function CasterSystemMovementTimer)
else
set g=GetAttachedGroup(t,"G")
endif
set t=CreateTimer()
call AttachBoolean(t,"IsCollisionMissile",true)
if UseNewCaster then
set m=AddCasterFacing(dirangle)
call AttachBoolean(t,"new",true)
else
set m=GetACaster()
call SetUnitFacing(m,dirangle)
endif
call SetUnitPosition(m,x,y)
call AttachObject(m,"CasterSystem_Timer",t)
call AttachReal(t,"speed",speed)
call AttachReal(t,"aspeed",AngleSpeed)
call AttachReal(t,"F",dirangle)
call AttachReal(t,"maxd",MaxDist)
call SetUnitFlyHeight(m,height,0)
call GroupAddUnit(g,m)
set R=CreateTrigger()
call AttachObject(R,"ac",TriggerAddAction(R,OnImpact))
call AttachObject(R,"m",m)
call TriggerRegisterUnitInRange(R,m,Collision,null)
call AttachObject(t,"T",R)
call AttachObject(t,"fx", AddSpecialEffectTarget(MissileModelPath,m,"origin") )
set t=null
set g=null
set R=null
set udg_currentcaster=m
set m=null
return udg_currentcaster
endfunction
function CollisionMissile_CreateLoc takes string MissileModelPath, location loc, real dirangle, real speed, real AngleSpeed, real MaxDist, real height, boolean UseNewCaster, real Collision, code OnImpact returns unit
return CollisionMissile_Create(MissileModelPath,GetLocationX(loc),GetLocationY(loc),dirangle,speed,AngleSpeed,MaxDist,height,UseNewCaster,Collision,OnImpact)
endfunction
//==================================================================================================
function IsPointWater takes real x, real y returns boolean
return IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x,y,PATHING_TYPE_AMPHIBIOUSPATHING))
endfunction
function IsPointWaterLoc takes location loc returns boolean
return IsPointWater(GetLocationX(loc),GetLocationY(loc))
endfunction
//==================================================================================================
function IsUnitSpellImmune takes unit u returns boolean
return IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)
endfunction
function IsUnitImmuneToPhisical takes unit u returns boolean
return (GetDamageFactor(u,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_DEMOLITION)==0)
endfunction
function IsUnitInvulnerable takes unit u returns boolean
return (GetDamageFactor(u,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL)==0)
endfunction
constant function WaterDetectorId takes nothing returns integer
return 'Asb2' //Left for compat
endfunction
//##End##
//##Start##
//==================================================================================================
function H2I takes handle h returns integer
return h
return 0
endfunction
//==================================================================================================
function LocalVars takes nothing returns gamecache
return InitGameCache("jasslocalvars.w3v")
endfunction
//==================================================================================================
function SetHandleInt takes handle subject, string name, integer value returns nothing
if value==0 then
call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
else
call StoreInteger(LocalVars(), I2S(H2I(subject)), name, value)
endif
endfunction
//==================================================================================================
function SetHandleReal takes handle subject, string name, real value returns nothing
if value==0 then
call FlushStoredReal(LocalVars(), I2S(H2I(subject)), name)
else
call StoreReal(LocalVars(), I2S(H2I(subject)), name, value)
endif
endfunction
//==================================================================================================
function SetHandleHandle takes handle subject, string name, handle value returns nothing
call SetHandleInt( subject, name, H2I(value) )
endfunction
//==================================================================================================
function GetHandleHandle takes handle subject, string name returns handle
return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
return null
endfunction
//==================================================================================================
function GetHandleInt takes handle subject, string name returns integer
return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
endfunction
//==================================================================================================
function GetHandleReal takes handle subject, string name returns real
return GetStoredReal(LocalVars(), I2S(H2I(subject)), name)
endfunction
//==================================================================================================
function FlushHandleLocals takes handle subject returns nothing
call FlushStoredMission(LocalVars(), I2S(H2I(subject)) )
endfunction
//##End##
//##Start##
//**************************************************************************************************
//*
//* UnitGuardUnitAI Function (Controls all the Diablo 2 summons system)
//*
//* To implement this function, you must select the contents of this trigger starting
//* with the //##Start## and finishing with the //##End##, and copy that TO YOUR MAP's
//* CUSTOM SCRIPT SECTION, (it is at the top of the trigger list in the trigger editor)
//*
//* DON'T JUST COPY THE TRIGGER; copy this to the custom script section
//*
//* (If you already have this functions in your map don't copy this one)
//*
//**************************************************************************************************
//=================================================================================================
//
// http://www.wc3jass.com : The place with tons of JASS scripts
//
//=================================================================================================
//==================================================================================================
// Unit Guard AI Configuration: (Added this section so you can easily customize the ai without
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Messing with the functions, just replace the numbers)
//
constant function UnitGuardUnitAI_maxdelay takes nothing returns real
return 2.5 //* The max delay betwen orders issued to the summon
endfunction
constant function UnitGuardUnitAI_mindelay takes nothing returns real
return 1.00 //* The min delay betwen orders issued to the summon
endfunction
constant function UnitGuardUnitAI_maxdistance takes nothing returns real
return 1000.0 //* If the distance betwen the summon and the master is greater than this value,
// The summon will move to the position of the master instead of attack move
endfunction
constant function UnitGuardUnitAI_cometomaxdist takes nothing returns real
return 500.0 //* Max distance for issued orders to approach the master
endfunction
constant function UnitGuardUnitAI_cometomindist takes nothing returns real
return 100.0 //* Min distance for issued orders to approach the master
endfunction
//==================================================================================================
function GuardUnit_GetSummonMaster takes unit u returns unit
return GetAttachedObject(u, "master")
endfunction
function GuardUnitOrder takes unit summon, unit master returns nothing
local integer o=GetUnitCurrentOrder(summon)
local real tx=GetUnitX(master)
local real ty=GetUnitY(master)
local real angle
local real dist
set dist=SquareRoot(Pow(tx-GetUnitX(summon),2) + Pow(ty-GetUnitY(summon),2))
if (dist > UnitGuardUnitAI_maxdistance() ) and (o == 0 or o == OrderId("attack") or o == OrderId("move") or o == OrderId("stop") or o==851971) then
call IssuePointOrder(summon, "move", tx,ty)
elseif dist >= UnitGuardUnitAI_cometomindist() and (o == 0 or o == 851971) then
set angle = GetRandomReal( GetUnitFacing(master)-80, GetUnitFacing(master)+80) * IntegerTertiaryOp( ModuloInteger( GetUnitPointValue(summon), 2) == 0,1,-1)
set dist = GetRandomReal(UnitGuardUnitAI_cometomindist(), UnitGuardUnitAI_cometomaxdist() )
set tx=tx+dist*CosBJ(angle)
set ty=ty+dist*SinBJ(angle)
if not IssuePointOrder(summon, "attack", tx, ty ) then
call IssuePointOrder(summon, "move", tx, ty )
endif
endif
set summon=null
set master=null
endfunction
function UnitGuardUnitAI_Smart_Order_timer takes nothing returns nothing
local timer t=GetExpiredTimer()
local unit s=GetAttachedUnit(t,"summon")
if (GetUnitCurrentOrder(s)!=851971) then
call CleanAttachedVars(t)
call DestroyTimer(t)
else
call GuardUnitOrder( s, GetAttachedUnit(s,"master"))
call TimerStart(t,0.1,false,function UnitGuardUnitAI_Smart_Order_timer)
endif
set t=null
endfunction
function UnitGuardUnitAI_Smart_Order_Actions takes nothing returns nothing
local timer t
if (GetIssuedOrderId() == 851971) then
set t=CreateTimer()
call AttachObject(t,"summon",GetTriggerUnit())
call TimerStart(t,0,false,function UnitGuardUnitAI_Smart_Order_timer)
set t=null
endif
endfunction
function UnitGuardUnitAI_loop takes nothing returns nothing
// Executed in another thread
local unit summon=bj_ghoul[0]
local unit master=GetAttachedUnit(summon,"master")
local trigger smart=CreateTrigger()
local integer n=0
local triggeraction ac=TriggerAddAction( smart, function UnitGuardUnitAI_Smart_Order_Actions)
call TriggerRegisterUnitEvent( smart, summon, EVENT_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterUnitEvent( smart, summon, EVENT_UNIT_ISSUED_POINT_ORDER )
loop
exitwhen (GetWidgetLife(summon)<=0)
call GuardUnitOrder( summon, master)
call PolledWait( GetRandomReal( UnitGuardUnitAI_mindelay(), UnitGuardUnitAI_maxdelay() ))
endloop
call CleanAttachedVars(summon)
call TriggerRemoveAction(smart,ac)
call DestroyTrigger(smart)
set ac=null
set summon=null
set master=null
set smart=null
endfunction
function UnitGuardUnitAI takes unit summon, unit master returns nothing
local unit a=bj_ghoul[0]
call AttachObject( summon, "master", master)
set bj_ghoul[0]=summon
call ExecuteFunc("UnitGuardUnitAI_loop")
set bj_ghoul[0]=a
set a=null
endfunction
//##End##
//##Start##
//***************************************************************************************************
//*
//* SimError: Simulates an Error message for a player, requires:
//*
//* To Implement The SimError function to your map if you don't have it yet, copy the
//* contents of this trigger (starting with the //##Start## and ending with the //##end##
//* TO YOUR MAP's CUSTOM SCRIPT SECTION (it is at the top of the trigger list in the
//* trigger editor)
//*
//* It WON'T WORK if you just copy this trigger to your map
//*
//* (If you already have this function in your map don't copy this one)
//*
//***************************************************************************************************
//===================================================================================================
//
// For more JASS functions visit: http://www.wc3jass.com
//
//===================================================================================================
//===================================================================================================
function SimError takes player ForPlayer, string msg returns nothing
local sound error=CreateSoundFromLabel( "InterfaceError",false,false,false,10,10)
if (GetLocalPlayer() == ForPlayer) then
call ClearTextMessages()
call DisplayTimedTextToPlayer( ForPlayer, 0.52, -1.00, 2.00, "|cffffcc00"+msg+"|r" )
call StartSound( error )
endif
call KillSoundWhenDone( error)
set error=null
endfunction
//##end##
//##Start##
//***************************************************************************************************
//*
//* GetPlayerNameColored: Returns A Colored Version of A Player`s Name
//*
//* To Implement This function to your map if you don't have it yet, copy the
//* contents of this trigger (starting with the //##Start## and ending with the //##end##
//* TO YOUR MAP's CUSTOM SCRIPT SECTION (it is at the top of the trigger list in the
//* trigger editor)
//*
//* It WON'T WORK if you just copy this trigger to your map
//*
//* (If you already have this function in your map don't copy this one)
//*
//***************************************************************************************************
//===================================================================================================
//
// For more JASS functions visit: http://www.wc3jass.com
//
//===================================================================================================
//===================================================================================================
function GetPlayerNameColored takes player id returns string
local playercolor col=GetPlayerColor(id)
local string r=GetPlayerName(id)
if col == PLAYER_COLOR_RED then
set r="|cffff0000"+r+"|r"
elseif col == PLAYER_COLOR_BLUE then
set r="|cff0000ff"+r+"|r"
elseif col == PLAYER_COLOR_CYAN then
set r="|cff93ffc9"+r+"|r"
elseif col == PLAYER_COLOR_PURPLE then
set r="|cff400080"+r+"|r"
elseif col == PLAYER_COLOR_YELLOW then
set r="|cffffff00"+r+"|r"
elseif col == PLAYER_COLOR_ORANGE then
set r="|cffff8000"+r+"|r"
elseif col == PLAYER_COLOR_GREEN then
set r="|cff00c400"+r+"|r"
elseif col == PLAYER_COLOR_PINK then
set r="|cffff80c0"+r+"|r"
elseif col == PLAYER_COLOR_LIGHT_GRAY then
set r="|cff808080"+r+"|r"
elseif col == PLAYER_COLOR_LIGHT_BLUE then
set r="|cffc1c1ff"+r+"|r"
elseif col == PLAYER_COLOR_AQUA then
set r="|cff5e5e2f"+r+"|r"
elseif col == PLAYER_COLOR_BROWN then
set r="|cff004000"+r+"|r"
else
set r="|cff000000"+r+"|r"
endif
set col=null
return r
endfunction
//##End##
//******************************************************************************************************
//*
//* Vexorian Hero Selection System VII functions
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* To Implement The Selection System functions to your map, you first need some stuff
//* to be already implemented in your map:
//*
//* - The SimError function (see above)
//* - The GetPlayerNameColored function (see above)
//* - Some Global Variables (see below)
//*
//* Then copy this trigger and change the rawcodes to the right ones in your map.
//*
//* Note: You can edit the messages used by the Selection system, they are extracted from the
//* Art - Special field of the Choose Hero Ability. Feel free to translate them to your language
//* Or to modiffy them to fit the style of your map.
//*
//******************************************************************************************************
//======================================================================================================
// Input constants
//
constant function hss_ChooseHeroSpellId takes nothing returns integer
return 'A01E' //Rawcode of the Choose Hero Spell in your map
endfunction
constant function hss_RandomHeroSpellId takes nothing returns integer
return 'A01F' //Rawcode of the Random Hero Spell in your map
//Use 0 to disable the random hero feature
endfunction
constant function hss_SelectionArrowSpellId takes nothing returns integer
return 'A01G' //Rawcode of the Selection Arrow ability.
endfunction
constant function hss_ComputerHeroes takes nothing returns boolean
return false //if you want computer heroes use true, otherwise use false
endfunction
constant function hss_DoCleanup takes nothing returns boolean
return true //if it is true, the hero gallery will be removed once everybody got its hero.
endfunction
constant function hss_DoubleHeroesEnabled takes nothing returns boolean
return false //If it is true, a player can choose heroes that were already chosen, when it is false
//he is not able to do that, and chosen heroes become 'ghosts'
endfunction
constant function hss_TimeLimit takes nothing returns integer
return 45 //Time limit for hero selection, use 0 here to disable the time limit.
endfunction
constant function hss_KillInactive takes nothing returns boolean
return false //if it is true, When the time limit ends, players get defeated instead of a random hero
endfunction
//******************************************************************************************************
//*
//* Theorically you won't need to change these functions unless you know JASS and want
//* to improve the Selection System to fit better on your map.
//*
//* ..........................
//* : Input Global Variables : (Used by the mapper to configure the Selection system)
//* ``````````````````````````
//* group udg_hss_SelectableHeroes Heroes used by the selection system
//*
//* group udg_hss_AvailableHeroes Heroes use by Random Hero functions
//*
//* rect array udg_hss_HeroSection Determines a Player's Hero Gallery (1 to 12)
//*
//* rect array udg_hss_HeroCreation Determines a Player's Hero Spawn Rect (1 to 12)
//*
//* trigger udg_hss_CreatedHeroTrigger Determines the trigger to be executed after hero creation
//*
//* ...........................
//* : Output Global Variables : (Used to store the results of the Selection system)
//* ```````````````````````````
//* unit array udg_hss_Heroes Stores a player's hero after its creation (1 to 12)
//* 13 to 24 temporary store the current selected hero
//*
//******************************************************************************************************
//======================================================================================================
// Filter functions:
//
function hssFilterIsPossible takes nothing returns boolean
return IsUnitInGroup(GetFilterUnit(), udg_hss_SelectableHeroes) and RectContainsUnit( udg_hss_HeroSection[GetConvertedPlayerId(bj_groupEnumOwningPlayer)], GetFilterUnit() )
endfunction
function hssFilterIsAvailable takes nothing returns boolean
if GetTriggerUnit() == null and FirstOfGroup(udg_hss_AvailableHeroes) == null then
//* In Case a Weird thing happened and there were not heroes available for computers
return hssFilterIsPossible()
endif
return IsUnitInGroup(GetFilterUnit(), udg_hss_AvailableHeroes) and RectContainsUnit( udg_hss_HeroSection[GetConvertedPlayerId(bj_groupEnumOwningPlayer)], GetFilterUnit() )
endfunction
function hssFilterIsComputerWithoutHero takes nothing returns boolean
return (GetPlayerController(GetFilterPlayer()) == MAP_CONTROL_COMPUTER) and (udg_hss_Heroes[GetConvertedPlayerId(GetFilterPlayer())] == null) // and udg_hss_Heroes[GetPlayerId(GetFilterPlayer()) + 13] == null
endfunction
//======================================================================================================
function hss_Message takes integer i returns string
return GetAbilityEffectById(hss_ChooseHeroSpellId(),EFFECT_TYPE_SPECIAL,i)
endfunction
//===========================================================================================
function SetPlayerHero takes player id, unit hero, string suffix returns nothing
//
// Determines a player's hero
// - id player argument is self explanatory (Create the hero for that player)
// - hero unit argument is self explanatory too (The hero that was in the gallery)
// - suffix string argument is added to the "(Player) has selected the (Hero)" message
//
// Will Run the trigger udg_hss_CreatedHeroTrigger after creating the hero
// (Use last created unit to reffer to the hero)
//
local integer P=GetPlayerId(id)+1
local real x=GetRectCenterX(udg_hss_HeroCreation[P])
local real y=GetRectCenterY(udg_hss_HeroCreation[P])
if (id == null) or (P > 12) or (hero == null) then
return //* Invalid Request, halt the function
endif
call GroupRemoveUnit( udg_hss_AvailableHeroes, hero ) //*Makes Hero Unselectable by Random Hero button / Computers
if not hss_DoubleHeroesEnabled() then
//*In case DoubleHeroesEnabled is false, make hero unselectable
call SetUnitColor( hero, GetPlayerColor(id) )
call UnitAddAbility(hero,'Aloc')
call SetUnitVertexColor( hero, 255, 255, 255, 127 )
endif
//* Create the new hero, select it and move the camera
set udg_hss_Heroes[P]=CreateUnit(id, GetUnitTypeId(hero),x,y, bj_UNIT_FACING )
call SelectUnitAddForPlayer( udg_hss_Heroes[P], id )
call SetCameraPositionForPlayer(id, x, y)
call DisplayTextToForce( GetPlayersAll(), GetPlayerNameColored(id)+hss_Message(1)+GetUnitName(hero)+" "+suffix)
//* In case there is a CreateHeroTrigger, Execute it and make sure Last Created Unit works
if udg_hss_CreatedHeroTrigger != null then
set bj_lastCreatedUnit=udg_hss_Heroes[P]
call ConditionalTriggerExecute( udg_hss_CreatedHeroTrigger )
endif
endfunction
//============================================================================================================
function hss_GetRandomHero takes player a, boolean forced returns unit
// Chooses a random hero, depending on the conditions, if forced is true it will even choose heroes that
// were already selected, if there are no available heroes left
//
local group heroes=CreateGroup()
local unit current
local boolexpr B=Condition(function hssFilterIsAvailable)
set bj_groupEnumOwningPlayer=a //* I use that Blizzard variable to make sure the filter chooses only the heroes a player can have
call GroupEnumUnitsOfPlayer(heroes,Player(PLAYER_NEUTRAL_PASSIVE),B)
set current = GroupPickRandomUnit(heroes)
if (current == null) and forced then //* No more available heroes, use a repeated hero
set bj_groupEnumOwningPlayer=a
call DestroyBoolExpr(B)
set B=Condition(function hssFilterIsPossible)
call GroupEnumUnitsOfPlayer(heroes,Player(15),B)
set current = GroupPickRandomUnit(heroes)
endif
call DestroyGroup(heroes)
call DestroyBoolExpr(B)
set udg_hss_Heroes[100]=current //Temp use of Heroes[100] to fix the leak of the return value
set current=null
set B=null
set heroes=null
return udg_hss_Heroes[100]
endfunction
//===========================================================================================
function hss_OrderToPreviewHero takes nothing returns nothing
//
// When A hero from the gallery is issued an order, check if it was the choose hero or the
// Random Hero Button, after that block the order by pausing the unit and ordering it to stop
//
local unit selunit=GetTriggerUnit()
local player selplayer=GetOwningPlayer(selunit)
if GetIssuedOrderId() == OrderId("stop") or GetUnitUserData( selunit) == 1 or udg_hss_Heroes[13+GetPlayerId(selplayer)] != selunit then
//* A lot of conditions added because this trigger was causing massive lag
set selunit=null
set selplayer=null
return
endif
call SetUnitUserData(selunit,1) //* Part of the things that help this trigger to be lag-free, this trigger won't run when the unit has a Custom Value of 1
if GetIssuedOrderId() == 852273 then //*Select Hero Clicked
call SetUnitOwner( selunit, Player(PLAYER_NEUTRAL_PASSIVE), true )
call UnitRemoveAbility( selunit,hss_SelectionArrowSpellId()) //* Remove the Selection Arrow Special Effect
call SetPlayerHero(selplayer, selunit, "")
elseif GetIssuedOrderId() == 852277 then //*Random Hero Clicked
set udg_hss_Heroes[100]=hss_GetRandomHero(selplayer,false)
if (udg_hss_Heroes[100] == null) then
//* There is a chance that the map had an incredibly low number of heroes and that eventually there
// weren't heroes available, in that case show an error message instead of continuing with the selection
call SimError(GetOwningPlayer(selunit), hss_Message(2))
else
call SetUnitOwner(selunit, Player(PLAYER_NEUTRAL_PASSIVE), true )
call UnitRemoveAbility(selunit, hss_SelectionArrowSpellId()) //* Remove the Selection Arrow Special Effect
call SetPlayerHero(selplayer, udg_hss_Heroes[100], hss_Message(3)) //* Calls the SetPlayerHero function with a "(Random Hero)" suffix for the message
endif
else
call SimError(GetOwningPlayer(selunit), hss_Message(4)) //* The Player was trying to use an ability, show an error to him/her/ it?
endif
//* Pause the unit, order it to stop and unpause the unit, so it ignores the issued order
set selunit=GetTriggerUnit()
call PauseUnit( selunit, true)
call IssueImmediateOrder( selunit, "stop" )
call PauseUnit(selunit, false)
call SetUnitUserData( selunit, 0 )
set selunit=null
set selplayer=null
endfunction
//===========================================================================================
function hss_HeroIsClicked takes nothing returns nothing
//
// This function is executed when a Player Clicks an unit, if the unit belongs to his gallery,
// Give the unit to the player, and show the Selection Arrow, if it doesn't, restore the previus
// selected unit.
//
local unit sel=GetTriggerUnit()
local player sp=GetTriggerPlayer()
local integer a
local unit old=udg_hss_Heroes[13+GetPlayerId(sp)] //* Save the current hero that is selected by the player into a variable
if old != sel then //* Just to make "clicking a hero a lot of times till it says something funny" possible
call SetUnitOwner( old, Player(15), true ) //* give the last unit back to Neutral Passive
call UnitRemoveAbility( old, hss_SelectionArrowSpellId()) //* Remove the Selection Arrow Special Effect
set udg_hss_Heroes[13+GetPlayerId(sp)] = null //* Clear the Global Variable
if udg_hss_Heroes[GetConvertedPlayerId(sp)] == null and IsUnitInGroup(sel,udg_hss_SelectableHeroes) and IsUnitOwnedByPlayer(sel,Player(15)) then
//* The Hero is a member of the Possible Selectable Heroes
if RectContainsUnit( udg_hss_HeroSection[GetConvertedPlayerId(sp)], sel ) then
//* The Hero can be used by the player
call SetUnitManaPercentBJ( sel, 100 ) //* Just in case the map author forgot to give the hero mana (So the hero abilities buttons don't show up blue)
set udg_hss_Heroes[13+GetPlayerId(sp)] = sel //* Save the selected unit into a global
call UnitAddAbility(sel, hss_SelectionArrowSpellId()) //* Show the Selection Arrow Special Effect
call SetUnitUserData( sel,1) //* Just In case. (See the OrderToPreviewHero function for more information)
call SetUnitOwner( sel, sp, true ) //* Give the selected unit to the player
call SetUnitUserData( sel,0) //* Just In case. ^
else
//* The Hero doesn't belong to the player's team, show error message
call SimError(sp, hss_Message(5))
endif
endif
endif
set sel=null
set sp=null
set old=null
endfunction
//===========================================================================================
function hss_HeroShareVision takes nothing returns nothing
//
// Executed for every Selectable Hero, makes sure a player can choose it and if that is true,
// makes the player share vision with the hero, so the player can click on the hero
//
if RectContainsUnit( udg_hss_HeroSection[bj_forLoopAIndex+1], GetEnumUnit() ) then
call UnitShareVision( GetEnumUnit(), Player(bj_forLoopAIndex), true)
endif
endfunction
//===========================================================================================
function hss_MakePlayerChooseHero_child takes nothing returns nothing
local player id=bj_groupEnumOwningPlayer
local unit current = udg_hss_Heroes[GetPlayerId(id) + 13]
call PolledWait(GetRandomReal(0.5,3))
call SetUnitUserData( current, 0)
if IsUnitOwnedByPlayer( current, id) then
call IssueImmediateOrderById( current, 852273)
endif
set id=null
set current=null
endfunction
function hss_MakePlayerChooseHero takes player id, unit hero returns boolean
//
// Makes a Player Choose a hero, but makes sure it looks as if the player choosed it
// calls hss_MakePlayerChooseHero_child in another thread, returns false if the hero
// wasn't selectable / the player already had a hero.
//
local boolean res=false
if (id==null) then
return false
endif
if (udg_hss_Heroes[GetPlayerId(id) + 13] != null) and (udg_hss_Heroes[GetPlayerId(id) + 13] != hero) then
call SetUnitOwner( udg_hss_Heroes[GetPlayerId(id) + 13], Player(15), true ) //* give the last unit back to Neutral Passive
call UnitRemoveAbility( udg_hss_Heroes[GetPlayerId(id) + 13], hss_SelectionArrowSpellId()) //* Remove the Selection Arrow Special Effect
endif
if (udg_hss_Heroes[GetPlayerId(id)+1] == null) and IsUnitInGroup(hero,udg_hss_SelectableHeroes) and IsUnitOwnedByPlayer(hero,Player(15)) then
set udg_hss_Heroes[GetPlayerId(id) + 13] = hero
call UnitAddAbility( hero, hss_SelectionArrowSpellId())
call SetUnitOwner( hero, id, true)
set bj_groupEnumOwningPlayer=id
call ExecuteFunc("hss_MakePlayerChooseHero_child") //Creates a new thread
set res=true
endif
set hero=null
set id=null
return res
endfunction
function hss_AIChoose takes nothing returns nothing
local integer a=0
local force forcevar=CreateForce()
local player ai
local unit current
local boolexpr B=Condition(function hssFilterIsComputerWithoutHero)
loop
call TriggerSleepAction( GetRandomReal(0.05, 2) ) //* To make things realistic
call ForceClear(forcevar)
call ForceEnumPlayers(forcevar,B) //* Enum Computer Players that don't have heroes into a force
set ai = ForcePickRandomPlayer(forcevar)
//* Once ai==null the force is empty => there are no more computer players that need a hero
exitwhen (ai==null) or (a>40) //* About the a>40 : There is a chance that it would happen (Low number of available heroes)
set current=hss_GetRandomHero(ai,(a>30)) //* a>30 because it could be that a player was about to select somebody
if (current!=null) then
call hss_MakePlayerChooseHero(ai, current)
endif
set a=a+1
endloop
call DestroyForce(forcevar)
call DestroyBoolExpr(B)
set B=null
set current=null
set forcevar=null
set ai=null
endfunction
function StartVxHSS takes boolean rand, boolean comps, boolean cleanup returns nothing
//
// (The Main Function that Starts the Selection System and Finishes it)
//
// - rand boolean argument determines the availability of the random hero option.
// - comps boolean argument determines if Computer Players can Choose their Heroes
// - cleanup boolean argument determines if the gallery heroes are removed once everybody gets a hero.
//
local group heroes=CreateGroup()
local unit current
local integer a=0
local real x //* To easily save a coordinate I use x and y
local real y
local trigger UnitSel=CreateTrigger()
local trigger UnitOrder=CreateTrigger()
local force forcevar
local player ai
local timer t=null
local timerdialog td=null
local triggeraction uoac=TriggerAddAction(UnitOrder, function hss_OrderToPreviewHero)
local triggeraction usac=TriggerAddAction(UnitSel, function hss_HeroIsClicked)
set bj_wantDestroyGroup=false
call GroupAddGroup(udg_hss_SelectableHeroes,heroes)
loop
set current = FirstOfGroup(heroes)
exitwhen (current == null) //* Clearly better than a ForGroup call
//* Hero Setup for the Selection System:
call GroupRemoveUnit(heroes, current)
call UnitRemoveAbility(current, 'Amov' ) //* Removes movement
call UnitAddAbility(current, hss_ChooseHeroSpellId() ) //* Adds Choose Hero Button
if rand then
call UnitAddAbility(current, hss_RandomHeroSpellId() ) //* Adds Random Hero Button
endif
//* Register Order events for the hero
call TriggerRegisterUnitEvent( UnitOrder, current, EVENT_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterUnitEvent( UnitOrder, current, EVENT_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterUnitEvent( UnitOrder, current, EVENT_UNIT_ISSUED_ORDER )
endloop
call DestroyGroup(heroes)
loop
exitwhen a>11
set x=GetRectCenterX(udg_hss_HeroSection[a+1])
set y=GetRectCenterY(udg_hss_HeroSection[a+1])
//* Move camera and spacebar point for the player
if GetLocalPlayer() == Player(a) then
call SetCameraPosition(x,y)
call SetCameraQuickPosition(x,y)
endif
set bj_forLoopAIndex=a
call ForGroup( udg_hss_SelectableHeroes, function hss_HeroShareVision)
call TriggerRegisterPlayerSelectionEventBJ( UnitSel, Player(a), true ) //* Register a selection event for the player
set a=a+1
endloop
//* Setup Completed
call TriggerSleepAction(0)
if (hss_TimeLimit()>0) then
set t=CreateTimer()
call TimerStart(t,hss_TimeLimit(),false,null)
set td=CreateTimerDialogBJ(t,hss_Message(0))
call TimerDialogDisplay(td,true)
endif
if rand and IsMapFlagSet(MAP_RANDOM_HERO) then
//* Random Hero feature is enabled and the Game Created Checked the Random Hero Option
//* So this will automatically choose a Random Hero for every player
set a=0
loop
exitwhen a>11
call TriggerSleepAction(0) //* Just to give war3 a breathing space
if (GetPlayerSlotState(Player(a)) == PLAYER_SLOT_STATE_PLAYING) and (comps or GetPlayerController(Player(a)) != MAP_CONTROL_COMPUTER) then
//* The Player is playing (uh?)
//* Computer Players shouldn't automatically get a hero if comps is false
call SetPlayerHero(Player(a), hss_GetRandomHero(Player(a),true), hss_Message(6)) //* Calls the SetPlayerHero function with an "(Automatic)" preffix
endif
set a=a+1
endloop
elseif comps then
//* Automatically Choose random heroes for computer players when comps is true
call ExecuteFunc("hss_AIChoose")
endif
//Periodic Check
//* The Function will now loop till the time every player has a hero, so the gallery and the
// variables will be cleared
set x=0 //* Now it gets funny, I am using the x real variable as a time counter
loop
set a=0
set y=0 //* Even more funny the y real counts the players that didn't choose a hero yet
loop
exitwhen a>11
if (udg_hss_Heroes[a+1] == null) and (GetPlayerSlotState(Player(a)) == PLAYER_SLOT_STATE_PLAYING) and (comps or (GetPlayerController(Player(a))!=MAP_CONTROL_COMPUTER)) then
//* The Player Doesn't have a hero yet, ignore Computer Players in case comps is false
if (t!=null) and (TimerGetRemaining(t)<=0) then
if hss_KillInactive() then
call CustomDefeatBJ(Player(a),hss_Message(8))
else
call SetPlayerHero(Player(a), hss_GetRandomHero(Player(a),true), hss_Message(7)) //* Calls the SetPlayerHero function with a "(Forced)" preffix
endif
endif
set y=y+1
elseif (GetLocalPlayer()==Player(a)) then
call TimerDialogDisplay(td,false)
endif
set a=a+1
endloop
exitwhen (y <= 0)
call TriggerSleepAction(0)
endloop
//* Every player has already selected a hero, so start self destruction (So your map has a little more memory available)
loop
set current = FirstOfGroup(udg_hss_SelectableHeroes)
exitwhen current == null or not cleanup //* So it won't remove the gallery when removegallery is false
call GroupRemoveUnit(udg_hss_SelectableHeroes, current)
call RemoveUnit( current)
endloop
//* Variable Cleanup :
call DestroyTimer(t)
call DestroyTimerDialog(td)
call DestroyGroup(udg_hss_SelectableHeroes)
call DestroyGroup(udg_hss_AvailableHeroes)
call TriggerRemoveAction(UnitSel,usac)
call DestroyTrigger(UnitSel)
call TriggerRemoveAction(UnitOrder,uoac)
call DestroyTrigger(UnitOrder)
set a=1
loop
exitwhen a>12
call TriggerSleepAction(0)
call RemoveRect(udg_hss_HeroSection[a])
call RemoveRect(udg_hss_HeroCreation[a])
set udg_hss_HeroSection[a] = null
set udg_hss_HeroCreation[a] = null
set udg_hss_Heroes[13+a-1] = null
set a=a+1
endloop
set t=null
set td=null
set uoac=null
set usac=null
set udg_hss_SelectableHeroes=null
set udg_hss_AvailableHeroes=null
set forcevar=null
set heroes=null
set current=null
endfunction
//============================================================================================================
function VxHSS takes nothing returns nothing
// Will call the StartVxHSS which works like before for compatibility's sake.
//
call StartVxHSS((hss_RandomHeroSpellId()>0),hss_ComputerHeroes(),hss_DoCleanup())
endfunction
//===========================================================================
function InitTrig_Selection_System takes nothing returns nothing
// If you make your map with JASS, you can simply have the setup process here, but call VxHSS
// in another thread
endfunction
function InitTrig_Special_Events takes nothing returns nothing
endfunction
//##Start##
//*************************************************************************************************
//*
//* Special Events
//*
//* Requires:
//* - udg_spellevents gamecache variable
//*
//* To be able to use Special Events in your map, make sure you have the udg_spellevents
//* gamecache variable, Either use the "Variable Copying Trigger" or create it with your
//* WE's variable editor.
//*
//* After that, you have to copy this to your map's custom script section!
//* (The Custom Script Section Is at the top of the list of the triggers and has the Map's name.)
//*
//* Select the text from the //##Start## to the //##End## and copy it to the custom script
//* section that is at the top of the trigger list and has your map's name.
//*
//* After copying them and saving in your map, you need to call SetupSpecialEvents() at map
//* Initialization in order to allow the system to work. (check next trigger)
//*
//* If you already have them in your map, Delete the ones in your map, then copy these ones,
//* this is a new version that fixes some memory leaks that were blizzard's fault, also the
//* Special Events functions have a new option.
//*
//* In theory, you may just copy the trigger, making sure it is above any other trigger, then
//* Instantly save, this is easier, but may not work well.
//*
//*************************************************************************************************
//==================================================================================================
//
// For more JASS scripts, visit : http://www.wc3JASS.com
//
//==================================================================================================
//==================================================================================================
function Eventscache takes nothing returns gamecache
if (udg_spellevents==null) then
call FlushGameCache(InitGameCache("spellevents.vx"))
set udg_spellevents=InitGameCache("spellevents.vx")
call ExecuteFunc("SpecialEvents_Init")
endif
return udg_spellevents
endfunction
function GetPassiveAbilityUser takes nothing returns unit
return GetStoredInteger(Eventscache(),"passives","unit")
return null
endfunction
function GetPassiveAbilityId takes nothing returns integer
return GetStoredInteger(Eventscache(),"passives","current")
endfunction
function events_H2I takes handle h returns integer
return h
return 0
endfunction
function PassiveAbilitiesPrepare takes nothing returns nothing
local gamecache g=Eventscache()
local integer n=GetStoredInteger(g,"passives","n")
local integer i=1
local integer array p
local string array s
local unit u
local group a=CreateGroup()
loop
exitwhen (i>n)
set p[i]=GetStoredInteger(g,"passives",I2S(i))
set s[i]=GetStoredString(g,"spelllearnfuncs", I2S(p[i]))
set i=i+1
endloop
call GroupEnumUnitsInRect(a,bj_mapInitialPlayableArea,null)
loop
set u=FirstOfGroup(a)
exitwhen (u==null)
set i=1
call StoreInteger(g,"passives","unit",events_H2I(u))
loop
exitwhen (i>n)
if (GetUnitAbilityLevel(u,p[i])>0) then
call StoreInteger(g,"passives","current",p[i])
call ExecuteFunc(s[i])
endif
set i=i+1
endloop
call GroupRemoveUnit(a,u)
endloop
set a=null
endfunction
//==================================================================================================
function PassiveAbilityBrowse takes gamecache g, unit u, string k returns nothing
local integer n=GetStoredInteger(g,"passives","n")
local integer un=0
local integer i=1
local integer s
call StoreInteger(g,"passives","unit",events_H2I(u))
loop
exitwhen (i>n)
set s=GetStoredInteger(g,"passives",I2S(i))
if (GetUnitAbilityLevel(u,s)>0) then
set un=un+1
call StoreInteger(g,"passiveREG"+I2S(un),k,s)
call StoreInteger(g,"passives","current",s)
call ExecuteFunc(GetStoredString(g,"spelllearnfuncs",I2S(s)))
endif
set i=i+1
endloop
if (un==0) then
call StoreBoolean(g,"pasignore",k,true)
else
call StoreInteger(g,"passiveREGN",k,un)
endif
endfunction
function DoPassiveAbilities takes gamecache g, unit u, string k returns nothing
local integer n=GetStoredInteger(g,"passiveREGN",k)
local integer i=1
local integer s
call StoreInteger(g,"passives","unit",events_H2I(u))
loop
exitwhen (i>n)
set s=GetStoredInteger(g,"passiveREG"+I2S(i),k)
if (GetUnitAbilityLevel(u,s)>0) then
call StoreInteger(g,"passives","current",s)
call ExecuteFunc(GetStoredString(g,"spelllearnfuncs",I2S(s)))
endif
set i=i+1
endloop
endfunction
function PassiveAbilitiesOnCreated takes gamecache g, unit u, string k returns nothing
if HaveStoredInteger(g,"passiveREGN",k) then
call DoPassiveAbilities(g,u,k)
else
call PassiveAbilityBrowse(g,u,k)
endif
endfunction
//==================================================================================================
function Trig_SpecialEvents_Actions takes nothing returns nothing
local unit u=GetTriggerUnit()
local eventid e=GetTriggerEventId()
local gamecache sp=Eventscache()
local integer s
local string k
if (e==EVENT_PLAYER_UNIT_SPELL_EFFECT) then
set k=I2S(GetSpellAbilityId())
if HaveStoredString( sp, "spellfuncs",k) then
call ExecuteFunc( GetStoredString( sp, "spellfuncs",k))
endif
elseif (e==EVENT_PLAYER_UNIT_SPELL_CAST) then
set k=I2S(GetSpellAbilityId())
if HaveStoredString( sp, "castfuncs", k) then
call ExecuteFunc( GetStoredString( sp, "castfuncs",k))
endif
elseif (e==EVENT_PLAYER_HERO_SKILL) then
set s=GetLearnedSkill()
set k=I2S(s)
if HaveStoredString( sp, "spelllearnfuncs",k) then
call StoreInteger(sp,"passives","unit",events_H2I(u))
call StoreInteger(sp,"passives","current",s)
call ExecuteFunc( GetStoredString( sp, "spelllearnfuncs",k))
endif
elseif (e==EVENT_PLAYER_UNIT_SUMMON) then
set k=I2S(GetUnitTypeId( GetSummonedUnit() ))
if HaveStoredString( sp, "unitfuncs",k) then
call ExecuteFunc( GetStoredString( sp, "unitfuncs", k))
endif
elseif (e==EVENT_PLAYER_UNIT_USE_ITEM) then
set k=I2S( GetItemTypeId( GetManipulatedItem() ))
if HaveStoredString( sp, "itemfuncs", k) then
call ExecuteFunc(GetStoredString(sp,"itemfuncs",k))
endif
elseif (e==EVENT_PLAYER_UNIT_PICKUP_ITEM) then
set k=I2S( GetItemTypeId( GetManipulatedItem() ))
if HaveStoredString( sp, "itemgetfuncs", k) then
call ExecuteFunc(GetStoredString( sp, "itemgetfuncs",k))
endif
else
set k=I2S(GetUnitTypeId(u))
if not(HaveStoredBoolean(sp,"pasignore",k)) then
call PassiveAbilitiesOnCreated(sp,u,k)
endif
endif
set u=null
set e=null
set sp=null
endfunction
//==================================================================================================
// Call This Function at map initialization if you want the whole thing to work.
//
function SetupSpecialEvents takes nothing returns nothing
call Eventscache() //Left For compat
endfunction
function SpecialEvents_Init takes nothing returns nothing
local trigger trig=CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_SUMMON, null)
call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_USE_ITEM, null)
call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_HERO_SKILL, null)
call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_SPELL_CAST, null)
set i=i+1
exitwhen i==bj_MAX_PLAYER_SLOTS
endloop
call TriggerRegisterEnterRectSimple(trig,bj_mapInitialPlayableArea)
call TriggerAddAction(trig,function Trig_SpecialEvents_Actions)
call TimerStart(CreateTimer(),0,false,function PassiveAbilitiesPrepare)
set trig=null
endfunction
//==================================================================================================
// Registers the function to be executed when the effect of an ability is started:
//
function RegisterAbilityEvent takes integer abilid, string funcname returns nothing
call StoreString( Eventscache(), "spellfuncs", I2S(abilid), funcname)
endfunction
//==================================================================================================
// Registers the function to be executed when an ability is about to be casted
//
function RegisterAbilityPreCastEvent takes integer abilid, string funcname returns nothing
call StoreString( Eventscache(), "castfuncs", I2S(abilid), funcname)
endfunction
//==================================================================================================
// Registers the function to be executed when an ability is learned:
//
function RegisterAbilityLearnEvent takes integer abilid, string funcname returns nothing
call StoreString( Eventscache(), "spelllearnfuncs", I2S(abilid), funcname)
endfunction
//==================================================================================================
// Registers the function to be executed when an ability is learned:
//
function RegisterPassiveAbility takes integer abilid, string funcname returns nothing
local gamecache g=Eventscache()
local integer n=GetStoredInteger(g,"passives","n")+1
call StoreString( Eventscache(), "spelllearnfuncs", I2S(abilid), funcname)
call StoreInteger(g,"passives","n",n)
call StoreInteger(g,"passives",I2S(n),abilid)
set g=null
endfunction
//==================================================================================================
// Registers the function to be executed when an unit type is summoned:
//
function RegisterItemUseEvent takes integer itemid, string funcname returns nothing
call StoreString( Eventscache(), "itemfuncs", I2S(itemid), funcname)
endfunction
//==================================================================================================
// Registers the function to be executed when an unit type enters to the map:
//
function RegisterUnitSummonEvent takes integer unitid, string funcname returns nothing
call StoreString( Eventscache(), "unitfuncs", I2S(unitid), funcname)
endfunction
//==================================================================================================
// Registers the function to be executed when an item type is acquired:
//
function RegisterItemGetEvent takes integer itemid, string funcname returns nothing
call StoreString( Eventscache(), "itemgetfuncs", I2S(itemid), funcname)
endfunction
//##End##
function InitTrig_Spell_Templates takes nothing returns nothing
endfunction
//##Start##
//*************************************************************************************************
//*
//* Alternative Spell Templates System
//*
//* Requires:
//* - Special Events Functions
//* - udg_spelltemplates gamecache variable
//*
//* To be able to use The spell Templates in your map, or to make your own spell templates,
//* First make sure you have the udg_spelltemplates gamecache variable, Either use next
//* "Variable Copying Trigger" or create iot with your variable editor.
//*
//* After that, you have to copy this to your map's custom script section!
//* (The Custom Script Section Is at the top of the list of the triggers and has the Map's name.)
//*
//* Note: Make sure you paste the functions bellow the Special Events functions.
//*
//* Select the text from the //##Start## to the //##End## and copy it to the custom script
//* section that is at the top of the trigger list and has your map's name.
//*
//* After copying them and saving in your map, you need to call SetupSpecialEvents() at map
//* Initialization in order to allow the system to work. (check next trigger)
//*
//* If you already have them in your map, Delete the ones in your map, then copy these ones,
//* this is a new version that fixes some memory leaks that were blizzard's fault, also the
//* Special Events functions have a new option.
//*
//* In theory, you may just copy the trigger, making sure it is above any other trigger, then
//* Instantly save, this is easier, but may not work well.
//*
//*************************************************************************************************
//==================================================================================================
//
// For more JASS scripts, visit : http://www.wc3JASS.com
//
//==================================================================================================
//==================================================================================================
function AbiCache takes nothing returns gamecache
if udg_spelltemplates==null then
call FlushGameCache(InitGameCache("spells.vx"))
set udg_spelltemplates=InitGameCache("spells.vx")
endif
return udg_spelltemplates
endfunction
//==================================================================================================
// Old version:
// Setups A template (function name) for an ability abid, if uselearnevent is true it will only
// Work for A hero learns a skill events.
//
function SetAbilityTemplate takes integer abid , string func, boolean uselearnevent returns nothing
if uselearnevent then
call RegisterAbilityLearnEvent( abid, func)
else
call RegisterAbilityEvent( abid, func)
endif
call StoreString( AbiCache(), "funcs", I2S(abid), func)
endfunction
//==================================================================================================
// Setups A template (function name) for an ACTIVE ability abid
//
function SetSpellTemplate takes integer abid, string func returns integer
call RegisterAbilityEvent( abid, func)
call StoreString( AbiCache(), "funcs", I2S(abid), func)
return abid
endfunction
//============================================================================================================
// Setups A template (function name) for a PASSIVE ability abid, the ability won't work if added by triggers
//
function SetPassiveTemplate takes integer abid, string func returns integer
call RegisterPassiveAbility(abid,func)
call StoreString( AbiCache(), "funcs", I2S(abid), func)
return abid
endfunction
//============================================================================================================
// Determine a Spell Template (function)'s default value for a datafield
// This is not a necessary step, just an useful step (integers and reals default as 0, strings as
// null, without this step)
//
function SetTemplateDefaultInt takes string func, string datafield, integer value returns nothing
call StoreInteger( AbiCache(), func, datafield, value)
endfunction
function SetTemplateDefaultReal takes string func, string datafield, real value returns nothing
call StoreReal( AbiCache(), func, datafield, value)
endfunction
function SetTemplateDefaultString takes string func, string datafield, string value returns nothing
call StoreString( AbiCache(), func, datafield, value)
endfunction
//==================================================================================================
// Set the value of an spell's datafield for an specific level, if specified level is 0, it will be
// the new default for all the levels of the ability
//
function SetAbilityDataString takes integer abid , string datafield, integer l, string value returns nothing
call StoreString( AbiCache(), I2S(abid), datafield+I2S(l), value )
endfunction
function SetAbilityDataInt takes integer abid , string datafield, integer l, integer value returns nothing
call StoreInteger( AbiCache(), I2S(abid), datafield+I2S(l), value )
endfunction
function SetAbilityDataReal takes integer abid , string datafield, integer l, real value returns nothing
call StoreReal( AbiCache(), I2S(abid), datafield+I2S(l), value )
endfunction
//==================================================================================================
// When spells have too much levels it is now possible to use formulae
// The resulting number is ( initial + [(current level of spell)^lpower]*lfactor
//
function SetAbilityFormulaInt takes integer abid, string datafield, integer initial, real lpower, real lfactor returns nothing
local gamecache a=AbiCache()
local string s=I2S(abid)
call StoreInteger(a,s,datafield+"0",initial)
call StoreReal(a,s,datafield+"#fc",lfactor)
call StoreReal(a,s,datafield+"#pw",lpower)
set a=null
endfunction
function SetAbilityFormulaReal takes integer abid, string datafield, real initial, real lpower, real lfactor returns nothing
local gamecache a=AbiCache()
local string s=I2S(abid)
call StoreReal(a,s,datafield+"0",initial)
call StoreReal(a,s,datafield+"#fc",lfactor)
call StoreReal(a,s,datafield+"#pw",lpower)
set a=null
endfunction
//==================================================================================================
// Read the value for a datafield of a spell's level, better keep some local level and spell
// variables to use these.
//
function GetAbilityDataInt takes integer s, integer l , string datafield returns integer
local gamecache a=AbiCache()
local integer r=0
local string sk=I2S(s)
local boolean b=false
local string sl=datafield+I2S(l)
if HaveStoredInteger( a, sk, sl) then
set r=GetStoredInteger( a, sk, sl)
elseif HaveStoredInteger( a, sk, datafield+"0") then
set r=GetStoredInteger( a, sk, datafield+"0")
if HaveStoredReal(a, sk, datafield+"#fc") then
set r=r+ R2I( 0.5+ Pow(l,GetStoredReal(a, sk, datafield+"#pw") )* GetStoredReal(a, sk, datafield+"#fc") )
//0.5 makes it round the value
endif
set b=true
elseif HaveStoredString( a, "funcs", sk ) then
set r=GetStoredInteger( a, GetStoredString( a, "funcs", I2S(s) ), datafield)
set b=true
endif
if (b) then
// This will make it faster next time it is used on the same datafield and levels,
// but slower the first time.
call StoreInteger(a,sk,sl,r)
endif
set a=null
return r
endfunction
//==================================================================================================
function GetAbilityDataReal takes integer s, integer l , string datafield returns real
local gamecache a=AbiCache()
local real r=0
local string sk=I2S(s)
local boolean b=false
local string sl=datafield+I2S(l)
if HaveStoredReal( a, sk, sl) then
set r=GetStoredReal( a, sk, sl)
elseif HaveStoredReal( a, sk, datafield+"0") then
set r=GetStoredReal( a, sk, datafield+"0")
if HaveStoredReal(a, sk, datafield+"#fc") then
set r=r+ Pow(l,GetStoredReal(a, sk, datafield+"#pw") )* GetStoredReal(a, sk, datafield+"#fc")
endif
set b=true
elseif HaveStoredString( a, "funcs", sk ) then
set r=GetStoredReal( a, GetStoredString( a, "funcs", sk ), datafield)
set b=true
endif
if (b) then
// This will make it faster next time it is used on the same datafield and levels,
// but slower the first time.
call StoreReal(a,sk,sl,r)
endif
set a=null
return r
endfunction
//==================================================================================================
function GetAbilityDataString takes integer s, integer l , string datafield returns string
local gamecache a=AbiCache()
local string r=""
local string sk=I2S(s)
if HaveStoredString( a, sk, datafield+I2S(l)) then
set r=GetStoredString( a, sk, datafield+I2S(l))
elseif HaveStoredString( a, sk, datafield+"0") then
set r=GetStoredString( a, sk, datafield+"0")
elseif HaveStoredString( a, "funcs", sk ) then
set r=GetStoredString( a, GetStoredString( a, "funcs", sk ), datafield)
endif
set a=null
return r
endfunction
//##End##
Name | Type | is_array | initial_value |
Armageddon_Caster | unit | Yes | |
Armageddon_Check | boolean | Yes | |
Armageddon_Countdown | timer | Yes | |
Armageddon_Group | group | Yes | |
BUTTON_Main | button | Yes | |
casters | group | No | |
castervars | real | Yes | |
Creep_Position | location | Yes | |
Creep_Type | unitcode | Yes | |
cscache | gamecache | No | |
currentabi | integer | No | |
currentcaster | unit | No | |
currenthurter | unit | No | |
Death_Count | integer | Yes | |
delayhack | real | No | |
DIALOG_Main | dialog | No | |
Difficult_Dialog_Difficulty | dialog | Yes | |
Difficult_TimeLeft | integer | No | |
Difficulty_DialogButton_Easy | button | Yes | |
Difficulty_DialogButton_Hard | button | Yes | |
Difficulty_DialogButton_Medium | button | Yes | |
Difficulty_EasyMediumHard | integer | Yes | |
Difficulty_PlayerHasVote | integer | No | |
Difficulty_PlayerIsPlaying | integer | No | |
Difficulty_Trigger | trigger | Yes | |
FistofHeavenAbilityCastPlace | location | No | |
FistofHeavenLighBallLevel | unitcode | No | |
FistofHeavenLightningBall | unit | Yes | |
FistofHeavenTarget | unit | No | |
Flame_Effect | effect | Yes | |
hss_AvailableHeroes | group | No | |
hss_CreatedHeroTrigger | trigger | No | |
hss_HeroCreation | rect | Yes | |
hss_Heroes | unit | Yes | |
hss_HeroSection | rect | Yes | |
hss_SelectableHeroes | group | No | |
INT_VotesMain | integer | Yes | |
Integer_MBTimer_hours | integer | No | |
Integer_MBTimer_mins | integer | No | |
Integer_MBTimer_secs | integer | No | |
Kill_Count | integer | Yes | |
LEADERBOARD_Kills | leaderboard | No | |
List | integer | No | |
Loop | integer | No | |
Mete_Glow | unit | No | |
Mete_Point | location | No | |
Meteor | unit | No | |
Multiboard_Spots | integer | Yes | |
NumPlayers | integer | No | |
NumVotes | integer | Yes | |
NumVotesNeededToKick | integer | Yes | |
PercentageVotedForKick | real | No | |
Player_Colors | string | Yes | |
Player_Count | integer | No | |
PlayerHasVotedForPlayer | boolean | Yes | |
PlayerWhoMightBeKicked | integer | No | |
PointMultiArrow | location | No | |
REAL_Handicap | real | No | |
RealMultiArrow | real | No | |
sourcehack | location | No | |
spellevents | gamecache | No | |
spelltemplates | gamecache | No | |
UnitMultiArrow | unit | No |
//***************************************************************************************************
//*
//* Shield Template
//*
//* Requires:
//* - A triggerer ability (can be either instant or unit targeteable)
//* - The Caster System 11.4 or greater
//* ( http://vexorian.wc3campaigns.com/ )
//* - The Alternative Spell Templates System
//* - This Trigger
//*
//* Art:
//* - The Triggerer Ability's Special art determines the missile effect
//* - The Triggerer Ability's Target art determines the damage/healing effect
//* - The Triggerer Ability's Effect art keeps spawning at the position of the missiles
//*
//***************************************************************************************************
//===================================================================================================
// Shield Spell Template Configuration:
//
function ShieldTemplateSetup takes nothing returns nothing
local integer D //An integer variable we use later to save the Damage Options so we give them to the templates
local integer s //An integer variable we use later to save the rawcodes of spells to save some time
//===================================================================================================
// Template Info:
//
// Template Name Id = "FireSpawnerTemplate"
// real "mainspeed" if the spell is unit targeteable and non instant, this should match
// the speed of the projectile of the triggerer ability.
// integer "n" is the total number of the shield's missiles
// real "dur" is the game-time duration of the shield's missiles
// real "area" is the acquire range for the missiles
// real "distance" is the distance the missiles take between them and the target
// real "speed" is the movement speed for each missile
// integer "pasN" is the total number of passive skills to add to the missiles.
// integer "pas1id" is #1 passive skill to add
// integer "pas2id" is #2 passive skill to add
// integer "pas...id" is #... passive skill to add (Data is ignored depending of "pasN"
// real "damage" Is the target damage
// real "dmgps" is the damage per movement each of the parts of the shield perform
// real "dmgpsarea" is the amount of damage that each of the missiles is able to perform at a target.
// integer "dmgoptions" The damage options , but In Saveable form ( CreateDamageOptions(<damageoptions>) ) ,
// see the caster system readme for more info, 0 for default. Area damage considers every option
// while target damage only considers attack and damage types.
// integer "spell" is the active spell that each of the missiles is able to cast at a target.
// integer "orderid" is the order id for that spell ( example: OrderId("chainlightning") or 12444234 )
// real "delay" is the time before recicling the caster after it casts the active spell
// for instant spells leave it as 0.
// real "cooldown" is the time before each of the missiles of the shield casts the active
// ability/ causes damage again.
// integer "goodspell" is 1 when the active spell or the damage affects allies,
// and 0 if they affect enemies. ("damage" can be a negative value and
// becomes healing)
// real "maxpercent" is the maximum percentage life a unit can have to become a valid target
// of the active spell and the damage.
// real "minpercent" is the minimum percentage life a unit can have to become a valid target
// of the active spell and the damage.
// integer "nonhero" is 1 if only non heroes can be acquired by the missiles.
// integer "clockwise" is 1 when the missiles go clockwise.
// integer "opposite" is 1 when you want each pair of missiles have opposite directions,
// integer "directmove" is 1 when the missiles are instantly moved instead of using orders
// integer "fromfacing" determines if the missiles move depending on the facing angle of the target
//
// The template tries to match the level of the castable and addable abilities to the level
// of the triggerer ability.
//
//===================================================================================================
// Shield Template Defaults:
//
call SetTemplateDefaultReal("ShieldTemplate","speed" ,400) //Shield bolt speed is 400 by default
call SetTemplateDefaultReal("ShieldTemplate","distance" ,150) //Distance between bolts and casters is 100 by default
call SetTemplateDefaultReal("ShieldTemplate","maxpercent",100) //Maximum Life Percentage required to make a bolt do something is 100% by default
call SetTemplateDefaultReal("ShieldTemplate","minpercent",0) //Mininmum Life Percentage required to make a bolt do something is 0% by default
call SetTemplateDefaultReal("ShieldTemplate","height" ,120) //Height of the shield bolts is 120 by default
call SetTemplateDefaultReal("ShieldTemplate","mainspeed" ,100) //Speed of projectile is 100 by default
//===================================================================================================
// Shield of divinity ('A01C')
//
// This was the original spell, this template was based on, to see the skill, Give the hero
// ability "Shield of divinity" to a hero and test the map)
//
set s=SetSpellTemplate('A01C',"ShieldTemplate")
set D=0 //Shield of divinity damage Options :
set D=DamageTypes(ATTACK_TYPE_CHAOS,DAMAGE_TYPE_DIVINE) //Chaos Divine damage
set D=CreateDamageOptions(D) //Save the damage options
call SetAbilityDataInt( s,"n", 1, 5 ) //Level 1: 5 bolts
call SetAbilityDataInt( s,"n", 2, 6 ) //Level 2: 6 bolts
call SetAbilityDataInt( s,"n", 3, 7 ) //Level 3: 7 bolts
call SetAbilityDataReal(s,"dur", 1, 52 ) //Level 1: Lasts 52 seconds
call SetAbilityDataReal(s,"dur", 2, 59 ) //Level 2: Lasts 59 seconds
call SetAbilityDataReal(s,"dur", 3, 66 ) //Level 3: Lasts 66 seconds
call SetAbilityDataReal(s,"area", 0, 300 ) //Target acquire area is 300
call SetAbilityDataReal(s,"damage", 1, -200) //Level 1: Heals 200 hp
call SetAbilityDataReal(s,"damage", 2, -300) //Level 2: Heals 300 hp
call SetAbilityDataReal(s,"damage", 3, -400) //Level 3: Heals 400 hp
call SetAbilityDataReal(s,"dmgoptions",0,D) //Using damage options D
call SetAbilityDataInt( s,"goodspell", 0, 1 ) //This is a positive spell
call SetAbilityDataReal(s,"maxpercent",0, 50 ) //Maximum percentage life required is 50%
//===================================================================================================
// Thor's Shield ('A01D')
//
set s=SetSpellTemplate('A01D',"ShieldTemplate")
call SetAbilityDataInt( s,"n" ,1,6 ) //Level 1: 6 Bolts
call SetAbilityDataInt( s,"n" ,2,8 ) //Level 2: 8 bolts
call SetAbilityDataInt( s,"n" ,3,10 ) //Level 3:10 Bolts
call SetAbilityDataReal(s,"dur" ,1,30 ) //Level 1: Lasts 30 seconds
call SetAbilityDataReal(s,"dur" ,2,50 ) //Level 2: Lasts 50 seconds
call SetAbilityDataReal(s,"dur" ,3,70 ) //Level 3: Lasts 70 seconds
call SetAbilityDataReal(s,"area" ,1,300) //Level 1: Target acquire area is 300
call SetAbilityDataReal(s,"area" ,2,400) //Level 2: Target acquire area is 400
call SetAbilityDataReal(s,"area" ,3,500) //Level 3: Target acquire area is 500
call SetAbilityDataReal(s,"distance",2,200) //Level 2: Distance between bolts and caster=200
call SetAbilityDataReal(s,"distance",3,250) //Level 3: Distance between bolts and caster=250
call SetAbilityDataReal(s,"cooldown",1,10 ) //Level 1: 10 seconds cooldown, for target acquire
call SetAbilityDataReal(s,"cooldown",2,8 ) //Level 2: 8 seconds cooldown, for target acquire
call SetAbilityDataReal(s,"cooldown",3,6 ) //Level 3: 6 seconds cooldown, for target acquire
call SetAbilityDataInt( s,"spell", 0,'A01E') //On target acquire cast ability A01E
call SetAbilityDataInt( s,"orderid", 0,OrderId("chainlightning") ) //Its orderid is chain lightning
call SetAbilityDataReal(s,"delay", 0,5 ) //Wait 0.5 seconds before recycling the caster
call SetAbilityDataInt( s,"opposite",0,1 ) //Half of the bolts move in opposite direction
//===================================================================================================
// Flaming Shield ('A01S')
//
set s=SetSpellTemplate('A01F',"ShieldTemplate")
call SetAbilityDataInt( s,"n", 0, 3 ) //Number of balls=3
call SetAbilityDataReal(s,"dur", 0, 60 ) //Lasts 60 seconds
call SetAbilityDataInt( s,"clockwise", 0, 1 ) //Make the balls move clockwise
call SetAbilityDataInt( s,"pasN", 0, 1 ) //Number of passive abilities added is 1
call SetAbilityDataInt( s,"pas1id", 1, 'A01G') //Level 1: Add ability A01G
call SetAbilityDataInt( s,"pas1id", 2, 'A01H') //Level 2: Add ability A01H
call SetAbilityDataInt( s,"pas1id", 3, 'A01I') //Level 3: Add ability A01I
call SetAbilityDataReal(s,"maxpercent",0, 0) //Causes the spell to ignore the acquiring targets part
call SetAbilityDataReal(s,"mainspeed", 0, 750) //Projectile speed of the ability is 750
//===================================================================================================
// Plague Shield ('A01K')
//
set s=SetSpellTemplate('A01K',"ShieldTemplate")
call SetAbilityDataInt( s,"n", 0,6 ) //Number of bolts=6
call SetAbilityDataReal(s,"dur", 1,52 ) //Level 1:Duration=52 seconds
call SetAbilityDataReal(s,"dur", 2,59 ) //Level 2:Duration=59 seconds
call SetAbilityDataReal(s,"dur", 3,66 ) //Level 3:Duration=66 seconds
call SetAbilityDataReal(s,"area", 0,600) //Minimum target acquire range of 600 seconds
call SetAbilityDataReal(s,"distance", 0,300) //Distance of bolts and caster is 300
call SetAbilityDataInt( s,"goodspell", 0,1) //This is actually a possitive spell
call SetAbilityDataReal(s,"maxpercent",0,20) //Maximum hp required on target to affect it = 20%
call SetAbilityDataInt( s,"spell" ,0,'A01J') //When a target is acquired cast A01J on it
call SetAbilityDataInt( s,"orderid" ,0,OrderId("doom")) //Orderid of that ability is doom
call SetAbilityDataReal(s,"delay" ,0,2) //Wait 2 seconds before recycling the caster
call SetAbilityDataInt( s,"pasN" ,0,1) //One passive skill is added
call SetAbilityDataInt( s,"pas1id" ,0,'A000') //The ability added is A000
call SetAbilityDataInt( s,"nonhero" ,0,1) //This would only work on non-hero units
//===================================================================================================
// Thunder Shield ('A01L')
//
set s=SetSpellTemplate('A01L',"ShieldTemplate")
set D=0 //Thunder shield damage options:
set D=DamageTypes(ATTACK_TYPE_CHAOS,DAMAGE_TYPE_LIGHTNING) //Chaos Divine damage
set D=D+DamageException(UNIT_TYPE_STRUCTURE,0.5) //Do 50% damage to buildings
set D=CreateDamageOptions(D) //Save the damage options
call SetAbilityDataInt( s,"n", 0, 2 ) //2 shield bolts
call SetAbilityDataReal(s,"dmgps", 0, 20) //20 damage per second
call SetAbilityDataReal(s,"dmgpsarea", 0, 75) //Over an area of 75
call SetAbilityDataReal(s,"dmgoptions",0,D) //Using damage options D
call SetAbilityDataReal(s,"dur", 0, 15) //Lasts 15 seconds
call SetAbilityDataReal(s,"maxpercent",0, 0 ) // Causes the spell to ignore the acquiring targets part
call SetAbilityDataInt( s,"opposite", 0, 1 ) //1 of the bolts moves on the opposite direction
call SetAbilityDataInt( s,"directmove",0, 1 ) //The movement of the bolts is instant
call SetAbilityDataInt( s,"fromfacing",0, 1 ) //Position of the bolts is based on the caster's facing
call SetAbilityDataReal(s,"height", 0, 0 ) //Height of the bolts is 0 (they are on the ground)
call SetAbilityDataReal(s,"distance", 0, 75) //Distance between bolts and caster=75
//===================================================================================================
// Ability Preloading
//
// Next is unrelated to the templates system, just avoids the first time cast lag, here you
// should preload any ability used as auxiliar ability for the template, just to avoid first
// time cast lag.
//
call PreloadAbility('A000')
call PreloadAbility('A00G')
call PreloadAbility('A00H')
call PreloadAbility('A00I')
call PreloadAbility('A00E')
endfunction
//===================================================================================================
// code:
//
function ShieldTemplate_Going takes nothing returns nothing
local unit u=udg_currentcaster
local unit t=bj_lastCreatedUnit
local integer s=udg_currentabi
local integer l=R2I( udg_castervars[10] )
local integer b=GetAbilityDataInt(s,l,"pasN")
local effect fx=bj_lastCreatedEffect
local group ignore=bj_groupRemoveGroupDest
local integer abi=GetAbilityDataInt(s,l,"spell")
local integer dopts=GetAbilityDataInt(s,l,"dmgoptions")
local gamecache g=CSCache()
call UnitMoveToUnitAsProjectile( u, 0.1, t, 30)
call DestroyEffect( AddSpellEffectTargetById( s, EFFECT_TYPE_TARGET, t, "origin" ) )
call DamageUnitByOptions(u,t,GetAbilityDataReal(s,l,"damage"),LoadDamageOptions(dopts))
call GroupRemoveUnit(ignore, t)
call DestroyEffect(fx)
if abi!=0 then
call UnitAddAbility( u, abi)
call SetUnitAbilityLevel(u,abi,l)
call IssueTargetOrderById( u, GetAbilityDataInt(s,l,"orderid"), t)
endif
loop
exitwhen b==0
call UnitRemoveAbility( u , GetAbilityDataInt(s,l,"pas"+I2S(b)+"id") )
set b=b-1
endloop
call PolledWait( RMaxBJ( GetAbilityDataReal(s,l,"delay") , 5) )
call UnitRemoveAbility(u, abi)
call RecicleCaster(u)
set g=null
set u=null
set t=null
set fx=null
set ignore=null
endfunction
function ShieldTemplate takes nothing returns nothing
local unit caster=GetTriggerUnit()
local unit target
local unit array elec
local effect array fx
local timer t=CreateTimer()
local real grad=0
local integer s=GetSpellAbilityId()
local integer l=GetUnitAbilityLevel(caster, s)
local integer a=0
local integer b=0
local integer n=GetAbilityDataInt(s,l,"n")
local real waitt=0
local group ignore=CreateGroup()
local group tolight=CreateGroup()
local unit picked
local integer abiN=GetAbilityDataInt(s,l,"pasN")
local integer array pass
local boolean good=GetAbilityDataInt(s,l,"goodspell") == 1
local real min=GetAbilityDataReal(s,l,"minpercent")
local real max=GetAbilityDataReal(s,l,"maxpercent")
local real area=GetAbilityDataReal(s,l,"area")
local real height=GetAbilityDataReal(s,l,"height")
local real x
local real y
local real dist=GetAbilityDataReal(s,l,"distance")
local boolean opposite=GetAbilityDataInt( s,l, "opposite")==1
local boolean clockwise=GetAbilityDataInt( s,l, "clockwise")==1
local boolean fromfacing=GetAbilityDataInt( s,l, "fromfacing")==1
local real angle
local integer dmgid=GetAbilityDataInt(s,l,"dmgoptions")
local real dmgps=GetAbilityDataReal(s,l,"dmgps")
if GetSpellTargetUnit() == null then
set target=caster
else
set target=GetSpellTargetUnit()
call PolledWait( SquareRoot( Pow( GetUnitX(target)-GetUnitX(caster),2) + Pow( GetUnitY(target)-GetUnitY(caster),2) ) /GetAbilityDataReal(s,l,"mainspeed") )
endif
set b=abiN
loop
exitwhen b==0
set pass[b]=GetAbilityDataInt(s,l,"pas"+I2S(b)+"id")
set b=b-1
endloop
call TimerStart( t, GetAbilityDataReal(s,l,"dur"), false, null)
set a=0
loop
exitwhen a>=n
set elec[a]=GetACaster()
set fx[a]= AddSpellEffectTargetById( s, EFFECT_TYPE_SPECIAL,elec[a],"origin")
call SetUnitOwner( elec[a], GetOwningPlayer(caster), true)
call SetUnitPosition( elec[a], GetUnitX(target), GetUnitY(target) )
call SetUnitMoveSpeed( elec[a],GetAbilityDataReal(s,l,"speed"))
call SetUnitFlyHeight( elec[a],height,0)
set b=abiN
loop
exitwhen b==0
call UnitAddAbility(elec[a],pass[a])
call SetUnitAbilityLevel(elec[a],pass[a],l)
set b=b-1
endloop
set a=a+1
endloop
loop
exitwhen (TimerGetRemaining(t)<=0) or (IsUnitDeadBJ(target)) or n <= 0
call TriggerSleepAction(0)
set a=0
set bj_groupEnumOwningPlayer=GetOwningPlayer(caster)
call GroupClear(tolight)
call GroupEnumUnitsInRange( tolight, GetUnitX(target), GetUnitY(target), area, null )
loop
set picked=FirstOfGroup(tolight)
exitwhen a>=n or picked==null or TimerGetElapsed(t) <= waitt
if IsUnitDeadBJ(picked) then
elseif good and not( IsUnitAlly(picked, GetOwningPlayer(caster)) ) then
elseif IsUnitType(picked,UNIT_TYPE_HERO) and GetAbilityDataInt( s,l, "nonhero")==1 then
elseif not(good) and not(IsUnitEnemy(picked, GetOwningPlayer(caster)) ) then
elseif IsUnitInGroup(picked,ignore) then
elseif GetUnitLifePercent(picked) > max or GetUnitLifePercent(picked) < min then
else
set bj_lastCreatedEffect=fx[a]
set bj_lastCreatedUnit=picked
set udg_currentcaster=elec[a]
call GroupRemoveUnit( tolight, picked)
call GroupAddUnit( ignore, picked)
set udg_currentabi=s
set udg_castervars[10]=l
set bj_groupRemoveGroupDest=ignore
call ExecuteFunc("ShieldTemplate_Going")
set waitt=TimerGetElapsed(t)+GetAbilityDataReal(s,l,"cooldown")
set elec[a]=elec[n-1]
set elec[n-1]=null
set fx[a]=fx[n-1]
set fx[n-1]=null
set n=n-1
endif
call GroupRemoveUnit( tolight, picked)
endloop
loop
exitwhen a>=n
if opposite then
if ModuloInteger(a,2) == 1 then
set angle=-( grad+(a-1)*360/n )
else
set angle=grad+a*360/n
endif
else
set angle=grad+a*360/n
endif
if clockwise then
set angle=-angle
endif
if fromfacing then
set angle=GetUnitFacing(target)+angle
endif
set x=GetUnitX(target)+dist*CosBJ(angle)
set y=GetUnitY(target)+dist*SinBJ(angle)
if GetAbilityDataInt(s,l,"directmove") == 1 or SquareRoot( Pow(x-GetUnitX(elec[a]),2) + Pow(y-GetUnitY(elec[a]),2) ) >= 1000 then
call SetUnitPosition(elec[a], x, y)
else
call IssuePointOrder(elec[a],"smart", x,y)
endif
call DestroyEffect( AddSpellEffectById( s,EFFECT_TYPE_EFFECT, GetUnitX(elec[a]), GetUnitY(elec[a]) ) )
if dmgps!=0 then
call DamageUnitsInAOEEx(caster, dmgps, GetUnitX(elec[a]), GetUnitY(elec[a]), GetAbilityDataReal(s,l,"dmgpsarea"), false,LoadDamageOptions(dmgid))
endif
set a=a+1
endloop
set grad = ModuloReal(grad+30,360)
endloop
call DestroyTimer(t)
call DestroyGroup(tolight)
call DestroyGroup(ignore)
set t=null
set tolight=null
set a=0
set udg_delayhack=5
loop
exitwhen a>=n
call DestroyEffect( fx[a] )
set b=abiN
loop
exitwhen b==0
call UnitRemoveAbility( elec[a], pass[b] )
set b=b-1
endloop
call RecicleCasterAfterCast(elec[a],0)
set fx[a]=null
set elec[a]=null
set a=a+1
endloop
set udg_delayhack=0
set ignore=null
set caster=null
set target=null
endfunction
function InitTrig_Shield_Template takes nothing returns nothing
call ExecuteFunc("ShieldTemplateSetup")
//Must use ExecuteFunc to prevent the Map init thread from getting too long and crash.
endfunction
//********************************************************************************************************
//*
//* Frozen Orb
//* ¯¯¯¯¯¯¯¯¯¯
//* Requires:
//*
//* - The Frozen Orb ability
//* - The Frozen Orb Freezing ability, should have as many levels as the frozen orb one
//* - The Caster System ( http://vexorian.wc3campaigns.com/ )
//* - This Trigger (MAKE SURE TO change the rawcodes in the triggers to the correct ones of
//* your map)
//* Notes:
//* - The Ability's First Special art is the main orb model
//* - The Ability's Second Special art is the bolt model
//*
//********************************************************************************************************
//========================================================================================================
// Frozen Orb Spell Configuration
//
constant function FrozenOrb_SpellId takes nothing returns integer
return 'A01O' //* Change this to match the rawcode of the Frozen Orb ability in your map
endfunction
constant function FrozenOrb_FreezeSpellId takes nothing returns integer
return 'A01P' //* Change this to match the rawcode of the Frozen Orb Freezing ability in your map
endfunction
constant function FrozenOrb_Damage takes real level returns real
return 15+15*level //* The single target damage by level formula
endfunction
function FrozenOrb_ImpactOptions takes integer level returns integer
return DamageOnlyEnemies() + DamageIgnore(UNIT_TYPE_FLYING)
//
// Options for impact (if the resulting damage factor is 0, they won't impact, then
// they won't do damage either) This allows you to have units that will get the impact of the shards
// without getting damaged/ freezed.
//
// Will only impact on non-flying enemies.
//
endfunction
function FrozenOrb_DamageOptions takes integer level returns integer
return DamageTypes(ATTACK_TYPE_NORMAL,DAMAGE_TYPE_COLD)
//
// Options for damage
//
// Will do cold spell damage, other damage options can be put, check caster system
// readme for more information, if damage is 0 freeze won't be used.
//
endfunction
constant function FrozenOrb_FinalBoltNumber takes integer level returns integer
return 8+5*level //* The number of bolts shoot at the end of the orb or when an unit is hit by it, (in a huge spiral)
endfunction
constant function FrozenOrb_OrbSpeed takes nothing returns real
return 500.0 //* The Speed of the orb
endfunction
constant function FrozenOrb_BoltSpeed takes nothing returns real
return 750.0 //* The Speed of the bolts
endfunction
constant function FrozenOrb_OrbDuration takes real level returns real
return 1.5+0.5*level //* The duration of the orb
endfunction
constant function FrozenOrb_BoltDuration takes real level returns real
return 0.75+level*0 //* The duration of each bolt
endfunction
constant function FrozenOrb_ImpactRange takes real level returns real
return 55+level*0 //* How close a bolt must be of an unit to impact against it. or how close it must be to the orb to make it strike the spiral.
endfunction
constant function FrozenOrb_Order takes nothing returns string
return "frostnova" //* The order string of the freezing ability (changing this would allow you to make
// the ability do something different than freezing)
endfunction
constant function FrozenOrb_BoltScale takes real level returns real
return 0.75+level*0 //* The scale of each bolt
endfunction
constant function FrozenOrb_OrbScale takes real level returns real
return 1.25+level*0 //* The scale of the orb
endfunction
constant function FrozenOrb_DirInc takes real level returns real
return 85+level*0 //* The orb's turn rate and bolt spawn direction change (by bolt spawn interval)
endfunction
constant function FrozenOrb_BoltSpawnInterval takes real level returns real
return 0.03-level*0 //*** The Spawn interval between creating each bolt.
endfunction
constant function FrozenOrb_Timer takes nothing returns real
return 0.05
//*** This is the timer period, a low value (0.01) will look better but will be worse lag wise, a high
// value (1.0) would be faster lag wise but will surelly look bad. I think 0.05 is perfect.
endfunction
constant function FrozenOrb_MissileEffects takes nothing returns effecttype
return EFFECT_TYPE_SPECIAL
endfunction
//========================================================================================================
function Trig_Frozen_Orb_Conditions takes nothing returns boolean
return (GetSpellAbilityId() == FrozenOrb_SpellId())
endfunction
function FrozenOrb_BoltEnd takes unit m, unit u, integer l, trigger t returns nothing
local real x
local unit d
call DestroyEffect(GetAttachedEffect(m,"fx"))
if u!=null then
set d=GetAttachedUnit(m,"u")
set x=GetDamageFactorByOptions(d,u,FrozenOrb_DamageOptions(l))
if (x!=0) then
call UnitDamageTarget(d,u,FrozenOrb_Damage(l)*x,true,false,null,null,null)
call CasterCastAbilityLevel(GetOwningPlayer(m),FrozenOrb_FreezeSpellId(),l,FrozenOrb_Order(),u,true)
endif
endif
call GroupRemoveUnit(GetAttachedGroup(m,"g"),m)
call CleanAttachedVars(m)
call ExplodeUnitBJ(m)
call TriggerRemoveAction(t,GetAttachedTriggerAction(t,"ac"))
call CleanAttachedVars(t)
call DestroyTrigger(t)
set d=null
endfunction
function FrozenOrb_BoltImpact takes nothing returns nothing
local trigger t=GetTriggeringTrigger()
local unit u=GetTriggerUnit()
local unit m=GetAttachedUnit(t,"b")
local integer l=GetAttachedInt(m,"l")
if (GetDamageFactorByOptions(m,u,FrozenOrb_ImpactOptions(l))!=0) then
call FrozenOrb_BoltEnd(m,u,l,t)
endif
set t=null
set u=null
set m=null
endfunction
function FrozenOrb_Bolt takes unit u, integer l, real x, real y, real f, group g, real in returns nothing
local unit b=AddCasterFacing(f)
local trigger t=CreateTrigger()
call SetUnitPosition(b,x,y)
set x=FrozenOrb_BoltScale(l)
call SetUnitScale(b,x,x,x)
call SetUnitFlyHeight(b,200,0)
call AttachObject(b,"fx",AddSpecialEffectTarget(GetAbilityEffectById(FrozenOrb_SpellId(),FrozenOrb_MissileEffects(),1),b,"origin" ))
call AttachObject(b,"u",u)
call SetUnitOwner(b,GetOwningPlayer(u),true)
call GroupAddUnit(g,b)
call AttachReal(b,"inc",in)
call TriggerRegisterUnitInRange(t,b,FrozenOrb_ImpactRange(l),null)
call AttachObject(t,"ac",TriggerAddAction(t,function FrozenOrb_BoltImpact))
call AttachObject(t,"b",b)
call AttachObject(b,"t",t)
call AttachObject(b,"g",g)
call AttachInt(b,"l",l)
set t=null
set b=null
endfunction
function FrozenOrb_Final takes unit m,integer l,timer t,group g returns nothing
local real d
local integer n=FrozenOrb_FinalBoltNumber(l)
local integer i=0
local real x=GetUnitX(m)
local real y=GetUnitY(m)
local unit ow=GetAttachedUnit(m,"u")
call DestroyEffect(GetAttachedEffect(m,"fx"))
call AttachBoolean(t,"sp",true)
loop
exitwhen i>=n
set d=((360.0*i)/n)
call FrozenOrb_Bolt(ow,l,x,y,d,g,20)
set i=i+1
endloop
call CleanAttachedVars(m)
call ExplodeUnitBJ(m)
set ow=null
endfunction
function FrozenOrb_OrbMov takes unit m,integer l, timer t,group g returns boolean
local real x=GetUnitX(m)
local real y=GetUnitY(m)
local real f=GetAttachedReal(t,"f")*bj_DEGTORAD
local real d=FrozenOrb_OrbSpeed()*FrozenOrb_Timer()
local real nx=x+d*Cos(f)
local real ny=y+d*Sin(f)
call SetUnitPosition(m,nx,ny)
if (SquareRoot(Pow(nx-GetUnitX(m),2)+Pow(ny-GetUnitY(m),2))>10) then
call FrozenOrb_Final(m,l,t,g)
return false
endif
return true
endfunction
function FrozenOrb_Mov takes nothing returns nothing
local timer t=GetExpiredTimer()
local group g=GetAttachedGroup(t,"g")
local group a=CreateGroup()
local unit m
local real f
local real inc
local real x
local real y
local real nx
local real ny
local integer tms
local real d=FrozenOrb_BoltSpeed()*FrozenOrb_Timer()
local integer l=GetAttachedInt(t,"l")
local real next=GetAttachedReal(t,"next")
local real elaps=GetAttachedReal(t,"elaps")+FrozenOrb_Timer()
local real dir
if not(GetAttachedBoolean(t,"sp")) then
set m=GetAttachedUnit(t,"u")
if FrozenOrb_OrbMov(m,l,t,g) then
call AttachReal(t,"elaps",elaps)
if (GetAttachedReal(t,"next")<=GetAttachedReal(t,"elaps")) then
call AttachReal(t,"next",elaps+FrozenOrb_BoltSpawnInterval(l))
set dir = GetAttachedReal(t,"dir")+FrozenOrb_DirInc(l)
call SetUnitFacing(m,dir)
call FrozenOrb_Bolt(GetAttachedUnit(m,"u"),l,GetUnitX(m),GetUnitY(m),dir,g,10)
call AttachReal(t,"dir",dir)
endif
endif
endif
call GroupAddGroup(g,a)
loop
set m=FirstOfGroup(a)
exitwhen m==null
set inc=GetAttachedReal(m,"inc")
if inc<=0 then
set inc=0
endif
set f=GetUnitFacing(m)+inc
set x=GetUnitX(m)
set y=GetUnitY(m)
if (inc>0) then
call AttachReal(m,"inc",inc-2)
endif
call SetUnitFacing(m,f)
set f=f*bj_DEGTORAD
set nx=x+d*Cos(f)
set ny=y+d*Sin(f)
call SetUnitPosition(m,nx,ny)
set tms=GetAttachedInt(m,"tms")+1
if (tms*FrozenOrb_Timer()>=FrozenOrb_BoltDuration(l)) or (SquareRoot(Pow(nx-GetUnitX(m),2)+Pow(ny-GetUnitY(m),2))>10) then
call FrozenOrb_BoltEnd(m,null,l,GetAttachedTrigger(m,"t"))
else
call AttachInt(m,"tms",tms)
endif
call GroupRemoveUnit(a,m)
endloop
if GetAttachedBoolean(t,"mainended") and (FirstOfGroup(g)==null) then
call CleanAttachedVars(t)
call DestroyGroup(g)
call DestroyTimer(t)
endif
call DestroyGroup(a)
set t=null
set g=null
set a=null
set m=null
endfunction
function Trig_Frozen_Orb_Actions takes nothing returns nothing
local unit u=GetTriggerUnit()
local integer s=GetSpellAbilityId()
local integer l=GetUnitAbilityLevel(u,s)
local location loc=GetSpellTargetLoc()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
local real f=Atan2BJ(GetLocationY(loc)-y,GetLocationX(loc)-x)
local unit m=AddCasterFacing(f)
local timer t=CreateTimer()
local group g=CreateGroup()
call SetUnitPosition(m,x,y)
set x=FrozenOrb_OrbScale(l)
call SetUnitScale(m,x,x,x)
call AttachInt(t,"l",l)
call AttachObject(m,"u",u)
call AttachObject(m,"g",g)
call SetUnitFlyHeight(m,200,0)
call AttachReal(t,"dir",ModuloReal(-f,360))
call AttachInt(m,"l",l)
call AttachObject( m,"fx",AddSpellEffectTargetById(s,FrozenOrb_MissileEffects(),m,"origin"))
call SetUnitOwner(m,GetOwningPlayer(u),true)
call RemoveLocation(loc)
call AttachObject(t,"u",m)
call AttachReal(t,"f",f)
call AttachObject(t,"g",g)
call TimerStart(t,FrozenOrb_Timer(),true,function FrozenOrb_Mov)
call PolledWait(FrozenOrb_OrbDuration(l))
if not(GetAttachedBoolean(t,"sp")) then
call FrozenOrb_Final(m,l,t,g)
endif
call AttachBoolean(t,"mainended",true)
set u=null
set loc=null
set m=null
set t=null
set g=null
endfunction
//========================================================================================================
function InitTrig_Frozen_Orb takes nothing returns nothing
local integer s=FrozenOrb_FreezeSpellId()
call PreloadAbility(s)
call Preload(GetAbilityEffectById(s,FrozenOrb_MissileEffects(),0))
call Preload(GetAbilityEffectById(s,FrozenOrb_MissileEffects(),1))
call Preload(GetAbilityEffectById(s,EFFECT_TYPE_CASTER,0))
set gg_trg_Frozen_Orb = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Frozen_Orb, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Frozen_Orb, Condition( function Trig_Frozen_Orb_Conditions ) )
call TriggerAddAction( gg_trg_Frozen_Orb, function Trig_Frozen_Orb_Actions )
endfunction
//********************************************************************************************************
//*
//* ArticBlast
//* ¯¯¯¯¯¯¯¯¯¯
//* Requires:
//* - The ArticBlast Ability
//* - The ArticBlast Slow Ability
//* - The ArticBlast Freezing Ability
//* - The Caster System ( http://vexorian.wc3campaigns.com/ ) (11.8 or greater)
//* - This Trigger (MAKE SURE TO change the rawcodes in the trigger to
//* the correct ones of your map)
//* Notes:
//* - The Ability's Caster art often appears on the caster
//* - The Ability's Second Caster art field is the attachment point of the caster art.
//* - The Ability's Missile art field is the bolt model
//* - The Ability's Target art appears on the affected units.
//* - The Ability's Second Target art field is the attachment point of the target art.
//*
//********************************************************************************************************
//========================================================================================================
// ArticBlast Spell Configuration:
//
constant function ArticBlast_SpellId takes nothing returns integer
return 'A01J' //ArticBlast's ability Rawcode in your map
endfunction
//
constant function ArticBlast_SpellToCast1_Id takes integer level returns integer
return 'A01H'
//Rawcode of the first ability to cast, in this case 'Artic Blast freezing'
//Use 0 if you don't want it to cast this spell
endfunction
//
constant function ArticBlast_SpellToCast2_Id takes integer level returns integer
return 'A01I'
//Rawcode of the Second ability to cast, in this case 'Artic Blast Slow'
//Use 0 if you don't want it to cast this spell
endfunction
//
constant function ArticBlast_SpellToCast1_OrderId takes integer level returns integer
return OrderId("frostnova") //OrderId of the first ability to cast
endfunction
//
constant function ArticBlast_SpellToCast2_OrderId takes integer level returns integer
return OrderId("cripple") //OrderId of the second ability to cast
endfunction
//
constant function ArticBlast_SpellToCast1_RecycleDelay takes integer level returns integer
return 0 //Caster Recycle delay of the first ability to cast
endfunction
//
constant function ArticBlast_SpellToCast2_RecycleDelay takes integer level returns integer
return 0 //Caster Recycle delay of the second ability to cast
endfunction
//
constant function ArticBlast_LaunchInterval takes real level returns real
return 0.105-0*level //The period of time between each bolt launch
endfunction
//
constant function ArticBlast_ManaDrainPerLaunch takes real level returns real
return 0.4+level*0.2 //Mana drained per bolt launch
endfunction
//
constant function ArticBlast_BufferMana takes real level returns real
return 9+2*level //The minimum mana the caster has to have to continue casting ArticBlast
endfunction
//
constant function ArticBlast_Scale takes real level returns real
return 0.9+0.1*level //The scale of the bolts
endfunction
//
constant function ArticBlast_MaxTurnAngle takes real level returns real
return 2+0*level //The maximum angle changed per 0.05 seconds (when changing the direction)
endfunction
//
constant function ArticBlast_Speed takes real level returns real
return 700+0*level //The speed of the bolts
endfunction
//
constant function ArticBlast_Area takes real level returns real
return 300+50*level //The area of effect of the spell, aka max distance the bolts can move.
endfunction
//
constant function ArticBlast_MaxLaunchDistVariation takes real level returns real
return 100.0-0*level //The maximum variation of distance for the initial position of the bolts
endfunction
//
constant function ArticBlast_MaxLaunchAngleVariation takes real level returns real
return 45.0-0*level //The maximum variation of angular position for the initial position of the bolts
endfunction
//
constant function ArticBlast_Damage takes real level returns real
return 5+2.5*level //Damage done by each bolt
endfunction
//
constant function ArticBlast_BoltCollisionSize takes real level returns real
return 75+10*level //Collision size of the bolts (how close an unit must be to the bolt to get damage)
endfunction
//
constant function ArticBlast_TargetEffectCooldown takes nothing returns real
return 0.5 //The cooldown of the target effect spawn
endfunction
//
constant function ArticBlast_EffectDeadAnimationTime takes nothing returns real
return 0.5 //The duration of the missile effect's dead animation
endfunction
//
function ArticBlast_DamageOptions takes integer level returns integer
return DamageTypes(ATTACK_TYPE_CHAOS,DAMAGE_TYPE_FIRE)+DamageOnlyEnemies()
//
// Does chaos damage that only affects enemy units.
//
// Other damage options can be used, and the ones here changed, check caster system's readme
// for more information
//
endfunction
//
constant function ArticBlast_Order takes nothing returns integer
return OrderId("monsoon")
//
// The order id of the ability used as base ability, not important if you just copied the ability in the
// map, but if you needed to have it based on let's say, blizzard, just replace that here.
//
endfunction
//
constant function ArticBlast_EnableAI takes nothing returns boolean
return true
//
// When it is true, non human player owned units that cast this spell will use a special AI encoded here
// that will allow them to use ArticBlast in a clever way, rather than just staying on a line of
// as they usually do, to test the AI try facing the bloodmage on the top left zone of this map.
//
endfunction
//==================================================================================================
function Trig_ArticBlast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == ArticBlast_SpellId()
endfunction
function ArticBlast_AngleCalc 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
function ArticBlast_AngleTurning takes nothing returns nothing
local timer t=GetExpiredTimer()
local real f=GetAttachedReal(t,"f")
local real c=GetAttachedReal(t,"c")
local real x=ArticBlast_AngleCalc(c,f,ArticBlast_MaxTurnAngle(GetAttachedInt(t,"l")))
call AttachReal(GetAttachedTrigger(t,"t"),"f",x)
call AttachReal(t,"c",x)
if ModuloReal(x,360)==ModuloReal(f,360) then
call AttachBoolean(GetAttachedTrigger(t,"t"),"hasturntimer",false)
call CleanAttachedVars(t)
call DestroyTimer(t)
endif
set t=null
endfunction
function ArticBlast_PrepareAngleTurning takes trigger t, real c, real f returns nothing
local timer x=CreateTimer()
call AttachObject(x,"t",t)
call AttachReal(x,"f",f)
call AttachReal(x,"c",c)
call AttachObject(t,"turntimer",x)
call AttachReal(t,"f",c)
call AttachBoolean(t,"hasturntimer",true)
call TimerStart(x,0.04,true,function ArticBlast_AngleTurning)
set x=null
endfunction
function ArticBlast_ResetFX takes nothing returns nothing
local timer x=GetExpiredTimer()
call AttachBoolean(GetAttachedUnit(x,"u"),"ArticBlast_IgnoreFX",false)
set x=null
endfunction
function ArticBlast_Spells takes unit o, unit u, integer l returns nothing
local player p=GetOwningPlayer(o)
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if (ArticBlast_SpellToCast1_Id(l)!=0) then
call CasterCastAbilityEx(p,x,y,0,ArticBlast_SpellToCast1_Id(l),l,I2S(ArticBlast_SpellToCast1_OrderId(l)),u,ArticBlast_SpellToCast1_RecycleDelay(l))
endif
if (ArticBlast_SpellToCast2_Id(l)!=0) then
call CasterCastAbilityEx(p,x,y,0,ArticBlast_SpellToCast2_Id(l),l,I2S(ArticBlast_SpellToCast2_OrderId(l)),u,ArticBlast_SpellToCast2_RecycleDelay(l))
endif
set p=null
endfunction
function ArticBlast_BoltImpact takes nothing returns nothing
local unit m=GetTriggerCollisionMissile()
local unit o=GetAttachedUnit(m,"u")
local unit u=GetTriggerUnit()
local integer l
local integer s
local real f
local timer x
if (u!=null) then
set l=GetAttachedInt(m,"l")
set f=GetDamageFactorByOptions(o,u,ArticBlast_DamageOptions(l))
if f!=0 then
set s=ArticBlast_SpellId()
if not(GetAttachedBoolean(u,"ArticBlast_IgnoreFX")) then
call DestroyEffect(AddSpellEffectTargetById(s,EFFECT_TYPE_TARGET,u,GetAbilityEffectById(s,EFFECT_TYPE_TARGET,1)))
call AttachBoolean(u,"ArticBlast_IgnoreFX",true)
set x=CreateTimer()
call AttachObject(x,"u",u)
call TimerStart(x,ArticBlast_TargetEffectCooldown(),false,function ArticBlast_ResetFX)
set x=null
endif
call UnitDamageTarget(o,u,ArticBlast_Damage(l)*f,true,false,null,null,null)
call ArticBlast_Spells(o,u,l)
endif
endif
set u=null
set m=null
set o=null
endfunction
function ArticBlast_Launch takes boolean cfc, unit u, integer l,real f returns nothing
local unit m
local real x=GetUnitX(u)
local real y=GetUnitY(u)
local real a
local real d
local trigger t
local integer s=ArticBlast_SpellId()
if GetWidgetLife(u)>0 then
if GetRandomInt(0,100)<=10 then
call DestroyEffect(AddSpellEffectTargetById(s,EFFECT_TYPE_CASTER,u,GetAbilityEffectById(s,EFFECT_TYPE_CASTER,1)))
endif
if cfc then
call SetUnitFacing(u,f)
endif
set a=ArticBlast_MaxLaunchAngleVariation(l)
set d=GetRandomReal(0,ArticBlast_MaxLaunchDistVariation(l))
set a=(f + GetRandomReal(-a,a))*bj_DEGTORAD
set m=CollisionMissile_Create(GetAbilityEffectById(ArticBlast_SpellId(),EFFECT_TYPE_MISSILE,0),x+d*Cos(a),y+d*Sin(a),f,ArticBlast_Speed(l),0,ArticBlast_Area(l),60,false,ArticBlast_BoltCollisionSize(l),function ArticBlast_BoltImpact)
set f=ArticBlast_Scale(l)
call SetUnitScale(m,f,f,f)
call SetUnitOwner(m,GetOwningPlayer(u),true)
call AttachObject(m,"u",u)
call AttachInt(m,"l",l)
endif
set t=null
set m=null
endfunction
function ArticBlast_EndTurn takes nothing returns nothing
local timer t=GetExpiredTimer()
call AttachReal(GetAttachedUnit(t,"u"),"ArticBlast_Current",0)
call CleanAttachedVars(t)
call DestroyTimer(t)
set t=null
endfunction
function ArticBlast_PrepareTurn takes unit u, real f returns nothing
local timer t=CreateTimer()
call AttachObject(t,"u",u)
if f==0 then
set f=0.1
endif
call AttachReal(u,"ArticBlast_Current",f)
call TimerStart(t,2,false,function ArticBlast_EndTurn)
set t=null
endfunction
function ArticBlast_DetectDirChangeT takes nothing returns nothing
local timer x=GetExpiredTimer()
if GetUnitCurrentOrder(GetAttachedUnit(x,"u"))!=ArticBlast_Order() then
call AttachInt(GetAttachedTrigger(x,"t"),"b",40)
endif
call DestroyTimer(x)
set x=null
endfunction
function ArticBlast_DetectDirChange takes trigger t, unit u returns nothing
local timer x=CreateTimer()
call AttachObject(x,"t",t)
call AttachObject(x,"u",u)
call TimerStart(x,0,false,function ArticBlast_DetectDirChangeT)
set x=null
endfunction
function ArticBlast_AI takes trigger t, unit u, integer l,real f returns boolean
local group g=CreateGroup()
local unit p
local player ow=GetOwningPlayer(u)
local unit tar=null
local real x=GetUnitX(u)
local real y=GetUnitY(u)
local integer d
local real gra
local integer b=0
local integer cl
local real max=ArticBlast_Area(l)
call GroupEnumUnitsInRange(g,x,y,max,null)
loop
set p=FirstOfGroup(g)
exitwhen p==null
call GroupRemoveUnit(g,p)
if IsUnitEnemy(p,ow) and (GetWidgetLife(p)>0) and IsUnitVisible(p,ow) then
set d=R2I(1000.*(max-SquareRoot(Pow(GetUnitX(p)-x,2)+Pow(GetUnitY(p)-y,2))))
if IsUnitType(p,UNIT_TYPE_HERO) then
set cl=(GetHeroLevel(p)*2)*d
else
set cl=(GetUnitLevel(p))*d
endif
if (cl>b) then
set b=cl
set tar=p
endif
endif
endloop
call DestroyGroup(g)
if tar!=null then
set gra=Atan2BJ(GetUnitY(tar)-y,GetUnitX(tar)-x)
call ArticBlast_PrepareAngleTurning(t,f,gra)
endif
set ow=null
set p=null
set g=null
set tar=null
return (b!=0)
endfunction
function ArticBlast_Control takes nothing returns nothing
//
// Main control trigger
// A trigger is created by Trig_ArticBlast_Actions, that trigger uses this function, the trigger
// executes each (launch interval) seconds, or when the unit starts the effect of a spell or stops casting
//
local trigger t=GetTriggeringTrigger() //The trigger is run, you can use this function to know which trigger we are talking about
local integer l=GetAttachedInt(t,"l") //This was saved in the function below.
local real f
local integer b=GetAttachedInt(t,"b") // "" "" ""
local unit u=GetAttachedUnit(t,"u") // '' '' ''
local eventid e=GetTriggerEventId()
// A trigger may have multiple events, so this works for letting us know which event caused
// the trigger to execute
if (b>=1) then
if (e==EVENT_UNIT_SPELL_EFFECT) then
call AttachInt(t,"b",b+40)
set b=40
else
call AttachInt(t,"b",b+1)
endif
endif
if (GetUnitX(u)!=GetAttachedReal(t,"x")) or (GetUnitY(u)!=GetAttachedReal(t,"y")) then
set b=40
endif
if (b==0) then
set f=GetUnitState(u,UNIT_STATE_MANA)
if (f<ArticBlast_BufferMana(l)) then
call PauseUnit(u,true)
call IssueImmediateOrder(u,"stop")
call PauseUnit(u,false)
set b=40
call AttachInt(t,"b",b)
else
call SetUnitState(u,UNIT_STATE_MANA,f-ArticBlast_ManaDrainPerLaunch(l))
if ((ArticBlast_EnableAI()) and (GetPlayerController(GetOwningPlayer(u))!=MAP_CONTROL_USER)) then
if not(GetAttachedBoolean(t,"hasturntimer")) and (GetRandomInt(0,100)<=10) then
if not( ArticBlast_AI(t,u,l,GetAttachedReal(t,"f")) ) then
call PauseUnit(u,true)
call IssueImmediateOrder(u,"stop")
call PauseUnit(u,false)
set b=40
call AttachInt(t,"b",b)
endif
endif
endif
endif
endif
set f=GetAttachedReal(t,"f")
if (b==0) and (e==EVENT_UNIT_SPELL_ENDCAST) then
call ArticBlast_DetectDirChange(t,u)
call AttachInt(t,"b",b+1)
if GetAttachedBoolean(t,"hasturntimer") then
call CleanAttachedVars(GetAttachedTimer(t,"turntimer"))
call DestroyTimer(GetAttachedTimer(t,"turntimer"))
call AttachBoolean(t,"hasturntimer",false)
endif
call ArticBlast_PrepareTurn(u, GetAttachedReal(t,"f"))
endif
if (b<40) then
call ArticBlast_Launch((b==0),u, l,f)
endif
if (b>=40) then
call TriggerRemoveAction(t,GetAttachedTriggerAction(t,"ac"))
call CleanAttachedVars(t)
call DestroyTrigger(t)
endif
set u=null
set t=null
set e=null
endfunction
function Trig_ArticBlast_Actions takes nothing returns nothing
//
//This is the first thing that runs whenever a hero starts casting the ArticBlast spell
//
local unit u=GetTriggerUnit()
local integer s=GetSpellAbilityId()
local integer l=GetUnitAbilityLevel(u,s)
local location loc=GetSpellTargetLoc()
local real f=Atan2BJ(-GetUnitY(u)+GetLocationY(loc) ,-GetUnitX(u)+GetLocationX(loc))
local trigger t=CreateTrigger()
// Creating a trigger in game is really important when you want to go for multinstance
// Spells, this trigger is used to detect whenever the unit starts or stops casting the spell
local real c
call CleanAttachedVars(t) //Clean the variables attached to trigger t
//I know that the trigger was just created
//But sometimes weird stuff happens.
call AttachReal(t,"x",GetUnitX(u))
call AttachReal(t,"y",GetUnitY(u))
call AttachObject(t,"u",u) //Save u at "u" for t
call AttachInt(t,"l",l) //Also save the level of the spell attached to t
set c=GetAttachedReal(u,"ArticBlast_Current") //If the unit was already casting ArticBlast, the current direction should be saved
//On the attached variable "ArticBlast_Current"
if c!=0 then //If c is not 0, then ArticBlast was being cast
call ArticBlast_PrepareAngleTurning(t,c,f) //So use ArticBlast's turning function
else
call AttachReal(t,"f",f) //If c is 0 then the unit was not casting ArticBlast and just use the current angle for f
endif
call TriggerRegisterUnitEvent(t,u,EVENT_UNIT_SPELL_ENDCAST) //Register the Stops casting an ability event for the trigger t
call TriggerRegisterUnitEvent(t,u,EVENT_UNIT_SPELL_EFFECT) //Register the Starts the effect of an ability event for the trigger t
call AttachObject(t,"ac",TriggerAddAction(t,function ArticBlast_Control))
//Another application for Attacheable variables is fixing the TriggerAction leak, this
//is an evil leak, if you create a trigger in game and give it a trigger action, you have
//To remove it from the trigger, else it will leak.
call TriggerRegisterTimerEvent(t,ArticBlast_LaunchInterval(l),true)
//Make a periodic event for the trigger, so it is execute each ArticBlast_LaunchInterval() seconds
call TriggerRegisterTimerEvent(t,0,false)
//Will make the Trigger execute instantly after this current trigger ends execution
call RemoveLocation(loc) //Remove point so it doesn't leak
set loc=null
set u=null
//weird bugs if you set t=null , yes, in very rare situations the return bug, and thereby
//attacheable variables get really weird bugs, this is related to how the stuff works, an
//depends on weird combinations of factors-
endfunction
//===========================================================================
function InitTrig_ArticBlast takes nothing returns nothing
set gg_trg_ArticBlast=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_ArticBlast,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_ArticBlast,Condition(function Trig_ArticBlast_Conditions))
call TriggerAddAction(gg_trg_ArticBlast,function Trig_ArticBlast_Actions)
endfunction
function GetAttributeGameCache takes nothing returns gamecache
return gg_trg_Attribute
return null
endfunction
function Initialize_Attribute_Variables takes nothing returns nothing
local gamecache g = GetAttributeGameCache()
local integer AbilityAttributeId = 'A01C' // <-- You can adjust the value
local integer PointsEachLevel = 5 // <-- You can adjust the value
local integer UnitDummyId = 'n00C' // <-- You can adjust the value
local integer ItemStrenghId = 'I010' // <-- You can adjust the value
local integer ItemAgilityId = 'I012' // <-- You can adjust the value
local integer ItemInteligenceId = 'I011' // <-- You can adjust the value
local integer ItemRemainingPointsId = 'I00Z' // <-- You can adjust the value
local integer ItemBlackFillingId = 'I014' // <-- You can adjust the value
local integer ItemBackId = 'I013' // <-- You can adjust the value
call StoreIntegerBJ( AbilityAttributeId, "Ability", "Ability", g )
call StoreIntegerBJ( PointsEachLevel, "PointsLevel", "Ability", g )
call StoreIntegerBJ( UnitDummyId, "Dummy", "Ability", g )
call StoreIntegerBJ( ItemStrenghId, "Strengh", "Item", g )
call StoreIntegerBJ( ItemAgilityId, "Agility", "Item", g )
call StoreIntegerBJ( ItemInteligenceId, "Inteligence", "Item", g )
call StoreIntegerBJ( ItemRemainingPointsId, "RemainPoints", "Item", g )
call StoreIntegerBJ( ItemBlackFillingId, "BlackFilling", "Item", g )
call StoreIntegerBJ( ItemBackId, "Back", "Item", g )
endfunction
function AttributeGameCache2Trigger takes gamecache g returns trigger
return g
return null
endfunction
function AttributeAbility takes nothing returns integer
return GetStoredInteger(GetAttributeGameCache(), "Ability", "Ability")
endfunction
function PointsProLevel takes nothing returns integer
return GetStoredInteger(GetAttributeGameCache(), "Ability", "Pointslevel")
endfunction
function DummyId takes nothing returns integer
return GetStoredInteger(GetAttributeGameCache(), "Ability", "Dummy")
endfunction
function StrenghId takes nothing returns integer
return GetStoredInteger(GetAttributeGameCache(), "Item", "Strengh")
endfunction
function AgilityId takes nothing returns integer
return GetStoredInteger(GetAttributeGameCache(), "Item", "Agility")
endfunction
function InteligenceId takes nothing returns integer
return GetStoredInteger(GetAttributeGameCache(), "Item", "Inteligence")
endfunction
function RemainingPointsId takes nothing returns integer
return GetStoredInteger(GetAttributeGameCache(), "Item", "RemainPoints")
endfunction
function BlackFillingId takes nothing returns integer
return GetStoredInteger(GetAttributeGameCache(), "Item", "BlackFilling")
endfunction
function BackId takes nothing returns integer
return GetStoredInteger(GetAttributeGameCache(), "Item", "Back")
endfunction
function GetNumRempoints takes unit u returns integer
return GetStoredInteger(GetAttributeGameCache(), GetPlayerName(GetOwningPlayer(u)), ("Pointsof" + GetHeroProperName(u)))
endfunction
function Trig_Attribut_ini_Actions takes nothing returns nothing
local gamecache g = GetAttributeGameCache()
local unit levhero = GetLevelingUnit()
local integer rempoints = GetNumRempoints(levhero)
call UnitAddAbilityBJ( AttributeAbility(), levhero )
set rempoints = rempoints + PointsProLevel()
call StoreIntegerBJ( rempoints, ("Pointsof" + GetHeroProperName(levhero)), GetPlayerName(GetOwningPlayer(levhero)), g )
endfunction
function Trig_Attribut_ini2_Conditions takes nothing returns boolean
if ( not ( IsUnitType(GetTrainedUnit(), UNIT_TYPE_HERO) == true ) ) then
return false
endif
return true
endfunction
function Trig_Attribut_ini2_Actions takes nothing returns nothing
local gamecache g = GetAttributeGameCache()
local unit trainedhero = GetTrainedUnit()
local integer rempoints = PointsProLevel()
call UnitAddAbilityBJ( AttributeAbility(), trainedhero )
call StoreIntegerBJ( rempoints, ("Pointsof" + GetHeroProperName(trainedhero)), GetPlayerName(GetOwningPlayer(trainedhero)), g )
endfunction
function Trig_Attribute3_Conditions takes nothing returns boolean
if ( not ( IsUnitType(GetSpellAbilityUnit(), UNIT_TYPE_HERO) == true ) ) then
return false
endif
if ( not ( GetSpellAbilityId() == AttributeAbility() ) ) then
return false
endif
return true
endfunction
function Trig_Attribute3_Actions takes nothing returns nothing
local gamecache g = GetAttributeGameCache()
local integer i = 1
local unit AbilityUnit = GetSpellAbilityUnit()
local unit dummyu
call CreateNUnitsAtLoc( 1, DummyId(), GetOwningPlayer(AbilityUnit), GetRectCenter(GetPlayableMapRect()), bj_UNIT_FACING )
set dummyu = GetLastCreatedUnit()
loop
exitwhen i > 6
call UnitRemoveItemFromSlotSwapped( i, AbilityUnit )
call UnitAddItemSwapped( GetLastRemovedItem(), dummyu )
set i = i + 1
endloop
call StoreUnitBJ( dummyu, GetHeroProperName(AbilityUnit), GetPlayerName(GetOwningPlayer(AbilityUnit)), g )
call UnitAddItemByIdSwapped( StrenghId(), AbilityUnit )
call UnitAddItemByIdSwapped( RemainingPointsId(), AbilityUnit )
call SetItemCharges( GetLastCreatedItem(), GetNumRempoints(AbilityUnit) )
call UnitAddItemByIdSwapped( AgilityId(), AbilityUnit )
call UnitAddItemByIdSwapped( BlackFillingId(), AbilityUnit )
call UnitAddItemByIdSwapped( InteligenceId(), AbilityUnit )
call UnitAddItemByIdSwapped( BackId(), AbilityUnit )
call UnitRemoveAbilityBJ( AttributeAbility(), AbilityUnit)
call RemoveUnit( dummyu )
endfunction
function Trig_Attribute4_Func004C takes nothing returns boolean
if ( ( GetItemTypeId(GetManipulatedItem()) == AgilityId() ) ) then
return true
endif
if ( ( GetItemTypeId(GetManipulatedItem()) == InteligenceId() ) ) then
return true
endif
if ( ( GetItemTypeId(GetManipulatedItem()) == StrenghId() ) ) then
return true
endif
if ( ( GetItemTypeId(GetManipulatedItem()) == BackId() ) ) then
return true
endif
return false
endfunction
function Trig_Attribute4_Conditions takes nothing returns boolean
if ( not ( IsUnitType(GetManipulatingUnit(), UNIT_TYPE_HERO) == true ) ) then
return false
endif
if ( not Trig_Attribute4_Func004C() ) then
return false
endif
return true
endfunction
function Trig_Attribute4_Func002F takes nothing returns boolean
if ( GetItemTypeId(GetManipulatedItem()) == BackId() ) then
return false
endif
return true
endfunction
function Trig_Attribute4_Func002C takes nothing returns boolean
if ( not ( GetNumRempoints(GetManipulatingUnit() ) == 0 ) ) then
return false
endif
return true
endfunction
function Trig_Attribute4_Func002D takes nothing returns boolean
if ( not ( GetItemTypeId(GetManipulatedItem()) == BackId() ) ) then
return false
endif
return true
endfunction
function Trig_Attribute4_Func002E takes nothing returns boolean
if ( not GetBooleanOr( Trig_Attribute4_Func002C(), Trig_Attribute4_Func002D() ) ) then
return false
endif
return true
endfunction
function Trig_Attribute4_Actions takes nothing returns nothing
local gamecache g = GetAttributeGameCache()
local unit Trigunit = GetManipulatingUnit()
local integer rempoints = GetNumRempoints( Trigunit )
local item RemainPoints = UnitItemInSlotBJ(GetManipulatingUnit(), 2)
local unit restoredu
local integer i = 1
call UnitAddAbilityBJ( AttributeAbility(), Trigunit )
if ( Trig_Attribute4_Func002F() ) then
set rempoints = rempoints - 1
call SetItemCharges( RemainPoints, rempoints )
call StoreIntegerBJ( rempoints, ("Pointsof" + GetHeroProperName(Trigunit)), GetPlayerName(GetOwningPlayer(Trigunit)), g )
call UnitRemoveAbilityBJ( AttributeAbility(), Trigunit)
endif
if ( Trig_Attribute4_Func002E() ) then
call RestoreUnitLocFacingAngleBJ( GetHeroProperName(Trigunit), GetPlayerName(GetOwningPlayer(Trigunit)), g, GetOwningPlayer(Trigunit), GetRectCenter(GetPlayableMapRect()), 0 )
set restoredu = GetLastRestoredUnitBJ()
loop
exitwhen i > 6
call RemoveItem( UnitItemInSlotBJ(Trigunit, i) )
call UnitRemoveItemSwapped( UnitItemInSlotBJ(restoredu, i), restoredu )
call UnitAddItemSwapped( GetLastRemovedItem(), Trigunit )
set i = i + 1
endloop
call RemoveUnit( restoredu )
endif
endfunction
//===========================================================================
function InitTrig_Attribute takes nothing returns nothing
local trigger Attribute1 = CreateTrigger( )
local trigger Attribute2 = CreateTrigger( )
local trigger Attribute3 = CreateTrigger( )
local trigger Attribute4 = CreateTrigger( )
set gg_trg_Attribute = AttributeGameCache2Trigger(InitGameCache( "Attribute.w3v" ))
call Initialize_Attribute_Variables()
call TriggerRegisterAnyUnitEventBJ( Attribute1, EVENT_PLAYER_HERO_LEVEL )
call TriggerAddAction( Attribute1, function Trig_Attribut_ini_Actions )
call TriggerRegisterAnyUnitEventBJ( Attribute2, EVENT_PLAYER_UNIT_TRAIN_FINISH )
call TriggerAddCondition( Attribute2, Condition( function Trig_Attribut_ini2_Conditions ) )
call TriggerAddAction( Attribute2, function Trig_Attribut_ini2_Actions )
call TriggerRegisterAnyUnitEventBJ( Attribute3, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( Attribute3, Condition( function Trig_Attribute3_Conditions ) )
call TriggerAddAction( Attribute3, function Trig_Attribute3_Actions )
call TriggerRegisterAnyUnitEventBJ( Attribute4, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddCondition( Attribute4, Condition( function Trig_Attribute4_Conditions ) )
call TriggerAddAction( Attribute4, function Trig_Attribute4_Actions )
endfunction
//********************************************************************************************************
//*
//* Molten Boulder
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Requires:
//*
//* - The Molten Boulder ability
//* - The Caster System ( http://www.wc3campaigns.com/forumdisplay.php?f=534 )
//* - This Trigger (MAKE SURE TO change the rawcodes in the trigger to the correct ones of
//* your map)
//* Notes:
//* - The Ability's First Missile art is one of the missile models
//* - The Ability's Second Missile art is the other one of the missile models
//* - The Ability's Third Missile art is the vertex color Red value
//* - The Ability's Fourth Missile art is the vertex color Green value
//* - The Ability's Fifth Missile art is the vertex color Blue value
//* - The Ability's Sixth Missile art is the the vertex color Alpha value
//* - The Ability's Special art is the the Final Explosion effect
//* - The Ability's Area Effect art is the flame effect
//* - The Ability's First Target art is the flame damage effect
//* - The Ability's Second Target art is the flame damage effect attachment point
//*
//********************************************************************************************************
//========================================================================================================
// Molten Boulder Spell Configuration
//
constant function MoltenBoulder_SpellId takes nothing returns integer
return 'A01B' //Change this to match the rawcode of the Molten Boulder ability in your map
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_Damage takes real level returns real
return 10+4*level //The impact damage done by the boulder
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_FlameSpawnInterval takes real level returns real
return 0.20-level*0 //The Spawn interval of each bolt, should be a multiple of the timer value (look below)
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_FlameDuration takes real level returns real
return 2+0.1*level //The single target damage by level formula
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_FlamePeriod takes real level returns real
return 0+level*0 //The damage interval for the flames (0 for minimum possible)
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_FlameArea takes real level returns real
return 75+25*level //The single target damage by level formula
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_FlameDamage takes real level returns real
return 15+10*level //The single target damage by level formula
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_FinalFlameNumber takes integer level returns integer
return 5+2*level //The number of flames spawned at the explosion of the boulder
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_FinalArea takes real level returns real
return 250+25*level //The final area of effect of the explosion
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_OrbSpeed takes nothing returns real
return 350.0 //The Speed of the boulder
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_OrbDuration takes real level returns real
return 1.5+0.5*level //The duration of the orb
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_ImpactRange takes real level returns real
return 100+level*0 //How close an unit be to the boulder to get effected by its damage and knockback
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_OrbScale takes real level returns real
return 2.55+level*0 //The scale of the boulder
endfunction
//--------------------------------------------------------------------------------------------------------
function MoltenBoulder_KnockbackOptions takes integer level returns integer
return DamageOnlyEnemies() + DamageException(UNIT_TYPE_FLYING,0)
//
// (This is for the Knockback, meaning that only in case these damage options determine an unit is
// immune, it won't be affected by the knockback, this has nothing to do with damage
//
// Will knockback enemy ground units
// other damage options can be put, check caster system readme for more information.
//
endfunction
//--------------------------------------------------------------------------------------------------------
function MoltenBoulder_DamageOptions takes integer level returns integer
return DamageTypes(ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE) + DamageOnlyEnemies() + DamageOnlyTo(UNIT_TYPE_GROUND)
//
// Will do fire spell damage, won't damage allies, and will only affect ground units.
// other damage options can be put, check caster system readme for more information.
//
// (This is for the Impact damage)
//
endfunction
//--------------------------------------------------------------------------------------------------------
function MoltenBoulder_FlameDamageOptions takes integer level returns integer
return DamageTypes(ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE) + DamageTrees() + DamageOnlyEnemies()
//* Will do fire spell damage and affect trees, it won't mess with allied units.
// other damage options can be put, check caster system readme for more information.
//
// (This is for the flames damage)
//
endfunction
//--------------------------------------------------------------------------------------------------------
constant function MoltenBoulder_Timer takes nothing returns real
return 0.05
//
// This is the timer period, a low value (0.01) will look better but will be worse lag-wise, a high
// value (1.0) would be faster lag-wise but will surelly look bad. I think 0.05 is the perfect value.
endfunction
//========================================================================================================
function Trig_MoltenBoulder_Conditions takes nothing returns boolean
return (GetSpellAbilityId() == MoltenBoulder_SpellId())
endfunction
function MoltenBoulder_Flame takes unit u, integer l, real x, real y returns nothing
local integer s=MoltenBoulder_SpellId()
call AddAreaDamagerForUnit(u,GetAbilityEffectById(s,EFFECT_TYPE_AREA_EFFECT,0),GetAbilityEffectById(s,EFFECT_TYPE_TARGET,0),GetAbilityEffectById(s,EFFECT_TYPE_TARGET,1),x,y,MoltenBoulder_FlameDamage(l),MoltenBoulder_FlamePeriod(l),MoltenBoulder_FlameDuration(l),MoltenBoulder_FlameArea(l),true,MoltenBoulder_FlameDamageOptions(l))
endfunction
function MoltenBoulder_Final takes unit m,integer l,timer t,group g returns nothing
local real d
local integer n=MoltenBoulder_FinalFlameNumber(l)
local integer i=0
local real x=GetUnitX(m)
local real y=GetUnitY(m)
local real h
local unit ow=GetAttachedUnit(m,"u")
call AttachBoolean(t,"mainended",true)
call DestroyEffect(GetAttachedEffect(m,"fx1"))
call DestroyEffect(GetAttachedEffect(m,"fx2"))
call DestroyEffect( AddSpellEffectById(MoltenBoulder_SpellId(),EFFECT_TYPE_SPECIAL,x,y) )
loop
exitwhen i>=n
set d=((360.0*i)/n)
set h=GetRandomReal(0,MoltenBoulder_FinalArea(l))
call MoltenBoulder_Flame(ow,l,x+h*CosBJ(d),y+h*SinBJ(d))
set i=i+1
endloop
call CleanAttachedVars(m)
call ExplodeUnitBJ(m)
set ow=null
endfunction
function MoltenBoulder_OrbMov takes unit m,integer l, timer t,group g returns boolean
local real x=GetUnitX(m)
local real y=GetUnitY(m)
local real f=GetAttachedReal(t,"f")*bj_DEGTORAD
local real d=MoltenBoulder_OrbSpeed()*MoltenBoulder_Timer()
local real nx=x+d*Cos(f)
local real ny=y+d*Sin(f)
call SetUnitPosition(m,nx,ny)
if SquareRoot(Pow(nx-GetUnitX(m),2)+Pow(ny-GetUnitY(m),2))>10 then
call MoltenBoulder_Final(m,l,t,g)
return false
endif
return true
endfunction
function MoltenBoulder_Mov takes nothing returns nothing
local timer t=GetExpiredTimer()
local group g=GetAttachedGroup(t,"g")
local group a
local unit m
local unit o
local unit u
local real f
local real inc
local real x
local real y
local real nx
local real ny
local real px
local real py
local integer tms
local integer l=GetAttachedInt(t,"l")
local integer num=GetAttachedInt(t,"num")+1
local real dir
if GetAttachedBoolean(t,"mainended") then
call CleanAttachedVars(t)
call DestroyGroup(g)
call DestroyTimer(t)
set t=null
set g=null
set a=null
set m=null
return
endif
call AttachInt(t,"num",num)
set o=GetAttachedUnit(t,"u")
set u=GetAttachedUnit(o,"u")
set x=GetUnitX(o)
set y=GetUnitY(o)
if ModuloInteger(num, R2I(MoltenBoulder_FlameSpawnInterval(l)/MoltenBoulder_Timer()))==0 then
set dir = GetRandomReal(0,360)
call SetUnitFacing(o,dir)
call MoltenBoulder_Flame(GetAttachedUnit(o,"u"),l,x,y)
call AttachReal(t,"dir",dir)
endif
set a=CreateGroup()
call GroupAddGroup(g,a)
set inc=MoltenBoulder_OrbSpeed()*MoltenBoulder_Timer()
loop
set m=FirstOfGroup(a)
exitwhen m==null
set nx=GetUnitX(m)
set ny=GetUnitY(m)
if IsUnitInRange(m,o,MoltenBoulder_ImpactRange(l)) and (GetWidgetLife(m)>0) then
call DamageUnitByOptions(u,m,MoltenBoulder_Damage(l),MoltenBoulder_DamageOptions(l))
set f=Atan2(ny-y,nx-x)
set px=nx+inc*Cos(f)
set py=ny+inc*Sin(f)
call SetUnitPosition(m,px,py)
if SquareRoot(Pow(GetUnitX(m)-px,2)+Pow(GetUnitY(m)-py,2))>20 then
call SetUnitPosition(m,nx,ny)
endif
else
call GroupRemoveUnit(g,m)
endif
call GroupRemoveUnit(a,m)
endloop
if not(MoltenBoulder_OrbMov(o,l,t,g)) then
call AttachBoolean(t,"mainended",true)
endif
call DestroyGroup(a)
set t=null
set g=null
set a=null
set m=null
endfunction
function MoltenBoulder_OrbImpact takes nothing returns nothing
local trigger t=GetTriggeringTrigger()
local unit u=GetTriggerUnit()
local unit m=GetAttachedUnit(t,"u")
local unit ow=GetAttachedUnit(m,"u")
local integer l=GetAttachedInt(m,"l")
local integer i=0
local real x=GetUnitX(m)
local real y=GetUnitY(m)
local real d
if GetDamageFactorByOptions(ow,u,MoltenBoulder_KnockbackOptions(l))!=0 then
call GroupAddUnit(GetAttachedGroup(m,"g"),u)
endif
call DamageUnitByOptions(ow,u,MoltenBoulder_Damage(l),MoltenBoulder_DamageOptions(l))
set t=null
set u=null
set m=null
set ow=null
endfunction
function Trig_MoltenBoulder_Actions takes nothing returns nothing
local unit u=GetTriggerUnit()
local integer s=GetSpellAbilityId()
local integer l=GetUnitAbilityLevel(u,s)
local location loc=GetSpellTargetLoc()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
local real f=Atan2BJ(GetLocationY(loc)-y,GetLocationX(loc)-x)
local unit m=AddCasterFacing(f)
local timer t=CreateTimer()
local group g=CreateGroup()
local trigger ran=CreateTrigger()
local triggeraction ac=TriggerAddAction(ran,function MoltenBoulder_OrbImpact)
call SetUnitPosition(m,x,y)
set x=MoltenBoulder_OrbScale(l)
call SetUnitScale(m,x,x,x)
call SetUnitVertexColor(m,S2I(GetAbilityEffectById(s,EFFECT_TYPE_MISSILE,2)),S2I(GetAbilityEffectById(s,EFFECT_TYPE_MISSILE,3)),S2I(GetAbilityEffectById(s,EFFECT_TYPE_MISSILE,4)),S2I(GetAbilityEffectById(s,EFFECT_TYPE_MISSILE,5)))
call AttachInt(t,"l",l)
call AttachObject(m,"u",u)
call AttachObject(m,"g",g)
call SetUnitFlyHeight(m,100,0)
call SetUnitFlyHeight(m,0,100)
call AttachReal(t,"dir",ModuloReal(-f,360))
call AttachObject(ran,"u",m)
call TriggerRegisterUnitInRange(ran,m,MoltenBoulder_ImpactRange(l),null)
call AttachInt(m,"l",l)
call AttachObject( m,"fx1",AddSpellEffectTargetById(s,EFFECT_TYPE_MISSILE,m,"origin"))
call AttachObject( m,"fx2",AddSpecialEffectTarget(GetAbilityEffectById(s,EFFECT_TYPE_MISSILE,1),m,"origin"))
call SetUnitOwner(m,GetOwningPlayer(u),true)
call RemoveLocation(loc)
call AttachObject(t,"u",m)
call AttachReal(t,"f",f)
call AttachObject(t,"g",g)
call TimerStart(t,MoltenBoulder_Timer(),true,function MoltenBoulder_Mov)
call PolledWait(MoltenBoulder_OrbDuration(l))
if not(GetAttachedBoolean(t,"sp")) then
call MoltenBoulder_Final(m,l,t,g)
endif
call AttachBoolean(t,"mainended",true)
call TriggerRemoveAction(ran,ac)
call DestroyTrigger(ran)
set u=null
set loc=null
set m=null
set t=null
set g=null
set ran=null
set ac=null
endfunction
//========================================================================================================
function InitTrig_MoltenBoulder takes nothing returns nothing
set gg_trg_MoltenBoulder = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_MoltenBoulder, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_MoltenBoulder, Condition( function Trig_MoltenBoulder_Conditions ) )
call TriggerAddAction( gg_trg_MoltenBoulder, function Trig_MoltenBoulder_Actions )
endfunction
//********************************************************************************************************
//*
//* Volcano
//* ¯¯¯¯¯¯¯
//* Requires:
//* - The Caster System 10.0 ( http://www.wc3campaigns.com/forumdisplay.php?f=534 )
//* - The handle variables functions.
//* - The Volcano Ability
//* - The Volcano Burning Rock Ability
//* - The Volcano Stunning Rock Ability
//* - This Trigger (Make sure it points to the right ability rawcodes)
//* Art:
//* - The Volcano Ability's Area Effect art is shown at the position of the
//* Volcano during its effect.
//* - The Volcano Ability's Effect Art keeps appearing at the center of the volcano.
//* - The Volcano Burning Rock Ability's Area effect art is the effect of the fire started.
//* - The Volcano Burning Rock Ability's Area target art is the target effect of the fire started.
//* the second target value would be the attachment point.
//*
//* Note: Just in case, the rock abilities will level up to the level of the triggering ability
//* if possible.
//*
//********************************************************************************************************
//========================================================================================================
// Volcano Spell Configuration :
//
constant function Volcano_SpellId takes nothing returns integer
return 'A01A' //// The Rawcode for the Volcano Ability in your map
endfunction
constant function Volcano_BurningRock_SpellId takes nothing returns integer
return 'A018' //// The Rawcode for the Volcano Burning Rock Ability in your map
endfunction
constant function Volcano_StunningRock_SpellId takes nothing returns integer
return 'A019' //// The Rawcode for the Volcano Stunning Rock Ability in your map
endfunction
constant function Volcano_RocksPerPeriod takes integer level returns integer
return 3*level //// Number of rocks per eruption period by level formula
endfunction
constant function Volcano_RockSpeed takes nothing returns real
return 700.0 //// Missile Speed of the Rock Abilities, must match the ones in the object editor
endfunction
constant function Volcano_Rock_Area takes real level returns real
return 150*level //// Area of effect for the rock impact damage, the burning rock damage per second and the Center of the volcano damage.
endfunction
constant function Volcano_Rock_Damage takes real level returns real
return 25+100*level//// Damage for the rock impact and the Center of the volcano.
endfunction
constant function Volcano_BurningRock_DamagePerSecond takes real level returns real
return 25+level*6 //// Damage per second for the burning rock started fire
endfunction
constant function Volcano_BurningRock_Duration takes real level returns real
return 6+level*0 //// Duration for the burning rock started fire
endfunction
constant function Volcano_TotalArea takes real level returns real
return 400+level*100 //// Total area of effect of the Volcano.
endfunction
constant function Volcano_AffectAllies takes integer level returns boolean
return false // true in case you want it to hurt allies, false otherwise
endfunction
function Volcano_DamageOptions takes integer level returns integer
return DamageTypes(ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE) + DontDamageSelf()
// Volcano's damage options, will do fire (magical) spell damage , and it won't affect the hero himself
// See caster system readme for more information.
endfunction
//===================================================================================================================================================
function Trig_Volcano_Conditions takes nothing returns boolean
return GetSpellAbilityId() == Volcano_SpellId()
endfunction
function Trig_VolcanoRock_Conditions takes nothing returns boolean
return GetSpellAbilityId()==Volcano_BurningRock_SpellId() or GetSpellAbilityId()==Volcano_StunningRock_SpellId()
endfunction
function Volcano_GetUnit takes unit d returns unit
return GetHandleHandle(d,"VolcanoUnit")
endfunction
function Volcano_Rock_Dmg takes nothing returns nothing
local unit u=GetTriggerUnit()
local unit o=Volcano_GetUnit(u)
local player p=GetOwningPlayer(u)
local location loc=GetSpellTargetLoc()
local integer s=GetSpellAbilityId()
local integer l=GetHandleInt(u,"VolcanoLevel")
call SetHandleInt(u,"VolcanoLevel",0)
call SetHandleHandle(u,"VolcanoUnit",null)
call PolledWait(SquareRoot(Pow(GetUnitX(u)-GetLocationX(loc),2)+Pow(GetUnitY(u)-GetLocationY(loc),2))/Volcano_RockSpeed())
call DamageUnitsInAOEExLoc( o, Volcano_Rock_Damage(l) ,loc, Volcano_Rock_Area(l),Volcano_AffectAllies(l),Volcano_DamageOptions(l))
if s==Volcano_BurningRock_SpellId() then
call AddAreaDamagerForUnitLoc(o,GetAbilityEffectById(s,EFFECT_TYPE_AREA_EFFECT,0), GetAbilityEffectById(s,EFFECT_TYPE_TARGET,0), GetAbilityEffectById(s,EFFECT_TYPE_TARGET,1), loc, Volcano_BurningRock_DamagePerSecond(l) , 1, Volcano_BurningRock_Duration(l), Volcano_Rock_Area(l), Volcano_AffectAllies(l), Volcano_DamageOptions(l))
endif
call RemoveLocation(loc)
set o=null
set loc=null
set p=null
set u=null
endfunction
function Trig_Volcano_Actions takes nothing returns nothing
local unit u=GetTriggerUnit()
local unit d
local integer s=GetSpellAbilityId()
local integer l=GetUnitAbilityLevel(u,s)
local location loc=GetSpellTargetLoc()
local real x=GetLocationX(loc)
local real y=GetLocationY(loc)
local real a=Volcano_TotalArea(l)
local real b
local real c
local trigger e=CreateTrigger()
local effect fx=AddSpellEffectByIdLoc(s,EFFECT_TYPE_AREA_EFFECT,loc)
local integer i=0
call TriggerRegisterUnitEvent(e,u,EVENT_UNIT_SPELL_ENDCAST)
loop
exitwhen GetTriggerEvalCount(e)>0
call TriggerSleepAction(0)
call DestroyEffect(AddSpellEffectByIdLoc(s,EFFECT_TYPE_EFFECT,loc))
set i=0
loop
exitwhen i==Volcano_RocksPerPeriod(l)
set udg_sourcehack=loc
set b=GetRandomReal(Volcano_Rock_Area(l),a)
set c=GetRandomReal(Volcano_Rock_Area(l),SquareRoot(a*a-b*b) )
set d=CasterCastAbilityLevelPoint(GetOwningPlayer(u), IntegerTertiaryOp(GetRandomInt(0,1)==1,Volcano_BurningRock_SpellId(),Volcano_StunningRock_SpellId()),l , "clusterrockets", x+IntegerTertiaryOp(GetRandomInt(0,1)==0,1,-1)*b,y+IntegerTertiaryOp(GetRandomInt(0,1)==0,1,-1)*c, false)
call SetHandleInt( d ,"VolcanoLevel",l)
call SetHandleHandle(d, "VolcanoUnit",u)
set udg_sourcehack=null
set i=i+1
endloop
call DamageUnitsInAOEExLoc( u, Volcano_Rock_Damage(l) ,loc, Volcano_Rock_Area(l), Volcano_AffectAllies(l), Volcano_DamageOptions(l))
endloop
call DestroyEffect(fx)
call DestroyTrigger(e)
call RemoveLocation(loc)
set loc=null
set fx=null
set e=null
set d=null
endfunction
//===========================================================================
function InitTrig_Volcano takes nothing returns nothing
call PreloadAbility(Volcano_BurningRock_SpellId())
call PreloadAbility(Volcano_StunningRock_SpellId())
call Preload("Abilities\\Spells\\Other\\Volcano\\Volcano.mdl")
set gg_trg_Volcano = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Volcano, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Volcano, Condition( function Trig_VolcanoRock_Conditions ) )
call TriggerAddAction( gg_trg_Volcano, function Volcano_Rock_Dmg )
set gg_trg_Volcano = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Volcano, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Volcano, Condition( function Trig_Volcano_Conditions ) )
call TriggerAddAction( gg_trg_Volcano, function Trig_Volcano_Actions )
endfunction
//===========================================================================
function InitTrig_Caster_Setup takes nothing returns nothing
call CreateCasters(12)
// Create 12 Initial casters available for any usage of a caster function
// Not a needed step, but might help a little against first cast lag
// Better if you do it , at least with a value of 1 , you can just copy this trigger to your map.
endfunction