//TESH.scrollpos=0
//TESH.alwaysfold=0
native UnitAlive takes unit id returns boolean
library GetLowestHandleId initializer Init
globals
private constant boolean SHOW=false
integer REALOFFSET
private leaderboard LB
private integer SECONDS=0
endglobals
private function h2i takes handle h returns integer
return GetHandleId(h)
return 0
endfunction
private function Update takes nothing returns nothing
local location array loc
local integer i=0
local integer index
local integer prevIndex=0
local integer next=0
loop
set loc[i]=Location(0.,0.)
set index=h2i(loc[i])-REALOFFSET
set i=i+1
if index==prevIndex+1 then
set next=next+1
else
set next=0
endif
set prevIndex=index
exitwhen next>=5
endloop
call LeaderboardSetItemValue(LB,0,index-i)
set SECONDS=SECONDS+1
call LeaderboardSetItemValue(LB,1,SECONDS)
loop
set i=i-1
call RemoveLocation(loc[i])
set loc[i]=null
exitwhen i<=0
endloop
endfunction
private function Start takes nothing returns nothing
set LB=CreateLeaderboard()
call LeaderboardSetLabel(LB,DARKGREY+"Max Handles")
call PlayerSetLeaderboard(GetLocalPlayer(),LB)
call LeaderboardDisplay(LB,true)
call LeaderboardAddItem(LB,GREEN+"Handle Count:",0,GetLocalPlayer())
call LeaderboardSetItemValue(LB,0,REALOFFSET-0x100000)
call LeaderboardSetSizeByItemCount(LB, 1)
call TimerStart(GetExpiredTimer(),1.,true,function Update)
call LeaderboardAddItem(LB,"",1,GetLocalPlayer())
call LeaderboardSetItemLabel(LB,1,GREEN+"Elapsed Time:")
call LeaderboardSetItemValue(LB,1,SECONDS)
call LeaderboardSetSizeByItemCount(LB,2)
endfunction
private function Init takes nothing returns nothing
local location l=Location(0.,0.)
set REALOFFSET=h2i(l)
static if SHOW then
call BJDebugMsg(DARKGREY+"This maps first handle id is: |r"+I2S(REALOFFSET))
call BJDebugMsg(DARKGREY+"The difference between it and 0x100000 is: |r"+I2S(REALOFFSET-0x100000))
call TimerStart(CreateTimer(),0.0,false,function Start)
endif
call RemoveLocation(l)
set l=null
endfunction
endlibrary
Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Initialization initializer Init
globals
private timer Weather = CreateTimer()
private weathereffect WeatherEffect = null
private trigger TreeRevive = CreateTrigger()
private rect array CreepSpawn
private integer array CreepsRect
private string array Footmensayings
unit Hero = null
timerdialog TDHero
unit Tauren = null
timerdialog TDTauren
endglobals
// Create random weather
private function RandomWeather takes nothing returns nothing
local integer i = GetRandomInt(0,6)
call PauseTimer(Weather)
call EnableWeatherEffect( WeatherEffect, false )
if i==1 then
set WeatherEffect = AddWeatherEffect(bj_mapInitialPlayableArea, 'RAhr')
call EnableWeatherEffect( WeatherEffect, true )
elseif i==2 then
set WeatherEffect = AddWeatherEffect(bj_mapInitialPlayableArea, 'RAlr')
call EnableWeatherEffect( WeatherEffect, true )
elseif i==3 then
set WeatherEffect = AddWeatherEffect(bj_mapInitialPlayableArea, 'FDwh')
call EnableWeatherEffect( WeatherEffect, true )
elseif i==4 then
set WeatherEffect = AddWeatherEffect(bj_mapInitialPlayableArea, 'FDwl')
call EnableWeatherEffect( WeatherEffect, true )
elseif i==5 then
set WeatherEffect = AddWeatherEffect(bj_mapInitialPlayableArea, 'WOlw')
call EnableWeatherEffect( WeatherEffect, true )
elseif i==6 then
set WeatherEffect = AddWeatherEffect(bj_mapInitialPlayableArea, 'RLlr')
call EnableWeatherEffect( WeatherEffect, true )
endif
call TimerStart(Weather, GetRandomReal(30., 60.), false, function RandomWeather)
endfunction
// Update sphere ability
private function ChangeSphere takes nothing returns nothing
if GetFloatGameState(GAME_STATE_TIME_OF_DAY)==6. then
call UnitRemoveAbility(Hero,'A001')
call UnitAddAbility(Hero,'A000')
else
call UnitRemoveAbility(Hero,'A000')
call UnitAddAbility(Hero,'A001')
endif
endfunction
// Revive creep camps
private function CreepFilter takes nothing returns boolean
return IsUnitEnemy(GetTriggerUnit(),Player(0)) and IsUnitType(GetTriggerUnit(),UNIT_TYPE_SUMMONED)==false and IsUnitType(GetTriggerUnit(),UNIT_TYPE_HERO)==false
endfunction
private function EnemyOfCreeps takes nothing returns boolean
if IsUnitEnemy(GetFilterUnit(),Player(12)) and UnitAlive(GetFilterUnit()) then
set bj_forceCountPlayers=bj_forceCountPlayers+1
endif
return false
endfunction
private function CreepRevive takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = H2I(u)
local integer i=CreepsRect[id]
local rect r = CreepSpawn[i]
local integer lvl = GetUnitLevel(u)+GetRandomInt(0,1)
local item it = null
local group g=NewGroup()
if GetRandomReal(0.,1.)<=.33 then // 33%
set it = CreateItem( ChooseRandomItemEx(ITEM_TYPE_PERMANENT,GetUnitLevel(u)), GetUnitX(u),GetUnitY(u) )
endif
call PolledWait2( GetRandomReal(35.,45.) )
loop
set bj_forceCountPlayers=0
call GroupEnumUnitsInRange(g,GetRectCenterX(r),GetRectCenterY(r),750.,Condition(function EnemyOfCreeps))
exitwhen bj_forceCountPlayers==0
call PolledWait2(4.)
endloop
call ReleaseGroup(g)
if lvl>10 then
set lvl=10
endif
if GetUnitTypeId(GetTriggerUnit()) == 'ogru' then
set u = CreateUnit( Player(PLAYER_NEUTRAL_AGGRESSIVE),'ogru',GetRandomReal(GetRectMinX(r), GetRectMaxX(r)),GetRandomReal(GetRectMinY(r), GetRectMaxY(r)), GetRandomReal(0.,360.) )
else
set u = CreateUnit( Player(PLAYER_NEUTRAL_AGGRESSIVE), ChooseRandomCreep(lvl),GetRandomReal(GetRectMinX(r), GetRectMaxX(r)),GetRandomReal(GetRectMinY(r), GetRectMaxY(r)), GetRandomReal(0.,360.) )
endif
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl",u,"origin"))
set id = H2I(u)
set CreepsRect[id]=i
if not IsItemOwned(it) or it==null then
call SetItemVisible(it,false)
call SetWidgetLife(it,0.)
endif
set u = null
endfunction
// Revive footmen
private function FootmenFilter takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'hfoo'
endfunction
private function FootmenRevive takes nothing returns nothing
call TextTag_Unit(GetTriggerUnit(),Footmensayings[GetRandomInt(1,3)],PC0)
call PolledWait2(15.)
set bj_lastCreatedUnit = CreateUnit( Player(0), 'hfoo', GetRandomReal(GetRectMinX(gg_rct_Start_Position), GetRectMaxX(gg_rct_Start_Position)), GetRandomReal(GetRectMinY(gg_rct_Start_Position), GetRectMaxY(gg_rct_Start_Position)), GetRandomReal(0, 360) )
call SetUnitAnimation(bj_lastCreatedUnit,"stand victory")
call QueueUnitAnimation(bj_lastCreatedUnit,"stand")
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl",bj_lastCreatedUnit,"origin"))
endfunction
// Cheats!
private function Cheats takes nothing returns nothing
local unit u
local group g
local integer i
if SubString(GetEventPlayerChatString(),0,5)=="level" then
set i=S2I(SubString(GetEventPlayerChatString(),6,8))
if GetHeroLevel(Hero)==10 then
call QuestMessageBJ(bj_FORCE_ALL_PLAYERS,12,RED+GetHeroProperName(Hero)+" is already level 10.")
elseif i>10 or i<=GetHeroLevel(Hero) then
call QuestMessageBJ(bj_FORCE_ALL_PLAYERS,12,RED+"Invalid level input.")
else
call SetHeroLevel(Hero,i,true)
endif
return
endif
if GetEventPlayerChatString()=="suicide" then
call UnitDamageTarget(Hero,Hero,99999.,false,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
return
elseif GetEventPlayerChatString()!="restore" then
return
endif
set g = NewGroup()
set bj_groupEnumOwningPlayer = Player(0)
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, filterGetUnitsInRectOfPlayer)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
if UnitAlive(u) then
call SetUnitState(u, UNIT_STATE_LIFE,99999.)
call SetUnitState(u, UNIT_STATE_MANA,99999.)
call UnitResetCooldown( u )
call UnitRemoveBuffs(u,false,true)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl",u,"origin"))
endif
endloop
call ReleaseGroup(g)
endfunction
// Revive dead heroes
private function HeroFilter takes nothing returns boolean
return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true
endfunction
private function ReviveTauren takes nothing returns nothing
call ReleaseTimer(GetExpiredTimer())
call ReviveHero( Tauren, GetRandomReal(GetRectMinX(gg_rct_Creep_Spawn_4), GetRectMaxX(gg_rct_Creep_Spawn_4)), GetRandomReal(GetRectMinY(gg_rct_Creep_Spawn_4), GetRectMaxY(gg_rct_Creep_Spawn_4)), true )
call SetWidgetLife(Tauren,99999.)
call SetUnitState(Tauren,UNIT_STATE_MANA,99999.)
call UnitResetCooldown(Tauren)
call UnitRemoveBuffs(Tauren,false,true)
call DestroyTimerDialog(TDTauren)
endfunction
private function RevivePlayerHero takes nothing returns nothing
call ReleaseTimer(GetExpiredTimer())
call ReviveHero( Hero, GetStartLocationX(0), GetStartLocationY(0), true )
call PanCameraToTimed( GetStartLocationX(0), GetStartLocationY(0), 0.5)
call ClearSelection()
call SelectUnit(Hero, true)
call SetWidgetLife(Hero,99999.)
call SetUnitState(Hero,UNIT_STATE_MANA,99999.)
call UnitResetCooldown(Hero)
call UnitRemoveBuffs(Hero,false,true)
call DestroyTimerDialog(TDHero)
endfunction
private function HeroRevive takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p = GetOwningPlayer(u)
local timer t = NewTimer()
if u==Hero then
call TimerStart(t,5.,false,function RevivePlayerHero)
set TDHero=CreateTimerDialog(t)
call TimerDialogDisplay(TDHero,true)
call TimerDialogSetTitle(TDHero,PC0+"Hero Revival")
call TextTag_Unit(Hero,"I will have my vengeance, in this life or the next",PC0)
else
call TextTag_Unit(GetKillingUnit(),"Hasta la vista baby",PC0)
call TextTag_Unit(GetTriggerUnit(),"Sweet serenity...",PC10)
call TimerStart(t,30.,false,function ReviveTauren)
set TDTauren=CreateTimerDialog(t)
call TimerDialogDisplay(TDTauren,true)
call TimerDialogSetTitle(TDTauren,PC10+"Tauren Chieftain Revival")
endif
endfunction
// Regrow destroyed trees
private function RegrowTrees takes nothing returns nothing
call PolledWait2( GetRandomReal(30.,45.) )
call DestructableRestoreLife( GetTriggerDestructable(), GetDestructableMaxLife(GetTriggerDestructable()), true )
endfunction
private function TreesSetup takes nothing returns nothing
call TriggerRegisterDeathEvent(TreeRevive, GetEnumDestructable())
endfunction
private function Init takes nothing returns nothing
local trigger trig = CreateTrigger()
local integer i = 1
local integer j = 1
local integer id
local unit u
local real maxX
local real minX
local real maxY
local real minY
// General setup
call EnumDestructablesInRect(GetWorldBounds(), null,function TreesSetup)
call TriggerAddAction( TreeRevive, function RegrowTrees )
call StartMeleeAI( Player(PLAYER_NEUTRAL_AGGRESSIVE), "map.ai" )
call FogEnable(false)
set bj_lastCreatedFogModifier = CreateFogModifierRect(Player(0),FOG_OF_WAR_VISIBLE,bj_mapInitialPlayableArea,true,false)
call FogModifierStart(bj_lastCreatedFogModifier)
call SetFloatGameState(GAME_STATE_TIME_OF_DAY, bj_TOD_DAWN)
call SuspendTimeOfDay(false)
call Preload("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl")
call Preload("Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl")
// Messages for map testers
call DisplayTextToPlayer(Player(0),0.,0.,"|c00FF2020Type 'restore' to gain full health, mana, and to recharge cooldowns for your hero and footmen. Type 'level ##' to increase the level of your hero or 'suicide' to off your champion.")
call DisplayTimedTextToPlayer( Player(0),0.,0., 20., "|c0000FF00Spells by emjlr3, terrain by AceHart:|r
|c00AAAAFFThanks to PipeDream, Vexorian, Zoxc, PitzerMike, SFilip and all those that made the JASS NewGen Pack possible.|r
|c00FFAA00Please give credit where due.|r" )
// Create hero
set Hero = CreateUnit( Player(0), 'Hblm', GetRectCenterX(gg_rct_Start_Position), GetRectCenterY(gg_rct_Start_Position), 270. )
call SelectUnit(Hero, true)
call SetPlayerTechResearched(Player(0),'Rhde',1)
// Create footmen
loop
exitwhen i > 6
set u = CreateUnit( Player(0), 'hfoo',GetUnitX(Hero)+200.*Cos((60.*i)*bj_DEGTORAD),GetUnitY(Hero)+200.*Sin((60.*i)*bj_DEGTORAD),(60.*i)-180.)
call QueueUnitAnimation(u,"stand")
set i = i + 1
endloop
// Create creeps
set i=2
set CreepSpawn[1]=gg_rct_Creep_Spawn_1
set CreepSpawn[2]=gg_rct_Creep_Spawn_2
set CreepSpawn[3]=gg_rct_Creep_Spawn_3
loop
exitwhen i>4
set maxX = GetRectMaxX(CreepSpawn[i-1])
set minX = GetRectMinX(CreepSpawn[i-1])
set maxY = GetRectMaxY(CreepSpawn[i-1])
set minY = GetRectMinY(CreepSpawn[i-1])
set j = 1
loop
exitwhen j > 6
set u = CreateUnit( Player(PLAYER_NEUTRAL_AGGRESSIVE), ChooseRandomCreep(GetRandomInt(i-1,i+1)), GetRandomReal(minX,maxX), GetRandomReal(minY,maxY), GetRandomReal(0, 360) )
set id=H2I(u)
set CreepsRect[id]=i-1
set j = j + 1
endloop
set i=i+1
endloop
// Create enemy hero and creeps
set CreepSpawn[4]=gg_rct_Creep_Spawn_4
set maxX = GetRectMaxX(CreepSpawn[4])
set minX = GetRectMinX(CreepSpawn[4])
set maxY = GetRectMaxY(CreepSpawn[4])
set minY = GetRectMinY(CreepSpawn[4])
set Tauren = CreateUnit( Player(PLAYER_NEUTRAL_AGGRESSIVE), 'Otch', GetRandomReal(minX,maxX), GetRandomReal(minY,maxY), GetRandomReal(0, 360) )
call SetHeroLevel( Tauren, 10, false )
call SelectHeroSkill( Tauren, 'AOre' )
call SelectHeroSkill( Tauren, 'AOsh' )
call SelectHeroSkill( Tauren, 'AOsh' )
call SelectHeroSkill( Tauren, 'AOsh' )
call SelectHeroSkill( Tauren, 'AOws' )
call SelectHeroSkill( Tauren, 'AOws' )
call SelectHeroSkill( Tauren, 'AOws' )
call SelectHeroSkill( Tauren, 'AOae' )
call SelectHeroSkill( Tauren, 'AOae' )
call SelectHeroSkill( Tauren, 'AOae' )
set i = 1
loop
exitwhen i > 3
set u = CreateUnit( Player(PLAYER_NEUTRAL_AGGRESSIVE), 'ogru', GetRandomReal(minX,maxX), GetRandomReal(minY,maxY), GetRandomReal(0, 360) )
set id=H2I(u)
set CreepsRect[id]=4
set i = i + 1
endloop
// Start weather effect timer and preload weather
call AddWeatherEffect(bj_mapInitialPlayableArea, 'RAhr')
call AddWeatherEffect(bj_mapInitialPlayableArea, 'RAlr')
call AddWeatherEffect(bj_mapInitialPlayableArea, 'FDwh')
call AddWeatherEffect(bj_mapInitialPlayableArea, 'FDwl')
call AddWeatherEffect(bj_mapInitialPlayableArea, 'WOlw')
call AddWeatherEffect(bj_mapInitialPlayableArea, 'RLlr')
call TimerStart(Weather,GetRandomReal(30.,45.),false,function RandomWeather)
// Create creep camp revival trigger
call TriggerRegisterPlayerUnitEvent(trig, Player(PLAYER_NEUTRAL_AGGRESSIVE), EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddCondition(trig,Condition(function CreepFilter))
call TriggerAddAction(trig, function CreepRevive )
// Create footmen revival trigger
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig,Player(0), EVENT_PLAYER_UNIT_DEATH,null )
call TriggerAddCondition(trig,Condition( function FootmenFilter ))
call TriggerAddAction( trig, function FootmenRevive )
// Create cheats trigger
set trig = CreateTrigger()
call TriggerRegisterPlayerChatEvent( trig, Player(0), "restore", true )
call TriggerRegisterPlayerChatEvent( trig, Player(0), "suicide", true )
call TriggerRegisterPlayerChatEvent( trig, Player(0), "level", false )
call TriggerAddAction( trig, function Cheats )
// Create hero revival trigger
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent( trig,Player(0), EVENT_PLAYER_UNIT_DEATH,null )
call TriggerRegisterPlayerUnitEvent( trig,Player(PLAYER_NEUTRAL_AGGRESSIVE), EVENT_PLAYER_UNIT_DEATH,null )
call TriggerAddCondition( trig, Condition( function HeroFilter ) )
call TriggerAddAction( trig, function HeroRevive )
// Time of day dependant sphere
set trig=CreateTrigger()
call TriggerRegisterGameStateEvent(trig, GAME_STATE_TIME_OF_DAY, EQUAL, 6.)
call TriggerRegisterGameStateEvent(trig, GAME_STATE_TIME_OF_DAY, EQUAL, 18.)
call TriggerAddAction(trig,function ChangeSphere)
call PreloadAbil('A001')
set Footmensayings[1]="I'll be back..."
set Footmensayings[2]="Catch you on the flip side"
set Footmensayings[3]="Wake me up when September ends"
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Bash initializer Init
globals
private constant integer ABIL = 'AOae'
private constant attacktype ATTACKTYPE = ATTACK_TYPE_HERO
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_NORMAL
private constant real DECELFACTOR = 0.95
private constant boolean KILLTREES = true
private constant string SLIDESFX = "sfx\\DustAndRocks.mdx"
private constant real TIMEOUT = 0.03125
private hashtable HT=InitHashtable()
private real FRAMERATE=1./TIMEOUT
endglobals
private function Chance takes integer level returns real
return .33
endfunction
private function Damage takes integer level returns real
return level*10.+15.
endfunction
private function Duration takes integer level returns real
return .75+level*.25
endfunction
private function SlideDamage takes integer level returns real
return level*10.
endfunction
private function SlideSpeed takes integer level returns real
return 500.+level*100.
endfunction
//===========================================================\\
private struct data
timer t
trigger trig
unit cast
unit targ
player p
effect sfx=null
real speed
real time=0.
real maxtime
real ang
real cos
real sin
real slidedamage
integer level
method onDestroy takes nothing returns nothing
call ReleaseTimer(.t)
if .sfx!=null then
call DestroyEffect(.sfx)
endif
call FlushChildHashtable(HT,h2i(.trig))
call DestroyTrigger(.trig)
endmethod
endstruct
private function Effects takes nothing returns nothing
local data d=GetTimerData(GetExpiredTimer())
call SetUnitPosition(d.targ,GetUnitX(d.targ)+d.speed*d.cos,GetUnitY(d.targ)+d.speed*d.sin)
call UnitDamageTarget(d.cast,d.targ,d.slidedamage,false,false,ATTACKTYPE,DAMAGETYPE,null)
static if KILLTREES then
call KillDesInRange(GetUnitX(d.targ),GetUnitY(d.targ),100.)
endif
set d.speed=d.speed*DECELFACTOR
set d.time=d.time+TIMEOUT
if d.time>=d.maxtime then
call d.destroy()
endif
endfunction
private function Actions takes nothing returns boolean
local data d=LoadInteger(HT,h2i(GetTriggeringTrigger()),0)
if GetEventDamageSource()==d.cast and GetEventDamage()>.1 then
call DisableTrigger(d.trig)
set d.level=GetUnitAbilityLevel(d.cast,ABIL)
call UnitDamageTarget(d.cast,d.targ,Damage(d.level),false,false,ATTACKTYPE,DAMAGETYPE,null)
set d.maxtime=Duration(d.level)
set d.speed=SlideSpeed(d.level)/FRAMERATE
set d.slidedamage=SlideDamage(d.level)/(d.maxtime/TIMEOUT)
set d.sfx=AddSpecialEffectTarget(SLIDESFX,d.targ,"origin")
set d.ang=Atan2(GetUnitY(d.targ)-GetUnitY(d.cast),GetUnitX(d.targ)-GetUnitX(d.cast))
set d.cos=Cos(d.ang)
set d.sin=Sin(d.ang)
call PauseTimer(d.t)
call TimerStart(d.t,TIMEOUT,true,function Effects)
endif
return false
endfunction
private function Destroy takes nothing returns nothing
local data d=GetTimerData(GetExpiredTimer())
call d.destroy()
endfunction
private function onDamage takes nothing returns nothing
local data d=data.create()
set d.cast=GetAttacker()
set d.p=GetOwningPlayer(d.cast)
set d.targ=GetTriggerUnit()
set d.trig=CreateTrigger()
call TriggerRegisterUnitEvent(d.trig,d.targ,EVENT_UNIT_DAMAGED)
call TriggerAddCondition(d.trig,Condition(function Actions))
call SaveInteger(HT,h2i(d.trig),0,d)
set d.t=NewTimer()
call SetTimerData(d.t,d)
call TimerStart(d.t,1.,false,function Destroy)
endfunction
private function Conditions takes nothing returns boolean
if GetUnitAbilityLevel(GetAttacker(),ABIL)>0 and GetRandomReal(0.0,1.0)<=Chance(GetUnitAbilityLevel(GetAttacker(),ABIL)) then
call onDamage()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ATTACKED)
call TriggerAddCondition(t,Condition(function Conditions))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Shockwave initializer Init
private keyword data
globals
private constant integer ABIL = 'AOsh'
private constant attacktype ATTACKTYPE = ATTACK_TYPE_MAGIC
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_MAGIC
private constant real DECELFACTOR = 0.95
private constant boolean ENDSLIDE = true
private constant boolean KILLTREES = true
private constant real RADIUS = 150.0
private constant real SCALE = 1.0
private constant real SLIDEBREAK = 10.0
private constant string SLIDESFX = "sfx\\DustAndRocks.mdx"
private constant real TIMEOUT = 0.03125
private constant string WAVESFX = "Abilities\\Spells\\Orc\\Shockwave\\ShockwaveMissile.mdl"
private data I
private unit T
private group G=CreateGroup()
private boolexpr B
private hashtable HT=InitHashtable()
private real FRAMERATE=1./TIMEOUT
endglobals
private function Damage takes integer level returns real
return level*33.
endfunction
private function SlideSpeed takes integer level returns real
return 500.+level*100.
endfunction
private function WaveDistance takes integer level returns real
return 900.+level*50.
endfunction
private function WaveSpeed takes integer level returns real
return 1050.
endfunction
//===========================================================\\
private struct data
timer t
unit cast
unit wave
player p
group g
effect sfx
real ang
real sin
real cos
real distance=0.
real totaldistance
real damage
real speed
real wavespeed
real break=SLIDEBREAK/FRAMERATE
integer level
static method RemoveSFX takes nothing returns nothing
local data this=I
call DestroyEffect(LoadEffectHandle(HT,h2i(.cast),h2i(GetEnumUnit())))
endmethod
method onDestroy takes nothing returns nothing
set I=this
call ForGroup(.g,function data.RemoveSFX)
call DestroyEffect(.sfx)
call RemoveUnit(.wave)
call ReleaseTimer(.t)
call ReleaseGroup(.g)
call FlushChildHashtable(HT,h2i(.cast))
endmethod
endstruct
private function Filt takes nothing returns boolean
local data d=I
local integer i
set T=GetFilterUnit()
if UnitAlive(T) and IsUnitEnemy(T,d.p) and not IsUnitInGroup(T,d.g) then
call SaveEffectHandle(HT,h2i(d.cast),h2i(T),AddSpecialEffectTarget(SLIDESFX,T,"origin"))
call UnitDamageTarget(d.cast,T,d.damage,false,false,ATTACKTYPE,DAMAGETYPE,null)
call GroupAddUnit(d.g,T)
endif
return false
endfunction
private function Movement takes nothing returns nothing
local data d=I
set T=GetEnumUnit()
call SetUnitPosition(T,GetUnitX(T)+d.cos,GetUnitY(T)+d.sin)
static if KILLTREES then
call KillDesInRange(GetUnitX(T),GetUnitY(T),100.)
endif
endfunction
private function EndSlide takes nothing returns nothing
local data d=GetTimerData(GetExpiredTimer())
set I=d
call ForGroup(d.g,function Movement)
set d.speed=d.speed*DECELFACTOR
if d.speed<=d.break then
call d.destroy()
else
set d.cos=d.speed*Cos(d.ang)
set d.sin=d.speed*Sin(d.ang)
endif
endfunction
private function Effects takes nothing returns nothing
local data d=GetTimerData(GetExpiredTimer())
set d.distance=d.distance+d.wavespeed
if d.distance>=d.totaldistance then
static if ENDSLIDE then
call ShowUnit(d.wave,false)
set d.speed=SlideSpeed(d.level)/FRAMERATE
set d.cos=d.speed*Cos(d.ang)
set d.sin=d.speed*Sin(d.ang)
call PauseTimer(d.t)
call TimerStart(d.t,TIMEOUT,true,function EndSlide)
else
call d.destroy()
endif
else
set I=d
call ForGroup(d.g,function Movement)
call SetUnitX(d.wave,GetUnitX(d.wave)+d.cos)
call SetUnitY(d.wave,GetUnitY(d.wave)+d.sin)
call GroupClear(G)
call GroupEnumUnitsInRange(G,GetUnitX(d.wave),GetUnitY(d.wave),RADIUS,B)
endif
endfunction
private function Actions takes nothing returns nothing
local data d=data.create()
set d.cast=GetTriggerUnit()
set d.p=GetOwningPlayer(d.cast)
set d.level=GetUnitAbilityLevel(d.cast,ABIL)
set d.ang=Atan2(GetSpellTargetY()-GetUnitY(d.cast),GetSpellTargetX()-GetUnitX(d.cast))
set d.wave=CreateUnit(d.p,CasterId,GetUnitX(d.cast),GetUnitY(d.cast),d.ang*bj_RADTODEG)
set d.wavespeed=WaveSpeed(d.level)/FRAMERATE
set d.sfx=AddSpecialEffectTarget(WAVESFX,d.wave,"origin")
call SetUnitScale(d.wave,SCALE,SCALE,SCALE)
set d.cos=d.wavespeed*Cos(d.ang)
set d.sin=d.wavespeed*Sin(d.ang)
set d.damage=Damage(d.level)
set d.totaldistance=WaveDistance(d.level)
set d.g=NewGroup()
set d.t=NewTimer()
call SetTimerData(d.t,d)
call TimerStart(d.t,TIMEOUT,true,function Effects)
endfunction
private function Conditions takes nothing returns boolean
if GetSpellAbilityId()==ABIL then
call Actions()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterUnitEvent(t,Tauren,EVENT_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Conditions))
set B=Condition(function Filt)
call Preload(WAVESFX)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Warstomp initializer Init
private keyword data
globals
private constant integer ABIL = 'AOws'
private constant real DECELFACTOR = 0.97
private constant boolean KILLTREES = true
private constant string SLIDESFX = "sfx\\DustAndRocks.mdx"
private constant real TIMEOUT = 0.03125
private data I
private unit T
private hashtable HT=InitHashtable()
private real FRAMERATE=1./TIMEOUT
endglobals
private function Duration takes integer level returns real
return level+1.
endfunction
private function Range takes integer level returns real
return level*50.+200.
endfunction
private function SlideSpeed takes integer level returns real
return 350.+level*50.
endfunction
//===========================================================\\
private struct data
timer t
unit cast
player p
group g
real speed
real time=0.
real maxtime
real x
real y
integer level
static method RemoveSFX takes nothing returns nothing
local data this=I
call DestroyEffect(LoadEffectHandle(HT,h2i(.cast),h2i(GetEnumUnit())))
endmethod
method onDestroy takes nothing returns nothing
set I=this
call ForGroup(.g,function data.RemoveSFX)
call ReleaseTimer(.t)
call ReleaseGroup(.g)
call FlushChildHashtable(HT,h2i(.cast))
endmethod
endstruct
private function Filt takes nothing returns boolean
local data d=I
set T=GetFilterUnit()
if UnitAlive(T) and IsUnitEnemy(T,d.p) then
call SaveEffectHandle(HT,h2i(d.cast),h2i(T),AddSpecialEffectTarget(SLIDESFX,T,"origin"))
return true
endif
return false
endfunction
private function Movement takes nothing returns nothing
local data d=I
set T=GetEnumUnit()
call SetUnitX(T,GetUnitX(T)+d.speed*Cos(Atan2(GetUnitY(T)-d.y,GetUnitX(T)-d.x)))
call SetUnitY(T,GetUnitY(T)+d.speed*Sin(Atan2(GetUnitY(T)-d.y,GetUnitX(T)-d.x)))
static if KILLTREES then
call KillDesInRange(GetUnitX(T),GetUnitY(T),100.)
endif
endfunction
private function Effects takes nothing returns nothing
local data d=GetTimerData(GetExpiredTimer())
set I=d
call ForGroup(d.g,function Movement)
set d.speed=d.speed*DECELFACTOR
set d.time=d.time+TIMEOUT
if d.time>=d.maxtime then
call d.destroy()
endif
endfunction
private function Actions takes nothing returns nothing
local data d=data.create()
set d.cast=GetTriggerUnit()
set d.p=GetOwningPlayer(d.cast)
set d.level=GetUnitAbilityLevel(d.cast,ABIL)
set d.maxtime=Duration(d.level)
set d.speed=SlideSpeed(d.level)/FRAMERATE
set d.x=GetUnitX(d.cast)
set d.y=GetUnitY(d.cast)
set d.g=NewGroup()
set I=d
call GroupEnumUnitsInRange(d.g,d.x,d.y,Range(d.level),Condition(function Filt))
set d.t=NewTimer()
call SetTimerData(d.t,d)
call TimerStart(d.t,TIMEOUT,true,function Effects)
endfunction
private function Conditions takes nothing returns boolean
if GetSpellAbilityId()==ABIL then
call Actions()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterUnitEvent(t,Tauren,EVENT_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Conditions))
call Preload(SLIDESFX)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ASCII initializer Init
globals
private constant integer Base10 = 0 // set to 0 for no conversion
private constant integer Rawcode = 0 // set to 0 for no conversion
//==NO TOUCHING==\\
private string array ASCII
private integer start=48
private integer end=122
endglobals
function Convert takes integer String returns nothing
local string s=""
local integer array count
local integer array Base
local integer array Char
set Base[1]=String
if String!=0 then
set ASCII[48]="0"
set ASCII[49]="1"
set ASCII[50]="2"
set ASCII[51]="3"
set ASCII[52]="4"
set ASCII[53]="5"
set ASCII[54]="6"
set ASCII[55]="7"
set ASCII[56]="8"
set ASCII[57]="9"
set ASCII[65]="A"
set ASCII[66]="B"
set ASCII[67]="C"
set ASCII[68]="D"
set ASCII[69]="E"
set ASCII[70]="F"
set ASCII[71]="G"
set ASCII[72]="H"
set ASCII[73]="I"
set ASCII[74]="J"
set ASCII[75]="K"
set ASCII[76]="L"
set ASCII[77]="M"
set ASCII[78]="N"
set ASCII[79]="O"
set ASCII[80]="P"
set ASCII[81]="Q"
set ASCII[82]="R"
set ASCII[83]="S"
set ASCII[84]="T"
set ASCII[85]="U"
set ASCII[86]="V"
set ASCII[87]="W"
set ASCII[88]="X"
set ASCII[89]="Y"
set ASCII[90]="Z"
set ASCII[97]="a"
set ASCII[98]="b"
set ASCII[99]="c"
set ASCII[100]="d"
set ASCII[101]="e"
set ASCII[102]="f"
set ASCII[103]="g"
set ASCII[104]="h"
set ASCII[105]="i"
set ASCII[106]="j"
set ASCII[107]="k"
set ASCII[108]="l"
set ASCII[109]="m"
set ASCII[110]="n"
set ASCII[111]="o"
set ASCII[112]="p"
set ASCII[113]="q"
set ASCII[114]="r"
set ASCII[115]="s"
set ASCII[116]="t"
set ASCII[117]="u"
set ASCII[118]="v"
set ASCII[119]="w"
set ASCII[120]="x"
set ASCII[121]="y"
set ASCII[122]="z"
set Char[1]=ModuloInteger(Base[1], 256)
set Base[2]=(Base[1]-Char[1])/256
set Char[2]=ModuloInteger(Base[2], 256)
set Base[3]=(Base[2]-Char[2])/256
set Char[3]=ModuloInteger(Base[3], 256)
set Base[4]=(Base[3]-Char[3])/256
set Char[4]=ModuloInteger(Base[4], 256)
set count[1]=1
loop
exitwhen count[1]==5
set count[2]=start
loop
if Char[count[1]]==count[2] then
set s=s+ASCII[count[2]]
exitwhen true
elseif count[2]>end then
call BJDebugMsg("|c00FF0000Error during ASCII base 10 to string conversion.|r")
return
endif
set count[2]=count[2]+1
endloop
set count[1]=count[1]+1
endloop
call BJDebugMsg("ASCII base 10 to string conversion is: |c00FF0000"+SubString(s,3,4)+SubString(s,2,3)+SubString(s,1,2)+SubString(s,0,1)+"|r")
endif
endfunction
private function Init takes nothing returns nothing
if Base10!=0 then
call Convert(Base10)
endif
if Rawcode!=0 then
call BJDebugMsg("WC3 ability rawcode to ASCII base 10 conversion is: |c00FF0000"+I2S(Rawcode)+"|r")
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
globals
// High enough so the unit is no longer visible, low enough so the
// game doesn't crash...
//
// I think you need 0.0 or soemthing negative prior to patch 1.22
//
private constant real EXTRA = 500.0
endglobals
//=========================================================================================
globals
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns nothing
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
endfunction
private function init takes nothing returns nothing
local trigger t=CreateTrigger()
local region r=CreateRegion()
local rect rc
set minx=GetCameraBoundMinX() - EXTRA
set miny=GetCameraBoundMinY() - EXTRA
set maxx=GetCameraBoundMaxX() + EXTRA
set maxy=GetCameraBoundMaxY() + EXTRA
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddAction(t, function dis)
//this is not necessary but I'll do it anyway:
set t=null
set r=null
set rc=null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Colors initializer Init
globals
constant string BLACK = "|c00000000"
constant string WHITE = "|c00FFFFFF"
constant string GOLD = "|c00FFCC00"
constant string GREY = "|c007d7d7d"
constant string DARKGREY= "|c00696969"
constant string RED = "|c00FF0000"
constant string GREEN = "|c0000FF00"
constant string BLUE = "|c000000FF"
constant string YELLOW = "|c00FFFF00"
constant string ORANGE = "|c00FF7F00"
constant string PINK = "|c00FF9696"
constant string LIME = "|c0096FF96"
constant string MAGENTA = "|c00FF00FF"
constant string NAVY = "|c00000064"
constant string PC0 = "|c00FF0303"
constant integer PC0_R = 255
constant integer PC0_G = 3
constant integer PC0_B = 3
constant string PC1 = "|c000042FF"
constant integer PC1_R = 0
constant integer PC1_G = 66
constant integer PC1_B = 255
constant string PC2 = "|c001CE6B9"
constant integer PC2_R = 28
constant integer PC2_G = 230
constant integer PC2_B = 185
constant string PC3 = "|c00540081"
constant integer PC3_R = 84
constant integer PC3_G = 0
constant integer PC3_B = 129
constant string PC4 = "|c00FFFC01"
constant integer PC4_R = 255
constant integer PC4_G = 252
constant integer PC4_B = 1
constant string PC5 = "|c00fEBA0E"
constant integer PC5_R = 254
constant integer PC5_G = 186
constant integer PC5_B = 14
constant string PC6 = "|c0020C000"
constant integer PC6_R = 32
constant integer PC6_G = 192
constant integer PC6_B = 0
constant string PC7 = "|c00E55BB0"
constant integer PC7_R = 229
constant integer PC7_G = 91
constant integer PC7_B = 176
constant string PC8 = "|c00959697"
constant integer PC8_R = 149
constant integer PC8_G = 150
constant integer PC8_B = 151
constant string PC9 = "|c007EBFF1"
constant integer PC9_R = 126
constant integer PC9_G = 191
constant integer PC9_B = 241
constant string PC10 = "|c00106246"
constant integer PC10_R = 16
constant integer PC10_G = 92
constant integer PC10_B = 70
constant string PC11 = "|c004E2A04"
constant integer PC11_R = 78
constant integer PC11_G = 42
constant integer PC11_B = 4
string array PC
integer array PC_R
integer array PC_G
integer array PC_B
endglobals
private function Init takes nothing returns nothing
set PC[0] = PC0
set PC[1] = PC1
set PC[2] = PC2
set PC[3] = PC3
set PC[4] = PC4
set PC[5] = PC5
set PC[6] = PC6
set PC[7] = PC7
set PC[8] = PC8
set PC[9] = PC9
set PC[10] = PC10
set PC[11] = PC11
set PC[12] = "cerror"
set PC_R[0] = PC0_R
set PC_R[1] = PC1_R
set PC_R[2] = PC2_R
set PC_R[3] = PC3_R
set PC_R[4] = PC4_R
set PC_R[5] = PC5_R
set PC_R[6] = PC6_R
set PC_R[7] = PC7_R
set PC_R[8] = PC8_R
set PC_R[9] = PC9_R
set PC_R[10] = PC10_R
set PC_R[11] = PC11_R
set PC_R[12] = -1
set PC_G[0] = PC0_G
set PC_G[1] = PC1_G
set PC_G[2] = PC2_G
set PC_G[3] = PC3_G
set PC_G[4] = PC4_G
set PC_G[5] = PC5_G
set PC_G[6] = PC6_G
set PC_G[7] = PC7_G
set PC_G[8] = PC8_G
set PC_G[9] = PC9_G
set PC_G[10] = PC10_G
set PC_G[11] = PC11_G
set PC_G[12] = -1
set PC_B[0] = PC0_B
set PC_B[1] = PC1_B
set PC_B[2] = PC2_B
set PC_B[3] = PC3_B
set PC_B[4] = PC4_B
set PC_B[5] = PC5_B
set PC_B[6] = PC6_B
set PC_B[7] = PC7_B
set PC_B[8] = PC8_B
set PC_B[9] = PC9_B
set PC_B[10] = PC10_B
set PC_B[11] = PC11_B
set PC_B[12] = -1
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//* [group] ENUM_GROUP As you might expect, this group is good for
//* when you need a group just for enumeration.
//* [boolexpr] BOOLEXPR_TRUE This is a true boolexpr, which is important
//* because a 'null' boolexpr in enumeration
//* calls results in a leak. Use this instead.
//* [boolexpr] BOOLEXPR_FALSE This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//* local group MyGroup = NewGroup()
//* call GroupRefresh(MyGroup)
//* call ReleaseGroup(MyGroup)
//* call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//* call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
//If you don't have xebasic in your map, this value will be used instead.
//This value corresponds to the max collision size of a unit in your map.
private constant real MAX_COLLISION_SIZE = 150.00
//If you are insane and don't care about any of the protection involved in
//this library, but want this script to be really fast, set this to true.
private constant boolean LESS_SAFETY = false
endglobals
globals
//* Constants that are available to the user
group ENUM_GROUP = CreateGroup()
boolexpr BOOLEXPR_TRUE = null
boolexpr BOOLEXPR_FALSE = null
endglobals
globals
//* Hashtable for debug purposes
private hashtable ht = InitHashtable()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Arrays and counter for the group stack
private group array Groups
private integer Count = 0
//* Variables for use with the GroupUnitsInArea function
private real X = 0.
private real Y = 0.
private real R = 0.
private hashtable H = InitHashtable()
endglobals
private function HookDestroyGroup takes group g returns nothing
if g == ENUM_GROUP then
call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
endif
endfunction
debug hook DestroyGroup HookDestroyGroup
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
static if not LESS_SAFETY then
call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
endif
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer id = GetHandleId(g)
static if LESS_SAFETY then
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
else
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif not HaveSavedInteger(ht, 0, id) then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
return false
elseif LoadInteger(ht, 0, id) == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
call SaveInteger(ht, 0, id, 2)
endif
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
return true
endfunction
private function Filter takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction
private function HookDestroyBoolExpr takes boolexpr b returns nothing
local integer bid = GetHandleId(b)
if HaveSavedHandle(H, 0, bid) then
//Clear the saved boolexpr
call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
call RemoveSavedHandle(H, 0, bid)
endif
endfunction
hook DestroyBoolExpr HookDestroyBoolExpr
private constant function GetRadius takes real radius returns real
static if LIBRARY_xebasic then
return radius+XE_MAX_COLLISION_SIZE
else
return radius+MAX_COLLISION_SIZE
endif
endfunction
function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
local integer bid = 0
//Set variables to new values
set X = x
set Y = y
set R = radius
if filter == null then
//Adjusts for null boolexprs passed to the function
set filter = Condition(function Filter)
else
//Check for a saved boolexpr
set bid = GetHandleId(filter)
if HaveSavedHandle(H, 0, bid) then
//Set the filter to use to the saved one
set filter = LoadBooleanExprHandle(H, 0, bid)
else
//Create a new And() boolexpr for this filter
set filter = And(Condition(function Filter), filter)
call SaveBooleanExprHandle(H, 0, bid, filter)
endif
endif
//Enumerate, if they want to use the boolexpr, this lets them
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
//Set variables to new values
set X = x
set Y = y
set R = radius
//Enumerate
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
private function True takes nothing returns boolean
return true
endfunction
private function False takes nothing returns boolean
return false
endfunction
private function Init takes nothing returns nothing
set BOOLEXPR_TRUE = Condition(function True)
set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library SimError initializer init
//**************************************************************************************************
//*
//* SimError
//*
//* Mimic an interface error message
//* call SimError(ForPlayer, msg)
//* ForPlayer : The player to show the error
//* msg : The error
//*
//* To implement this function, copy this trigger and paste it in your map.
//* Unless of course you are actually reading the library from wc3c's scripts section, then just
//* paste the contents into some custom text trigger in your map.
//*
//**************************************************************************************************
//==================================================================================================
globals
private sound error
endglobals
//====================================================================================================
function SimError takes player ForPlayer, string msg returns nothing
set msg="\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00"+msg+"|r"
if (GetLocalPlayer() == ForPlayer) then
call ClearTextMessages()
call DisplayTimedTextToPlayer( ForPlayer, 0.52, 0.96, 2.00, msg )
call StartSound( error )
endif
endfunction
private function init takes nothing returns nothing
set error=CreateSoundFromLabel("InterfaceError",false,false,false,10,10)
//call StartSound( error ) //apparently the bug in which you play a sound for the first time
//and it doesn't work is not there anymore in patch 1.22
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//==============================================================================
// TEXT TAG - Floating text system by Cohadar - v5.0
//==============================================================================
//
// PURPOUSE:
// * Displaying floating text - the easy way
// * Has a set of useful and commonly needed texttag functions
//
// CREDITS:
// * DioD - for extracting proper color, fadepoint and lifespan parameters
// for default warcraft texttags (from miscdata.txt)
//
// HOW TO IMPORT:
// * Just create a trigger named TextTag
// convert it to text and replace the whole trigger text with this one
//==============================================================================
library TextTag
globals
// for custom centered texttags
private constant real MEAN_CHAR_WIDTH = 5.5
private constant real MAX_TEXT_SHIFT = 200.0
private constant real DEFAULT_HEIGHT = 16.0
// for default texttags
private constant real SIGN_SHIFT = 16.0
private constant real FONT_SIZE = 0.024
private constant string MISS = "miss"
endglobals
//===========================================================================
// Custom centered texttag on (x,y) position
// color is in default wc3 format, for example "|cFFFFCC00"
//===========================================================================
public function XY takes real x, real y, string text, string color returns nothing
local texttag tt = CreateTextTag()
local real shift = RMinBJ(StringLength(text)*MEAN_CHAR_WIDTH, MAX_TEXT_SHIFT)
call SetTextTagText(tt, color+text, FONT_SIZE)
call SetTextTagPos(tt, x-shift, y, DEFAULT_HEIGHT)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.5)
call SetTextTagLifespan(tt, 4.0)
call SetTextTagPermanent(tt, false)
set tt = null
endfunction
//===========================================================================
// Custom centered texttag above unit
//===========================================================================
public function Unit takes unit whichUnit, string text, string color returns nothing
local texttag tt = CreateTextTag()
local real shift = RMinBJ(StringLength(text)*MEAN_CHAR_WIDTH, MAX_TEXT_SHIFT)
call SetTextTagText(tt, color+text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit)-shift, GetUnitY(whichUnit), DEFAULT_HEIGHT)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.5)
call SetTextTagLifespan(tt, 4.0)
call SetTextTagPermanent(tt, false)
set tt = null
endfunction
//===========================================================================
// Standard wc3 gold bounty texttag, displayed only to killing player
//===========================================================================
public function GoldBounty takes unit whichUnit, integer bounty, player killer returns nothing
local texttag tt = CreateTextTag()
local string text = "+" + I2S(bounty)
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit)-SIGN_SHIFT, GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 255, 220, 0, 255)
call SetTextTagVelocity(tt, 0.0, 0.03)
call SetTextTagVisibility(tt, GetLocalPlayer()==killer)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 3.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
//==============================================================================
public function LumberBounty takes unit whichUnit, integer bounty, player killer returns nothing
local texttag tt = CreateTextTag()
local string text = "+" + I2S(bounty)
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit)-SIGN_SHIFT, GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 0, 200, 80, 255)
call SetTextTagVelocity(tt, 0.0, 0.03)
call SetTextTagVisibility(tt, GetLocalPlayer()==killer)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 3.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
//===========================================================================
public function ManaBurn takes unit whichUnit, integer dmg returns nothing
local texttag tt = CreateTextTag()
local string text = "-" + I2S(dmg)
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit)-SIGN_SHIFT, GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 82, 82 ,255 ,255)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 5.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
//===========================================================================
public function Miss takes unit whichUnit returns nothing
local texttag tt = CreateTextTag()
call SetTextTagText(tt, MISS, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit), GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 255, 0, 0, 255)
call SetTextTagVelocity(tt, 0.0, 0.03)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 1.0)
call SetTextTagLifespan(tt, 3.0)
call SetTextTagPermanent(tt, false)
set tt = null
endfunction
//===========================================================================
public function CriticalStrike takes unit whichUnit, integer dmg returns nothing
local texttag tt = CreateTextTag()
local string text = I2S(dmg) + "!"
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit), GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 255, 0, 0, 255)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 5.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
//===========================================================================
public function ShadowStrike takes unit whichUnit, integer dmg, boolean initialDamage returns nothing
local texttag tt = CreateTextTag()
local string text = I2S(dmg)
if initialDamage then
set text = text + "!"
endif
call SetTextTagText(tt, text, FONT_SIZE)
call SetTextTagPos(tt, GetUnitX(whichUnit), GetUnitY(whichUnit), 0.0)
call SetTextTagColor(tt, 160, 255, 0, 255)
call SetTextTagVelocity(tt, 0.0, 0.04)
call SetTextTagVisibility(tt, true)
call SetTextTagFadepoint(tt, 2.0)
call SetTextTagLifespan(tt, 5.0)
call SetTextTagPermanent(tt, false)
set text = null
set tt = null
endfunction
endlibrary
//TESH.scrollpos=33
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFFSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = false
private constant boolean USE_FLEXIBLE_OFFSET = true
private integer OFFSET
private integer VOFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
set tT[0]=CreateTimer()
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
set OFFSET=REALOFFSET
set VOFFSET=OFFSET
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=120
//TESH.alwaysfold=0
library UtilityFunctions initializer Init needs TimerUtils
globals
constant integer CasterId = 'n000' // - Caster dummy rawcode
integer HandleOffset // - First HandleId
private constant integer LifeBonus='dprv' // - Shield System
endglobals
//==================================================================================================
// - Making the obsolete return bug fix more convenient
function H2I takes handle h returns integer
return GetHandleId(h)-HandleOffset
endfunction
function h2i takes handle h returns integer
return GetHandleId(h)-HandleOffset
endfunction
//==================================================================================================
// - Geometry
function ABPXY takes real x1, real y1, real x2, real y2 returns real // - Angle between coords, returns radians
return Atan2(y2-y1, x2-x1)
endfunction
function AngleBetweenPointsXY takes real x1, real y1, real x2, real y2 returns real
return ABPXY(x1,y1,x2,y2)
endfunction
function ABU takes unit a, unit b returns real // - Angle between units, returns radians
return Atan2(GetUnitY(b) - GetUnitY(a), GetUnitX(b)- GetUnitX(a))
endfunction
function AngleBetweenUnits takes unit a, unit b returns real
return ABU(a,b)
endfunction
function DBPXY takes real x1, real y1, real x2, real y2 returns real // - Distance between coords
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
function DistanceBetweenPointsXY takes real x1, real y1, real x2, real y2 returns real
return DBPXY(x1,y1,x2,y2)
endfunction
function DBU takes unit a, unit b returns real // - Distance between units
local real dx = GetUnitX(b) - GetUnitX(a)
local real dy = GetUnitY(b) - GetUnitY(a)
return SquareRoot(dx * dx + dy * dy)
endfunction
function DistanceBetweenUnits takes unit a, unit b returns real
return DBU(a,b)
endfunction
globals
private location LOC = Location(0.,0.)
endglobals
function GetXYZ takes real x, real y returns real // - Z height at a coordinate
call MoveLocation(LOC,x,y)
return GetLocationZ(LOC)
endfunction
function GetCoordinateZ takes real x, real y returns real
return GetXYZ(x,y)
endfunction
function GetUnitZ takes unit a returns real // - Z height where a unit resides
call MoveLocation(LOC,GetUnitX(a),GetUnitY(a))
return GetLocationZ(LOC)
endfunction
//==================================================================================================
// - Quicker to write function to display text when testing
function Echo takes string s returns nothing
if (IsPlayerInForce(GetLocalPlayer(), bj_FORCE_ALL_PLAYERS)) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, s)
endif
endfunction
//==================================================================================================
// - Pre loading abilities
function PreloadAbil takes integer abil returns nothing
debug if bj_ghoul[33]!=null and UnitAlive(bj_ghoul[33]) then
call UnitAddAbility(bj_ghoul[33],abil)
debug else
debug call BJDebugMsg("PreloadAbil Error: No preload unit found")
debug endif
endfunction
//==================================================================================================
// - Destroy an effect after a duration
private struct timedeffects
effect e
timer t
endstruct
private function EndEffect takes nothing returns nothing
local timedeffects d = GetTimerData(GetExpiredTimer())
call DestroyEffect(d.e)
call ReleaseTimer(d.t)
call d.destroy()
endfunction
function DestroyEffectTimed takes effect sfx, real time returns nothing
local timedeffects d = timedeffects.create()
set d.e = sfx
set d.t = NewTimer()
call TimerStart(d.t,time,false,function EndEffect)
call SetTimerData(d.t,d)
endfunction
//==================================================================================================
// - Self explanatory
globals
timer GameTime = CreateTimer()
endglobals
function PolledWait2 takes real duration returns nothing
local real timeRemaining
local real st = TimerGetElapsed(GameTime)
if duration > 0. then
loop
set timeRemaining = duration - TimerGetElapsed(GameTime) + st
exitwhen timeRemaining <= 0
if timeRemaining > 2.00 then
call TriggerSleepAction(0.1 * timeRemaining)
else
call TriggerSleepAction(0.0)
endif
endloop
endif
endfunction
//==================================================================================================
// - Kill destructables in an area
globals
private rect R
private boolexpr ValidDes
private unit treedummy
endglobals
private function KillDestructables takes nothing returns boolean
if IssueTargetOrder(treedummy,"harvest",GetFilterDestructable()) then
call KillDestructable(GetFilterDestructable())
endif
return false
endfunction
function KillDesInRange takes real x, real y, real radius returns nothing
call SetRect(R,x-radius,y-radius,x+radius,y+radius)
call PauseUnit(treedummy,false)
call EnumDestructablesInRect(R,ValidDes,null)
call PauseUnit(treedummy,true)
endfunction
function KillDestructablesInRange takes real x, real y, real radius returns nothing
call KillDesInRange(x,y,radius)
endfunction
//===================================================================================================
// - Setup player colors and names, or get them
// - Courtesy of Acehart
globals
string array PlayerColors
string array PlayerNames
endglobals
function Colors_and_Names takes nothing returns nothing
local integer i = 0
loop
exitwhen i > bj_MAX_PLAYERS
if ( GetPlayerColor(Player(i)) == PLAYER_COLOR_RED ) then
set PlayerColors[i] = "|c00ff0303"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_BLUE ) then
set PlayerColors[i] = "|c000042ff"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_CYAN ) then
set PlayerColors[i] = "|c001ce6b9"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_PURPLE ) then
set PlayerColors[i] = "|c00540081"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_YELLOW ) then
set PlayerColors[i] = "|c00fffc01"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_ORANGE ) then
set PlayerColors[i] = "|c00ff8000"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_GREEN ) then
set PlayerColors[i] = "|c0020c000"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_PINK ) then
set PlayerColors[i] = "|c00e55bb0"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_LIGHT_GRAY ) then
set PlayerColors[i] = "|c00959697"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_LIGHT_BLUE ) then
set PlayerColors[i] = "|c007ebff1"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_AQUA ) then
set PlayerColors[i] = "|c00106246"
elseif ( GetPlayerColor(Player(i)) == PLAYER_COLOR_BROWN ) then
set PlayerColors[i] = "|c004e2a04"
else
set PlayerColors[i] = "|c00000000"
endif
set PlayerNames[i] = PlayerColors[i] + GetPlayerName(Player(i)) + "|r"
set i = i + 1
endloop
endfunction
//==================================================================================================
// - Manipulate resources without the customary long functions
function AddGold takes player p, integer gold returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD , GetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD)+gold)
endfunction
function SetGold takes player p, integer gold returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD , gold)
endfunction
function SubtractGold takes player p, integer gold returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD , GetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD)-gold)
endfunction
function AddLumber takes player p, integer lumber returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER , GetPlayerState(p,PLAYER_STATE_RESOURCE_LUMBER)+lumber)
endfunction
function SetLumber takes player p, integer lumber returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER ,lumber)
endfunction
function SubtractLumber takes player p, integer lumber returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER , GetPlayerState(p,PLAYER_STATE_RESOURCE_LUMBER)-lumber)
endfunction
//==================================================================================================
// - Shield unit from a specific amount of damage
////! external ObjectMerger w3a AIlz dprv anam "Life Bonus" ansf "(Shield System)" Ilif 1 500000 aite 0
private struct shield
unit u
real newhp
timer t
endstruct
private function Restore takes nothing returns nothing
local shield d = GetTimerData(GetExpiredTimer())
call UnitRemoveAbility(d.u,LifeBonus)
call SetWidgetLife(d.u,d.newhp)
call ReleaseTimer(d.t)
call d.destroy()
endfunction
// life is the shield's life, damage is the damage event value
// life can be greater then damage, but obviously can only increase to a units max hp
function ShieldUnit takes unit u, real life, real damage returns nothing
local shield d
if life<.01 then
debug call BJDebugMsg("Damage is to small to bother with.")
return
elseif GetWidgetLife(u)+life-damage<.405 then
debug call BJDebugMsg(GetUnitName(u)+"'s shield does nothing.")
return
endif
set d = shield.create()
set d.u = u
set d.newhp=GetWidgetLife(u)+life-damage
call UnitAddAbility(u,LifeBonus)
call SetWidgetLife(u,999999.)
set d.t = NewTimer()
call SetTimerData(d.t,d)
call TimerStart(d.t,0.0,false,function Restore)
endfunction
//==================================================================================================
// - Custom end game triggers
globals
private trigger VictoryTrigger = CreateTrigger()
private boolean VictoryEnabled = false
private trigger DefeatTrigger = CreateTrigger()
private boolean DefeatEnabled = false
endglobals
function CustomDefeat takes player p returns nothing
local dialog d = DialogCreate()
call RemovePlayer(p,PLAYER_GAME_RESULT_DEFEAT)
set bj_changeLevelShowScores = true
call DialogSetMessage(d,"Defeat!")
call TriggerRegisterDialogButtonEvent(DefeatTrigger,DialogAddButton(d,"Quit Game",GetLocalizedHotkey("GAMEOVER_QUIT_MISSION")))
if DefeatEnabled==false then
call TriggerAddAction(DefeatTrigger,function CustomDefeatQuitBJ)
set DefeatEnabled = true
endif
call DialogDisplay(p,d,true)
if GetLocalPlayer()==p then
call StartSound(bj_defeatDialogSound)
call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_UI, 1.)
endif
set d = null
endfunction
function CustomVictory takes player p returns nothing
local dialog d = DialogCreate()
call RemovePlayer(p,PLAYER_GAME_RESULT_VICTORY)
set bj_changeLevelShowScores = true
call DialogSetMessage(d,GetLocalizedString("GAMEOVER_VICTORY_MSG"))
call TriggerRegisterDialogButtonEvent(VictoryTrigger,DialogAddButton(d,"Quit Game",GetLocalizedHotkey("GAMEOVER_QUIT_MISSION")))
if VictoryEnabled==false then
call TriggerAddAction(VictoryTrigger,function CustomVictoryQuitBJ)
set VictoryEnabled = true
endif
call DialogDisplay(p,d,true)
if GetLocalPlayer()==p then
call StartSound(bj_victoryDialogSound)
call VolumeGroupSetVolume(SOUND_VOLUMEGROUP_UI, 1.)
endif
set d = null
endfunction
//==================================================================================================
private function Init takes nothing returns nothing
set R = Rect(0.,0.,100.,100.)
set ValidDes = Condition(function KillDestructables)
call TimerStart(GameTime,99999.,false,null)
call Colors_and_Names()
set bj_ghoul[33] = CreateUnit(Player(15),CasterId,0.,0.,0.)
call UnitApplyTimedLife(bj_ghoul[33],'BTLF',.01)
call ShowUnit(bj_ghoul[33],false)
call PreloadAbil(LifeBonus)
set HandleOffset=REALOFFSET
set treedummy = CreateUnit(Player(15),'hfoo', 0.0, 0.0, 0.0)
call ShowUnit(treedummy, false)
call UnitAddAbility(treedummy,'Ahrl')
call UnitAddAbility(treedummy,'Aloc')
call PauseUnit(treedummy, true)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Boomerang initializer Init
//*********************************************************************
//* Boomerang v1.02
//* by: emjlr3
//* ----------
//*
//* Requirements:
//* *A point target ability, like the "Boomerang" ability found in this map
//* *A dummy unit, like the "Caster Dummy" unit found in this map
//* *UnitAlive native, found in the custom script section of this map
//* *TimerUtils library
//* http://www.wc3c.net/showthread.php?t=101322
//* *GroupUtils library
//* http://www.wc3c.net/showthread.php?t=104464
//* *A copy of this trigger
//* *Although not required, the BoundSentinel library is recommended
//* http://www.wc3c.net/showthread.php?t=102576
//*
//* (requires vJass) More abilities at http://www.thehelper.net/forums
//*
//* Credits:
//* *Vexorian for his TimerUils library
//* *Rising_Dusk for his GroupUtils library
//*
//* Important:
//* *SFX strings can be set to "" for no effect.
//* *The boomerang returns to where the hero was, not where it is. Using
//* an ability with a follow through time can help alleviate this problem
//* if you choose not to use the PAUSE option.
//* *Stacking casts of the buff will overwrite the previous cast only
//* when it's buff duration exceeds that left from the previous use.
//* *DISARMABIL and HARVEST need only be changed if you have modified
//* the base ability. If so, copy and paste a new, un-edited version and
//* use it's rawcode for these values.
//*
//********************************************************************
//==CONFIGURATION==\\
globals
private constant attacktype ATTACK = ATTACK_TYPE_MAGIC // Ability damage attacktype
private constant boolean KILLTREES = true // Have boomerang destroy trees in it's path
private constant boolean PAUSE = false // Pause caster until boomerange returns
private constant boolean PRELOAD = true // Preload DISARMABIL and effects, will use MISSILE as dummy unit
private constant boolean REMOVE = true // Remove ABIL during boomerang movement
private constant damagetype DAMAGE = DAMAGE_TYPE_MAGIC // Ability damage damagetype
private constant integer ABIL = 'A005' // Boomerang ability rawcode
private constant integer DISARMABIL = 'Abun' // Cargo Hold (Orc Burrow) ability rawcode
private constant integer HARVEST = 'Ahrl' // Harvest (Ghouls Lumber) ability rawcode
private constant integer MAXHANDLES = 8190 // Map's max handle count, don't change if unsure
private constant integer MISSILE = 'n000' // Boomerang dummy unit rawcode
private constant integer OFFSET = 0x100000 // Map's first handle id, don't change if unsure
private constant real BUFFACC = .15 // Periodic check on afflicted units for buff removal, lower values decrease performance
private constant real HEIGHT = 40. // Boomerang fly height
private constant real RANGE = 175. // Target and tree intersection range
private constant real TIMEOUT = 0.03 // Periodic timer interval, lower values decrease performance
private constant string BOOMSFX = "Abilities\\Weapons\\BloodElfSpellThiefMISSILE\\BloodElfSpellThiefMISSILE.mdl" // Boomerang model
private constant string BOOMSFXAP = "origin" // Attachment point for BOOMSFX on MISSILE
private constant string BUFFSFX = "Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl" // Target buff model
private constant string BUFFSFXAP = "overhead" // Attachment point for BUFFSFX
private constant string TARGETSFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl" // Boomerang strikes target model
private constant string TARGETSFXAP = "chest" // Attachment point for TARGETSFX
endglobals
private function Damage takes integer level returns real
return 100.*level // Damage dealt when the boomerang strikes a target
endfunction
private function Duration takes integer level returns real
return 1.*level // Buff duration
endfunction
private function Life takes integer level, real distance returns real
return .5+distance/500. // Time it takes the boomerang to finish it's trajectory, distance is the cast distance
endfunction
private function Targets takes unit caster, unit target returns boolean
return true // Custom boomerang targeting boolean function
endfunction
private function Width takes integer level, real distance returns real
return distance/2. // Radius of the boomerang arc, distance is the cast distance
endfunction
//==NO TOUCHING PAST THIS POINT==\\
private keyword data
private keyword disarm
globals
private boolexpr BOOL
private group DISARMGROUP = CreateGroup()
private group GROUP = CreateGroup()
private constant real HALFPI = bj_PI/2.
private rect RECT
private unit TARG
private data TEMPDATA
private unit TREEDUMMY
private data array DATA
private integer DATACOUNT = 0
private timer DATATIMER = CreateTimer()
private disarm array UNITDISARM[MAXHANDLES]
endglobals
private function h2i takes unit u returns integer
return GetHandleId(u)-OFFSET
endfunction
private struct disarm
timer t
unit u
effect sfx
real time=0.
real max
method destroy takes nothing returns nothing
call UnitRemoveAbility(.u,DISARMABIL)
call DestroyEffect(.sfx)
call ReleaseTimer(.t)
call GroupRemoveUnit(DISARMGROUP,.u)
call .deallocate()
endmethod
endstruct
private struct data
group g
unit u
unit boom
effect sfx
player p
real face
real x
real y
real a
real cosa
real sina
real dist
real width
real xd
real yd
real damage
real life
real halfmaxticks
integer i=0
integer lvl
integer maxticks
boolean early=false
method destroy takes nothing returns nothing
local integer i=1
call ReleaseGroup(.g)
static if REMOVE then
call SetPlayerAbilityAvailable(.p,ABIL,true)
endif
static if PAUSE then
call PauseUnit(.u,false)
endif
call DestroyEffect(.sfx)
call RemoveUnit(.boom)
if .early then
loop
exitwhen DATA[i]==this
set i=i+1
endloop
set DATA[i]=DATA[DATACOUNT]
set DATACOUNT=DATACOUNT-1
endif
call .deallocate()
endmethod
endstruct
//=====================================================================
private function KillTrees takes nothing returns boolean
if IssueTargetOrder(TREEDUMMY,"harvest",GetFilterDestructable()) then
call KillDestructable(GetFilterDestructable())
endif
return false
endfunction
private function KillTreesInRange takes real x, real y, real radius returns nothing
call SetRect(RECT,x-radius,y-radius,x+radius,y+radius)
call PauseUnit(TREEDUMMY,false)
call EnumDestructablesInRect(RECT,Condition(function KillTrees),null)
call PauseUnit(TREEDUMMY,true)
endfunction
private function Update takes nothing returns nothing
local disarm d=GetTimerData(GetExpiredTimer())
if not UnitAlive(d.u) or d.time>=d.max then
call d.destroy()
else
set d.time=d.time+BUFFACC
endif
endfunction
private function Filt takes nothing returns boolean
local data d=TEMPDATA
local disarm di
set TARG=GetFilterUnit()
if IsUnitEnemy(TARG,d.p) and UnitAlive(TARG) and not IsUnitInGroup(TARG,d.g) and Targets(d.u,TARG) then
call GroupAddUnit(d.g,TARG)
call DestroyEffect(AddSpecialEffectTarget(TARGETSFX,TARG,TARGETSFXAP))
call UnitDamageTarget(d.u,TARG,d.damage,false,false,ATTACK,DAMAGE,null)
call UnitAddAbility(TARG,DISARMABIL)
call UnitMakeAbilityPermanent(TARG,true,DISARMABIL)
if not IsUnitInGroup(TARG,DISARMGROUP) then
set di=disarm.create()
set di.max=Duration(d.lvl)
set di.t=NewTimer()
set di.u=TARG
set di.sfx=AddSpecialEffectTarget(BUFFSFX,TARG,BUFFSFXAP)
call SetTimerData(di.t,di)
call TimerStart(di.t,BUFFACC,true,function Update)
set UNITDISARM[h2i(TARG)]=di
call GroupAddUnit(DISARMGROUP,TARG)
else
set di=UNITDISARM[h2i(TARG)]
if di.max-di.time<Duration(d.lvl) then
set di.time=0.
set di.max=Duration(d.lvl)
endif
endif
endif
return false
endfunction
private function Effects takes nothing returns nothing
local data d
local integer i=1
local real r
local real ra
local real rb
local real x
local real y
loop
exitwhen i>DATACOUNT
set d=DATA[i]
set r=(1-I2R(d.i)/d.halfmaxticks)*bj_PI
set ra=d.dist/2.*Cos(r)
set rb=d.width/2.*Sin(r)
set x=d.xd+ra*d.cosa-rb*d.sina
set y=d.yd+ra*d.sina+rb*d.cosa
if d.i>=d.maxticks then
static if KILLTREES then
call KillTreesInRange(x,y,RANGE)
endif
call d.destroy()
set DATA[i]=DATA[DATACOUNT]
set DATACOUNT=DATACOUNT-1
set i=i-1
else
static if KILLTREES then
call KillTreesInRange(x,y,RANGE)
endif
set d.i=d.i+1
call SetUnitX(d.boom,x)
call SetUnitY(d.boom,y)
call SetUnitFacing(d.boom,(d.a+r-HALFPI)*bj_RADTODEG)
set TEMPDATA=d
call GroupEnumUnitsInRange(GROUP,x,y,RANGE,BOOL)
endif
set i=i+1
endloop
if DATACOUNT==0 then
call PauseTimer(DATATIMER)
endif
endfunction
private function Actions takes nothing returns nothing
local data d=data.create()
local real dx
local real dy
set d.u=GetTriggerUnit()
set d.p=GetOwningPlayer(d.u)
set d.face=GetUnitFacing(d.u)
set d.x=GetUnitX(d.u)
set d.y=GetUnitY(d.u)
set d.boom=CreateUnit(d.p,CasterId,d.x,d.y,d.face)
set d.sfx=AddSpecialEffectTarget(BOOMSFX,d.boom,BOOMSFXAP)
set dx=GetSpellTargetX()-d.x
set dy=GetSpellTargetY()-d.y
set d.dist=SquareRoot(dx*dx+dy*dy)
set d.a=Atan2(dy,dx)
set d.cosa=Cos(d.a)
set d.sina=Sin(d.a)
set d.xd=d.x+d.dist/2.*Cos(d.a)
set d.yd=d.y+d.dist/2.*Sin(d.a)
set d.lvl=GetUnitAbilityLevel(d.u,ABIL)
set d.damage=Damage(d.lvl)
set d.width=Width(d.lvl,d.dist)
set d.life=Life(d.lvl,d.dist)
set d.maxticks=R2I(d.life/TIMEOUT)
set d.halfmaxticks=d.maxticks/2.
set d.g=NewGroup()
set DATACOUNT=DATACOUNT+1
set DATA[DATACOUNT]=d
if DATACOUNT==1 then
call TimerStart(DATATIMER,TIMEOUT,true,function Effects)
endif
call SetUnitPathing(d.boom,false)
call UnitAddAbility(d.boom,'Aloc')
call SetUnitFlyHeight(d.boom,HEIGHT,0.)
static if REMOVE then
call SetPlayerAbilityAvailable(d.p,ABIL,false)
endif
static if PAUSE then
call PauseUnit(d.u,true)
endif
endfunction
//======================================================================
private function Conditions takes nothing returns boolean
if GetSpellAbilityId()==ABIL then
call Actions()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
local integer i=0
loop
exitwhen i>bj_MAX_PLAYERS
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
set i=i+1
endloop
call TriggerAddCondition(t,Condition(function Conditions))
set BOOL=Condition(function Filt)
static if PRELOAD then
set TARG=CreateUnit(Player(15),MISSILE,0.,0.,0.)
call UnitAddAbility(TARG,DISARMABIL)
call UnitApplyTimedLife(TARG,'BTLF',.001)
call Preload(BOOMSFX)
call Preload(BUFFSFX)
call Preload(TARGETSFX)
endif
static if KILLTREES then
set RECT=Rect(0.,0.,100.,100.)
set TREEDUMMY = CreateUnit(Player(15),MISSILE,0.,0.,0.)
call ShowUnit(TREEDUMMY,false)
call UnitAddAbility(TREEDUMMY,HARVEST)
call UnitAddAbility(TREEDUMMY,'Aloc')
call PauseUnit(TREEDUMMY,true)
endif
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Orbital initializer Init
//*********************************************************************
//* Orbital v1.02
//* by: emjlr3
//* ----------
//*
//* Requirements:
//* *An instant cast ability, like the "Orbital" ability found in this map
//* *A dummy unit, like the "Caster Dummy" unit found in this map
//* *UnitAlive native, found in the custom script section of this map
//* *A copy of this trigger
//* *Although not required, the BoundSentinel library is recommended
//* http://www.wc3c.net/showthread.php?t=102576
//*
//* (requires vJass) More abilities at http://www.thehelper.net/forums
//*
//* Credits:
//* *DotA for spell architecture inspiration
//*
//* Important:
//* *SFX strings can be set to "" for no effect.
//* *Instance limit of 8190/OMAX.
//* *One instance per unit. This is, for the most part, rendered
//* safe through clever ability availability manipulation.
//*
//********************************************************************
//==CONFIGURATION==\\
globals
private constant attacktype ATTACK = ATTACK_TYPE_MAGIC // Collision damage attacktype
private constant boolean CLK = true // Rotate clockwise
private constant boolean PRELOAD = true // Preload effects and TARGET ability, will use DUM as dummy unit
private constant damagetype DAMAGE = DAMAGE_TYPE_MAGIC // Collision damage damagetype
private constant integer ABIL = 'A002' // Orbital ability rawcode
private constant integer DUM = 'n000' // Orbital dummy unit rawcode
private constant integer MAXHANDLES = 8190 // Map's max handle count, don't change if unsure
private constant integer OFFSET = 0x100000 // Map's first handle id, don't change if unsure
private constant integer OMAX = 4 // Max number of orbitals
private constant integer TARGET = 'A004' // Target Orbitals ability rawcode
private constant real SPEED = 18. // Speed at which orbitals follow targets, distance/TIMEOUT
private constant real TIMEOUT = .03 // Periodic timer interval
private constant string MDL = "Abilities\\Spells\\Other\\Volcano\\VolcanoMissile.mdl" // Orbital model
private constant string MDLAP = "origin" // Attachment point for MDL
private constant string SFX = "Abilities\\Spells\\Other\\Volcano\\VolcanoMissile.mdl" // Effect on targets following collision
private constant string SND = "Abilities\\Spells\\Other\\SoulBurn\\SoulBurn1.wav" // Sound to play when orbitals reach max strength
endglobals
private function Damage takes integer level, real currtime, real maxtime returns real
// currtime is current elapsed time of spell, maxtime is the total time required for orbitals to reach maximum power
return level*10+level*20*RMinBJ(currtime/maxtime,1.) // Damage/heal effect on applicable targets
endfunction
private function Distance takes integer level returns real
return 200. // Orbitals rotation distance from caster
endfunction
private function Orbitals takes integer level returns integer
return 4 // Number of orbitals
endfunction
private function Range takes integer level, real currtime, real maxtime returns real
// currtime is current elapsed time of spell, maxtime is the total time required for orbitals to reach maximum power
return 200.+100.*RMinBJ(currtime/maxtime,1.) // Collision effects radius
endfunction
private function ReachMax takes integer level returns real
return 12.*.75 // Time required for orbitals to reach maximum strength
endfunction
private function ScaleIncrease takes integer level, real currtime, real maxtime returns real
// currtime is current elapsed time of spell, maxtime is the total time required for orbitals to reach maximum power
return .5+1.*RMinBJ(currtime/maxtime,1.) // Orbital model scale @ time currtime
endfunction
private function StartScale takes integer level returns real
return .5 // Orbital initial model scale
endfunction
private function Targets takes unit caster, unit target returns boolean
return true // Custom orbital targeting boolean function
endfunction
private function Time takes integer level returns real
return 12. // Max timed life of orbitals
endfunction
private function Update takes integer level returns real
return 360.*TIMEOUT // Rate at which orbitals coords around caster change, angle degrees/TIMEOUT
endfunction
//==NO TOUCHING PAST THIS POINT==\\
private keyword data
globals
private boolexpr BOOL
private integer COUNT = 0
private data array DATA[MAXHANDLES]
private data array DATASTACK
private group EXPLODE = CreateGroup()
private group GROUP = CreateGroup()
private constant real MODSPEED = SPEED*SPEED
private constant integer RMAX = OMAX+1
private sound SOUND
private unit TARG
private data TEMPD
private timer TIMER = CreateTimer()
endglobals
private function Filt takes nothing returns boolean
local data d=TEMPD
local unit TARG=GetFilterUnit()
local real r
local real rr
if UnitAlive(TARG) and Targets(d.u,TARG) then
set r=Damage(d.lvl,d.time,d.maxtime)
if IsUnitEnemy(TARG,d.p) then
call UnitDamageTarget(d.u,TARG,r,false,false,ATTACK,DAMAGE,null)
else
call SetWidgetLife(TARG,GetWidgetLife(TARG)+r)
endif
endif
return false
endfunction
private struct data
unit u
unit target
unit array orbital[RMAX]
effect array sfx[RMAX]
player p
integer lvl
integer stack
integer mode=0
integer array gotem[RMAX]
integer count
real time=0.
real maxtime
real update
real array degree[RMAX]
real reachmax
real dist
real startscale
boolean max=false
method destroy takes nothing returns nothing
local integer i=1
loop
exitwhen i>.count
if .gotem[i]!=1 then
set TEMPD=this
call GroupEnumUnitsInRange(EXPLODE,GetUnitX(.orbital[i]),GetUnitY(.orbital[i]),Range(.lvl,.time,.maxtime),BOOL)
call DestroyEffect(AddSpecialEffect(SFX,GetUnitX(.orbital[i]),GetUnitY(.orbital[i])))
call DestroyEffect(.sfx[i])
call RemoveUnit(.orbital[i])
endif
set i=i+1
endloop
set DATASTACK[.stack]=DATASTACK[COUNT]
set COUNT=COUNT-1
call GroupRemoveUnit(GROUP,.u)
call UnitRemoveAbility(.u,TARGET)
call SetPlayerAbilityAvailable(.p,ABIL,true)
call .deallocate()
endmethod
endstruct
private function Effects takes nothing returns nothing
local data d
local integer i=1
local integer c=1
local real x
local real y
local real r
local boolean b=true
loop
exitwhen i>COUNT
set d=DATASTACK[i]
if d.time>d.maxtime and d.mode==0 then
set d.mode=1
set d.target=d.u
call UnitRemoveAbility(d.u,TARGET)
call SetPlayerAbilityAvailable(d.p,ABIL,true)
elseif d.mode==0 then
set x=GetUnitX(d.u)
set y=GetUnitY(d.u)
set r=ScaleIncrease(d.lvl,d.time,d.reachmax)
loop
exitwhen c>d.count
if UnitAlive(d.orbital[c]) and d.orbital[c]!=null then
set d.degree[c]=d.degree[c]+d.update
static if CLK then
call SetUnitFacing(d.orbital[c],d.degree[c]+90.)
else
call SetUnitFacing(d.orbital[c],d.degree[c]-90.)
endif
call SetUnitX(d.orbital[c],x+d.dist*Cos(d.degree[c]*bj_DEGTORAD))
call SetUnitY(d.orbital[c],y+d.dist*Sin(d.degree[c]*bj_DEGTORAD))
call SetUnitScale(d.orbital[c],r,r,r)
endif
set c=c+1
endloop
if d.time>=d.reachmax and not d.max then
if GetLocalPlayer()==d.p then
call StartSound(SOUND)
set d.max=true
endif
endif
set d.time=d.time+TIMEOUT
elseif d.mode==1 then
loop
exitwhen c>d.count
if UnitAlive(d.target) and d.target!=null then
if d.gotem[c]!=1 then
set x=GetUnitX(d.orbital[c])
set y=GetUnitY(d.orbital[c])
if Pow(GetUnitX(d.target)-x,2)+Pow(GetUnitY(d.target)-y,2)<=MODSPEED then
set TEMPD=d
call GroupEnumUnitsInRange(EXPLODE,x,y,Range(d.lvl,d.time,d.maxtime),BOOL)
call DestroyEffect(AddSpecialEffect(SFX,x,y))
call DestroyEffect(d.sfx[c])
call RemoveUnit(d.orbital[c])
set d.gotem[c]=1
else
set b=false
set r=Atan2(GetUnitY(d.target)-y,GetUnitX(d.target)-x)
call SetUnitFacing(d.orbital[c],r*bj_RADTODEG)
call SetUnitX(d.orbital[c],x+SPEED*Cos(r))
call SetUnitY(d.orbital[c],y+SPEED*Sin(r))
endif
endif
else
call d.destroy()
set i=i-1
exitwhen true
endif
set c=c+1
endloop
if b then
call d.destroy()
set i=i-1
exitwhen true
endif
endif
set i=i+1
endloop
if COUNT==0 then
call PauseTimer(TIMER)
endif
endfunction
private function Actions takes nothing returns nothing
local data d=data.create()
local real x
local real xu
local real y
local real yu
local integer i=1
set d.u=GetTriggerUnit()
set d.p=GetOwningPlayer(d.u)
set d.lvl=GetUnitAbilityLevel(d.u,ABIL)
set d.update=Update(d.lvl)
set d.maxtime=Time(d.lvl)
set d.reachmax=ReachMax(d.lvl)
set d.count=Orbitals(d.lvl)
set d.dist=Distance(d.lvl)
set d.startscale=StartScale(d.lvl)
set COUNT=COUNT+1
set d.stack=COUNT
if COUNT==1 then
call TimerStart(TIMER,TIMEOUT,true,function Effects)
endif
set DATASTACK[COUNT]=d
call SetPlayerAbilityAvailable(d.p,ABIL,false)
call UnitAddAbility(d.u,TARGET)
call SetPlayerAbilityAvailable(d.p,TARGET,true)
set xu=GetUnitX(d.u)
set yu=GetUnitY(d.u)
loop
exitwhen i>d.count
set d.degree[i]=360.*i/I2R(d.count)
set x=xu+d.dist*Cos(bj_DEGTORAD*d.degree[i])
set y=yu+d.dist*Sin(bj_DEGTORAD*d.degree[i])
static if CLK then
set d.orbital[i]=CreateUnit(d.p,CasterId,x,y,d.degree[i]+90.)
else
set d.orbital[i]=CreateUnit(d.p,CasterId,x,y,d.degree[i]-90.)
endif
call SetUnitPathing(d.orbital[i],false)
call SetUnitScale(d.orbital[i],d.startscale,d.startscale,d.startscale)
set d.sfx[i]=AddSpecialEffectTarget(MDL,d.orbital[i],MDLAP)
set d.gotem[i]=0
set i=i+1
endloop
set DATA[GetHandleId(d.u)-OFFSET]=d
call GroupAddUnit(GROUP,d.u)
endfunction
//======================================================================
private function Conditions takes nothing returns boolean
local data d
if GetSpellAbilityId()==ABIL then
call Actions()
elseif GetSpellAbilityId()==TARGET then
set d=DATA[GetHandleId(GetTriggerUnit())-OFFSET]
set d.target=GetSpellTargetUnit()
set d.mode=1
call UnitRemoveAbility(d.u,TARGET)
call SetPlayerAbilityAvailable(d.p,ABIL,true)
elseif IsUnitInGroup(GetTriggerUnit(),GROUP) and GetTriggerEventId()==EVENT_PLAYER_UNIT_DEATH then
set d=DATA[GetHandleId(GetTriggerUnit())-OFFSET]
call d.destroy()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
local integer i=0
loop
exitwhen i>bj_MAX_PLAYERS
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_DEATH,null)
set i=i+1
endloop
call TriggerAddCondition(t,Condition(function Conditions))
set BOOL=Condition(function Filt)
set SOUND=CreateSound(SND,false,false,true,10,10,"DefaultEAXON")
call SetSoundDuration(SOUND,1579)
call SetSoundChannel(SOUND,0)
static if PRELOAD then
set TARG=CreateUnit(Player(15),DUM,0.,0.,0.)
call UnitAddAbility(TARG,TARGET)
call UnitApplyTimedLife(TARG,'BTLF',.001)
call Preload(MDL)
call Preload(SFX)
endif
endfunction
endscope