//TESH.scrollpos=63
//TESH.alwaysfold=0
globals
real array GLOBAL_BACKSTAB
location array p
integer VAMP
group SA = CreateGroup()
integer ROL = 0
endglobals
function Func_SA takes unit who, unit to, real many, real del returns nothing
local unit x = who
local unit y = to
local real count = many
local real t = del
local real t2 = 0.50
local texttag text
local real pos = 150
local location xp = GetUnitLoc(y)
if IsUnitInGroup(y , SA) == false then
call PauseUnit(y , true)
call SetUnitTimeScalePercent( y, 0 )
call GroupAddUnit(SA, y)
set text = CreateTextTagLocBJ("Darkness!", xp, pos, 12, 1.00, 1.00, 1.00, 0 )
call SetTextTagVelocityBJ( text, 75.00, 90 )
call SetTextTagPermanentBJ( text, false )
call SetTextTagLifespanBJ( text, 5)
call SetTextTagFadepointBJ( text, 2.5)
else
return
endif
loop
exitwhen count <= 0
set count = count - 1
call TriggerSleepAction(t)
endloop
call TriggerSleepAction(t2)
call PauseUnit(y , false)
call SetUnitTimeScalePercent( y, 100 )
call GroupRemoveUnit(SA , y)
call DestroyTextTag(text)
call RemoveLocation(xp)
set x = null
set y = null
endfunction
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 Error 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
Name | Type | is_array | initial_value |
A_Temp_Group | group | No | |
A_Temp_Loc | location | No | |
Angle | real | No | |
Angle_Copy | real | Yes | |
B_Check | integer | No | |
B_Hash | hashtable | No | |
B_MissileDummy | handle | No | |
B_MissileGroup | group | No | |
B_Points | location | Yes | |
BF_Caster_Group | group | No | |
BF_Flame_Group | group | No | |
BF_Hash | hashtable | No | |
BF_Reals | real | Yes | |
blue | boolean | No | false |
bPoint | location | Yes | |
Caster | unit | No | |
cineTimer44B | timer | No | |
cineTimer44B_Copy | timer | No | |
cineTimer44C | timer | No | |
cineTimer44C_Copy | timer | No | |
cineUnit | unit | No | |
Corrupted | integer | No | 0 |
CorruptionValue | integer | No | |
cPoint | location | Yes | |
cUnit | unit | Yes | |
Damage | real | No | |
DemonSummoner | group | No | |
Distance | real | Yes | |
Effect | effect | Yes | |
Enemies | group | No | |
EWFGroup | group | No | |
EWFTemp | unit | No | |
EWFTInt | integer | No | |
EWGroup | group | No | |
FleeingBolts | group | No | |
gDamage | group | No | |
green | boolean | No | false |
Hashtable | hashtable | No | |
Heros | unitcode | Yes | |
HoT_Const_AoE | real | No | |
HoT_Const_Dmg_Base | real | No | |
HoT_Const_Dmg_Bonus | real | No | |
HoT_Const_Dmg_Burn | real | No | |
HoT_Const_Dmg_Stun | real | No | |
HoT_Const_Dmg_Stun_Bonus | real | No | |
HoT_Const_Duration | real | No | |
HoT_Const_Range | real | No | |
HoT_Const_Stun_Duration | real | No | |
HoT_Group | group | No | |
HoT_Hash | hashtable | No | |
HoT_Lightning_Group | group | No | |
HoT_Slam_Group | group | No | |
HoT_Stun_Group | group | No | |
HoT_Targets | group | No | |
HoT_Up_Group | group | No | |
i | integer | No | 0 |
Integer | integer | Yes | |
itemTable | itemcode | Yes | |
itemTableCount | integer | No | |
JD_Angle | real | Yes | |
JD_Counter | real | Yes | |
JD_Distances | real | Yes | |
JD_Effect | string | Yes | |
JD_Group | group | No | |
JD_Integers | integer | Yes | |
JD_LevelOfAbility | integer | Yes | |
JD_PickGroup | group | No | |
JD_ReachedDistance | real | Yes | |
JD_SpeedUnits | real | Yes | |
JD_TempPoint | location | Yes | |
JD_TreesDestroy | boolean | Yes | |
JD_Unit | unit | Yes | |
JDA_DestroyTrees_Dash | boolean | No | |
JDA_LevelOfAbility | integer | No | |
JDA_SpecialEffect | string | No | |
JDA_Speed | real | No | |
JDA_TargetPoint | location | No | |
JDA_Unit | unit | No | |
KB_Angle | real | Yes | |
KB_Casters | unit | Yes | |
KB_CountBuffs | integer | No | |
KB_DestroyTrees | boolean | Yes | |
KB_EffectCounter | integer | Yes | |
KB_EffectCounter2 | integer | Yes | |
KB_Effects_1 | string | Yes | |
KB_Effects_2 | string | Yes | |
KB_GeneralIntegers | integervar | Yes | |
KB_KnockbackedUnits | group | No | |
KB_Levels | integer | Yes | |
KB_MaxDistance | real | Yes | |
KB_ReachedDistance | real | Yes | |
KB_ReducedReal | real | No | |
KB_ReduceSpeedReal | real | Yes | |
KB_SpecificSpeed | real | Yes | |
KB_StartPositions | location | Yes | |
KB_TempPoint | location | Yes | |
KB_TempReal | real | No | |
KB_TotalKnockUnits | integer | No | |
KB_Units | unit | Yes | |
KBA_Caster | unit | No | |
KBA_DestroyTrees | boolean | No | |
KBA_DistancePerLevel | real | No | |
KBA_Level | integer | No | |
KBA_SpecialEffects | string | Yes | |
KBA_Speed | real | No | |
KBA_StartingPosition | location | No | |
KBA_TargetUnit | unit | No | |
kills | integer | Yes | |
LS_Dummy | unit | No | |
LS_GeneralInteger | integervar | No | |
LS_Groups | group | Yes | |
LS_TempPoint | location | Yes | |
MaxDistance | real | Yes | |
Minutes | integer | No | |
Mode | real | No | |
Monster1Type | unitcode | Yes | |
Monster2Type | unitcode | Yes | |
Monster3Type | unitcode | Yes | |
MONSTERSPEED | group | No | |
mPoint | location | Yes | |
MUI | integer | Yes | |
MUI_1 | integer | No | |
MUI_2 | integer | No | |
MUI_3 | integervar | No | |
ND | integervar | No | |
ND_Angle | real | Yes | |
ND_Caster | unit | Yes | |
ND_CastNumber | integer | No | |
ND_Distance | real | Yes | |
ND_Effect | integer | Yes | |
ND_Gyro | unit | Yes | |
ND_Off | boolean | Yes | |
ND_Point | location | Yes | |
ND_Speed | real | Yes | |
ND_Switch | integer | No | |
NullingPower | group | No | |
orange | boolean | No | false |
pink | boolean | No | false |
players | integer | No | 0 |
Players2 | integer | No | |
playersEast | integer | No | |
playersNorth | integer | No | |
playersSouth | integer | No | |
playersWest | integer | No | |
PointResearch | location | No | |
Points | location | Yes | |
PointWorldTree | location | No | |
purple | boolean | No | false |
Random | integer | No | |
random2 | integer | No | |
Range | real | Yes | |
Real | real | Yes | |
red | boolean | No | false |
RedirectMana | real | No | |
regionCenters | location | Yes | |
regions | rect | Yes | |
ReturningBolts | group | No | |
RobotArmyCount | integer | No | |
Round | integer | No | 0 |
SC_Boolean | boolean | Yes | |
SC_Caster | unit | Yes | |
SC_CasterLoc | location | Yes | |
SC_Counter | integer | Yes | |
SC_Damage | real | Yes | |
SC_EchoingFinale | boolean | Yes | |
SC_Index1 | integer | No | |
SC_Index2 | integer | No | |
SC_Index3 | integervar | No | |
SC_Level | integer | Yes | |
SC_Spirit | unit | Yes | |
SC_SpiritLoc | location | Yes | |
SC_TargetLoc | location | Yes | |
SC_Timer | timer | Yes | |
SD | real | No | |
Seconds | integer | No | |
Shockwave_Angle | real | No | |
Shockwave_Group | group | Yes | |
Shockwave_Point | location | Yes | |
skip | boolean | No | |
Spawner | boolean | No | true |
spawnInterval | real | No | |
SpawnNum | integer | No | |
SpawnPlayersSide | integer | No | |
SpawnRegion | rect | No | |
SpawnUnitType | unitcode | No | |
SpecialBoolean | boolean | No | |
SpecialSpawnRegion | rect | No | |
SpecialSummonCount | integer | No | |
SpecialSummonExtra | integer | No | |
SpecialTempSpawnPoint | location | No | |
SpecialUnitType | unitcode | No | |
Speed | real | Yes | |
Spheres | group | No | |
SR_Angle | real | Yes | |
SR_Boolean | boolean | Yes | |
SR_Caster | unit | Yes | |
SR_Duration | real | Yes | |
SR_Group | group | Yes | |
SR_Index | integer | Yes | |
SR_Loc | location | Yes | |
SR_Projectile | unit | Yes | |
SR_WaitCounter | real | Yes | |
SSGroup | group | No | |
SSTemp | unit | No | |
SummonTrigger | trigger | No | |
Superspeed_Boosts | real | Yes | |
Superspeed_Effects_On | boolean | No | |
Superspeed_Group_1 | group | No | |
Superspeed_Group_2 | group | No | |
Superspeed_Hash | hashtable | No | |
Superspeed_Reals | real | Yes | |
Target | unit | No | |
teal | boolean | No | false |
Temp_Group_1 | group | No | |
Temp_Group_2 | group | No | |
Temp_Lightning | lightning | No | |
Temp_Loc_1 | location | No | |
Temp_Loc_2 | location | No | |
Temp_Loc_3 | location | No | |
Temp_Loc_4 | location | No | |
Temp_Real_1 | real | No | |
Temp_Real_2 | real | No | |
Temp_Real_3 | real | No | |
Temp_Unit_1 | unit | No | |
Temp_Unit_2 | unit | No | |
Temp_Unit_3 | unit | No | |
Temp_Unit_4 | unit | No | |
TempDyingUnitPosition | location | No | |
TempInteger | integer | No | |
TempNoTargetPoint | location | No | |
TempRedirectPoint | location | No | |
TempSpawnPoint | location | No | |
TIME | leaderboard | No | |
TimeGroup | force | No | |
timer | timer | No | |
tPoint | location | No | |
UNITSINMAP | group | No | |
VAMPIRECOUNTER | integer | Yes | |
x | unit | No | |
yellow | boolean | No | false |
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Dreadlord_ConA takes nothing returns nothing
local unit y
local unit x
local real t = 1.00
set y = CreateUnitAtLoc(GetOwningPlayer(GetEnumUnit()), 'u002', PolarProjectionBJ(GetUnitLoc(GetEnumUnit()), GetRandomInt(150, 300) , ( GetUnitFacing(GetEnumUnit()) + 90.00 )), bj_UNIT_FACING )
set x = CreateUnitAtLoc(GetOwningPlayer(GetEnumUnit()), 'u002', PolarProjectionBJ(GetUnitLoc(GetEnumUnit()), GetRandomInt(150, 300) , ( GetUnitFacing(GetEnumUnit()) - 90.00 )), bj_UNIT_FACING )
call IssuePointOrderLocBJ( y, "move", GetRectCenter(GetPlayableMapRect()) )
call IssuePointOrderLocBJ( x, "move", GetRectCenter(GetPlayableMapRect()) )
call IssueImmediateOrderBJ(GetEnumUnit(), "locustswarm" )
call TriggerSleepAction(t)
call SetUnitInvulnerable(y , false)
call SetUnitInvulnerable(x , false)
set x = null
set y = null
endfunction
function Trig_Dreadlord_Actions takes nothing returns nothing
local group UNITSINMAP
local group Temp
local integer n
local unit temp
set UNITSINMAP = GetUnitsOfTypeIdAll('U003')
call ForGroupBJ( UNITSINMAP, function Dreadlord_ConA )
call DestroyGroup(UNITSINMAP)
endfunction
//===========================================================================
function InitTrig_Dreadlord takes nothing returns nothing
local trigger Dreadlord = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( Dreadlord, 1.50 )
call TriggerAddAction( Dreadlord, function Trig_Dreadlord_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Hax_ConA takes nothing returns nothing
local unit y
set y = CreateUnitAtLoc(GetOwningPlayer(GetEnumUnit()), 'osp4', PolarProjectionBJ(GetUnitLoc(GetEnumUnit()), GetRandomInt(250, 500) , ( GetUnitFacing(GetEnumUnit()) + GetRandomReal(0, 360) )), bj_UNIT_FACING )
set y = null
endfunction
function Trig_Hax_Actions takes nothing returns nothing
local group UNITSINMAP
local group Temp
local integer n
local unit temp
set UNITSINMAP = GetUnitsOfTypeIdAll('U00C')
call ForGroupBJ( UNITSINMAP, function Hax_ConA )
call DestroyGroup(UNITSINMAP)
endfunction
//===========================================================================
function InitTrig_Haxor_Spawns takes nothing returns nothing
local trigger Hax = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( Hax, 1.00 )
call TriggerAddAction( Hax, function Trig_Hax_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Replacing_Units_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A019'
endfunction
function Trig_Replacing_Units_Actions takes nothing returns nothing
local unit x = GetTriggerUnit()
local real t = 0.10
call TriggerSleepAction(t)
call SetUnitAnimation(x, "stand" )
set x = null
endfunction
//===========================================================================
function InitTrig_Replacing_Units takes nothing returns nothing
local trigger Replacing_Units = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Replacing_Units, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition(Replacing_Units, Condition( function Trig_Replacing_Units_Conditions ) )
call TriggerAddAction( Replacing_Units, function Trig_Replacing_Units_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Backstab_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'E001'
endfunction
function Trig_Backstab_Actions takes nothing returns nothing
local unit x = GetAttacker()
local unit y = GetTriggerUnit()
local string se = "Abilities\\Spells\\Human\\MarkOfChaos\\MarkOfChaosTarget.mdl"
local real pos = 100
local real time = 2.50
local real chance = GetRandomInt(1, 100)
local location xp = GetUnitLoc(x)
local real dmg = GetUnitAbilityLevel(x, 'A000') * 2500
local real t = 4.00
local effect eff
if chance <= GLOBAL_BACKSTAB[GetConvertedPlayerId(GetOwningPlayer(x))] then
set eff = AddSpecialEffectTarget(se, x, "weapon")
call SetUnitPositionLoc( x, PolarProjectionBJ(GetUnitLoc(y), 128.00, GetRandomReal(0, 360.00)) )
call SetUnitAnimation(x , "slam")
call UnitDamageTarget( x, y, dmg,true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS )
call IssueTargetOrder(x, "attack", y)
endif
call DestroyEffect(eff)
call RemoveLocation(xp)
set x = null
set y = null
endfunction
//===========================================================================
function InitTrig_Backstab takes nothing returns nothing
local trigger Backstab = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Backstab, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( Backstab, Condition( function Trig_Backstab_Conditions ) )
call TriggerAddAction( Backstab, function Trig_Backstab_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Holy_Warrior_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A001'
endfunction
function Trig_Holy_Warrior_Actions takes nothing returns nothing
local unit x = GetTriggerUnit()
set GLOBAL_BACKSTAB[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))] = 50
call TriggerSleepAction(40.00)
set GLOBAL_BACKSTAB[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))] = 25
set x = null
endfunction
//===========================================================================
function InitTrig_Holy_Warrior takes nothing returns nothing
local trigger Holy_Warrior = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(Holy_Warrior, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( Holy_Warrior, Condition( function Trig_Holy_Warrior_Conditions ) )
call TriggerAddAction( Holy_Warrior, function Trig_Holy_Warrior_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Teleport initializer onInit
globals
private location array p
endglobals
// function for group conditions
private function Group_Con takes nothing returns boolean
return ( IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false ) and (GetOwningPlayer(GetFilterUnit()) == GetOwningPlayer(GetTriggerUnit()))
endfunction
// function for group actions
function Group_Act takes nothing returns nothing
local string e = "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl"
call AddSpecialEffectLoc(e , GetUnitLoc(GetEnumUnit()))
call SetUnitPositionLoc(GetEnumUnit(), p[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))])
call AddSpecialEffectLoc(e , GetUnitLoc(GetEnumUnit()))
endfunction
// function for trigger conditions
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00B'
endfunction
// function for trigger actions
private function Actions takes nothing returns nothing
local unit x = GetTriggerUnit()
local location px = GetUnitLoc(x)
local group g = GetUnitsInRangeOfLocMatching(500.00, GetUnitLoc(x), Condition(function Group_Con))
local real delay = 1.6 - ((GetUnitAbilityLevel(x, 'A00B') * 0.5))
// End of locals, start of main code.
set p[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))] = GetSpellTargetLoc()
call TriggerSleepAction(delay)
call ForGroup(g , function Group_Act)
// Nulling variables
set x = null
call RemoveLocation(p[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))])
call RemoveLocation(px)
call DestroyGroup(g)
endfunction
private function onInit takes nothing returns nothing
local trigger Teleport = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Teleport, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( Teleport, Condition( function Conditions ) )
call TriggerAddAction( Teleport, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Striking_Array_Conditions takes nothing returns boolean
return GetUnitAbilityLevelSwapped('A00F', GetAttacker()) >= 1
endfunction
function Trig_Striking_Array_Actions takes nothing returns nothing
local unit x = GetAttacker()
local unit y = GetTriggerUnit()
local real count = 5
local texttag text
local real pos = 100
local real dmg = GetUnitAbilityLevelSwapped('A00F', x) * 1000
local integer lvl = GetUnitAbilityLevelSwapped('A00F', x)
local location xp = GetUnitLoc(y)
local real t = 1.00
local effect e
local real chance = GetRandomReal(1, 100)
if chance <= 10 + (5 * lvl) then
set e = AddSpecialEffectTarget("war3mapImported\\GrudgeAura.mdx" , y , "origin")
call Func_SA(x , y , count , t)
loop
exitwhen count <= 0
set count = count - 1
call UnitDamageTarget(x, y , dmg, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
set text = CreateTextTagLocBJ( R2S(dmg)+"!" , xp, pos, 12, 10.00, 10.00, 10.00, 0 )
call SetTextTagVelocityBJ( text, 60.00, 90 )
call SetTextTagPermanentBJ( text, false )
call SetTextTagLifespanBJ( text, 2)
call SetTextTagFadepointBJ( text, 0.5)
call TriggerSleepAction(t)
call DestroyTextTag(text)
endloop
endif
call RemoveLocation(xp)
set x = null
set y = null
call DestroyEffect(e)
endfunction
//===========================================================================
function InitTrig_Striking_Array takes nothing returns nothing
local trigger Striking_Array = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Striking_Array, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( Striking_Array, Condition( function Trig_Striking_Array_Conditions ) )
call TriggerAddAction( Striking_Array, function Trig_Striking_Array_Actions )
endfunction
//TESH.scrollpos=4
//TESH.alwaysfold=0
function Trig_Paralysation_Conditions takes nothing returns boolean
return GetUnitAbilityLevelSwapped('A00H', GetAttacker()) >= 1 or (GetUnitTypeId(GetAttacker()) == 'n002' ) or (GetUnitTypeId(GetAttacker()) == 'n004') or (GetUnitTypeId(GetAttacker()) == 'n005')
endfunction
function Trig_Paralysation_Actions takes nothing returns nothing
local unit x = GetAttacker()
local unit y = GetTriggerUnit()
local texttag text
local real pos = 100
local location xp = GetUnitLoc(y)
local real t = 2.50
local real to = 1.00
local effect s
local real dmg
local real ti
if (GetUnitTypeId(x) == 'n004' ) then
set dmg = 150
set ti = 1
endif
if (GetUnitTypeId(x) == 'n002' ) then
set dmg = 300
set ti = 2
endif
if (GetUnitTypeId(x) == 'n005' ) then
set dmg = 450
set ti = 3
endif
if (GetUnitTypeId(x) == 'E005' ) then
set dmg = (GetUnitAbilityLevelSwapped('A00H', x)) * 300
set ti = (GetUnitAbilityLevelSwapped('A00H', x) * 2) - 1
endif
if (GetUnitTypeId(x) == 'E006' ) then
set dmg = (GetUnitAbilityLevelSwapped('A00H', x)) * 300
set ti = (GetUnitAbilityLevelSwapped('A00H', x) * 2) - 1
endif
loop
exitwhen ti <= 0
call CreateTextTagLocBJ( R2S(dmg)+"!" , xp, pos, 12, 10.00, 100.00, 10.00, 0 )
set text = GetLastCreatedTextTag()
call SetTextTagVelocityBJ( text, 60.00, 90 )
call SetTextTagPermanentBJ( text, false )
call SetTextTagLifespanBJ( text, 1)
call SetTextTagFadepointBJ( text, 0.1)
set s = AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\CorrosiveBreath\\ChimaeraAcidTargetArt.mdl", y , "origin")
call UnitDamageTarget(x, y , dmg, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
call TriggerSleepAction(to)
call DestroyTextTag(text)
call DestroyEffect(s)
set ti = ti - 1
endloop
set x = null
set y = null
endfunction
//===========================================================================
function InitTrig_Paralysation takes nothing returns nothing
local trigger Paralysation = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Paralysation, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( Paralysation, Condition( function Trig_Paralysation_Conditions ) )
call TriggerAddAction( Paralysation, function Trig_Paralysation_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Reality_Conditions takes nothing returns boolean
return GetLearnedSkillBJ() == 'A00K'
endfunction
function Trig_Reality_Actions takes nothing returns nothing
local unit x = GetTriggerUnit()
local real lv = GetUnitLevel(x)
local unit y = CreateUnitAtLoc(GetOwningPlayer(x), 'E006' , GetUnitLoc(x) , 0.00)
call SetHeroLevel(y , R2I(lv) , true)
set x = null
set y = null
endfunction
//===========================================================================
function InitTrig_Reality takes nothing returns nothing
local trigger Reality = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Reality, EVENT_PLAYER_HERO_SKILL )
call TriggerAddCondition(Reality, Condition( function Trig_Reality_Conditions ) )
call TriggerAddAction( Reality, function Trig_Reality_Actions )
endfunction
//TESH.scrollpos=6
//TESH.alwaysfold=0
function Trig_Shockwave_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00M'
endfunction
function Trig_Shockwave_Actions takes nothing returns nothing
local unit x = GetTriggerUnit()
local real r = GetUnitFacing(x)
local location p = GetUnitLoc(x)
local location temp
local unit y
local real count = 12
call PauseUnit(x , true)
loop
set count = count - 1
exitwhen count <= 0
call SetUnitFacingTimed( x, r, 0.30 )
call AddSpecialEffectLoc("Abilities\\Spells\\Human\\MarkOfChaos\\MarkOfChaosTarget.mdl" , p)
set temp = PolarProjectionBJ(p , 100 , r)
set y = CreateUnitAtLoc(GetOwningPlayer(x), 'n006', temp, r)
call UnitApplyTimedLife( y ,'BTLF', 3.00 )
set r = r + 36
call IssueImmediateOrderBJ(y, "stop" )
call TriggerSleepAction(0.3)
call IssuePointOrderLocBJ( y, "shockwave", PolarProjectionBJ(GetUnitLoc(y), 100.00, GetUnitFacing(y)) )
call RemoveLocation(temp)
endloop
call PauseUnit(x , false)
call RemoveLocation(p)
set x = null
set y = null
endfunction
//===========================================================================
function InitTrig_Shockwave takes nothing returns nothing
local trigger Shockwave = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Shockwave, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( Shockwave, Condition( function Trig_Shockwave_Conditions ) )
call TriggerAddAction( Shockwave, function Trig_Shockwave_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Bleeding_Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'h001'
endfunction
function Trig_Bleeding_Actions takes nothing returns nothing
local unit x = GetAttacker()
local unit y = GetTriggerUnit()
call AddSpecialEffectTargetUnitBJ( "origin", y, "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl" )
set x = null
set y = null
endfunction
//===========================================================================
function InitTrig_Bleeding takes nothing returns nothing
local trigger Bleeding = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Bleeding, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( Bleeding, Condition( function Trig_Bleeding_Conditions ) )
call TriggerAddAction( Bleeding, function Trig_Bleeding_Actions )
endfunction
//TESH.scrollpos=45
//TESH.alwaysfold=0
//***********************************************************************************
//* By Kingz: *
//* Basic Stuff Library *
//* A library i made to speed up my coding of the submision *
//* Contains several usefull functions and several functions i use *
//* are simmilar to existing ones. *
//* Also contains the Max/Min values of the maps X/Y which are used as boundaries *
//* Used in all of the spells in this submision to provide easier coding *
//***********************************************************************************
library MathBasic initializer XY
globals
real MaxX // used for the maps Max X
real MaxY // used for the maps Max Y
real MinX // used for the maps Min X
real MinY // used for the maps Min Y
private constant real OffsetAngle = 0 // used for the Z facing function but is model based,for this model the value is 0
endglobals
//parabola function for the missile - Credits go to Moyack
constant function ParabolaZ takes real h,real d,real cd returns real
return (4*h / d)*(d - cd)*(cd / d)
endfunction
//when you need that extra true
constant function dummyFilter takes nothing returns boolean
return true
endfunction
//polar projection x
function PPX takes real x,real dist,real rad returns real
return x + dist * Cos(rad)
endfunction
//polar projection y
function PPY takes real y,real dist,real rad returns real
return y + dist * Sin(rad)
endfunction
//radian between locations
function RBL takes real x1, real y1, real x2, real y2 returns real
return Atan2(y2 - y1, x2 - x1)
endfunction
//distance between locations
function DBL takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1))
endfunction
// used for dummy unit z facings
function SetUnitZFacing takes unit whichUnit, real facingAngle returns nothing
local integer i = R2I((facingAngle+OffsetAngle)*0.7+0.5)
if i>0 then
call SetUnitAnimationByIndex(whichUnit, i)
else
call SetUnitAnimationByIndex(whichUnit, i+252)
endif
endfunction
//sets up the min/max X/Y values
function XY takes nothing returns nothing
set MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set MinX = GetRectMinX(bj_mapInitialPlayableArea)
set MinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library TimedFadeUnit
struct fade2
unit u
real per
real str
static thistype array index
static integer num = 0
static timer counter = CreateTimer()
static method CreateInstance takes nothing returns fade2
local fade2 this = fade2.allocate()
set fade2.index[fade2.num] = this
set fade2.num = fade2.num +1
return this
endmethod
static method onLoop takes nothing returns nothing
local fade2 this
local integer i = 0
loop
exitwhen i >= fade2.num
set this = fade2.index[i]
set this.per = this.per - this.str
call SetUnitVertexColor(this.u,255,255,255,R2I(this.per))
if this.per <= 0.00 then
call this.destroy()
set fade2.num = fade2.num - 1
set fade2.index[i] = fade2.index[num]
endif
set i = i+1
endloop
if fade2.num == 0 then
call PauseTimer(fade2.counter)
endif
endmethod
method onDestroy takes nothing returns nothing
call RemoveUnit(this.u)
set this.u = null
endmethod
endstruct
function FadeUnitTimed takes unit u, real timeout, real startper returns nothing
local fade2 this = fade2.CreateInstance()
set this.u = u
set this.per = (1.0 - startper) * 255
set this.str = (this.per / timeout) * 0.02
if fade2.num == 1 then
call TimerStart(fade2.counter,0.02,true,function fade2.onLoop)
endif
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library TimedAnimationStop
struct animation2
unit u
real t
static thistype array ind
static integer num = 0
static timer timeout = CreateTimer()
method onDestroy takes nothing returns nothing
set this.u = null
endmethod
static method Create takes nothing returns animation2
local animation2 this = animation2.allocate()
set animation2.ind[num] = this
set animation2.num = animation2.num +1
return(this)
endmethod
static method StopAnimation2 takes nothing returns nothing
local animation2 this
local integer i = 0
loop
exitwhen i >= animation2.num
set this = animation2.ind[i]
set this.t = this.t - 0.02
if this.t <= 0.00 then
call PauseUnit(this.u,true)
call SetUnitTimeScale(this.u,0)
call this.destroy()
set animation2.num = animation2.num - 1
set animation2.ind[i] = animation2.ind[animation2.num]
endif
set i = i +1
endloop
if animation2.num == 0 then
call PauseTimer(animation2.timeout)
endif
endmethod
endstruct
function StopAnimationTimed takes unit u, real time returns nothing
local animation2 this = animation2.Create()
set this.u = u
set this.t = time
if animation2.num == 1 then
call TimerStart(animation2.timeout,0.02,true,function animation2.StopAnimation2)
endif
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 = 197.
//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 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 OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//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
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=-1
//TESH.alwaysfold=0
//***************************************************************************
//*
//* TimedHandles - By TriggerHappy187
//*
//***************************************************************************
//*
//* Installation
//* Simply copy this script into your map, as well as TimerUtils.
//*
//***************************************************************************
//*
//* Documentation
//*
//* All this script does it associates a handle to a
//* timer and then destroys the handle upon the timer's expiration.
//*
//***************************************************************************
//*
//* The Public Functions
//*
//* $DESTROY$Timed - Starts the handle and it's timer, once it expires
//* the handle will be destroyed.
//*
//***************************************************************************
//*
//* Examples
//*
//* call DestroyEffectTimed(AddSpecialEffect("MODELNAME", X, X), 2)
//* call DestroyEffectTimed(AddSpecialEffectTarget("MODELNAME", unit, "attachment-point"), 2)
//*
//***************************************************************************
library TimedHandles requires TimerUtils
//! textmacro TIMEDHANDLES takes HANDLE,DESTROY
struct $HANDLE$timed
$HANDLE$ $HANDLE$_var
private static method remove takes nothing returns nothing
local timer t = GetExpiredTimer()
local $HANDLE$timed d = GetTimerData(t)
call $DESTROY$(d.$HANDLE$_var)
call ReleaseTimer(t)
call d.destroy()
endmethod
static method create takes $HANDLE$ h, real timeout returns $HANDLE$timed
local $HANDLE$timed t = $HANDLE$timed.allocate()
local timer ti = NewTimer()
set t.$HANDLE$_var = h
call SetTimerData(ti, t)
call TimerStart(ti, timeout, false, function $HANDLE$timed.remove)
return t
endmethod
endstruct
function $DESTROY$Timed takes $HANDLE$ h, real duration returns nothing
call $HANDLE$timed.create(h, duration)
endfunction
//! endtextmacro
//! runtextmacro TIMEDHANDLES("effect","DestroyEffect")
//! runtextmacro TIMEDHANDLES("lightning","DestroyLightning")
//! runtextmacro TIMEDHANDLES("weathereffect","RemoveWeatherEffect")
//! runtextmacro TIMEDHANDLES("item","RemoveItem")
//! runtextmacro TIMEDHANDLES("ubersplat","DestroyUbersplat")
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//a simple library which is used to inline GroupAddGroup() function
//made by Anachron
library Group2Group
globals
private group tmp = null
endglobals
private function addGroupUnit takes nothing returns nothing
call GroupAddUnit(tmp, GetEnumUnit())
endfunction
function Group2Group takes group src, group tar returns group
set tmp = tar
call ForGroup(src, function addGroupUnit)
return tar
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Windcut initializer InitWindCut requires TimerUtils,GroupUtils,MathBasic,TimedFadeUnit,TimedAnimationStop,Group2Group
//SETTINGS
globals
// ID's
private constant integer Spell_ID = 'A00Q' // spell ID must match this value
private constant integer Dummy_ID = 'e008' // dummy unit Id must match this value
// end of ID setup
private constant boolean InvulnerableCaster = false // if true caster is invulnerable
// damage
private constant real BaseDamage = 30000 // base damage per slash
private constant real DamageInc = 0 // damage added on base damage with every levelup of the ability
// end of damage options
// eyecandy
private constant string SlashEff = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl" // effect created on unit strike
private constant string WeaponEff = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl" // effect created on illusions blade
private constant string TrailEff = "Abilities\\Weapons\\GlaiveMissile\\GlaiveMissileTarget.mdl" // trail effect which is created on the ground as the hero moves
private constant integer ESR = 1 // ESR = Effect Spam Ration, increase in this = less effects, decrease = more effects (used for trail effects)
// end of eyecandy options
// fade options
private constant real CasterFade = 0.55 // takes a value from 0.00 to 1.00; 0.00 is transparent, 1.00 is normal value of every unit.
// 0.7 = 70% visibility, 30% transparency
private constant real ImageFade = 0.45 // same as CasterFade but for illusions
private constant real FadeTime = 0.3 // fade time for illusions, 0.3 = 0.3 seconds of delay before the trail illusions behind the heroes are removed
private constant real AnimStopValue = 0.85 // varies from model to model, takes a value when the animation is stoped
// blademaster's animation of attack ("attack") is 1.167 seconds so this is
// a user defined value, there is no equation for it
private constant real FadeTimeEx = 3.00 // this value is used for the illusions that play the attack animation
// this value should be larget than FadeTime to show the full eyecandy
// and the effect of TimedAnimationStop
// end of fade options
// speed related things
private constant real FPS = 30.00 // optimal values from 30 to 60
private constant real ChargeSpeed = 3000 * (1/FPS) // speed of the hero,uses WC3 movement speed values, don't touch anything after the sign *
private constant real AoE = 750 // AoE which is actualy used for a strange AoE calculated by distance from caster to cast point
// end of speed options
endglobals
//END OF SETTINGS
// Don't Touch the stuff bellow this point
globals
private unit TU = null
private player TP = null
private real TR = 0.00
private group FG = CreateGroup()
private constant real MinOffset = 50.00
endglobals
private function GroupFilter takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > .405 and IsUnitInGroup(GetFilterUnit(),FG)==false and GetFilterUnit() != TU and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false and IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING)==false and IsUnitEnemy(GetFilterUnit(),TP) and IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL)==false
endfunction
private function groupfunc takes nothing returns nothing
call GroupAddUnit(FG,GetEnumUnit())
endfunction
private constant function GetDamage takes integer lvl returns real
return BaseDamage + (lvl-1)*DamageInc
endfunction
private function ExtractInteger takes real r returns integer
local integer i = R2I(r)
local real s = r - I2R(i)
if s >= 0.50 then
set i = i+1
endif
return i
endfunction
private struct windcut
unit u
unit tar
group g
group d
timer t
real x
real y
real tx
real ty
real rad
real tpx
real tpy
real dmg
method onDestroy takes nothing returns nothing
call SetUnitVertexColor(this.u,255,255,255,255)
if InvulnerableCaster then
call SetUnitInvulnerable(this.u,false)
endif
call SetUnitTimeScale(this.u,1)
set this.u = null
call GroupClear(this.g)
call GroupClear(this.d)
call ReleaseGroup(this.g)
call ReleaseGroup(this.d)
set this.g = null
set this.d = null
endmethod
static method Create takes nothing returns windcut
local windcut this = windcut.allocate()
return(this)
endmethod
static method motion takes nothing returns nothing
local windcut this = GetTimerData(GetExpiredTimer())
local unit tu = CreateUnit(GetOwningPlayer(this.u),Dummy_ID,this.x,this.y,this.rad*bj_RADTODEG)
call SetUnitX(tu,this.x)
call SetUnitY(tu,this.y)
call SetUnitFacing(this.u,this.rad*bj_RADTODEG)
if this.tar != null then
set this.tx = GetUnitX(this.tar)
set this.ty = GetUnitY(this.tar)
set this.rad = RBL(this.x,this.y,this.tx,this.ty)
set this.x = this.x + ChargeSpeed * Cos(this.rad)
set this.y = this.y + ChargeSpeed * Sin(this.rad)
call SetUnitX(this.u,this.x)
call SetUnitY(this.u,this.y)
if TrailEff != "" and GetRandomInt(0,ESR) == ESR then
call DestroyEffectTimed(AddSpecialEffect(TrailEff,this.x,this.y),1)
endif
if DBL(this.x,this.y,this.tx,this.ty) <= 128 and this.tar != null then
call UnitDamageTarget(this.u,this.tar,this.dmg,true,false,null,null,null)
if WeaponEff != "" then
call DestroyEffectTimed(AddSpecialEffectTarget(WeaponEff,tu,"weapon"),FadeTimeEx/2)
endif
if SlashEff != "" then
call DestroyEffectTimed(AddSpecialEffectTarget(SlashEff,this.tar,"chest"),FadeTimeEx/2)
endif
call SetUnitAnimation(tu,"attack")
call FadeUnitTimed(tu,FadeTimeEx,ImageFade)
call StopAnimationTimed(tu,0.80)
call GroupRemoveUnit(this.g,this.tar)
set this.tar = FirstOfGroup(this.g)
else
call FadeUnitTimed(tu,FadeTime,ImageFade)
endif
else
if DBL(this.x,this.y,this.tpx,this.tpy) <= MinOffset then
call RemoveUnit(tu)
call PauseTimer(GetExpiredTimer())
call ReleaseTimer(GetExpiredTimer())
set this.t = null
call this.destroy()
else
if TrailEff != "" and GetRandomInt(0,ESR) == ESR then
call DestroyEffectTimed(AddSpecialEffect(TrailEff,this.x,this.y),1)
endif
set this.rad = RBL(this.x,this.y,this.tpx,this.tpy)
set this.x = this.x + ChargeSpeed * Cos(this.rad)
set this.y = this.y + ChargeSpeed * Sin(this.rad)
call SetUnitX(this.u,this.x)
call SetUnitY(this.u,this.y)
call FadeUnitTimed(tu,FadeTime,ImageFade)
endif
endif
if this.x > MaxX or this.x < MinX or this.y > MaxY or this.y < MinY then
set this.tar = null
set this.x = this.x - ChargeSpeed * Cos(this.rad)
set this.y = this.y - ChargeSpeed * Sin(this.rad)
set this.tpx = this.x
set this.tpy = this.y
endif
endmethod
endstruct
private function condition2run takes nothing returns boolean
local windcut this
local real d
local integer groupnum
local integer i
local real x
local real y
if GetSpellAbilityId() == Spell_ID then
set this = windcut.Create()
set this.g = NewGroup()
set this.d = NewGroup()
set this.u = GetTriggerUnit()
set this.t = NewTimer()
set this.x = GetUnitX(this.u)
set this.y = GetUnitY(this.u)
set this.tpx = GetSpellTargetX()
set this.tpy = GetSpellTargetY()
set this.rad = RBL(this.x,this.y,this.tpx,this.tpy)
set this.dmg = GetDamage(GetUnitAbilityLevel(this.u,Spell_ID))
call SetUnitVertexColor(this.u,255,255,255, 255 - R2I(CasterFade*255))
if InvulnerableCaster then
call SetUnitInvulnerable(this.u,true)
endif
call SetUnitTimeScale(this.u,0)
set d = DBL(this.x,this.y,this.tpx,this.tpy)
set groupnum = ExtractInteger(d / AoE)
set i = 0
set x = this.x
set y = this.y
if groupnum < 1 then
set groupnum = 1
endif
loop
exitwhen i > groupnum
set TU = this.u
set TP = GetOwningPlayer(TU)
call GroupEnumUnitsInRange(this.d,x,y,AoE,Filter(function GroupFilter))
call ForGroup(this.d,function groupfunc)
call Group2Group(this.d,this.g)
set x = x + (AoE) * Cos(this.rad)
set y = y + (AoE) * Sin(this.rad)
call GroupClear(this.d)
set i = i+1
endloop
call GroupClear(FG)
call SetTimerData(this.t,integer(this))
call TimerStart(this.t,1/FPS,true,function windcut.motion)
set this.tar = FirstOfGroup(this.g)
set this.tx = GetUnitX(this.tar)
set this.ty = GetUnitY(this.tar)
set this.rad = RBL(this.x,this.y,this.tx,this.ty)
endif
return false
endfunction
private function InitWindCut takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function condition2run))
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=1
//*********************************************************************************
// CREDITS *
//*********************************************************************************
//***************************************************************************************************************** *
//Credits to Rising_Dusk *
//Credits to Vexorian for so many reasons(do i even have to name them?) *
//Credits to TriggerHappy187 for TimedHandles library *
//Credits to Volvox for making the terrain. *
//Credits to Eccho for the test map. *
//*****************************************************************************************************************
function InitTrig_Credits takes nothing returns nothing
endfunction
//TESH.scrollpos=24
//TESH.alwaysfold=0
library_once TimerUtils initializer init
//*********************************************************************
//* TimerUtils (Blue flavor for 1.23b or later)
//* ----------
//*
//* 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.wc3campaigns.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.
//*
//* Blue Flavor: Slower than the red flavor, it got a 408000 handle id
//* limit, which means that if more than 408000 handle ids
//* are used in your map, TimerUtils might fail, this
//* value is quite big and it is much bigger than the
//* timer limit in Red flavor.
//*
//********************************************************************
//==================================================================================================
globals
private hashtable hasht //I <3 blizz
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
call SaveInteger(hasht,0, GetHandleId(t), value)
endfunction
function GetTimerData takes timer t returns integer
return LoadInteger(hasht, 0, GetHandleId(t))
endfunction
//==========================================================================================
globals
private timer array tT
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
set tT[0]=CreateTimer()
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==8191) 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
set hasht = InitHashtable()
endfunction
endlibrary
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
private constant boolean ALLOW_OUTSIDE_PLAYABLE_MAP_AREA = false
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns boolean
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
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
local region r = CreateRegion()
local rect map
local rect rc
if ALLOW_OUTSIDE_PLAYABLE_MAP_AREA then
set map = GetWorldBounds()
else
set map = bj_mapInitialPlayableArea
endif
set minx = GetRectMinX(map)
set miny = GetRectMinY(map)
set maxx = GetRectMaxX(map)
set maxy = GetRectMaxY(map)
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
if ALLOW_OUTSIDE_PLAYABLE_MAP_AREA then
call RemoveRect(map)
endif
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddCondition(t, Condition(function dis))
set rc=null
set map = null
endfunction
endlibrary
//TESH.scrollpos=25
//TESH.alwaysfold=0
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
// use the dummy.mdx model, so remember to import it as
// well, just use copy&paste to copy the dummy from the
// xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
// this rawcode to another spell that morphs into a flier
// in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
// raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
// timer that depends on it, if you put a low value
// the movement will look good but it may hurt your
// performance, if instead you use a high value it
// will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
// you got a unit bigger than 197.0 it would be
// a good idea to update this constant, since some
// enums will not find it. Likewise, if none of
// your units can go bellow X and X is much smaller
// than 197.0, it would be a good idea to update
// as well, since it will improve the performance
// those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************
//===========================================================================
globals
constant integer XE_DUMMY_UNITID = 'u004'
constant integer XE_HEIGHT_ENABLER = 'Amrf'
constant integer XE_TREE_RECOGNITION = 'Aeat'
constant real XE_ANIMATION_PERIOD = 0.025
constant real XE_MAX_COLLISION_SIZE = 197.0
endglobals
endlibrary
//TESH.scrollpos=216
//TESH.alwaysfold=0
library xefx initializer init requires xebasic
//**************************************************
// xefx 0.7
// --------
// Recommended: ARGB (adds ARGBrecolor method)
// For your movable fx needs
//
//**************************************************
//==================================================
globals
private constant integer MAX_INSTANCES = 8190 //change accordingly.
private constant real RECYCLE_DELAY = 4.0
//recycling, in order to show the effect correctly, must wait some time before
//removing the unit.
private timer recycler
private timer NOW
endglobals
private struct recyclebin extends array
unit u
real schedule
static recyclebin end=0
static recyclebin begin=0
static method Recycle takes nothing returns nothing
call RemoveUnit(.begin.u) //this unit is private, systems shouldn't mess with it.
set .begin.u=null
set .begin=recyclebin(integer(.begin)+1)
if(.begin==.end) then
set .begin=0
set .end=0
else
call TimerStart(recycler, .begin.schedule-TimerGetElapsed(NOW), false, function recyclebin.Recycle)
endif
endmethod
endstruct
private function init takes nothing returns nothing
set recycler=CreateTimer()
set NOW=CreateTimer()
call TimerStart(NOW,43200,true,null)
endfunction
struct xefx[MAX_INSTANCES]
public integer tag=0
private unit dummy
private effect fx=null
private real zang=0.0
private integer r=255
private integer g=255
private integer b=255
private integer a=255
private integer abil=0
static method create takes real x, real y, real facing returns xefx
local xefx this=xefx.allocate()
set this.dummy= CreateUnit(Player(15), XE_DUMMY_UNITID, x,y, facing*bj_RADTODEG)
call UnitAddAbility(this.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(this.dummy,'Aloc')
call UnitRemoveAbility(this.dummy,XE_HEIGHT_ENABLER)
call SetUnitX(this.dummy,x)
call SetUnitY(this.dummy,y)
return this
endmethod
method operator owner takes nothing returns player
return GetOwningPlayer(this.dummy)
endmethod
method operator owner= takes player p returns nothing
call SetUnitOwner(this.dummy,p,false)
endmethod
method operator teamcolor= takes playercolor c returns nothing
call SetUnitColor(this.dummy,c)
endmethod
method operator scale= takes real value returns nothing
call SetUnitScale(this.dummy,value,value,value)
endmethod
//! textmacro XEFX_colorstuff takes colorname, colorvar
method operator $colorname$ takes nothing returns integer
return this.$colorvar$
endmethod
method operator $colorname$= takes integer value returns nothing
set this.$colorvar$=value
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
//! endtextmacro
//! runtextmacro XEFX_colorstuff("red","r")
//! runtextmacro XEFX_colorstuff("green","g")
//! runtextmacro XEFX_colorstuff("blue","b")
//! runtextmacro XEFX_colorstuff("alpha","a")
method recolor takes integer r, integer g , integer b, integer a returns nothing
set this.r=r
set this.g=g
set this.b=b
set this.a=a
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
implement optional ARGBrecolor
method operator abilityid takes nothing returns integer
return this.abil
endmethod
method operator abilityid= takes integer a returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(a!=0) then
call UnitAddAbility(this.dummy,a)
endif
set this.abil=a
endmethod
method operator abilityLevel takes nothing returns integer
return GetUnitAbilityLevel( this.dummy, this.abil)
endmethod
method operator abilityLevel= takes integer newLevel returns nothing
call SetUnitAbilityLevel(this.dummy, this.abil, newLevel)
endmethod
method flash takes string fx returns nothing
call DestroyEffect(AddSpecialEffectTarget(fx,this.dummy,"origin"))
endmethod
method operator xyangle takes nothing returns real
return GetUnitFacing(this.dummy)*bj_DEGTORAD
endmethod
method operator xyangle= takes real value returns nothing
call SetUnitFacing(this.dummy,value*bj_RADTODEG)
endmethod
method operator zangle takes nothing returns real
return this.zang
endmethod
method operator zangle= takes real value returns nothing
local integer i=R2I(value*bj_RADTODEG+90.5)
set this.zang=value
if(i>=180) then
set i=179
elseif(i<0) then
set i=0
endif
call SetUnitAnimationByIndex(this.dummy, i )
endmethod
method operator x takes nothing returns real
return GetUnitX(this.dummy)
endmethod
method operator y takes nothing returns real
return GetUnitY(this.dummy)
endmethod
method operator z takes nothing returns real
return GetUnitFlyHeight(this.dummy)
endmethod
method operator z= takes real value returns nothing
call SetUnitFlyHeight(this.dummy,value,0)
endmethod
method operator x= takes real value returns nothing
call SetUnitX(this.dummy,value)
endmethod
method operator y= takes real value returns nothing
call SetUnitY(this.dummy,value)
endmethod
method operator fxpath= takes string newpath returns nothing
if (this.fx!=null) then
call DestroyEffect(this.fx)
endif
if (newpath=="") then
set this.fx=null
else
set this.fx=AddSpecialEffectTarget(newpath,this.dummy,"origin")
endif
endmethod
method hiddenReset takes string newfxpath, real newfacing returns nothing
local real x = GetUnitX(this.dummy)
local real y = GetUnitY(this.dummy)
local real z = this.z
local real za = this.zangle
local integer level = this.abilityLevel
set fxpath=null
call RemoveUnit(this.dummy)
set this.dummy= CreateUnit(Player(15), XE_DUMMY_UNITID, x,y, newfacing*bj_RADTODEG)
if(level != 0) then
call UnitAddAbility(this.dummy, abilityid)
endif
call UnitAddAbility(this.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(this.dummy,'Aloc')
call UnitRemoveAbility(this.dummy,XE_HEIGHT_ENABLER)
call SetUnitX(this.dummy,x)
call SetUnitY(this.dummy,y)
set this.z = z
set zangle = za
endmethod
private method onDestroy takes nothing returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(this.fx!=null) then
call DestroyEffect(this.fx)
set this.fx=null
endif
if (recyclebin.end==MAX_INSTANCES) then
//I'd like to see this happen...
call TimerStart(recycler,0,false,function recyclebin.Recycle)
call ExplodeUnitBJ(this.dummy)
else
set recyclebin.end.u=this.dummy
set recyclebin.end.schedule=TimerGetElapsed(NOW)+RECYCLE_DELAY
set recyclebin.end= recyclebin( integer(recyclebin.end)+1)
if( recyclebin.end==1) then
call TimerStart(recycler, RECYCLE_DELAY, false, function recyclebin.Recycle)
endif
call SetUnitOwner(this.dummy,Player(15),false)
endif
set this.dummy=null
endmethod
method hiddenDestroy takes nothing returns nothing
call ShowUnit(dummy,false)
call destroy()
endmethod
endstruct
endlibrary
//TESH.scrollpos=120
//TESH.alwaysfold=0
library xedamage initializer init requires xebasic
//************************************************************************
// xedamage 0.8
// --------
// For all your damage and targetting needs.
//
//************************************************************************
//===========================================================================================================
globals
private constant integer MAX_SUB_OPTIONS = 3
private constant real FACTOR_TEST_DAMAGE = 0.01
// a low damage to do on units to test their damage factors for specific
// attacktype/damagetype combos.
// You'll need something as high as 20.0 to make it work well with armor resistances.
// (Yes, you read it correctly, 20 ...
//
// If you use such a large value, there may be conflicts with some things relying on damage
// (ie they are not away of the isDummyDamage tag that xedamage posseses.) which may be quite bad if you think about it...
// then maybe it is better to change it to 0.01 ... then will work fine, just fine - but it will generally ignore armor -
// I am leaving it as 0.01 by default, because honestly, I'd rather make it ignore armor than have a lot of people sending me
// rants about how they detect 20.0 damage where none is visible...
private constant real MAX_DAMAGE_FACTOR = 3.00
// The maximum damage factor in the map. I think 3 is fine.
//=======================================================
private constant real EPSILON = 0.000000001
private unit dmger
private constant integer MAX_SPACE = 8190 // MAX_SPACE/MAX_SUB_OPTIONS is the instance limit for xedamage, usually big enough...
endglobals
private keyword structInit
struct xedamage[MAX_SPACE]
//----
// fields and methods for a xedamage object, they aid determining valid targets and special
// damage factor conditions.
//
// Notice the default values.
//
boolean damageSelf = false // the damage and factor methods usually have a source unit parameter
// xedamage would consider this unit as immune unless you set damageSelf to true
boolean damageAllies = false // Alliance dependent target options.
boolean damageEnemies = true // *
boolean damageNeutral = true // *
boolean ranged = true // Is the attack ranged? This has some effect on the AI of the affected units
// true by default, you may not really need to modify this.
boolean visibleOnly = false // Should only units that are visible for source unit's owner be affected?
boolean deadOnly = false // Should only corpses be affected by "the damage"? (useful when using xedamage as a target selector)
boolean alsoDead = false // Should even corpses and alive units be considered?
boolean damageTrees = false //Also damage destructables? Notice this is used only in certain methods.
//AOE for example targets a circle, so it can affect the destructables
//in that circle, a custom spell using xedamage for targetting configuration
//could also have an if-then-else implemented so it can verify if it is true
//then affect trees manually.
//
// Damage type stuff:
// .dtype : the "damagetype" , determines if the spell is physical, magical or ultimate.
// .atype : the "attacktype" , deals with armor.
// .wtype : the "weapontype" , determines the sound effect to be played when damage is done.
//
// Please use common.j/blizzard.j/ some guide to know what damage/attack/weapon types can be used
//
damagetype dtype = DAMAGE_TYPE_UNIVERSAL
attacktype atype = ATTACK_TYPE_NORMAL
weapontype wtype = WEAPON_TYPE_WHOKNOWS
//
// Damage type 'tag' people might use xedamage.isInUse() to detect xedamage usage, there are other static
// variables like xedamage.CurrentDamageType and xedamage.CurrentDamageTag. The tag allows you to specify
// a custom id for the damage type ** Notice the tag would aid you for some spell stuff, for example,
// you can use it in a way similar to Rising_Dusk's damage system.
//
integer tag = 0
//
// if true, forceDamage will make xedamage ignore dtype and atype and try as hard as possible to deal 100%
// damage.
boolean forceDamage = false
//
// Ally factor! Certain spells probably have double purposes and heal allies while harming enemies. This
// field allows you to do such thing.
//
real allyfactor = 1.0
//
// field: .exception = SOME_UNIT_TYPE
// This field adds an exception unittype (classification), if the unit belongs to this unittype it will
// be ignored.
//
method operator exception= takes unittype ut returns nothing
set this.use_ex=true
set this.ex_ut=ut
endmethod
//
// field: .required = SOME_UNIT_TYPE
// This field adds a required unittype (classification), if the unit does not belong to this unittype
// it will be ignored.
//
method operator required= takes unittype ut returns nothing
set this.use_req=true
set this.req_ut=ut
endmethod
private boolean use_ex = false
private unittype ex_ut = null
private boolean use_req = false
private unittype req_ut = null
private unittype array fct[MAX_SUB_OPTIONS]
private real array fc[MAX_SUB_OPTIONS]
private integer fcn=0
//
// method .factor(SOME_UNIT_TYPE, factor)
// You might call factor() if you wish to specify a special damage factor for a certain classification,
// for example call d.factor(UNIT_TYPE_STRUCTURE, 0.5) makes xedamage do half damage to structures.
//
method factor takes unittype ut, real fc returns nothing
if(this.fcn==MAX_SUB_OPTIONS) then
debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to factor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of factor() calls")
return
endif
set this.fct[this.fcn] = ut
set this.fc[this.fcn] = fc
set this.fcn = this.fcn+1
endmethod
private integer array abifct[MAX_SUB_OPTIONS]
private real array abifc[MAX_SUB_OPTIONS]
private integer abifcn=0
//
// method .abilityFactor('abil', factor)
// You might call abilityFactor() if you wish to specify a special damage factor for units that have a
// certain ability/buff.
// for example call d.abilityFactor('A000', 1.5 ) makes units that have the A000 ability take 50% more
// damage than usual.
//
method abilityFactor takes integer abilityId, real fc returns nothing
if(this.abifcn==MAX_SUB_OPTIONS) then
debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to abilityFactor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of abilityFactor() calls")
return
endif
set this.abifct[this.abifcn] = abilityId
set this.abifc[this.abifcn] = fc
set this.abifcn = this.abifcn+1
endmethod
private boolean usefx = false
private string fxpath
private string fxattach
//
// method .useSpecialEffect("effect\\path.mdl", "origin")
// Makes it add (and destroy) an effect when damage is performed.
//
method useSpecialEffect takes string path, string attach returns nothing
set this.usefx = true
set this.fxpath=path
set this.fxattach=attach
endmethod
//********************************************************************
//* Now, the usage stuff:
//*
//================================================================================
// static method xedamage.isInUse() will return true during a unit damaged
// event in case this damage was caused by xedamage, in this case, you can
// read variables like CurrentDamageType, CurrentAttackType and CurrentDamageTag
// to be able to recognize what sort of damage was done.
//
readonly static damagetype CurrentDamageType=null
readonly static attacktype CurrentAttackType=null
readonly static integer CurrentDamageTag =0
private static integer inUse = 0
static method isInUse takes nothing returns boolean
return (inUse>0) //inline friendly.
endmethod
readonly static boolean isDummyDamage = false
//========================================================================================================
// This function calculates the damage factor caused by a certain attack and damage
// type, it is static : xedamage.getDamageTypeFactor(someunit, ATTAcK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, 100)
//
static method getDamageTypeFactor takes unit u, attacktype a, damagetype d returns real
local real hp=GetWidgetLife(u)
local real mana=GetUnitState(u,UNIT_STATE_MANA)
local real r
local real fc = FACTOR_TEST_DAMAGE
//Since a unit is in that point, we don't need checks.
call SetUnitX(dmger,GetUnitX(u))
call SetUnitY(dmger,GetUnitY(u))
call SetUnitOwner(dmger,GetOwningPlayer(u),false)
set r=hp
if (hp< FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR) then
call SetWidgetLife(u, hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR )
set r = hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR
set fc = GetWidgetLife(u)-hp + EPSILON
endif
set isDummyDamage = true
call UnitDamageTarget(dmger,u, fc ,false,false,a,d,null)
static if DEBUG_MODE then
if IsUnitType(u, UNIT_TYPE_DEAD) and (hp>0.405) then
call BJDebugMsg("xedamage: For some reason, the unit being tested by getDamageTypeFactor has died. Verify MAX_DAMAGE_FACTOR is set to a correct value. ")
endif
endif
set isDummyDamage = false
call SetUnitOwner(dmger,Player(15),false)
if (mana>GetUnitState(u,UNIT_STATE_MANA)) then
//Unit had mana shield, return 1 and restore mana too.
call SetUnitState(u,UNIT_STATE_MANA,mana)
set r=1
else
set r= (r-GetWidgetLife(u)) / fc
endif
call SetWidgetLife(u,hp)
return r
endmethod
private method getTargetFactorCore takes unit source, unit target, boolean usetypes returns real
local player p=GetOwningPlayer(source)
local boolean allied=IsUnitAlly(target,p)
local boolean enemy =IsUnitEnemy(target,p)
local boolean neutral=allied
local real f
local real negf=1.0
local integer i
if(this.damageAllies != this.damageNeutral) then
set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_REQUEST ))
//I thought accuracy was not as important as speed , I think that REQUEST is false is enough to consider
// it neutral.
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_RESPONSE ))
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_XP ))
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_SPELLS ))
set allied= allied and not(neutral)
endif
if (not this.damageAllies) and allied then
return 0.0
elseif (not this.damageEnemies) and enemy then
return 0.0
elseif( (not this.damageSelf) and (source==target) ) then
return 0.0
elseif (not this.damageNeutral) and neutral then
return 0.0
elseif( this.use_ex and IsUnitType(target, this.ex_ut) ) then
return 0.0
elseif( this.visibleOnly and not IsUnitVisible(target,p) ) then
return 0.0
elseif ( this.deadOnly and not IsUnitType(target,UNIT_TYPE_DEAD) ) then
return 0.0
elseif ( not(this.alsoDead) and IsUnitType(target,UNIT_TYPE_DEAD) ) then
return 0.0
endif
set f=1.0
if ( IsUnitAlly(target,p) ) then
set f=f*this.allyfactor
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
if (this.use_req and not IsUnitType(target,this.req_ut)) then
return 0.0
endif
set i=.fcn-1
loop
exitwhen (i<0)
if( IsUnitType(target, this.fct[i] ) ) then
set f=f*this.fc[i]
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
set i=i-1
endloop
set i=.abifcn-1
loop
exitwhen (i<0)
if( GetUnitAbilityLevel(target,this.abifct[i] )>0 ) then
set f=f*this.abifc[i]
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
set i=i-1
endloop
set f=f*negf
if ( f<EPSILON) and (f>-EPSILON) then
return 0.0
endif
if( this.forceDamage or not usetypes ) then
return f
endif
set f=f*xedamage.getDamageTypeFactor(target,this.atype,this.dtype)
if ( f<EPSILON) and (f>-EPSILON) then
return 0.0
endif
return f
endmethod
//====================================================================
// With this you might decide if a unit is a valid target for a spell.
//
method getTargetFactor takes unit source, unit target returns real
return this.getTargetFactorCore(source,target,true)
endmethod
//======================================================================
// a little better, I guess
//
method allowedTarget takes unit source, unit target returns boolean
return (this.getTargetFactorCore(source,target,false)!=0.0)
endmethod
//=======================================================================
// performs damage to the target unit, for unit 'source'.
//
method damageTarget takes unit source, unit target, real damage returns boolean
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
local real f = this.getTargetFactorCore(source,target,false)
local real pl
if(f!=0.0) then
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
set pl=GetWidgetLife(target)
call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
if(pl != GetWidgetLife(target) ) then
if(usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
return true
endif
endif
return false
endmethod
//=======================================================================================
// The same as damageTarget, but it forces a specific damage value, good if you already
// know the target.
//
method damageTargetForceValue takes unit source, unit target, real damage returns nothing
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
if( usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
set .inUse = .inUse +1
call UnitDamageTarget(source,target, damage, true, .ranged, null, null, .wtype )
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
endmethod
//=====================================================================================
// Notice: this will not Destroy the group, but it will certainly empty the group.
//
method damageGroup takes unit source, group targetGroup, real damage returns integer
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
local unit target
local real f
local integer count=0
local real hp
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
loop
set target=FirstOfGroup(targetGroup)
exitwhen (target==null)
call GroupRemoveUnit(targetGroup,target)
set f= this.getTargetFactorCore(source,target,false)
if (f!=0.0) then
set count=count+1
if(usefx) then
set hp = GetWidgetLife(target)
endif
call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
if(usefx and (hp > GetWidgetLife(target)) ) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
endif
endloop
set .inUse = .inUse -1
set .CurrentDamageTag=tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
return count
endmethod
private static xedamage instance
private integer countAOE
private unit sourceAOE
private real AOEx
private real AOEy
private real AOEradius
private real AOEdamage
private static boolexpr filterAOE
private static boolexpr filterDestAOE
private static group enumgroup
private static rect AOERect
private static method damageAOE_Enum takes nothing returns boolean
local unit target=GetFilterUnit()
local xedamage this=.instance //adopting a instance.
local real f
local real hp
if( not IsUnitInRangeXY(target,.AOEx, .AOEy, .AOEradius) ) then
set target=null
return false
endif
set f=.getTargetFactorCore(.sourceAOE, target, false)
if(f!=0.0) then
set .countAOE=.countAOE+1
if(this.usefx) then
set hp =GetWidgetLife(target)
endif
call UnitDamageTarget(.sourceAOE,target, f*this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
if(this.usefx and (hp > GetWidgetLife(target) ) ) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
endif
set .instance= this //better restore, nesting IS possible!
set target=null
return false
endmethod
private static method damageAOE_DestructablesEnum takes nothing returns boolean
local destructable target=GetFilterDestructable()
local xedamage this=.instance //adopting a instance.
local real dx=.AOEx-GetDestructableX(target)
local real dy=.AOEy-GetDestructableY(target)
if( dx*dx + dy*dy >= .AOEradius+EPSILON ) then
set target=null
return false
endif
set .countAOE=.countAOE+1
if(.usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
call UnitDamageTarget(.sourceAOE,target, this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
set .instance= this //better restore, nesting IS possible!
set target=null
return false
endmethod
//==========================================================================================
// will affect trees if damageTrees is true!
//
method damageAOE takes unit source, real x, real y, real radius, real damage returns integer
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
set .instance=this
set .countAOE=0
set .sourceAOE=source
set .AOEx=x
set .AOEradius=radius
set .AOEy=y
set .AOEdamage=damage
call GroupEnumUnitsInRange(.enumgroup,x,y,radius+XE_MAX_COLLISION_SIZE, .filterAOE)
if(.damageTrees) then
call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
set .AOEradius=.AOEradius*.AOEradius
call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
endif
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
return .countAOE
endmethod
method damageAOELoc takes unit source, location loc, real radius, real damage returns integer
return .damageAOE(source, GetLocationX(loc), GetLocationY(loc), radius, damage)
endmethod
//==========================================================================================
// only affects trees, ignores damageTrees
//
method damageDestructablesAOE takes unit source, real x, real y, real radius, real damage returns integer
set .instance=this
set .countAOE=0
set .sourceAOE=source
set .AOEx=x
set .AOEradius=radius*radius
set .AOEy=y
set .AOEdamage=damage
//if(.damageTrees) then
call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
//endif
return .countAOE
endmethod
method damageDestructablesAOELoc takes unit source, location loc, real radius, real damage returns integer
return .damageDestructablesAOE(source,GetLocationX(loc), GetLocationY(loc), radius, damage)
endmethod
//'friend' with the library init
static method structInit takes nothing returns nothing
set .AOERect= Rect(0,0,0,0)
set .filterAOE= Condition(function xedamage.damageAOE_Enum)
set .filterDestAOE = Condition( function xedamage.damageAOE_DestructablesEnum)
set .enumgroup = CreateGroup()
endmethod
endstruct
private function init takes nothing returns nothing
set dmger=CreateUnit(Player(15), XE_DUMMY_UNITID , 0.,0.,0.)
call UnitAddAbility(dmger,'Aloc')
call xedamage.structInit()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library CrowAttack requires TimerUtils, SimError, xefx, xedamage, optional BoundSentinel
//-----------------------------------------------------------------------------------------------
// Crow Attack v1.00 by scorpion182
// requires: TimerUtils, SimError, xe, BoundSentinel by vexorian
//
//
//
//
//-----------------------------------------------------------------------------------------------
//-----------------------CALIBRATION SECTION-----------------------------------------------------
globals
private constant integer SPELL_ID = 'A00Z' // spell rawcode
private constant real CROW_SCALE = 1.0 //crow scaling value
private constant string CROW_PATH = "units\\critters\\Vulture\\Vulture.mdl" //crow path
private constant string CASTER_ART = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
private constant integer RED = 0 //coloring in RGB
private constant integer GREEN = 0
private constant integer BLUE = 0
private constant integer ALPHA = 255
private constant real CASTING_TIME = 0.50 //spell casting time
private constant integer MAX_CROW = 35 //maximum crow instance
private constant real FINISH_DIST = 80. //finish point min distance
private constant real MIN_DIST = 1.00 //minimum casting distance
private constant real CROW_H = 150. //crow movement height
private constant real SPEED = 1500. * XE_ANIMATION_PERIOD //crow movement speed
private constant string ERROR_MSG = "" //error message
private constant string DAMAGE_FX = "" //effect on-damage, because it's used xe_animation_period (0.025) it would be lag
private constant string DAMAGE_ATTCH = "origin" //damage effect attachment point
endglobals
private constant function GetCrowCount takes integer lvl returns integer
return 10 //how many crows?
endfunction
private constant function GetCollision takes integer lvl returns real
return 300. //crow collision size to give damage
endfunction
private constant function GetAoE takes integer lvl returns real
return 500. //crow aoe summon
endfunction
private constant function GetDamage takes integer lvl returns real
return 1000.00 * lvl //does 10 damage per second each crow
endfunction
//damage filter
private function DamageOptions takes xedamage spellDamage returns nothing
set spellDamage.dtype = DAMAGE_TYPE_UNIVERSAL
set spellDamage.atype = ATTACK_TYPE_NORMAL
set spellDamage.exception = UNIT_TYPE_STRUCTURE //don't damage building
set spellDamage.visibleOnly = true //only damage visible unit
set spellDamage.damageAllies = false //damage allies if true
set spellDamage.damageTrees = true //damage destructables?
endfunction
//-----------------------END OF CALIBRATION SECTION----------------------------------------------
globals
private xedamage xed
endglobals
private struct data
unit caster
timer t
integer lvl
integer alpha = 255
integer alph = 255
real cx
real cy
real tx
real ty
real dur_f
real alpha_dec = 100. / (CASTING_TIME/XE_ANIMATION_PERIOD)
xefx array fx [MAX_CROW]
real array distdone [MAX_CROW]
real array distance [MAX_CROW]
integer array status [MAX_CROW]
real array ang [MAX_CROW]
integer crow_count = 0
boolean finish = false
boolean start_create = false
real angle
static method create takes unit c, real cx, real cy, real tx, real ty returns thistype
local thistype this = thistype.allocate()
set .caster = c
set .tx = tx
set .ty = ty
set .cx = cx
set .cy = cy
set .angle=Atan2(ty - cy, tx - cx)
set .lvl = GetUnitAbilityLevel(c, SPELL_ID)
set .t = NewTimer()
call PauseUnit(c, true)
return this
endmethod
private method onDestroy takes nothing returns nothing
local integer i = 0
call DestroyEffect(AddSpecialEffect(CASTER_ART, .tx, .ty))
loop
exitwhen i == GetCrowCount(.lvl)
call .fx[i].hiddenDestroy()
set i = i + 1
endloop
call ReleaseTimer(.t)
call PauseUnit(.caster, false)
endmethod
static method onLoop takes nothing returns nothing
local thistype this = thistype (GetTimerData(GetExpiredTimer()))
local integer i = 0
local real a
local real dis
local real x
local real y
local real dx
local real dy
if not .finish then
if .alpha>0 then
set .alpha = .alpha - PercentTo255(.alpha_dec)
call SetUnitVertexColor(.caster, 255, 255, 255, .alpha)
else
if not .start_create then
set .start_create = true
call DestroyEffect(AddSpecialEffect(CASTER_ART, .cx, .cy))
loop
exitwhen i == GetCrowCount(.lvl)
set a = GetRandomReal(0, 2 * bj_PI)
set dis = GetRandomReal(1, GetAoE(.lvl))
set x = cx + dis * Cos (a)
set y = cy + dis * Sin (a)
set .fx[i] = xefx.create(x, y, .angle)
set .fx[i].fxpath = CROW_PATH
set .fx[i].scale = CROW_SCALE
set .fx[i].z = CROW_H
call .fx[i].recolor(RED, GREEN, BLUE, ALPHA)
set dx = tx - .fx[i].x
set dy = ty - .fx[i].y
set .distance[i] = SquareRoot(dx * dx + dy * dy)
set .distdone[i] = 0.
set .status[i] = 1
set i = i +1
endloop
endif
if .crow_count != GetCrowCount(.lvl) then
set i = 0
loop
exitwhen i == GetCrowCount(.lvl)
if .status[i] != 0 then
if .distdone[i] < .distance[i] then
set .distdone[i]=.distdone[i] + SPEED
set .ang[i] = Atan2(ty - .fx[i].y, tx - .fx[i].x)
set .fx[i].x = .fx[i].x + SPEED * Cos(.ang[i])
set .fx[i].y = .fx[i].y + SPEED * Sin(.ang[i])
call xed.damageAOE(.caster,.fx[i].x, .fx[i].y, GetCollision(.lvl), GetDamage(.lvl) * XE_ANIMATION_PERIOD)
else
set .status[i] = 0
set .crow_count = .crow_count + 1
endif
endif
set i = i + 1
endloop
else
set .finish = true
call SetUnitX(.caster, .tx)
call SetUnitY(.caster, .ty)
endif
endif
else
if .alpha <= 255 then
set .alpha = .alpha + PercentTo255(.alpha_dec)
set .alph = .alph - PercentTo255(.alpha_dec)
call SetUnitVertexColor(.caster, 255, 255, 255, .alpha)
set i = 0
loop
exitwhen i == GetCrowCount(.lvl)
call .fx[i].recolor(RED, GREEN, BLUE, .alph)
set i = i + 1
endloop
else
call .destroy()
endif
endif
endmethod
static method SpellEffect takes nothing returns boolean
local thistype this
if GetSpellAbilityId() == SPELL_ID then
set this = thistype.create(GetTriggerUnit(), GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), GetSpellTargetX(), GetSpellTargetY())
call SetTimerData(.t, this)
call TimerStart(.t, XE_ANIMATION_PERIOD, true, function thistype.onLoop)
endif
return false
endmethod
static method CheckMinDistance takes nothing returns boolean
local unit u = GetTriggerUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real dx = x - GetSpellTargetX()
local real dy = y - GetSpellTargetY()
if (GetSpellAbilityId() == SPELL_ID and dx * dx + dy * dy<MIN_DIST * MIN_DIST) then
call PauseUnit(u, true)
call IssueImmediateOrder(u, "stop")
call PauseUnit(u, false)
endif
set u = null
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.SpellEffect))
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
call TriggerAddCondition(t, Condition(function thistype.CheckMinDistance))
//init xedamage
set xed=xedamage.create()
call DamageOptions(xed)
call xed.useSpecialEffect(DAMAGE_FX,DAMAGE_ATTCH)
endmethod
endstruct
endlibrary
//TESH.scrollpos=21
//TESH.alwaysfold=0
library IsTerrainWalkable initializer Init
//*****************************************************************
//* IsTerrainWalkable
//*
//* rewritten in vJass by: Anitarf
//* original implementation: Vexorian
//*
//* A function for checking if a point is pathable for ground
//* units (it does so by attempting to move an item there and
//* checking where it ended up), typically used to stop sliding
//* units before they end up stuck in trees. If the point is not
//* pathable, the function will also determine the nearest point
//* that is (the point where the item ends up).
//*****************************************************************
globals
// this value is how far from a point the item may end up for the point to be considered pathable
private constant real MAX_RANGE = 10.0
// the following two variables are set to the position of the item after each pathing check
// that way, if a point isn't pathable, these will be the coordinates of the nearest point that is
public real X = 0.0
public real Y = 0.0
// END OF CALIBRATION SECTION
// ================================================================
private rect r
private item check
private item array hidden
private integer hiddenMax = 0
endglobals
private function Init takes nothing returns nothing
set check = CreateItem('ciri',0,0)
call SetItemVisible(check,false)
set r = Rect(0.0,0.0,128.0,128.0)
endfunction
private function HideBothersomeItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set hidden[hiddenMax]=GetEnumItem()
call SetItemVisible(hidden[hiddenMax],false)
set hiddenMax=hiddenMax+1
endif
endfunction
// ================================================================
function IsTerrainWalkable takes real x, real y returns boolean
// first, hide any items in the area so they don't get in the way of our item
call MoveRectTo(r, x,y)
call EnumItemsInRect(r,null,function HideBothersomeItem)
// try to move the check item and get it's coordinates
call SetItemPosition(check,x,y)//this unhides the item...
set X = GetItemX(check)
set Y = GetItemY(check)
call SetItemVisible(check,false)//...so we must hide it again
// before returning, unhide any items that got hidden at the start
loop
exitwhen hiddenMax<=0
set hiddenMax=hiddenMax-1
call SetItemVisible(hidden[hiddenMax],true)
set hidden[hiddenMax]=null
endloop
// return pathability status
return (x-X)*(x-X)+(y-Y)*(y-Y) < MAX_RANGE*MAX_RANGE
endfunction
endlibrary
//TESH.scrollpos=52
//TESH.alwaysfold=0
library groupaddunitsnearline
globals
//upper bound for the collision size of units
private constant real MAX_COLLISSION = 128.
//this is aproximately how much space of the rects is used by the line
//a higher value yields less unnecessary checks but also more rects
private constant real desiredefficiency = 0.6
//---
private rect temprect = Rect(0,0,0,0)
private group tempenumgroup = CreateGroup()
private group tempgroup
private real temppx
private real temppy
private real tempdnx
private real tempdny
private real tempwidth
private real tempd
endglobals
//returns the maximum of 4 reals
private function max4 takes real a, real b, real c, real d returns real
local real max = a
if b > max then
set max = b
endif
if c > max then
set max = c
endif
if d > max then
set max = d
endif
return max
endfunction
//returns the minimum of 4 reals
private function min4 takes real a, real b, real c, real d returns real
local real min = a
if b < min then
set min = b
endif
if c < min then
set min = c
endif
if d < min then
set min = d
endif
return min
endfunction
private function Add takes nothing returns boolean
//position of unit
local real x = GetUnitX(GetFilterUnit())
local real y = GetUnitY(GetFilterUnit())
//vector from the beginning of the line to the unit
local real dx = x - temppx
local real dy = y - temppy
//distance from the beginning of the line to that point on the line which is closest to the unit (uses dot-product)
local real d = dx * tempdnx + dy * tempdny
local real cx
local real cy
//cut off points outside the line
if d <= 0 then
set d = 0
elseif d >= tempd then
set d = tempd
endif
//the closest point to the unit on the line
set cx = temppx + d * tempdnx
set cy = temppy + d * tempdny
if IsUnitInRangeXY(GetFilterUnit(), cx, cy, tempwidth) then
call GroupAddUnit(tempgroup, GetFilterUnit())
endif
return false
endfunction
function GroupAddUnitsNearLine takes group g, real px, real py, real qx, real qy, real width returns nothing
//the line width width
local real l1x
local real l1y
local real l2x
local real l2y
local real l3x
local real l3y
local real l4x
local real l4y
//d = from p to q
local real dx = qx - px
local real dy = qy - py
local real dlen = SquareRoot(dx*dx + dy*dy)
//normalized d
local real dxn = dx / dlen
local real dyn = dy / dlen
//divisions
local integer divisions = 1
//bonus for correct overlapping of rects
local real bonusx = 0.
local real bonusy = 0.
//integer for loop
local integer i
//the outer rect
local real rectminx
local real rectmaxx
local real rectminy
local real rectmaxy
set width = width + MAX_COLLISSION
//calculate the number of divisions needed to approximately match desiredefficiency
if dx != 0 and dy != 0 then
set divisions = 1 + R2I(SquareRoot(desiredefficiency*desiredefficiency / (width*width/(dx*dx) + width*width/(dy*dy))))
endif
//this calculates a bonus so that there are intersections between the different rects
//(without this we would miss some units between the rects)
if dy != 0 and divisions > 1 then
set bonusx = width / 2 * dlen / dx// ?dy
endif
if dx != 0 and divisions > 1 then
set bonusy = width / 2 * dlen / dy // ? dx
endif
//calculate first line segment
set l1x = - width*dyn
set l1y = width*dxn
set l2x = width*dyn
set l2y = - width*dxn
set l3x = l2x + dx/divisions + bonusx
set l3y = l2y + dy/divisions + bonusy
set l4x = l1x + dx/divisions + bonusx
set l4y = l1y + dy/divisions + bonusy
//calculate bounds of the first line segment
set rectminx = min4(l1x,l2x,l3x,l4x)
set rectmaxx = max4(l1x,l2x,l3x,l4x)
set rectminy = min4(l1y,l2y,l3y,l4y)
set rectmaxy = max4(l1y,l2y,l3y,l4y)
//set temp vars for groupenum
set tempgroup = g
set temppx = px
set temppy = py
set tempdnx = dxn
set tempdny = dyn
set tempwidth = width - MAX_COLLISSION
set tempd = dlen
set i = 0
loop
exitwhen i >= divisions
//---
//move rect to right position
call SetRect(temprect, px + i * dx / divisions + rectminx, py + i * dy / divisions + rectminy, px + i * dx / divisions + rectmaxx, py + i * dy / divisions + rectmaxy)
//enum units in rect
call GroupEnumUnitsInRect(tempenumgroup, temprect, Condition(function Add))
//---
set i = i + 1
endloop
endfunction
endlibrary
//TESH.scrollpos=30
//TESH.alwaysfold=0
scope DarkAgility initializer init
//*************************************************************************************************************//
// Dark Agility v0.02 //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// IsTerrainWalkable by Antiarf //
// IsUnitNearLine by peq //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
private keyword Main
private keyword Shadow
private keyword Arrow
globals
//ID of the spell
private constant integer SPELL_ID = 'A015'
private constant integer DUMMY_ID = 'h005'
private constant integer HERO_DUMMY_ID = 'h004'
//Interval of the moves
private constant real TIMER_INTERVAL = 0.05
//Main
private constant integer COLOR_RED = 125
private constant integer COLOR_GREEN = 125
private constant integer COLOR_BLUE = 125
private constant integer COLOR_ALPHA = 255
private constant integer ANIMATION = 0
private constant real SPEED = 2500.00
private constant real ILLU_TIME = 0.5
private constant real SHADOW_INTERVAL = 0.035
private constant real PICK_INTERVAL = 0.20
private constant real ANI_TIME = 1.000
private constant real ANI_SPEED = 15.00
private constant real ANI_SPEED_SHADOW = 1.00
private constant real SHADOW_SIZE = 1.00
private constant real Z_START = 300.00
private constant string DAMAGE_SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
//Arrow
private constant integer A_COLOR_RED = 255
private constant integer A_COLOR_GREEN = 255
private constant integer A_COLOR_BLUE = 255
private constant integer A_COLOR_ALPHA = 125
private constant real SHOOT_RANGE = 750.00
private constant real SHOOT_SPEED = 1000.00
private constant real SHOOT_AOE = 25.00
private constant real SHOOT_SIZE = 1.00
private constant string SHOOT_MODEL = "Abilities\\Weapons\\Arrow\\ArrowMissile.mdl"
private constant string SHOOT_ADD = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
private constant string SHOOT_DMG_SFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl"
//System
private Main TEMPMAIN
private Arrow TEMPARROW
private Shadow TEMPSHADOW
private group TEMPGROUP = CreateGroup()
endglobals
private function HIT_FUNC takes Main m, unit target returns nothing
//Do your uber crazy things, like knockback, dot, slow ...
endfunction
private function ARROW_HIT_FUNC takes Arrow a returns nothing
//Do your uber crazy things, like knockback, dot, slow ... //Care arrow gets destroyed after call
endfunction
private function DAMAGE takes integer level returns real
return 500.00 * level
endfunction
private function ARROW_DAMAGE takes integer level returns real
return 500.00 * level
endfunction
private function AOE takes integer level returns real
return 150.00 * level
endfunction
private function CD takes integer level returns real
return 0.29 - 0.03 * level
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private function AngleBetweenUnits takes unit u, unit u2 returns real
return bj_RADTODEG * Atan2(GetUnitY( u2 ) - GetUnitY( u ), GetUnitX( u2 ) - GetUnitX( u ))
endfunction
private function AngleBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
private function DistanceBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
private function A_OuterControl takes nothing returns nothing
set TEMPARROW = GetTimerData( GetExpiredTimer() )
call TEMPARROW.control()
endfunction
private function OuterControl takes nothing returns nothing
set TEMPMAIN = GetTimerData( GetExpiredTimer() )
call TEMPMAIN.control()
endfunction
private function RemoveShadow takes nothing returns nothing
local timer t = GetExpiredTimer()
set TEMPSHADOW = GetTimerData( t )
set TEMPSHADOW.alpha = TEMPSHADOW.alpha - TEMPSHADOW.alphaneg
call SetUnitVertexColor( TEMPSHADOW.u, COLOR_RED, COLOR_GREEN, COLOR_BLUE, R2I( TEMPSHADOW.alpha - 0.5 ) )
if TEMPSHADOW.alpha <= 0.00 then
call KillUnit( TEMPSHADOW.u )
call RemoveUnit( TEMPSHADOW.u )
call ReleaseTimer( t )
endif
set t = null
endfunction
private struct Shadow
unit u = null
real alpha = 0.00
real alphaneg = 0.00
static method create takes unit u returns thistype
local thistype this = thistype.allocate()
set .u = u
set .alpha = COLOR_ALPHA
set .alphaneg = .alpha * TIMER_INTERVAL / ILLU_TIME
return this
endmethod
endstruct
private struct Arrow
unit u = null
unit caster = null
unit target = null
integer level = 1
effect model = null
effect add = null
timer t = null
method onDestroy takes nothing returns nothing
call DestroyEffect( AddSpecialEffectTarget( SHOOT_DMG_SFX, .target, "chest" ) )
call UnitDamageTarget( .caster, .target, ARROW_DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call ARROW_HIT_FUNC( this )
call DestroyEffect( .model )
call DestroyEffect( .add )
set .model = null
set .add = null
call KillUnit( .u )
set .u = null
set .caster = null
set .target = null
call ReleaseTimer( .t )
set .t = null
endmethod
method control takes nothing returns nothing
local real angle = AngleBetweenUnits( .u, .target )
local real x = GetUnitX( .u )
local real y = GetUnitY( .u )
local real z = GetUnitFlyHeight( .target ) - GetUnitFlyHeight( .u )
local integer times = 0
call SetUnitFacing( .u, angle )
set angle = angle * bj_DEGTORAD
set x = x + Cos( angle ) * SHOOT_SPEED * TIMER_INTERVAL
set y = y + Sin( angle ) * SHOOT_SPEED * TIMER_INTERVAL
set times = R2I( DistanceBetweenCoordinates( GetUnitX( .u ), x, GetUnitY( .u ), y ) / ( SHOOT_SPEED * TIMER_INTERVAL ) + 0.5 )
call SetUnitX( .u, x )
call SetUnitY( .u, y )
if IsUnitInRange( .u, .target, SHOOT_AOE ) then
call .destroy()
return
endif
if z != 0.00 then
call SetUnitFlyHeight( .u, GetUnitFlyHeight( .u ) + z / times, 0 )
endif
endmethod
static method create takes unit caster, unit target, integer level returns thistype
local thistype this = thistype.allocate()
set .caster = caster
set .target = target
set .u = CreateUnit( GetOwningPlayer( caster ), DUMMY_ID, GetUnitX( caster ), GetUnitY( caster ), 0.00 )
set .level = level
set .model = AddSpecialEffectTarget( SHOOT_MODEL, .u, "origin" )
set .add = AddSpecialEffectTarget( SHOOT_ADD, .u, "origin" )
set .t = NewTimer()
call SetUnitFlyHeight( .u, Z_START, 0 )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function A_OuterControl )
call SetUnitScale( .u, SHOOT_SIZE, SHOOT_SIZE, SHOOT_SIZE )
call SetUnitVertexColor( .u, A_COLOR_RED, A_COLOR_GREEN, A_COLOR_BLUE, A_COLOR_ALPHA )
return this
endmethod
endstruct
private struct Main
unit caster = null
real targx = 0.00
real targy = 0.00
real x = 0.00
real y = 0.00
real vx = 0.00
real vy = 0.00
real angle = 0.00
real distance = 0.00 //Distance moved
real fdistance = 0.00 //Full distance
real pickint = 0.00
real shadowint = 0.00
real aniint = 0.00
real shotint = 0.00
integer level = 1
integer i = 0
timer t = null
group g = null
group targets = null
method shot takes nothing returns nothing
local unit u = GroupPickRandomUnit( .targets )
if u != null then
call Arrow.create( .caster, u, .level )
endif
set u = null
endmethod
method createShadow takes nothing returns nothing
local timer t = NewTimer()
local unit u = CreateUnit( Player( 12 ), HERO_DUMMY_ID, .x, .y, .angle )
set TEMPSHADOW = Shadow.create( u )
call SetUnitTimeScale( u, ANI_SPEED_SHADOW )
call SetUnitAnimationByIndex( u, ANIMATION )
call SetUnitScale( u, SHADOW_SIZE, SHADOW_SIZE, SHADOW_SIZE )
call SetUnitVertexColor( u, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_ALPHA )
call SetTimerData( t, TEMPSHADOW )
call TimerStart( t, TIMER_INTERVAL, true, function RemoveShadow )
endmethod
method pick takes nothing returns nothing
local unit u = null
call GroupEnumUnitsInRange( TEMPGROUP, .x, .y, AOE( .level ), Condition( function IsAliveAndUnitAndNotMagicImmune ) )
loop
set u = FirstOfGroup( TEMPGROUP )
if IsUnitEnemy( u, GetOwningPlayer( .caster ) ) then
if not IsUnitInGroup( u, .g ) then
call DestroyEffect( AddSpecialEffectTarget( DAMAGE_SFX, u, "chest" ) )
call UnitDamageTarget( .caster, u, DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call HIT_FUNC( this, u )
call GroupAddUnit( .g, u )
endif
endif
call GroupRemoveUnit( TEMPGROUP, u )
set u = null
endloop
endmethod
method control takes nothing returns nothing
if .i == 3 then
call PauseUnit( .caster, true )
else
set .i = .i + 1
endif
if .distance >= .fdistance then
call .destroy()
endif
set .distance = .distance + SPEED * TIMER_INTERVAL
set .x = .x + .vx
set .y = .y + .vy
call SetUnitX( .caster, .x )
call SetUnitY( .caster, .y )
set .shotint = .shotint + TIMER_INTERVAL
if .shotint >= CD( .level ) then
set .shotint = 0.00
call .shot()
endif
set .pickint = .pickint + TIMER_INTERVAL
if .pickint >= PICK_INTERVAL then
set .pickint = 0.00
call .pick()
endif
set .shadowint = .shadowint + TIMER_INTERVAL
if .shadowint >= SHADOW_INTERVAL then
set .shadowint = 0.00
call .createShadow()
endif
set .aniint = .aniint + TIMER_INTERVAL
if .aniint >= ANI_TIME / ANI_SPEED then
set .aniint = 0.00
call SetUnitAnimationByIndex( .caster, ANIMATION )
endif
endmethod
method onDestroy takes nothing returns nothing
call SetUnitAnimation( .caster, "stand" )
call SetUnitTimeScale( .caster, 1.00 )
call PauseUnit( .caster, false )
call SetUnitPathing( .caster, true )
set .caster = null
call GroupClear( .g )
call DestroyGroup( .g )
set .g = null
call GroupClear( .targets )
call DestroyGroup( .targets )
set .targets = null
call ReleaseTimer( .t )
set .t = null
endmethod
static method create takes unit caster, real targx, real targy returns thistype
local thistype this = thistype.allocate()
local integer i
local real x
local real y
local unit u
set .caster = caster
set .targx = targx
set .targy = targy
set .x = GetUnitX( caster )
set .y = GetUnitY( caster )
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .t = NewTimer()
call SetTimerData( .t, this )
set .angle = AngleBetweenCoordinates( .x, targx, .y, targy )
set .distance = DistanceBetweenCoordinates( .x, targx, .y, targy )
set .distance = .distance / ( SPEED * TIMER_INTERVAL )
set .vx = Cos( .angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set .vy = Sin( .angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set i = R2I( .distance + 0.5 ) * 4
set x = .x
set y = .y
set .g = CreateGroup()
set .targets = CreateGroup()
call GroupAddUnitsNearLine( .targets, .x, .y, .targx, .targy, SHOOT_RANGE )
call SetUnitPathing( .caster, false )
loop
exitwhen i < 0
set x = x + .vx / 4
set y = y + .vy / 4
// if not IsTerrainWalkable( x, y ) or IsTerrainPathable( x, y, PATHING_TYPE_WALKABILITY ) then
// set .targx = x
// set .targy = y
//exitwhen true
//endif
set i = i - 1
endloop
set .distance = 0.00
set .fdistance = DistanceBetweenCoordinates( .x, .targx, .y, .targy )
call GroupAddGroup( .targets, TEMPGROUP )
loop
set u = FirstOfGroup( TEMPGROUP )
exitwhen u == null
if GetUnitTypeId( u ) != DUMMY_ID and GetUnitTypeId( u ) != HERO_DUMMY_ID and IsUnitEnemy( u, GetOwningPlayer( .caster ) ) and GetWidgetLife( u ) > 0.405 and IsUnitType(u, UNIT_TYPE_STRUCTURE) == false and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) == false then
//good target
else
//not good
call GroupRemoveUnit( .targets, u )
endif
call GroupRemoveUnit( TEMPGROUP, u )
set u = null
endloop
call SetUnitTimeScale( .caster, ANI_SPEED )
call SetUnitAnimationByIndex( .caster, ANIMATION )
call TimerStart( .t, TIMER_INTERVAL, true, function OuterControl )
return this
endmethod
endstruct
private function IsSpell takes nothing returns nothing
if GetSpellAbilityId() == SPELL_ID then
call Main.create( GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY() )
endif
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddAction( t, function IsSpell )
set t = null
endfunction
endscope
//TESH.scrollpos=64
//TESH.alwaysfold=0
scope ShadowShot initializer init
//*************************************************************************************************************//
// Shadow Shot v0.02 //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// IsTerrainWalkable by Antiarf //
// //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
private keyword Main
private keyword Sub
private keyword Arrow
globals
//ID of the spell
private constant integer SPELL_ID = 'A016'
//ID of your dummy
private constant integer DUMMY_ID = 'h006'
//Interval of the moves
private constant real TIMER_INTERVAL = 0.035
//Shooters
//Color in rgb
private constant integer S_COLOR_RED = 255
private constant integer S_COLOR_GREEN = 255
private constant integer S_COLOR_BLUE = 255
//Alpha color reached befor shot.
private constant integer S_COLOR_ALPHA = 125
//Time the units need to appear.
private constant real SHOW_TIME = 1.00
//Time the units need to disappear.
private constant real HIDE_TIME = 1.00
//Time of the attack animation.
private constant real ANIMATION_TIME = 0.70
//Size of the units
private constant real SHOOTER_SIZE = 1.00
//Z-start of the missiles
private constant real SHOOTER_MISSILE_Z = 60.00
//Place a unit needs
private constant real SHOOTER_COL = 100.00
//Max angle the units can have
private constant real SHOOTER_ANGLE = 45.00
//Animation string
private constant string ANIMATION = "attack"
//Missile
//Color in rgb
private constant integer M_COLOR_RED = 255
private constant integer M_COLOR_GREEN = 255
private constant integer M_COLOR_BLUE = 255
private constant integer M_COLOR_ALPHA = 125
//Pick units in each
private constant integer PICK_EACH_X_TIMES = 3
//Speed of the arrows in wc3 units
private constant real SPEED = 600.00
//Size of the missile
private constant real MISSILE_SIZE = 1.00
//Model of the missile
private constant string MODEL = "Abilities\\Weapons\\Arrow\\ArrowMissile.mdl"
//SFX on damage
private constant string DAMAGE_SFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl"
//Additionall model
private constant string ADD_MODEL = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
//Should the missile disappear on collision with doodads cliff ...
private constant boolean IS_COLLISION = false
//System
private Main TEMPMAIN
private Sub TEMPSUB
private Arrow TEMPARROW
private group TEMPGROUP = CreateGroup()
private hashtable HASH = InitHashtable()
endglobals
private function HIT_FUNC takes Arrow arrow, unit target returns nothing
//Do your uber crazy things, like knockback, dot, slow ...
endfunction
private function DAMAGE takes integer level returns real
return 10000.00
endfunction
private function AOE takes integer level returns real
return 300.00
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private function AngleBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
private function DistanceBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
private function OuterControl takes nothing returns nothing
set TEMPMAIN = GetTimerData( GetExpiredTimer() )
call TEMPMAIN.control()
endfunction
private function A_OuterControl takes nothing returns nothing
set TEMPARROW = GetTimerData( GetExpiredTimer() )
call TEMPARROW.control()
endfunction
private struct Arrow
unit u = null
unit caster = null
effect model = null
effect sfx = null
group g = null
real range = 0.00
real dist = 0.00
real vx = 0.00
real vy = 0.00
real alpha = M_COLOR_ALPHA
real alphalose = 0.00
integer level = 1
integer times = 0
timer t = null
boolean vanish = false
method onDestroy takes nothing returns nothing
call ReleaseTimer( .t )
set .t = null
call DestroyEffect( .model )
call DestroyEffect( .sfx )
set .model = null
set .sfx = null
call KillUnit( .u )
set .u = null
call GroupClear( .g )
call DestroyGroup( .g )
set .g = null
endmethod
method dealDamage takes unit u returns nothing
call DestroyEffect( AddSpecialEffectTarget( DAMAGE_SFX, u, "chest" ) )
if .vanish then
call UnitDamageTarget( .caster, u, DAMAGE( .level ) * .alpha / M_COLOR_ALPHA, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
else
call UnitDamageTarget( .caster, u, DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
endif
call HIT_FUNC( this, u )
endmethod
method control takes nothing returns nothing
local real x = GetUnitX( .u ) + .vx
local real y = GetUnitY( .u ) + .vy
local unit u
if GetWidgetLife( .u ) <= 0.405 then
call .destroy()
endif
if not .vanish then
set .dist = .dist - SPEED * TIMER_INTERVAL
if .dist <= 0.00 then
set .vanish = true
endif
endif
if .vanish then
set .alpha = .alpha - .alphalose
call SetUnitVertexColor( .u, M_COLOR_RED, M_COLOR_GREEN, M_COLOR_GREEN, R2I( .alpha + 0.5 ) )
endif
set .range = .range - SPEED * TIMER_INTERVAL
call SetUnitX( .u, x )
call SetUnitY( .u, y )
if IS_COLLISION then
endif
set .times = .times + 1
if .times >= PICK_EACH_X_TIMES then
set .times = 0
call GroupEnumUnitsInRange( TEMPGROUP, x, y, AOE( .level ), Condition( function IsAliveAndUnitAndNotMagicImmune ) )
loop
set u = FirstOfGroup( TEMPGROUP )
exitwhen u == null
if IsUnitEnemy( u, GetOwningPlayer( .caster ) ) then
if not IsUnitInGroup( u, .g ) then
call .dealDamage( u )
call GroupAddUnit( .g, u )
endif
endif
call GroupRemoveUnit( TEMPGROUP, u )
set u = null
endloop
endif
if .range <= 0.00 then
call .destroy()
endif
endmethod
static method create takes Main root, real x, real y, real angle returns thistype
local thistype this = thistype.allocate()
set .caster = root.caster
set .g = CreateGroup()
set .range = root.distance * 2.00
set .level = root.level
set .dist = root.distance
set .vx = Cos( angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set .vy = Sin( angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set .u = CreateUnit( GetOwningPlayer( .caster ), DUMMY_ID, x, y, angle )
set .model = AddSpecialEffectTarget( MODEL, .u, "origin" )
set .sfx = AddSpecialEffectTarget( ADD_MODEL, .u, "origin" )
set .alphalose = M_COLOR_ALPHA * TIMER_INTERVAL / ( .dist / ( SPEED * TIMER_INTERVAL ) )
call SetUnitFlyHeight( .u, SHOOTER_MISSILE_Z, 0 )
call SetUnitScale( .u, MISSILE_SIZE, MISSILE_SIZE, MISSILE_SIZE )
call SetUnitVertexColor( .u, S_COLOR_RED, S_COLOR_GREEN, S_COLOR_BLUE, S_COLOR_ALPHA )
set .t = NewTimer()
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function A_OuterControl )
return this
endmethod
endstruct
private struct Sub
unit u = null
real angle = 0.00
Main root = 0
method onDestroy takes nothing returns nothing
call KillUnit( .u )
call RemoveUnit( .u )
set .u = null
endmethod
method shot takes nothing returns nothing
call Arrow.create( .root, GetUnitX( .u ), GetUnitY( .u ), .angle )
endmethod
method attack takes nothing returns nothing
call SetUnitAnimation( .u, ANIMATION )
endmethod
method adjustAlpha takes nothing returns nothing
call SetUnitVertexColor( .u, S_COLOR_RED, S_COLOR_GREEN, S_COLOR_BLUE, R2I( .root.alpha + 0.5 ) )
endmethod
static method create takes Main root, real angle returns thistype
local thistype this = thistype.allocate()
local real x = root.x + Cos( angle * bj_DEGTORAD ) * root.distance
local real y = root.y + Sin( angle * bj_DEGTORAD ) * root.distance
set .root = root
set .angle = angle + 180.00
set .u = CreateUnit( Player( 12 ), GetUnitTypeId( root.caster ), x, y, .angle )
call SetUnitColor( .u, GetPlayerColor( GetOwningPlayer( root.caster ) ) )
call SetUnitScale( .u, SHOOTER_SIZE, SHOOTER_SIZE, SHOOTER_SIZE )
call SetUnitVertexColor( .u, S_COLOR_RED, S_COLOR_GREEN, S_COLOR_BLUE, R2I( root.alpha ) )
call SetUnitPathing( .u, false )
call SetUnitX( .u, x )
call SetUnitY( .u, y )
call UnitAddAbility( .u, 'Aloc' )
call PauseUnit( .u, true )
return this
endmethod
endstruct
private struct Main
unit caster = null
integer shooter = 0
real alpha = 0
integer level = 1
real time = 0.00
real x = 0.00
real y = 0.00
real distance = 0.00
timer t = null
boolean show = true
boolean shot = false
boolean hide = false
method control takes nothing returns nothing
local real r
local integer i
//SHOW
if .show then
set r = S_COLOR_ALPHA * TIMER_INTERVAL / SHOW_TIME
set .alpha = .alpha + r
set .time = .time - TIMER_INTERVAL
set i = 0
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.adjustAlpha()
set i = i + 1
endloop
if .time <= 0.00 then
set .show = false
set .shot = true
set .time = ANIMATION_TIME
set i = 0
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.attack()
set i = i + 1
endloop
endif
return
endif
//ATTACK
if .shot then
set .time = .time - TIMER_INTERVAL
if .time <= 0.00 then
set i = 0
set .shot = false
set .hide = true
set .time = HIDE_TIME
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.shot()
set i = i + 1
endloop
endif
return
endif
//HIDE
if .hide then
set r = S_COLOR_ALPHA * TIMER_INTERVAL / SHOW_TIME
set .alpha = .alpha - r
set .time = .time - TIMER_INTERVAL
set i = 0
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.adjustAlpha()
set i = i + 1
endloop
if .time <= 0.00 then
call .destroy()
endif
endif
endmethod
method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i > .shooter
set TEMPSUB = LoadInteger( HASH, this, i )
call TEMPSUB.destroy()
set i = i + 1
endloop
call FlushChildHashtable( HASH, this )
set .caster = null
call ReleaseTimer( .t )
set .t = null
endmethod
static method create takes unit caster, real x, real y returns thistype
local thistype this = thistype.allocate()
local real distance = DistanceBetweenCoordinates( GetUnitX( caster ), x, GetUnitY( caster ), y )
local real bogen = 2 * bj_PI * distance * ( SHOOTER_ANGLE * 2.00 ) / 360.00
local integer count = R2I( bogen / SHOOTER_COL + 0.5 )
local real angle = AngleBetweenCoordinates( GetUnitX( caster ), x, GetUnitY( caster ), y )
local real r = 0.00
local integer i = 0
set bogen = SHOOTER_ANGLE * 2 / count
set .caster = caster
set .shooter = count
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .time = SHOW_TIME
set .alpha = 0
set .x = x
set .y = y
set .t = NewTimer()
set .distance = distance
call SetTimerData( .t, this )
set r = ( angle + 180.00 ) - SHOOTER_ANGLE
loop
exitwhen i > count
set TEMPSUB = Sub.create( this, r )
call SaveInteger( HASH, this, i, TEMPSUB )
set r = r + bogen
set i = i + 1
endloop
call TimerStart( .t, TIMER_INTERVAL, true, function OuterControl )
return this
endmethod
endstruct
private function IsSpell takes nothing returns nothing
if GetSpellAbilityId() == SPELL_ID then
call Main.create( GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY() )
endif
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddAction( t, function IsSpell )
set t = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Tree_Lives_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A017'
endfunction
function Trig_Tree_Lives_Actions takes nothing returns nothing
local unit x = GetTriggerUnit()
local destructable tree = GetSpellTargetDestructable()
local location y = GetDestructableLoc(tree)
local unit d = CreateUnitAtLoc(GetOwningPlayer(x),'n008', y, bj_UNIT_FACING )
local real t = 1.
loop
call TriggerSleepAction(t)
call SetUnitLifeBJ(d, GetUnitState(d, UNIT_STATE_LIFE) - 2)
exitwhen IsUnitDeadBJ(d) == true
endloop
call RemoveLocation(y)
set x = null
set d = null
set tree = null
endfunction
//===========================================================================
function InitTrig_Tree_Lives takes nothing returns nothing
local trigger Tree_Lives = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(Tree_Lives, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( Tree_Lives, Condition( function Trig_Tree_Lives_Conditions ) )
call TriggerAddAction( Tree_Lives, function Trig_Tree_Lives_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Water_Guard_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01A'
endfunction
function Trig_Water_Guard_Actions takes nothing returns nothing
local unit x = GetTriggerUnit()
local unit d1
local unit d2
local unit d3
local unit d4
local real t = ((GetUnitAbilityLevel(x, 'A01A')) * 5) + 10
set d1 = CreateUnitAtLoc(GetOwningPlayer(x) , 'h007' , GetRectCenter(gg_rct_Reg1), 180.00 )
set d2 = CreateUnitAtLoc(GetOwningPlayer(x) , 'h007' , GetRectCenter(gg_rct_Reg2), 270.00 )
set d3 = CreateUnitAtLoc(GetOwningPlayer(x) , 'h007' , GetRectCenter(gg_rct_Reg3), 0.00 )
set d4 = CreateUnitAtLoc(GetOwningPlayer(x) , 'h007' , GetRectCenter(gg_rct_Reg4), 90.00 )
call TriggerSleepAction(t)
call KillUnit(d1)
call KillUnit(d2)
call KillUnit(d3)
call KillUnit(d4)
set x = null
set d1 = null
set d2 = null
set d3 = null
set d4 = null
endfunction
//===========================================================================
function InitTrig_Water_Guard takes nothing returns nothing
local trigger Water_Guard = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Water_Guard, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( Water_Guard, Condition( function Trig_Water_Guard_Conditions ) )
call TriggerAddAction(Water_Guard, function Trig_Water_Guard_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope EntaglingRootsDummy initializer InitTrig_Entagling_Roots
private function Conditions takes nothing returns boolean
return GetUnitTypeId(GetAttacker()) == 'n008'
endfunction
private function Actions takes nothing returns nothing
local unit u = GetAttacker()
local unit y = GetTriggerUnit()
local unit d
local location l
local integer chance = GetRandomInt(0, 100)
if chance < 15 then
set l = GetUnitLoc(u)
set d = CreateUnitAtLoc(GetOwningPlayer(u), 'h015', l, 0.)
call UnitApplyTimedLife( d, 'BTLF', 1.5)
call IssueTargetOrder(d, "entanglingroots", y)
call RemoveLocation(l)
set d = null
set l = null
endif
set u = null
set y = null
endfunction
//===========================================================================
private function InitTrig_Entagling_Roots takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Wall_of_Pain_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01H'
endfunction
function Trig_Wall_of_Pain_Actions takes nothing returns nothing
local unit x = GetTriggerUnit()
local location l = GetSpellTargetLoc()
local unit y = CreateUnitAtLoc(GetOwningPlayer(x) , 'h009' , l, 0.00)
local real t = 2.5 + (GetUnitAbilityLevelSwapped('A01H', x) * 3.0)
call TriggerSleepAction(t)
call KillUnit(y)
set x = null
set y = null
call RemoveLocation(l)
endfunction
//===========================================================================
function InitTrig_Wall_of_Pain takes nothing returns nothing
local trigger Wall_of_Pain = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Wall_of_Pain, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( Wall_of_Pain, Condition( function Trig_Wall_of_Pain_Conditions ) )
call TriggerAddAction( Wall_of_Pain, function Trig_Wall_of_Pain_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Domination initializer InitTrig_Domination
private function Conditions takes nothing returns boolean
return ( GetUnitTypeId(GetAttacker()) == 'E00E' ) and ( GetUnitAbilityLevel(GetAttacker(),'A01M') > 0 )
endfunction
private function Actions takes nothing returns nothing
local unit u = GetAttacker()
local unit y = GetTriggerUnit()
local location l = GetUnitLoc(u)
local real t = 1.5
local unit dummy
local integer lvl = GetUnitAbilityLevel(u,'A01M')
local integer chance = GetRandomInt(0, 100)
if chance >= 10 + (lvl * 5) then
set dummy = CreateUnitAtLoc(GetOwningPlayer(u), 'h00A', l, 0.)
call SetUnitAbilityLevel(dummy, 'A01Q', lvl)
call IssueTargetOrder( dummy, "chainlightning", y )
call TriggerSleepAction(t)
call RemoveUnit(dummy)
endif
call RemoveLocation(l)
set u = null
set y = null
set dummy = null
endfunction
//===========================================================================
private function InitTrig_Domination takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope LSLeo initializer InitTrig_Lightning_Strike
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A01N'
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit y = GetSpellTargetUnit()
local unit d
local real t = 0.25
local integer c = 20
loop
exitwhen c <= 0
// call AddSpecialEffectTarget( "war3mapImported\\Great Lightning.mdx", y, "origin" )
set d = CreateUnitAtLoc(GetOwningPlayer(u), 'h011', GetUnitLoc(y), 0.00)
call IssueImmediateOrder(d, "stomp")
call UnitApplyTimedLife(d, 'BTLF', 2.00)
set c = c - 1
call TriggerSleepAction(t)
endloop
set u = null
set y = null
endfunction
//===========================================================================
private function InitTrig_Lightning_Strike takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
This is the Advanced Shockwave Spell by Paladon.
I´ll try to comment my triggering as far as i´m able to.
You may need triggering basics to understand what i´m doing exactly,
but i´m sure that this documentation will be helpful to those who want to
learn some advanced features of GUI triggering.
Thanks for testing this spell.
Paladon
PS:
This spell is created due to a request and uses my Knockback System.
If you need further informations and examples about this system, please search for it in the spell section of //www.hiveworkshop.com
Changelog:
Added the Knockback System readmes and fixed a minor flaw concerning the balance of the spell.
I additionally added some more detailed comments at several places since someone asked me to do so.
I´d be glad if you credit me if you´re using this spell, or the systems it uses, in your very own map.
//TESH.scrollpos=0
//TESH.alwaysfold=0
library WrathOfZeus initializer init requires optional GroupUtils
globals
private constant integer ABILITY_ID = 'A022' //Raw code of the triggering ability
private constant integer DUMMY_ID = 'e00N' //The dummy unit, please import dummy.mdl and make a proper dummy unit
private constant integer STATIC_LINKS = 20 //The links that are created when the orb crashes
private constant integer CHARGED_BOLTS_AMOUNT = 3 //The amount of orbiting missiles that are created around the caster when the ability is learned
private constant real CHARGED_BOLTS_SIZE = .88 //The scale value of the orbiting missiles
private constant real PRIMARY_BASE_DAMAGE = 10000 //The base damage when the orb crashes
private constant real PRIMARY_INC_DAMAGE = 0 // The increment damage of the orb
private constant real SECONDARY_BASE_DAMAGE = 10000 //The damage each static link deals
private constant real SECONDARY_INC_DAMAGE = 0 // The increment damage of each static link
private constant real BOLT_SCALE = 2.75 //The scale of the lightning bolt
private constant real NORMAL_OFFSET = 145 //The default rotating offset of the orbiting bolts
private constant real MAX_OFFSET = 425 //The maximum rotating offset the bolts can reach when overloading
private constant real ENUM_OFFSET = 75 //the range that units are checked from each static link. You should decrease this if you use a LOT of static links!
private constant string BALL_ART = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl" //The missiles that rotate around the cast
private constant string TAIL_LIGHTNING = "CLPB" //The lightning tail of the bolt
private constant string CHARGED_LIGHTNING = "CLSB" //The lightning tail of the secondary static links
private constant string ORBITAL_LIGHTNING = "DRAB" //The lightning that links all the orbital missiles
private constant string BOLT_LIGHTNING = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl" //The lightning bolt art
private constant string PRIMARY_EFFECT = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl" //The effect that is created upon impact
private constant string SECONDARY_EFFECT = "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldBuff.mdl" //The effect that is created on damaged units of secondary effect
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
///
private constant boolean USE_GROUPUTILS = true //Whether to use Group utils library, if the library isn't found, it will CreateGroup() instead
///
endglobals
////===============
globals
private location loc = Location(0, 0)
private location loc2 = Location(0, 0)
private integer instance = 0
private boolexpr BE
private constant group Group = CreateGroup()
private constant integer Cbolts = CHARGED_BOLTS_AMOUNT - 1
private real MINX
private real MINY
private real MAXX
private real MAXY
endglobals
/////=================
//Extra functions
//
private function SafeX takes real x returns real
local real rx=MINX+50
if(x<rx)then
return rx
endif
set rx=MAXX-50
if(x>rx)then
return rx
endif
return x
endfunction
private function SafeY takes real y returns real
local real ry=MINY+50
if(y<ry)then
return ry
endif
set ry=MAXY-50
if(y>ry)then
return ry
endif
return y
endfunction
/////////=======================================
private struct spark
unit u
lightning l
real ang
real sx
real sy
real x
real y
real time = 1.5
real time2 = 2
real dmg
group damaged
static integer tot = 0
static spark array ar
static timer stim = CreateTimer()
static method SecondaryEffects takes unit u, unit t, real x, real y returns nothing
local integer i = 1
local spark data
loop
exitwhen i > STATIC_LINKS
set data = spark.create()
set data.u = u
set data.sx = x
set data.sy = y
set data.x = x
set data.y = y
set data.ang = (360 / STATIC_LINKS) * i
static if USE_GROUPUTILS then
static if LIBRARY_GroupUtils then
set data.damaged = NewGroup()
else
set data.damaged = CreateGroup()
debug call BJDebugMsg(LIBRARY_PREFIX+": Could not find GroupUtils")
endif
else
set data.damaged = CreateGroup()
endif
if t != null then
call GroupAddUnit(data.damaged, t)
endif
set data.dmg = SECONDARY_BASE_DAMAGE + (SECONDARY_INC_DAMAGE * (GetUnitAbilityLevel(data.u, ABILITY_ID) - 1))
set data.l = AddLightning(CHARGED_LIGHTNING, true, x, y, x+5, y+5)
call SetLightningColor(data.l, .7, .7, 1, .7)
if spark.tot == 0 then
call TimerStart(spark.stim, .042, true, function spark.Loop)
endif
set spark.ar[spark.tot] = data
set spark.tot = spark.tot + 1
set i = i + 1
endloop
endmethod
static method Enum takes nothing returns boolean
local spark data = instance
local unit e = GetFilterUnit()
if IsUnitInGroup(e, data.damaged) then
set e = null
return false
else
if (not(IsUnitType(e, UNIT_TYPE_STRUCTURE))) and (GetWidgetLife(e)>.405) and (IsUnitEnemy(e, GetOwningPlayer(data.u))) then
call DestroyEffect(AddSpecialEffectTarget(SECONDARY_EFFECT, e, "origin"))
call UnitDamageTarget(data.u, e, data.dmg, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
call GroupAddUnit(data.damaged, e)
endif
endif
set e = null
return false
endmethod
static method Loop takes nothing returns nothing
local spark data
local integer i = 0
local real p
loop
exitwhen i >= spark.tot
set data = spark.ar[i]
if data.time > 0 then
set data.time = data.time - .042
set data.x = SafeX(data.x + 30 * Cos(data.ang * bj_DEGTORAD))
set data.y = SafeX(data.y + 30 * Sin(data.ang * bj_DEGTORAD))
set p = SquareRoot((data.x - data.sx) * (data.x - data.sx) + (data.y - data.sy) * (data.y - data.sy))
if p > 450 then
set data.sx = data.sx + 30 * Cos(data.ang * bj_DEGTORAD)
set data.sy = data.sy + 30 * Sin(data.ang * bj_DEGTORAD)
endif
set instance = data
call GroupEnumUnitsInRange(Group, data.x, data.y, ENUM_OFFSET, BE)
call MoveLocation(loc, data.sx, data.sy)
call MoveLocation(loc2, data.x, data.y)
call MoveLightningEx(data.l, true, data.sx, data.sy, GetLocationZ(loc), data.x, data.y, GetLocationZ(loc2))
else
if (SquareRoot((data.x - data.sx) * (data.x - data.sx) + (data.y - data.sy) * (data.y - data.sy)) > 50) and data.time2 > 0 then
set data.sx = data.sx + 30 * Cos(data.ang * bj_DEGTORAD)
set data.sy = data.sy + 30 * Sin(data.ang * bj_DEGTORAD)
call MoveLocation(loc, data.sx, data.sy)
call MoveLocation(loc2, data.x, data.y)
call MoveLightningEx(data.l, true, data.sx, data.sy, GetLocationZ(loc), data.x, data.y, GetLocationZ(loc2))
set instance = data
call GroupEnumUnitsInRange(Group, data.sx, data.sy, 125, BE)
set data.time2 = data.time2 - .04
else
call data.destroy()
set spark.tot = spark.tot - 1
set spark.ar[i] = spark.ar[spark.tot]
endif
endif
set i = i + 1
endloop
if spark.tot == 0 then
call PauseTimer(spark.stim)
endif
endmethod
method onDestroy takes nothing returns nothing
call DestroyLightning(.l)
static if USE_GROUPUTILS then
static if LIBRARY_GroupUtils then
call ReleaseGroup(.damaged)
else
call DestroyGroup(.damaged)
debug call BJDebugMsg(LIBRARY_PREFIX+": Could not find GroupUtils")
endif
else
call DestroyGroup(.damaged)
endif
endmethod
endstruct
private struct bolt
unit u
unit t
unit d
real damage
lightning l
effect art
static integer total = 0
static bolt array arr
static timer tim = CreateTimer()
static method create takes unit u, unit t returns bolt
local bolt data = bolt.allocate()
local real x
local real y
local real x2
local real y2
local sound snd
local string array s
local integer r = GetRandomInt(0, 1)
set s[0] = "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldTarget.wav"
set s[1] = "Abilities\\Spells\\Orc\\LightningBolt\\LightningBolt.wav"
set data.u = u
set snd = CreateSound(s[r], false, false, true, 12700, 12700, "")
set x = GetUnitX(data.u) + 100 * Cos(GetUnitFacing(data.u) * bj_DEGTORAD)
set y = GetUnitY(data.u) + 100 * Sin(GetUnitFacing(data.u) * bj_DEGTORAD)
set data.d = CreateUnit(GetOwningPlayer(data.u), DUMMY_ID, x, y, 0)
call AttachSoundToUnit(snd, data.d)
set x2 = GetUnitX(data.d) + 200 * Cos((GetUnitFacing(data.u)-180) * bj_DEGTORAD)
set y2 = GetUnitY(data.d) + 200 * Sin((GetUnitFacing(data.u)-180) * bj_DEGTORAD)
set data.t = t
call UnitAddAbility(data.d, 'Amrf')
call UnitRemoveAbility(data.d, 'Amrf')
call SetUnitFlyHeight(data.d, 90, 550)
call SetUnitTimeScale(data.d, 0)
call SetUnitScale(data.d, BOLT_SCALE, BOLT_SCALE, BOLT_SCALE)
set data.l = AddLightning(TAIL_LIGHTNING, true, x2, y2, x, y)
call StartSound(snd)
call KillSoundWhenDone(snd)
set snd = null
set data.damage = PRIMARY_BASE_DAMAGE + (PRIMARY_INC_DAMAGE * (GetUnitAbilityLevel(data.u, ABILITY_ID)-1))
set data.art = AddSpecialEffectTarget(BOLT_LIGHTNING, data.d, "origin")
if bolt.total == 0 then
call TimerStart(bolt.tim, .0303, true, function bolt.Loop)
endif
set bolt.arr[bolt.total] = data
set bolt.total = bolt.total + 1
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\StormBolt\\StormBoltMissile.mdl", data.u, "weapon,right"))
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl", data.d, "origin"))
return data
endmethod
static method Loop takes nothing returns nothing
local bolt data
local integer i = 0
local real p = 0
local real a=0
local real x=0
local real y=0
local real x2=0
local real y2=0
local real z=0
local real d=0
local real dx=0
local real dy=0
loop
exitwhen i >= bolt.total
set data = bolt.arr[i]
set x = GetUnitX(data.d)
set y = GetUnitY(data.d)
set x2 = GetUnitX(data.t)
set y2 = GetUnitY(data.t)
set a = bj_RADTODEG * Atan2(y2 - y, x2 - x)
call SetUnitFacing(data.d, a)
if IsUnitInRange(data.d, data.t, 50) then
call DestroyEffect(data.art)
call KillUnit(data.d)
call DestroyEffect(AddSpecialEffectTarget(PRIMARY_EFFECT, data.t, "origin"))
call UnitDamageTarget(data.u, data.t, data.damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
call spark.SecondaryEffects(data.u, data.t, x2, y2)
call DestroyLightning(data.l)
set data.d = CreateUnit(Player(12), DUMMY_ID, x2, y2, 0)
call SetUnitScale(data.d, 3.5, 3.5, 3.5)
call SetUnitVertexColor(data.d, 170, 170, 255, 255)
call DestroyEffect(AddSpecialEffectTarget(PRIMARY_EFFECT, data.d, "origin"))
call KillUnit(data.d)
call data.destroy()
set bolt.total = bolt.total - 1
set bolt.arr[i] = bolt.arr[bolt.total]
else
set p = SquareRoot((x - x2) * (x - x2) + (y - y2) * (y - y2))
set d = 17 + (p * .012)
///------------------------------------
set dx = SafeX(x + d * Cos(a * bj_DEGTORAD))
set dy = SafeY(y + d * Sin(a * bj_DEGTORAD))
call SetUnitX(data.d, dx)
call SetUnitY(data.d, dy)
////-----------------------------------
set x = GetUnitX(data.d)
set y = GetUnitY(data.d)
set a = (a-180)
set dx = x + 200 * Cos(a * bj_DEGTORAD)
set dy = y + 200 * Sin(a * bj_DEGTORAD)
call MoveLocation(loc, dx, dy)
call MoveLocation(loc2, x, y)
call MoveLightningEx(data.l, true, dx, dy, (GetLocationZ(loc)+90), x, y, (GetLocationZ(loc2)+GetUnitFlyHeight(data.d)))
endif
set i = i + 1
endloop
if bolt.total == 0 then
call PauseTimer(bolt.tim)
endif
endmethod
endstruct
// Charged bolts //
private struct Charged
unit u
unit array mis[CHARGED_BOLTS_AMOUNT]
real array fh[CHARGED_BOLTS_AMOUNT]
real array fi[CHARGED_BOLTS_AMOUNT]
real array x[CHARGED_BOLTS_AMOUNT]
lightning array l[CHARGED_BOLTS_AMOUNT]
lightning array l2[CHARGED_BOLTS_AMOUNT]
boolean array fb[CHARGED_BOLTS_AMOUNT]
effect array fx[CHARGED_BOLTS_AMOUNT]
boolean dead = false //If the flag is turned on, the charged bolts dissapear until the hero is alive again
real tick = 0
real xtick = .94 //Defines the duration of the lightning rotation
real rat = SquareRoot(NORMAL_OFFSET) / bj_PI
real limit = NORMAL_OFFSET
boolean charged = false
static thistype array arr
static integer total = 0
static timer tim = CreateTimer()
////
private static string str1 = "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldBuff.mdl"
////
static method create takes unit u returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local trigger t = CreateTrigger()
local real x
local real y
local real cx = GetUnitX(u)
local real cy = GetUnitY(u)
set this.u = u
loop
exitwhen i > Cbolts
set this.mis[i] = CreateUnit(GetOwningPlayer(u), 'e00N', GetUnitX(u), GetUnitY(u), 0)
set this.fx[i] = AddSpecialEffectTarget(BALL_ART , this.mis[i], "origin")
set x = cx + 60 * Cos(( (360 / (Cbolts+1)) * (i+1) ) * bj_DEGTORAD)
set y = cy + 60 * Sin(( (360 / (Cbolts+1)) * (i+1) ) * bj_DEGTORAD)
call SetUnitX(this.mis[i], x)
call SetUnitY(this.mis[i], y)
call UnitAddAbility(this.mis[i], 'Amrf')
call SetUnitTimeScale(this.mis[i], 0)
call UnitRemoveAbility(this.mis[i], 'Amrf')
set this.fh[i] = 30 * i
call SetUnitFlyHeight(this.mis[i], this.fh[i], 0)
call SetUnitScale(this.mis[i], CHARGED_BOLTS_SIZE, CHARGED_BOLTS_SIZE, CHARGED_BOLTS_SIZE)
set this.fb[i] = true
set this.x[i] = bj_RADTODEG * Atan2(y - cy, x - cx)
set i = i + 1
endloop
call TriggerAddCondition(t, Condition(function Charged.ready))
call TriggerRegisterUnitEvent(t, u, EVENT_UNIT_SPELL_CAST)
if thistype.total == 0 then
call TimerStart(thistype.tim, .047, true, function Charged.fly)
endif
set thistype.total = thistype.total + 1
set thistype.arr[thistype.total - 1] = this
return this
endmethod
static method ready takes nothing returns boolean
local thistype this
local integer i = 0
local integer k = 0
local sound snd
if GetSpellAbilityId()!= ABILITY_ID then
return false
else
set this = thistype.GetInstance(GetTriggerUnit())
if this.charged then
return false
endif
set snd = CreateSound("Units\\Orc\\StasisTotem\\StasisTotem.wav", false, false, true, 12700, 12700, "")
call AttachSoundToUnit(snd, GetTriggerUnit())
set this.charged = true
set this.xtick = .8
set this.rat = this.rat + SquareRoot(MAX_OFFSET)
set this.limit = MAX_OFFSET
call StartSound(snd)
call KillSoundWhenDone(snd)
set snd = null
loop
exitwhen i>Cbolts
set k = i + 1
if k > Cbolts then
set k = 0
endif
set this.l[i] = AddLightning(CHARGED_LIGHTNING, true, GetUnitX(this.mis[i]), GetUnitY(this.mis[i]), GetUnitX(this.u), GetUnitY(this.u))
call SetLightningColor(this.l[i], 1, 1, 1, .6)
set this.l2[i] = AddLightning(ORBITAL_LIGHTNING, true, GetUnitX(this.mis[i]), GetUnitY(this.mis[i]), GetUnitX(this.mis[k]), GetUnitY(this.mis[k]))
call SetLightningColor(this.l2[i], .3, .1, 1, 1)
set i = i + 1
endloop
endif
return false
endmethod
static method GetInstance takes unit u returns integer
local thistype this
local integer i = 0
loop
exitwhen i >= thistype.total
set this = thistype.arr[i]
if IsUnit(u, this.u) then
return this
endif
set i = i + 1
endloop
return 0
endmethod
static method fly takes nothing returns nothing
local thistype this
local integer i = 0
local integer k = 0
local real x =0
local real y =0
local real cx
local real cy
local integer j = 0
loop
exitwhen i >= thistype.total
set this = thistype.arr[i]
set k = 0
set j = 0
set cx = GetUnitX(this.u)
set cy = GetUnitY(this.u)
loop
exitwhen k > Cbolts
set j = k + 1
if j > Cbolts then
set j = 0
endif
if (not(this.dead)) and this.mis[k] != null then
if this.fb[k] then
set this.fh[k] = this.fh[k] + 3
else
set this.fh[k] = this.fh[k] - 3
endif
if GetUnitFlyHeight(this.mis[k])<50 then
set this.fb[k] = true
elseif GetUnitFlyHeight(this.mis[k]) > 275 then
set this.fb[k] = false
endif
set this.tick = this.tick + .047
call SetUnitFlyHeight(this.mis[k], this.fh[k], 530)
set this.x[k] = this.x[k] + 4
if this.rat < this.limit then
set this.rat = this.rat + 2
elseif this.rat > this.limit then
set this.rat = this.rat - .5
endif
set x = cx + this.rat * Cos(this.x[k] * bj_DEGTORAD)
set y = cy + this.rat * Sin(this.x[k] * bj_DEGTORAD)
call SetUnitX(this.mis[k], x)
call SetUnitY(this.mis[k], y)
if this.charged then
if this.xtick > 0 then
set this.x[k] = this.x[k] + 6
call MoveLocation(loc, x, y)
call MoveLocation(loc2, GetUnitX(this.u), GetUnitY(this.u))
call MoveLightningEx(this.l[k], true, x, y, (GetLocationZ(loc)+GetUnitFlyHeight(this.mis[k])), cx, cy, (GetLocationZ(loc2)+GetUnitFlyHeight(this.u)+20))
call MoveLocation(loc2, GetUnitX(this.mis[j]), GetUnitY(this.mis[j]))
call MoveLightningEx(this.l2[k], true, x, y, (GetLocationZ(loc)+GetUnitFlyHeight(this.mis[k])), GetUnitX(this.mis[j]), GetUnitY(this.mis[j]), (GetLocationZ(loc2)+GetUnitFlyHeight(this.mis[j])))
else
call DestroyLightning(this.l[k])
call DestroyLightning(this.l2[k])
endif
endif
if this.tick > 1.75 then
set this.tick = 0
call DestroyEffect(AddSpecialEffectTarget(thistype.str1 , this.mis[k], "origin"))
endif
endif
set k = k + 1
endloop
if this.charged then
if this.xtick > 0 then
set this.xtick = this.xtick - .05
else
set this.charged = false
set this.limit = NORMAL_OFFSET
endif
endif
if GetWidgetLife(this.u)<.405 then
call this.hide()
set this.dead = true
elseif GetWidgetLife(this.u)>=.405 and this.dead then
set this.dead = false
call this.show()
endif
set i = i + 1
endloop
endmethod
method hide takes nothing returns nothing
local integer i = 0
loop
exitwhen i > Cbolts
if .mis[i] != null then
//call UnitRemoveAbility(.mis[i], 'Aloc')
call ShowUnit(.mis[i], false)
endif
set i = i + 1
endloop
endmethod
method show takes nothing returns nothing
local integer i = 0
loop
exitwhen i > Cbolts
if .mis[i] != null then
call ShowUnit(.mis[i], true)
call UnitAddAbility(.mis[i], 'Aloc')
endif
set i = i + 1
endloop
endmethod
endstruct
///////===================\\\\\\\
private function BoltStart takes nothing returns nothing
call bolt.create(GetTriggerUnit(), GetSpellTargetUnit())
endfunction
private function IsBolt takes nothing returns boolean
return GetSpellAbilityId() == ABILITY_ID
endfunction
private function BoltCharge takes nothing returns boolean
if GetLearnedSkill() == ABILITY_ID then
if GetUnitAbilityLevel(GetTriggerUnit(), ABILITY_ID)<2 then
call Charged.create(GetTriggerUnit())
endif
endif
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger ( )
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function IsBolt))
call TriggerAddAction(t, function BoltStart)
set t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
call TriggerAddCondition(t, Condition(function BoltCharge))
set t = null
set BE = Condition(function spark.Enum)
set MINX = GetRectMinX(bj_mapInitialPlayableArea)
set MINY = GetRectMinY(bj_mapInitialPlayableArea)
set MAXX = GetRectMaxX(bj_mapInitialPlayableArea)
set MAXY = GetRectMaxY(bj_mapInitialPlayableArea)
endfunction
endlibrary