//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
Aleatoire | integer | No | |
Alpha | force | No | |
Angle | real | No | |
armeselect | integer | Yes | |
att | unit | Yes | |
blabla | dialog | No | |
blabla_Copier | button | Yes | |
BootsType | integer | Yes | |
buff | effect | No | |
cameradead | integer | Yes | 1 |
cameratype | integer | Yes | 1 |
car | unit | No | |
card | unit | No | |
cardor | unit | No | |
Charge | integer | Yes | |
cheat | integer | No | |
Circle | real | No | |
Config | integer | Yes | |
Debug | integervar | No | |
dialogue | dialog | No | |
distancage | real | Yes | |
distance | real | No | |
DS_BallCreationInterval | integer | Yes | |
DS_BallDamages | real | Yes | |
DS_BallDamagesAoe | real | Yes | |
DS_BallDamagesType | attacktype | No | |
DS_BallDamagesTypes2 | damagetype | No | |
DS_BallDirectionAndSpeed | real | Yes | |
DS_BallHeightIncrease | real | Yes | |
DS_BallLifeSteal | real | Yes | |
DS_BallLiveTime | real | Yes | |
DS_BallLocation | location | No | |
DS_BallLocationNew | location | No | |
DS_BallsGroup | group | No | |
DS_CasterLocation | location | No | |
DS_CastersGroup | group | No | |
DS_CircleAoe | real | Yes | |
DS_CircleDirectionAndSpeed | real | Yes | |
DS_CircleStartAngle | real | Yes | |
DS_Duration | real | Yes | |
DS_Effect | string | No | |
DS_Hashtable | hashtable | No | |
DS_NumberOfCircle | integer | Yes | |
DS_TempInteger | integer | No | |
DS_TempInteger2 | integer | No | |
DS_TempReal | real | No | |
DS_TempUnit | unit | No | |
DS_TempUnit2 | unit | No | |
emplacement | location | No | |
Engish | force | No | |
Etage | player | No | |
F_Integers | integer | Yes | |
F_ReachedFading | real | Yes | |
F_Time | real | Yes | |
F_Unit | unit | Yes | |
FA_Time | real | No | |
FA_Unit | unit | No | |
fin | boolean | Yes | |
FP_Point | location | No | |
French | force | No | |
fuir | button | Yes | |
fuyard | force | No | |
fuyardnavire | force | No | |
G | integervar | No | |
G_Angle | real | Yes | |
G_AoeFinal | real | Yes | |
G_AoeSelect | real | Yes | |
G_Caster | unit | Yes | |
G_Damage | real | Yes | |
G_Distance | real | Yes | |
G_Dummy | unit | Yes | |
G_ExGroup | group | Yes | |
G_Fly | integer | Yes | |
G_Group | group | Yes | |
G_Height | real | Yes | |
G_Level | integer | Yes | |
G_Off | boolean | Yes | |
G_Point | location | Yes | |
G_Skip | integer | No | |
G_Speed | real | Yes | |
G_Times | integer | No | |
Ghost | unit | No | |
GhostAppear | unit | Yes | |
ghostcall | integer | No | |
Groupe | force | No | |
h_Bolean | boolean | No | |
h_Bolean2 | boolean | No | |
h_Caster | unit | No | |
h_hook | unit | Yes | |
h_Number | integer | No | |
integer | integer | No | |
intro | string | Yes | |
isPlayingGroup | group | No | |
JD_Angle | real | Yes | |
JD_Animations | string | Yes | |
JD_Counter | real | Yes | |
JD_Distances | real | Yes | |
JD_Effect | string | Yes | |
JD_Group | group | No | |
JD_HighSettings | real | Yes | |
JD_Integers | integer | Yes | |
JD_JumpHigh | real | Yes | |
JD_LevelOfAbility | integer | Yes | |
JD_PickGroup | group | No | |
JD_ReachedDistance | real | Yes | |
JD_RealTimer | real | Yes | |
JD_SpeedUnits | real | Yes | |
JD_TempPoint | location | Yes | |
JD_TreesDestroy | boolean | Yes | |
JD_Unit | unit | Yes | |
JDA_Animation | string | No | |
JDA_AnimationSpeed | real | No | |
JDA_Collusion | boolean | No | |
JDA_DestroyTrees_Dash | boolean | No | |
JDA_JumpHigh_Distance | real | No | |
JDA_LevelOfAbility | integer | No | |
JDA_SpecialEffect | string | No | |
JDA_Speed | real | No | |
JDA_TargetPoint | location | No | |
JDA_Unit | unit | No | |
joueur_radio | force | No | |
JoueurDansMultitable | integer | Yes | |
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 | |
key | unit | No | |
key_item | item | No | |
killer | unit | Yes | |
Kills | integer | Yes | |
langue | dialog | No | |
LF_lastCreatedSound | sound | No | |
LF_x_channel | integer | No | |
LF_x_duration | integer | No | |
LF_x_eaxSetting | string | No | |
LF_x_fadeInRate | integer | No | |
LF_x_fadeOutRate | integer | No | |
LF_x_is3D | boolean | No | |
LF_x_looping | boolean | No | |
LF_x_Path | string | No | |
LF_x_pitch | real | No | |
LF_x_stopwhenoutofrange | boolean | No | |
LF_x_volume | integer | No | |
Life | integer | Yes | 3 |
LimiteDecoupeur | integer | Yes | |
LimitePanneau | integer | Yes | |
Lock | integer | No | |
LoopingInteger | integervar | No | |
Magnetic_Saw_Hash | hashtable | No | |
Magnetised_Group | group | No | |
Mana | real | No | |
message | texttag | Yes | |
Multiboard | multiboard | No | |
navire | integer | No | |
nom_joueur | string | Yes | |
Nuit | boolean | No | |
number | integer | No | |
numberage | integer | No | |
objet | itemcode | Yes | |
p | player | No | |
PD_Angle | real | Yes | |
PD_Distances | real | Yes | |
PD_Integers | integer | Yes | |
PD_ReachedDistance | real | Yes | |
PD_RealTimer | real | Yes | |
PD_SpeedUnits | real | Yes | |
PD_TempPoint | location | Yes | |
PD_TestGroup | group | No | |
PD_TreesDestroy | boolean | Yes | |
PD_Unit | unit | Yes | |
pla | player | No | |
PlayerDead | force | No | |
PlayerGroup | force | No | |
PlayerIn | force | No | |
PlayerUnit | unit | Yes | |
popo | boolean | No | |
position | location | Yes | |
putride | unit | Yes | |
pyramid | unit | No | |
RadioHerz | integer | Yes | |
randomsound | integer | No | |
Region | rect | Yes | |
ReviveRegion | rect | No | |
Saw_Creation | integer | No | |
Saws | group | No | |
SB_Angle | real | Yes | |
SB_AOE | real | Yes | |
SB_Caster | unit | No | |
SB_Casters | unit | Yes | |
SB_ConvertedDamage | real | Yes | |
SB_CountIntegers | integer | Yes | |
SB_Damage | real | No | |
SB_DestroyTrees | boolean | No | |
SB_Distances | real | Yes | |
SB_DmgAOE | real | No | |
SB_Group | group | No | |
SB_HighSettings | real | Yes | |
SB_Integers | integer | Yes | |
SB_JumpHigh | real | Yes | |
SB_Points | location | Yes | |
SB_ReachedDistance | real | Yes | |
SB_Reals | real | No | |
SB_RealTimer | real | Yes | |
SB_SpeedIncreasement | real | No | |
SB_SpeedUnits | real | Yes | |
SB_TempPoint | location | Yes | |
SB_TotalUnitGroup | group | No | |
SB_TreesDestroy | boolean | Yes | |
SB_Unit | unit | Yes | |
SBA_Integers | integer | No | |
SBA_JumpHigh_Distance | real | No | |
SBA_Speed | real | No | |
SBA_TargetPoint | location | No | |
SBA_Unit | unit | No | |
Scaretype | integer | No | |
SE_AttackType | attacktype | No | |
SE_DamageType | damagetype | No | |
SE_ExplosionDamages | real | Yes | |
SE_ExplosionDamagesAoe | real | Yes | |
SE_ExplosionModel | string | No | |
SE_Hash | hashtable | No | |
SE_Integer | integer | No | |
SE_Integer2 | integer | No | |
SE_Integer3 | integer | No | |
SE_Integer4 | integer | No | |
SE_Point | location | No | |
SE_Point2 | location | No | |
SE_Real | real | No | |
SE_Real2 | real | No | |
SE_Real3 | real | No | |
SE_RockGroup | group | No | |
SE_RockHeightDecrement | real | Yes | |
SE_RockHeightSpeed | real | Yes | |
SE_RocksAngle | real | Yes | |
SE_RocksAngleRandom | real | Yes | |
SE_RockScaleMax | real | Yes | |
SE_RockScaleMin | real | Yes | |
SE_RocksDamages | real | Yes | |
SE_RocksDamagesAoe | real | Yes | |
SE_RocksIntervalAngle | real | Yes | |
SE_RocksNumber | integer | Yes | |
SE_RockSpeed | real | Yes | |
SE_RocksUnitType | unitcode | No | |
SE_SandInterval | integer | Yes | |
SE_SandModel | string | No | |
SE_SandSpeed | real | Yes | |
SE_SandUnitType | unitcode | No | |
SE_Unit | unit | No | |
SE_Unit2 | unit | No | |
SE_WaveGroup | group | No | |
Shade | unit | No | |
ShadeTarget | unit | No | |
ShieldType | integer | Yes | |
Shockwave_Angle | real | No | |
Shockwave_Group | group | Yes | |
Shockwave_Point | location | Yes | |
Skill | integer | Yes | |
Sound | sound | No | |
Speed | integer | No | |
Start | boolean | No | |
target | unit | Yes | |
Temp_Group | group | Yes | |
Temp_Point | location | Yes | |
Temp_Unit | handle | No | |
TempAngle | real | No | |
TempGroup | group | No | |
TempPoint | location | No | |
TempPoint2 | location | No | |
temps | weathereffect | Yes | |
TempTarget | unit | No | |
TempX | real | No | |
TempY | real | No | |
titi | player | No | |
TK_AttackType | attacktype | No | |
TK_DamageType | damagetype | No | |
TK_FlyingUnits | group | No | |
TK_FSpeed | real | Yes | |
TK_HDmgInPercIncreasement | real | No | |
TK_HDmgInPercStart | real | No | |
TK_Hero | unit | Yes | |
TK_ImpactDmgIncreasement | real | No | |
TK_ImpactDmgStart | real | No | |
TK_ImpactSFX | string | No | |
TK_Integers | integer | Yes | |
TK_Interval | real | Yes | |
TK_Level | integer | Yes | |
TK_LiftSFX | string | No | |
TK_LiftSFXTimer | real | No | |
TK_LsfxT | real | Yes | |
TK_MaxHeight | real | Yes | |
TK_MaxHeightIncreasement | real | No | |
TK_MaxHeightStart | real | No | |
TK_MinHeightIncreasement | real | No | |
TK_MinHeightStart | real | No | |
TK_Pause | boolean | No | |
TK_Speed | real | No | |
TK_SpeedVariationPerc | real | No | |
TK_SpellAoEIncreasement | real | No | |
TK_SpellAoEStart | real | No | |
TK_StartSFX | string | No | |
TK_TempPoint | location | Yes | |
TK_Unit | unit | Yes | |
TK_UnitGroup | group | No | |
Trap | player | No | |
true_navire | unit | No | |
tueur | player | No | |
UC_Counter | integer | Yes | |
UC_Groups | group | Yes | |
UC_Inv | boolean | Yes | |
UC_SETTINGS_AreaOfEffect | real | Yes | |
UC_SETTINGS_Collosion | boolean | No | |
UC_SETTINGS_DestroyTrees_Dash | boolean | No | |
UC_SETTINGS_Invulnerable | boolean | No | |
UC_SETTINGS_Speed | real | No | |
UC_Target | unit | No | |
UC_TempPoint | location | Yes | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UMovNext | integer | Yes | |
UMovPrev | integer | Yes | |
unitage | unit | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitMoving | boolean | Yes | |
UnitMovingEvent | real | No | |
UnitMovingX | real | Yes | |
UnitMovingY | real | Yes | |
Vie | real | No | |
vitesse | real | Yes | |
YourSounds | sound | Yes |
function Trig_At_0s_Actions takes nothing returns nothing
call BlzLoadTOCFile( "war3mapimported\\myconsoleUI.toc" )
call BlzCreateSimpleFrame( "MyConsoleUIHuman", BlzGetFrameByName("ConsoleUI", 0), 0 )
call BlzCreateSimpleFrame( "MyConsoleUIOrc", BlzGetFrameByName("ConsoleUI", 0), 0 )
call BlzCreateSimpleFrame( "MyConsoleUIUndead", BlzGetFrameByName("ConsoleUI", 0), 0 )
call BlzCreateSimpleFrame( "MyConsoleUINightelf", BlzGetFrameByName("ConsoleUI", 0), 0 )
call BlzFrameSetVisible( BlzGetFrameByName("MyConsoleUIUndead", 0), false )
call BlzFrameSetVisible( BlzGetFrameByName("MyConsoleUINightelf", 0), false )
call BlzFrameSetVisible( BlzGetFrameByName("MyConsoleUIOrc", 0), false )
call BlzFrameSetVisible( BlzGetFrameByName("MyConsoleUIHuman", 0), false )
call BlzFrameSetLevel( BlzGetFrameByName("ResourceBarFrame", 0), 3 )
endfunction
//===========================================================================
function InitTrig_At_0s takes nothing returns nothing
set gg_trg_At_0s = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_At_0s, 0.00 )
call TriggerAddAction( gg_trg_At_0s, function Trig_At_0s_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_GoldBag_Actions takes nothing returns nothing
local integer MAX_CHARGES = 10
local unit u = GetTriggerUnit()
local item picked_item = GetManipulatedItem()
local item slot_item = null
local integer picked_item_id = GetItemTypeId(picked_item)
local integer charges_source = GetItemCharges(picked_item)
local integer charges_target = 0
local integer i = 0
if(picked_item_id=='pres')then
loop
exitwhen i > 5 or charges_source <= 0
set slot_item = UnitItemInSlot(u,i)
set charges_target = GetItemCharges(slot_item)
if (slot_item!=picked_item) and (GetItemTypeId(slot_item)==picked_item_id) and (charges_target<MAX_CHARGES) then
if(charges_target+charges_source>MAX_CHARGES)then
call SetItemCharges(slot_item,MAX_CHARGES)
set charges_source = charges_source-(MAX_CHARGES-charges_target)
else
call SetItemCharges(slot_item,charges_target+charges_source)
set charges_source = 0
endif
endif
set i = i + 1
endloop
if charges_source == 0 then
call RemoveItem(picked_item)
else
call SetItemCharges(picked_item,charges_source)
endif
endif
set picked_item = null
set u = null
set slot_item = null
endfunction
//===========================================================================
function InitTrig_GoldBag takes nothing returns nothing
set gg_trg_GoldBag = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_GoldBag, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_GoldBag, function Trig_GoldBag_Actions )
endfunction
//TESH.scrollpos=9
//TESH.alwaysfold=0
function Trig_GoldBag_Copier_8_Actions takes nothing returns nothing
local integer MAX_CHARGES = 10
local unit u = GetTriggerUnit()
local item picked_item = GetManipulatedItem()
local item slot_item = null
local integer picked_item_id = GetItemTypeId(picked_item)
local integer charges_source = GetItemCharges(picked_item)
local integer charges_target = 0
local integer i = 0
if(picked_item_id=='I00G')then
loop
exitwhen i > 5 or charges_source <= 0
set slot_item = UnitItemInSlot(u,i)
set charges_target = GetItemCharges(slot_item)
if (slot_item!=picked_item) and (GetItemTypeId(slot_item)==picked_item_id) and (charges_target<MAX_CHARGES) then
if(charges_target+charges_source>MAX_CHARGES)then
call SetItemCharges(slot_item,MAX_CHARGES)
set charges_source = charges_source-(MAX_CHARGES-charges_target)
else
call SetItemCharges(slot_item,charges_target+charges_source)
set charges_source = 0
endif
endif
set i = i + 1
endloop
if charges_source == 0 then
call RemoveItem(picked_item)
else
call SetItemCharges(picked_item,charges_source)
endif
endif
set picked_item = null
set u = null
set slot_item = null
endfunction
//===========================================================================
function InitTrig_GoldBag_Copier_8 takes nothing returns nothing
set gg_trg_GoldBag_Copier_8 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_GoldBag_Copier_8, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_GoldBag_Copier_8, function Trig_GoldBag_Copier_8_Actions )
endfunction
//TESH.scrollpos=9
//TESH.alwaysfold=0
function Trig_GoldBag_Copier_7_Actions takes nothing returns nothing
local integer MAX_CHARGES = 10
local unit u = GetTriggerUnit()
local item picked_item = GetManipulatedItem()
local item slot_item = null
local integer picked_item_id = GetItemTypeId(picked_item)
local integer charges_source = GetItemCharges(picked_item)
local integer charges_target = 0
local integer i = 0
if(picked_item_id=='I00F')then
loop
exitwhen i > 5 or charges_source <= 0
set slot_item = UnitItemInSlot(u,i)
set charges_target = GetItemCharges(slot_item)
if (slot_item!=picked_item) and (GetItemTypeId(slot_item)==picked_item_id) and (charges_target<MAX_CHARGES) then
if(charges_target+charges_source>MAX_CHARGES)then
call SetItemCharges(slot_item,MAX_CHARGES)
set charges_source = charges_source-(MAX_CHARGES-charges_target)
else
call SetItemCharges(slot_item,charges_target+charges_source)
set charges_source = 0
endif
endif
set i = i + 1
endloop
if charges_source == 0 then
call RemoveItem(picked_item)
else
call SetItemCharges(picked_item,charges_source)
endif
endif
set picked_item = null
set u = null
set slot_item = null
endfunction
//===========================================================================
function InitTrig_GoldBag_Copier_7 takes nothing returns nothing
set gg_trg_GoldBag_Copier_7 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_GoldBag_Copier_7, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_GoldBag_Copier_7, function Trig_GoldBag_Copier_7_Actions )
endfunction
//TESH.scrollpos=9
//TESH.alwaysfold=0
function Trig_GoldBag_Copier_6_Actions takes nothing returns nothing
local integer MAX_CHARGES = 10
local unit u = GetTriggerUnit()
local item picked_item = GetManipulatedItem()
local item slot_item = null
local integer picked_item_id = GetItemTypeId(picked_item)
local integer charges_source = GetItemCharges(picked_item)
local integer charges_target = 0
local integer i = 0
if(picked_item_id=='I000')then
loop
exitwhen i > 5 or charges_source <= 0
set slot_item = UnitItemInSlot(u,i)
set charges_target = GetItemCharges(slot_item)
if (slot_item!=picked_item) and (GetItemTypeId(slot_item)==picked_item_id) and (charges_target<MAX_CHARGES) then
if(charges_target+charges_source>MAX_CHARGES)then
call SetItemCharges(slot_item,MAX_CHARGES)
set charges_source = charges_source-(MAX_CHARGES-charges_target)
else
call SetItemCharges(slot_item,charges_target+charges_source)
set charges_source = 0
endif
endif
set i = i + 1
endloop
if charges_source == 0 then
call RemoveItem(picked_item)
else
call SetItemCharges(picked_item,charges_source)
endif
endif
set picked_item = null
set u = null
set slot_item = null
endfunction
//===========================================================================
function InitTrig_GoldBag_Copier_6 takes nothing returns nothing
set gg_trg_GoldBag_Copier_6 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_GoldBag_Copier_6, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_GoldBag_Copier_6, function Trig_GoldBag_Copier_6_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_GoldBag_Copier_5_Actions takes nothing returns nothing
local integer MAX_CHARGES = 10
local unit u = GetTriggerUnit()
local item picked_item = GetManipulatedItem()
local item slot_item = null
local integer picked_item_id = GetItemTypeId(picked_item)
local integer charges_source = GetItemCharges(picked_item)
local integer charges_target = 0
local integer i = 0
if(picked_item_id=='I00C')then
loop
exitwhen i > 5 or charges_source <= 0
set slot_item = UnitItemInSlot(u,i)
set charges_target = GetItemCharges(slot_item)
if (slot_item!=picked_item) and (GetItemTypeId(slot_item)==picked_item_id) and (charges_target<MAX_CHARGES) then
if(charges_target+charges_source>MAX_CHARGES)then
call SetItemCharges(slot_item,MAX_CHARGES)
set charges_source = charges_source-(MAX_CHARGES-charges_target)
else
call SetItemCharges(slot_item,charges_target+charges_source)
set charges_source = 0
endif
endif
set i = i + 1
endloop
if charges_source == 0 then
call RemoveItem(picked_item)
else
call SetItemCharges(picked_item,charges_source)
endif
endif
set picked_item = null
set u = null
set slot_item = null
endfunction
//===========================================================================
function InitTrig_GoldBag_Copier_5 takes nothing returns nothing
set gg_trg_GoldBag_Copier_5 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_GoldBag_Copier_5, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_GoldBag_Copier_5, function Trig_GoldBag_Copier_5_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_GoldBag_Copier_4_Actions takes nothing returns nothing
local integer MAX_CHARGES = 20
local unit u = GetTriggerUnit()
local item picked_item = GetManipulatedItem()
local item slot_item = null
local integer picked_item_id = GetItemTypeId(picked_item)
local integer charges_source = GetItemCharges(picked_item)
local integer charges_target = 0
local integer i = 0
if(picked_item_id=='I00K')then
loop
exitwhen i > 5 or charges_source <= 0
set slot_item = UnitItemInSlot(u,i)
set charges_target = GetItemCharges(slot_item)
if (slot_item!=picked_item) and (GetItemTypeId(slot_item)==picked_item_id) and (charges_target<MAX_CHARGES) then
if(charges_target+charges_source>MAX_CHARGES)then
call SetItemCharges(slot_item,MAX_CHARGES)
set charges_source = charges_source-(MAX_CHARGES-charges_target)
else
call SetItemCharges(slot_item,charges_target+charges_source)
set charges_source = 0
endif
endif
set i = i + 1
endloop
if charges_source == 0 then
call RemoveItem(picked_item)
else
call SetItemCharges(picked_item,charges_source)
endif
endif
set picked_item = null
set u = null
set slot_item = null
endfunction
//===========================================================================
function InitTrig_GoldBag_Copier_4 takes nothing returns nothing
set gg_trg_GoldBag_Copier_4 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_GoldBag_Copier_4, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_GoldBag_Copier_4, function Trig_GoldBag_Copier_4_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_GoldBag_Copier_3_Actions takes nothing returns nothing
local integer MAX_CHARGES = 10
local unit u = GetTriggerUnit()
local item picked_item = GetManipulatedItem()
local item slot_item = null
local integer picked_item_id = GetItemTypeId(picked_item)
local integer charges_source = GetItemCharges(picked_item)
local integer charges_target = 0
local integer i = 0
if(picked_item_id=='I006')then
loop
exitwhen i > 5 or charges_source <= 0
set slot_item = UnitItemInSlot(u,i)
set charges_target = GetItemCharges(slot_item)
if (slot_item!=picked_item) and (GetItemTypeId(slot_item)==picked_item_id) and (charges_target<MAX_CHARGES) then
if(charges_target+charges_source>MAX_CHARGES)then
call SetItemCharges(slot_item,MAX_CHARGES)
set charges_source = charges_source-(MAX_CHARGES-charges_target)
else
call SetItemCharges(slot_item,charges_target+charges_source)
set charges_source = 0
endif
endif
set i = i + 1
endloop
if charges_source == 0 then
call RemoveItem(picked_item)
else
call SetItemCharges(picked_item,charges_source)
endif
endif
set picked_item = null
set u = null
set slot_item = null
endfunction
//===========================================================================
function InitTrig_GoldBag_Copier_3 takes nothing returns nothing
set gg_trg_GoldBag_Copier_3 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_GoldBag_Copier_3, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_GoldBag_Copier_3, function Trig_GoldBag_Copier_3_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_GoldBag_Copier_2_Actions takes nothing returns nothing
local integer MAX_CHARGES = 10
local unit u = GetTriggerUnit()
local item picked_item = GetManipulatedItem()
local item slot_item = null
local integer picked_item_id = GetItemTypeId(picked_item)
local integer charges_source = GetItemCharges(picked_item)
local integer charges_target = 0
local integer i = 0
if(picked_item_id=='phea')then
loop
exitwhen i > 5 or charges_source <= 0
set slot_item = UnitItemInSlot(u,i)
set charges_target = GetItemCharges(slot_item)
if (slot_item!=picked_item) and (GetItemTypeId(slot_item)==picked_item_id) and (charges_target<MAX_CHARGES) then
if(charges_target+charges_source>MAX_CHARGES)then
call SetItemCharges(slot_item,MAX_CHARGES)
set charges_source = charges_source-(MAX_CHARGES-charges_target)
else
call SetItemCharges(slot_item,charges_target+charges_source)
set charges_source = 0
endif
endif
set i = i + 1
endloop
if charges_source == 0 then
call RemoveItem(picked_item)
else
call SetItemCharges(picked_item,charges_source)
endif
endif
set picked_item = null
set u = null
set slot_item = null
endfunction
//===========================================================================
function InitTrig_GoldBag_Copier_2 takes nothing returns nothing
set gg_trg_GoldBag_Copier_2 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_GoldBag_Copier_2, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_GoldBag_Copier_2, function Trig_GoldBag_Copier_2_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_GoldBag_Copier_Actions takes nothing returns nothing
local integer MAX_CHARGES = 10
local unit u = GetTriggerUnit()
local item picked_item = GetManipulatedItem()
local item slot_item = null
local integer picked_item_id = GetItemTypeId(picked_item)
local integer charges_source = GetItemCharges(picked_item)
local integer charges_target = 0
local integer i = 0
if(picked_item_id=='pghe')then
loop
exitwhen i > 5 or charges_source <= 0
set slot_item = UnitItemInSlot(u,i)
set charges_target = GetItemCharges(slot_item)
if (slot_item!=picked_item) and (GetItemTypeId(slot_item)==picked_item_id) and (charges_target<MAX_CHARGES) then
if(charges_target+charges_source>MAX_CHARGES)then
call SetItemCharges(slot_item,MAX_CHARGES)
set charges_source = charges_source-(MAX_CHARGES-charges_target)
else
call SetItemCharges(slot_item,charges_target+charges_source)
set charges_source = 0
endif
endif
set i = i + 1
endloop
if charges_source == 0 then
call RemoveItem(picked_item)
else
call SetItemCharges(picked_item,charges_source)
endif
endif
set picked_item = null
set u = null
set slot_item = null
endfunction
//===========================================================================
function InitTrig_GoldBag_Copier takes nothing returns nothing
set gg_trg_GoldBag_Copier = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_GoldBag_Copier, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_GoldBag_Copier, function Trig_GoldBag_Copier_Actions )
endfunction
//TESH.scrollpos=142
//TESH.alwaysfold=0
scope DemonicPentagram initializer DemonicPentagramInit
globals
// ___ _ ___ _
// | \ ___ _ __ ___ _ _ (_)__ | _ \___ _ _| |_ __ _ __ _ _ _ __ _ _ __
// | |) / -_) ' \/ _ \ ' \| / _| | _/ -_) ' \ _/ _` / _` | '_/ _` | ' \
// |___/\___|_|_|_\___/_||_|_\__| |_| \___|_||_\__\__,_\__, |_| \__,_|_|_|_|
// |___/
// Made by "esdo" ( HiveWorkshop.com ) v 1.1a
//
// AUTHOR'S NOTE:
// My first vJass spell uploaded on hive... Hope you guys enjoy this efficient,
// leakless spell... Please give me credit if you ever use this!!!
// AUTHOR'S NOTE END
//
// DESCRIPTION:
// Curses an area, slowing and disabling all enemies inside, preventing spellcasting
// and any kind of attack. A pentagram is slowly drawn inside the area and, once its
// complete, the whole area will violently explode, dealing damage based on the caster's
// selected stat.
// DESCRIPTION END
//
// CREDITS:
// - Me, "esdo", for creating this spell.
// - "Deathismyfriend" and many other members of the Hive, that helped me learn Jass
// and fix my code.
// CREDITS END
//
// CONFIGURATION:
// "Size" defines the radius of the cursed area. Remember to change the radius effect
// to match this one in the "Pentagram [Effect 1]" spell!
private constant real SIZE = 700
//
// "ATTRIBUTE_USED" defines the used attribute for damage. You should edit only the latter
// part of the var, that is, the "_" and the last three letters. Use _STR for strenght,
// _AGI for agility and _INT for intelligence.
private constant integer ATTRIBUTE_USED = bj_HEROSTAT_STR
//
endglobals
//
// This function allows the user to configure it's own desired spell damage. It takes
// the hero's attribute and skill level as parameters.
private function GetDamageDealt takes real attribute, real level returns real
return attribute * level + 0 // <== This will be the damage done.
endfunction
globals
//
// "ATTACK_TYPE" defines the type of the attack dealt when the pentagram explodes.
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_CHAOS
//
// "DAMAGE_TYPE" is the type of damage dealt by the pentagram explosion.
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
//
// "EFFECT_PATH" is the \\path of the special effect shown upon pentagram explosion.
private constant string EFFECT_PATH = "Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl"
//
// "DUMMY_ID" is the integer ID of the "Dummy" unit.
private constant integer DUMMY_ID = 'n003'
//
// "EFFECT_ID" is the inreger ID of the "Pentagram Dummy" unit.
private constant integer EFFECT_ID = 'h01N'
//
// "SPELL1_ID" is the integer ID of the "Demonic Pentagram" spell.
private constant integer SPELL1_ID = 'ANvc'
//
// "SPELL2_ID" is the integer ID of the "Pentagram [Effect1]" spell.
private constant integer SPELL2_ID = 'A01C'
//
// CONFIGURATION END
endglobals
private struct Pentagram
unit Caster
unit Draw
unit Dummy
group Effects
real Distance
integer SidesDrawn
real Facing
endstruct
globals
private timer Periodic = CreateTimer()
private integer Index = 0
private real TriSideSize = ( 0.95 * SIZE ) * 2
private Pentagram array Data
private integer Expire
endglobals
private function DemonicPentagramDraw takes nothing returns nothing
local effect s
local unit u
local integer i = 1
local real ox
local real oy
local real nx
local real ny
local real a
local player p
local group g = CreateGroup()
loop
exitwhen i > Index
set p = GetOwningPlayer( Data[i].Caster )
set ox = GetUnitX( Data[i].Draw )
set oy = GetUnitY( Data[i].Draw )
set nx = ox + 10 * Cos( Data[i].Facing * bj_DEGTORAD)
set ny = oy + 10 * Sin( Data[i].Facing * bj_DEGTORAD)
call SetUnitPosition( Data[i].Draw, nx, ny )
call GroupAddUnit( Data[i].Effects, CreateUnit( p, EFFECT_ID, nx, ny, 0 ))
set Data[i].Distance = Data[i].Distance + 10
if ( Data[i].Distance >= TriSideSize ) then
set Data[i].Distance = 0
set Data[i].Facing = Data[i].Facing - 144
set Data[i].SidesDrawn = Data[i].SidesDrawn + 1
if ( Data[i].SidesDrawn == 5 ) then
set ox = GetUnitX(Data[i].Dummy)
set oy = GetUnitY(Data[i].Dummy)
call KillUnit( Data[i].Draw )
call KillUnit( Data[i].Dummy )
set Expire = i
call GroupEnumUnitsInRange( g, ox, oy, SIZE, null )
loop
set u = FirstOfGroup( g )
exitwhen u == null
if ( IsPlayerAlly( GetOwningPlayer( Data[i].Caster ), GetOwningPlayer(u)) == false ) then
call UnitDamageTarget( Data[i].Caster, u, GetDamageDealt( GetHeroStatBJ( ATTRIBUTE_USED, Data[i].Caster, true ),IncUnitAbilityLevel( Data[i].Caster, SPELL1_ID )) , true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS)
endif
call GroupRemoveUnit( g, u )
endloop
loop
set u = FirstOfGroup( Data[i].Effects )
exitwhen u == null
set ox = GetUnitX( u )
set oy = GetUnitY( u )
set s = AddSpecialEffect( EFFECT_PATH, ox, oy )
call DestroyEffect( s )
call KillUnit(u)
call GroupRemoveUnit( Data[i].Effects, u )
endloop
set Data[i] = Data[Index]
call Data[Index].destroy()
set Index = Index - 1
if ( Index == 0 ) then
call PauseTimer( Periodic )
endif
set i = i - 1
endif
endif
set i = i + 1
endloop
call DestroyGroup(g)
set s = null
set u = null
set g = null
endfunction
private function Trig_DemonicPentagram_Actions takes nothing returns nothing
local integer i = 0
local player p
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real dx
local real dy
set Index = Index + 1
set Data[Index] = Pentagram.create()
set Data[Index].SidesDrawn = 0
set Data[Index].Caster = GetTriggerUnit()
set Data[Index].Facing = 108
set p = GetOwningPlayer( Data[Index].Caster )
set Data[Index].Dummy = CreateUnit( p, DUMMY_ID, x, y , 0 )
call UnitAddAbility( Data[Index].Dummy, SPELL2_ID)
call IssuePointOrder( Data[Index].Dummy, "cloudoffog", x, y )
set Data[Index].Draw = CreateUnit( p, DUMMY_ID, x, (y-SIZE), 108 )
set x = GetUnitX( Data[Index].Dummy )
set y = GetUnitY( Data[Index].Dummy )
set Data[Index].Distance = 0
call DestroyGroup( Data[Index].Effects )
set Data[Index].Effects = CreateGroup()
loop
exitwhen i == 360
set dx = x + SIZE * Cos( i * bj_DEGTORAD)
set dy = y + SIZE * Sin( i * bj_DEGTORAD)
call GroupAddUnit( Data[Index].Effects, CreateUnit( p, EFFECT_ID, dx, dy, 0 ))
set i = i + 2
endloop
if ( Index == 1 ) then
call TimerStart( Periodic, 0.03, false, function DemonicPentagramDraw )
endif
set p = null
endfunction
private function Trig_DemonicPentagram_Conditions takes nothing returns boolean
if ( GetSpellAbilityId() == SPELL1_ID ) then
call Trig_DemonicPentagram_Actions()
endif
return false
endfunction
//===========================================================================
private function DemonicPentagramInit takes nothing returns nothing
set gg_trg_DemonicPentagram = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_DemonicPentagram, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_DemonicPentagram, Condition( function Trig_DemonicPentagram_Conditions ) )
endfunction
endscope
//TESH.scrollpos=42
//TESH.alwaysfold=0
//! zinc
library TheArcaneLeash requires DyMotionMain, DyMotionMath, DyMotionMotion, DyMotionAPI
{
//: ===------
// Customizable Properties
//: ===------
//*****************************\\
//=-=-=» Main Properties «=-=-=\\
//: ===------
// the raw code of the spell itself
constant integer SPELL_ID = 'A01M';
//: ===------
// the raw code of the Dummy Stun Spell
constant integer STUN_SPELL_ID = 'A01N';
//: ===------
// this is the buff that will be used when units are stunned
constant integer STUN_BUFF_ID = 'BSTN';
//: ===------
// this shouldn't be changed, unless you use another ability to stun, firebolt does that, so we put here the issue order id
constant string STUN_ORDER_ID = "thunderbolt";
//: ===------
// this is part of the Stun countdown, better not mess with it
constant real INTERVAL = 0.2;
//: ===------
// the radius at which each missile will pick a unit
constant real GRAB_RADIUS = 80.;
//: ===------
// This is the effect that will appear when the caster casts the spell
constant string FX = "Units\\Undead\\Abomination\\AbominationExplosion.mdl";
//: ===------
// This effect appears when a grabbed unit is thrown away
constant string FX2 = "Units\\Undead\\Abomination\\AbominationExplosion.mdl";
//: ===------
// this is the damage dealt to the unit
function DAMAGE( integer lvl ) -> real
{ return 0. * lvl; }
//: ===------
// This is the duration of the stun, half duration for heroes
function STUN_DURATION( integer lvl ) -> real
{ return 3. * lvl; }
//***********************************\\
//=-=-=» Projectile Properties «=-=-=\\
//: ===------
// The model effect of the projectiles
constant string PROJECTILE_FX = "Abilities\\Weapons\\MeatwagonMissile\\MeatwagonMissile.mdl";
//: ===------
// this is the trail effect of the projectiles
constant string PROJECTILE_FX2 = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl";
//: ===------
// number of projectiles
constant integer PROJECTILE_N = 10;
//: ===------
// The speed of the projectiles while they are in the air
constant real PROJECTILE_INITIAL_SPEED = 400.;//per second
//: ===------
// The speed of the projectiles once they hit the ground
constant real PROJECTILE_GROUND_SPEED = 1000.;//per second
//: ===------
// the angle speed at which the missiles will rotate, giving that awesome effect you've seen ^^
constant real PROJECTILE_ANGLE_SPEED = bj_PI;//per second
//: ===------
// The projectiles maximum height, or the maximum height they can reach during the flight
constant real PROJECTILE_MAX_HEIGHT = 500.;
//: ===------
// The maximum distance the projectiles will fly until hit the ground
constant real PROJECTILE_MAX_DISTANCE = 600.;
//: ===------
// this is the life time of the projectiles, it's also the same value of how long the hero is channeling the spell
// if you change this value, you better change the channel duration on the spell editor too
constant real PROJECTILE_DURATION = 18.;
//**********************************\\
//=-=-=» Knockback Properties «=-=-=\\
//: ===------
// Speed at which units will be knockbacked
constant real KNOCK_SPEED = 1500.;//per second
//: ===------
// the effect of the knockback, usually dust effects
constant string KNOCK_FX = "Small Dust.mdl";
//: ===------
// End of Customizable Properties
//: ===------
function SpellStartActions( )
{
Jump jp;
unit c = GetTriggerUnit( );
integer i;
real a = dm_2Pi / PROJECTILE_N;
real x = GetUnitX( c ), y = GetUnitY( c );
for ( 1 <= i <= PROJECTILE_N )
{
jp = Jump.create( c, x, y, a * i, PROJECTILE_MAX_DISTANCE );
jp.FxPath = PROJECTILE_FX;
jp.Speed = PROJECTILE_INITIAL_SPEED;
jp.MaxHeight = PROJECTILE_MAX_HEIGHT;
jp.LifeTime = PROJECTILE_DURATION;
jp.Size = 1.6;
}
DestroyEffect( AddSpecialEffect( FX, x, y ) );
c = null;
}
struct Data
{
unit stunned;
unit dummy;
real duration;
integer id;
static method StunUnit( unit stunned, real duration )
{
Data d = Data.allocate( );
d.stunned = stunned;
d.duration = duration;
d.dummy = Recycle.Dummy;
SetUnitX( d.dummy, GetUnitX( stunned ) );
SetUnitY( d.dummy, GetUnitY( stunned ) );
PauseUnit( d.dummy, false );
UnitAddAbility( d.dummy, STUN_SPELL_ID );
IssueTargetOrder( d.dummy, STUN_ORDER_ID, stunned );
if ( N == 0 ) TimerStart( T, INTERVAL, true, function Data.Update );
d.id = N;
dat[N] = d;
N += 1;
}
static method Update( )
{
integer i;
for ( 0 <= i < N )
{
if ( dat[i].duration > 0. )
dat[i].duration -= INTERVAL;
else
dat[i].destroy( );
}
}
method onDestroy( )
{
UnitRemoveAbility( stunned, STUN_BUFF_ID );
UnitRemoveAbility( dummy, STUN_SPELL_ID );
Recycle.Dummy = dummy;
N -= 1;
dat[id] = dat[N];
dat[id].id = id;
if ( N == 0 ) PauseTimer( T );
}
private static timer T = CreateTimer( );
private static Data dat[];
private static integer N = 0;
}
struct Jump extends dmMotion
{
private boolean IsFlying = true;
private real MaxDist;
private real dist = 0.; //current distance
private real arc = 0.6;
private real iniZ;
unit Grabbed = null;
unit Source;
method operator Arc= ( real value )
{ arc = 4 * value; }
method operator MaxHeight= ( real value )
{ arc = 4 * value / MaxDist; }
private static group GrabbedGroup = CreateGroup( );
static method create( unit caster, real x, real y, real angle, real maxDist ) -> Jump
{
Jump jp = Jump.allocate( x, y, angle, null );
jp.Source = caster;
jp.Owner = GetOwningPlayer( caster );
jp.MaxDist = maxDist;
MoveLocation( loc, x, y );
jp.iniZ = GetLocationZ( loc );
return jp;
}
method onMotion( )
{
unit u;
if ( GetWidgetLife( Source ) < 0.405 )
destroy( );
else
{
if ( IsFlying )
{
dist += Speed * dm_UPDATE_INTERVAL;
MoveLocation( loc, X, Y );
H = arc * ( MaxDist - dist ) * ( dist / MaxDist ) - GetLocationZ( loc ) + iniZ;
if ( H > 0. ) Z = H;
else
{
IsFlying = false;
Speed = PROJECTILE_GROUND_SPEED;
Z = 70.;
AngleSpeed = PROJECTILE_ANGLE_SPEED;
}
}
else
{
DestroyEffect( AddSpecialEffect( PROJECTILE_FX2, X, Y ) );
if ( Grabbed != null )
{
SetUnitX( Grabbed, X );
SetUnitY( Grabbed, Y );
}
else
{
GroupEnumUnitsInRange( tempGroup, X, Y, GRAB_RADIUS, null );
u = FirstOfGroup( tempGroup );
if ( u != null && IsUnitEnemy( u, Owner ) && GetWidgetLife( u ) > 0.405 && !IsUnitType( u, UNIT_TYPE_FLYING )
&& !IsUnitType( u, UNIT_TYPE_MAGIC_IMMUNE ) && !IsUnitInGroup( u, GrabbedGroup ) )
{
Grabbed = u;
GroupAddUnit( GrabbedGroup, u );
PauseUnit( u, true );
}
GroupClear( tempGroup );
u = null;
}
}
}
}
method onDestroy( )
{
if ( Grabbed != null )
{
KnockbackAngleRadians( Grabbed, Angle, KNOCK_SPEED, KNOCK_FX );
GroupRemoveUnit( GrabbedGroup, Grabbed );
PauseUnit( Grabbed, false );
UnitDamageTarget( Source, Grabbed, DAMAGE( GetUnitAbilityLevel( Source, SPELL_ID ) ), true, false, null, null, null );
if ( IsUnitType( Grabbed, UNIT_TYPE_HERO ) )
Data.StunUnit( Grabbed, STUN_DURATION( GetUnitAbilityLevel( Source, SPELL_ID ) ) / 2. );
else
Data.StunUnit( Grabbed, STUN_DURATION( GetUnitAbilityLevel( Source, SPELL_ID ) ) );
Grabbed = null;
DestroyEffect( AddSpecialEffect( FX2, X, Y ) );
}
}
private static location loc = Location( 0., 0. );
private static real H = 0.;
}
function onInit( )
{
trigger t = CreateTrigger( );
integer i;
unit u = Recycle.Dummy;
for ( 0 <= i < 12 )
TriggerRegisterPlayerUnitEvent( t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null );
TriggerAddCondition( t, function( ) -> boolean { return GetSpellAbilityId( ) == SPELL_ID; } );
TriggerAddAction( t, function SpellStartActions );
UnitAddAbility( u, SPELL_ID );
UnitRemoveAbility( u, SPELL_ID );
UnitAddAbility( u, STUN_SPELL_ID );
UnitRemoveAbility( u, STUN_SPELL_ID );
Recycle.Dummy = u;
Preload( FX );
Preload( FX2 );
Preload( PROJECTILE_FX );
Preload( PROJECTILE_FX2 );
Preload( KNOCK_FX );
u = null;
t = null;
}
}
//! endzinc
//TESH.scrollpos=32
//TESH.alwaysfold=0
//! zinc
library DyMotionAPI requires DyMotionMain, DyMotionMath, DyMotionMotion
{
//: ==----
// Function Knockback
//
//: ==----
public function Knockback( unit c, unit t, real speed, string fx )
{ dmKnockback.create( t, Atan2( GetUnitY( t ) - GetUnitY( c ), GetUnitX( t ) - GetUnitX( c ) ), speed, speed / 0.5 * dm_UPDATE_INTERVAL, fx ); }
//
public function KnockbackAngle( unit t, real angle, real speed, string fx )
{ dmKnockback.create( t, angle * bj_DEGTORAD, speed, speed / 0.5 * dm_UPDATE_INTERVAL, fx ); }
//
public function KnockbackAngleRadians( unit t, real angle, real speed, string fx )
{ dmKnockback.create( t, angle, speed, speed / 0.5 * dm_UPDATE_INTERVAL, fx ); }
//
public function KnockbackXY( unit t, real x, real y, real speed, string fx )
{ dmKnockback.create( t, Atan2( GetUnitY( t ) - y, GetUnitX( t ) - x ), speed, speed / 0.5 * dm_UPDATE_INTERVAL, fx ); }
//
public function KnockbackLoc( unit t, location loc, real speed, string fx )
{ dmKnockback.create( t, Atan2( GetUnitY( t ) - GetLocationY( loc ), GetUnitX( t ) - GetLocationX( loc ) ), speed, speed / 0.5 * dm_UPDATE_INTERVAL, fx ); }
//
public function KnockbackTimed( unit c, unit t, real speed, real duration, string fx )
{ dmKnockback.create( t, Atan2( GetUnitY( t ) - GetUnitY( c ), GetUnitX( t ) - GetUnitX( c ) ), speed, speed / duration * dm_UPDATE_INTERVAL, fx ); }
//
public function KnockbackAoE( unit c, real x, real y, real radius, real speed, string fx )
{
tR1 = speed;
tS = fx;
tR2 = x;
tR3 = y;
GroupEnumUnitsInRange( tG, x, y, radius, function( ) -> boolean
{
tU = GetFilterUnit( );
if ( GetWidgetLife( tU ) > 0.405 ) KnockbackXY( tU, tR2, tR3, tR1, tS );
return false;
} );
}
//
public function Knockback_Ex( unit c, unit t, real speed, real friction, string fx )
{ dmKnockback.create( t, Atan2( GetUnitY( t ) - GetUnitY( c ), GetUnitX( t ) - GetUnitX( c ) ), speed, friction, fx ); }
//
public function KnockbackAngle_Ex( unit t, real angle, real speed, real friction, string fx )
{ dmKnockback.create( t, angle * bj_DEGTORAD, speed, friction, fx ); }
//
public function KnockbackAngleRadians_Ex( unit t, real angle, real speed, real friction, string fx )
{ dmKnockback.create( t, angle, speed, friction, fx ); }
//
public function KnockbackXY_Ex( unit t, real x, real y, real speed, real friction, string fx )
{ dmKnockback.create( t, Atan2( GetUnitY( t ) - y, GetUnitX( t ) - x ), speed, friction, fx ); }
//
public function KnockbackLoc_Ex( unit t, location loc, real speed, real friction, string fx )
{ dmKnockback.create( t, Atan2( GetUnitY( t ) - GetLocationY( loc ), GetUnitX( t ) - GetLocationX( loc ) ), speed, friction, fx ); }
//
public function KnockbackAoE_Ex( unit c, real x, real y, real radius, real speed, real friction, string fx )
{
tR1 = speed;
tS = fx;
tR2 = x;
tR3 = y;
tR4 = friction;
GroupEnumUnitsInRange( tG, x, y, radius, function( ) -> boolean
{
tU = GetFilterUnit( );
if ( GetWidgetLife( tU ) > 0.405 ) KnockbackXY_Ex( tU, tR2, tR3, tR1, tR4, tS );
return false;
} );
}
//: ==----
// Function Orbiting
//
//: ==----
public function MissileOrbitingUnit( unit u, string sfx, real angSpeed, real radius, real duration )
{
dmMotion m = dmMotion.create( GetUnitX( u ), GetUnitY( u ), 0., null );
m.FxPath = sfx;
m.Speed = 100.;
m.SetOrbitingUnit( u, radius, angSpeed );
m.LifeTime = duration;
}
public function MissileOrbitingXY( real x, real y, string sfx, real angSpeed, real radius, real duration )
{
dmMotion m = dmMotion.create( x, y, 0., null );
m.FxPath = sfx;
m.Speed = 100.;
m.SetOrbitingPoint( x, y, radius, angSpeed );
m.LifeTime = duration;
}
public function MissileOrbitingLocation( location loc, string sfx, real angSpeed, real radius, real duration )
{
dmMotion m = dmMotion.create( GetLocationX( loc ), GetLocationY( loc ), 0., null );
m.FxPath = sfx;
m.Speed = 100.;
m.SetOrbitingPoint( GetLocationX( loc ), GetLocationY( loc ), radius, angSpeed );
m.LifeTime = duration;
}
public function MultipleMissilesOrbitingUnit( unit u, integer n, string sfx, real angSpeed, real radius, real duration )
{
dmMotion m;
integer i;
real a;
real x = GetUnitX( u ), y = GetUnitY( u );
if ( n <= 1 ) n = 2;
a = dm_2Pi / n;
for ( 1 <= i <= n )
{
m = dmMotion.create( x, y, a * i, null );
m.FxPath = sfx;
m.Speed = 100.;
m.SetOrbitingUnit( u, radius, angSpeed );
m.LifeTime = duration;
}
}
public function MultipleMissilesOrbitingXY( real x, real y, integer n, string sfx, real angSpeed, real radius, real duration )
{
dmMotion m;
integer i;
real a;
if ( n <= 1 ) n = 2;
a = dm_2Pi / n;
for ( 1 <= i <= n )
{
m = dmMotion.create( x, y, a * i, null );
m.FxPath = sfx;
m.Speed = 100.;
m.SetOrbitingPoint( x, y, radius, angSpeed );
m.LifeTime = duration;
}
}
public function MultipleMissilesOrbitingLocation( location loc, integer n, string sfx, real angSpeed, real radius, real duration )
{
dmMotion m;
integer i;
real a;
real x = GetLocationX( loc ), y = GetLocationY( loc );
if ( n <= 1 ) n = 2;
a = dm_2Pi / n;
for ( 1 <= i <= n )
{
m = dmMotion.create( x, y, a * i, null );
m.FxPath = sfx;
m.Speed = 100.;
m.SetOrbitingPoint( x, y, radius, angSpeed );
m.LifeTime = duration;
}
}
//: ==----
// temporary variables
//: ==----
group tG = CreateGroup( );
unit tU;
real tR1, tR2, tR3, tR4;
string tS;
//: ==----
// API structs
//: ==----
struct dmKnockback extends dmMotion
{
string Fx;
static method create( unit u, real angle, real speed, real friction, string fx ) -> dmKnockback
{
dmKnockback kb = dmKnockback.allocate( 0., 0., angle, u );
kb.Speed = speed;
kb.Acceleration = -friction;
kb.Fx = fx;
return kb;
}
method onMotion( )
{
DestroyEffect( AddSpecialEffect( Fx, X, Y ) );
if ( Speed <= -Acceleration || !IsTerrainWalkable( X, Y, 10. ) ) destroy( );
}
}
public struct dmJump extends dmMotion
{
private real MaxDist;
private real dist = 0.; //current distance
private real arc = 0.6;
private real iniZ;
private real defaultHeight = 0.;
method operator Arc= ( real value )
{ arc = 4 * value; }
method operator MaxHeight= ( real value )
{ arc = 4 * value / MaxDist; }
static method create( real x, real y, real angle, real maxDist ) -> dmJump
{
dmJump jp = dmJump.allocate( x, y, angle, null );
jp.MaxDist = maxDist;
MoveLocation( loc, x, y );
jp.iniZ = GetLocationZ( loc );
return jp;
}
static method createWithUnit( unit u, real angle, real maxDist ) -> dmJump
{
dmJump jp = dmJump.allocate( 0., 0., angle, u );
UnitAddAbility( u, dm_FLYING );
UnitRemoveAbility( u, dm_FLYING );
jp.MaxDist = maxDist;
jp.defaultHeight = GetUnitDefaultFlyHeight( u );
MoveLocation( loc, GetUnitX( u ), GetUnitY( u ) );
jp.iniZ = GetLocationZ( loc )+ jp.defaultHeight;
return jp;
}
method onMotion( )
{
dist += Speed * dm_UPDATE_INTERVAL;
MoveLocation( loc, X, Y );
H = arc * ( MaxDist - dist ) * ( dist / MaxDist ) - GetLocationZ( loc ) + iniZ;
if ( H > 0. ) Z = H;
else destroy( );
}
method onDestroy( )
{
Z = defaultHeight;
}
private static location loc = Location( 0., 0. );
private static real H = 0.;
}
/*struct dmOrbitMissile extends dmMotion
{
dmCollision collider;
dmDamage damager;
static method create( unit t, real angle, real anglespeed, real radius ) -> dmOrbitMissile
{
dmOrbitMissile ob = dmOrbitMissile.allocate( GetUnitX( t ), GetUnitY( t ), angle, null );
ob.SetOrbitingUnit( t, radius, anglespeed );
return ob;
}
method onMotion( )
{
if ( collider != 0 )
{
if ( collider.CheckCollisions( X, Y ) )
{
}
}
else if ( damager != 0 )
{
}
}
method onDestroy( )
{
}
}*/
public struct dmChain
{
static constant integer MAX_CHAIN_SEGMENTS = 2000;
static constant real DEFAULT_CHAIN_SPEED = 1000.;
static constant real DEFAULT_MAX_DISTANCE = 2300.;
static constant real DEFAULT_CHAIN_INTERVAL = 0.1;
static constant real DEFAULT_CHAIN_COLLISION = 30.;
static constant string DEFAULT_TIP_CHAIN_FX = "Abilities\\Weapons\\MeatwagonMissile\\MeatwagonMissile.mdl";
static constant string DEFAULT_BODY_CHAIN_FX = "Abilities\\Weapons\\MeatwagonMissile\\MeatwagonMissile.mdl";
static constant real DEFAULT_TIP_SIZE = 4.;
static constant real DEFAULT_BODY_SIZE = 4.;
unit Caster, Target = null;
real tX, tY; //it can target a position instead of a unit
real Speed = DEFAULT_CHAIN_SPEED;
real Collision = DEFAULT_CHAIN_COLLISION;
real MaxDistance = DEFAULT_MAX_DISTANCE;
real Damage = 0.;
real TipSize = DEFAULT_TIP_SIZE;
real BodySize = DEFAULT_BODY_SIZE;
string TipFx = DEFAULT_TIP_CHAIN_FX;
string BodyFx = DEFAULT_BODY_CHAIN_FX;
boolean UseCasterFacingAngle = false;
method operator ChainInterval= ( real value )
{
PauseTimer( T );
TimerStart( T, value, true, function dmChain.Update );
interval = value;
}
method operator First ( ) -> dmChainSegment
{ return ChainSegments[0]; }
method operator Last ( ) -> dmChainSegment
{ return ChainSegments[ChainN-1]; }
private boolean HaveTarget = false;
private real interval = DEFAULT_CHAIN_INTERVAL;
private integer id;
static method createOnTarget( unit caster, unit target ) -> dmChain
{
dmChain c = dmChain.allocate( );
c.Caster = caster;
c.Target = target;
Indexing( c );
return c;
}
static method createOnPoint( unit caster, real x, real y ) -> dmChain
{
dmChain c = dmChain.allocate( );
c.Caster = caster;
c.tX = x; c.tY = y;
Indexing( c );
return c;
}
method NewChainSegment( )
{
dmChainSegment ch;
if ( ChainN >= MAX_CHAIN_SEGMENTS )
{
debug BJDebugMsg( "Segments limit reached" );
Return( );
return;
}
ch = dmChainSegment.create( GetUnitX( Caster ), GetUnitY( Caster ), 0., null );
ch.LifeTime = 2000.;
ch.Speed = Speed;
ch.Caster = Caster;
ch.tag = id;
if ( ChainN == 0 )
{
ch.FxPath = TipFx;
ch.Size = TipSize;
if ( Target != null )
ch.SetHomingUnit( Target );
else
ch.Angle = Atan2( tY - ch.Y, tX - ch.X );
}
else
{
ch.FxPath = BodyFx;
ch.Size = BodySize;
ch.SetHomingUnit( ChainSegments[ChainN - 1].Object );
}
ChainSegments[ChainN] = ch;
ChainN += 1;
}
method Return( )
{
dmChainSegment c;
integer i;
HaveTarget = true;
if ( Damage > 0. && First.Attached != null )
UnitDamageTarget( Caster, First.Attached, Damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null );
Last.SetHomingUnit( Caster );
Last.Returning = true;
Last.AutoFacing = false;
for ( ChainN - 1 > i > 0 )
{
c = ChainSegments[i];
c.SetHomingUnit( ChainSegments[i + 1].Object );
c.Returning = true;
c.AutoFacing = false;
}
First.SetHomingUnit( ChainSegments[1].Object );
First.Returning = true;
First.AutoFacing = false;
}
static method RemoveLastChainSegment( integer Id )
{
C[Id].ChainSegments[C[Id].ChainN-2].SetHomingUnit( C[Id].Caster );
C[Id].ChainN -= 1;
}
private static method Update( )
{
dmChainSegment cs[]; //chain segments
dmChain c;
unit u;
integer i, i2;
for ( 0 <= i < N )
{
c = C[i];
if ( !c.HaveTarget )
{
c.NewChainSegment( );
if ( c.Target != null )
{
if ( IsUnitInRange( c.First.Object, c.Target, c.Collision ) )
{
c.First.Attached = c.Target;
c.Return( );
}
}
else
{
if ( c.MaxDistance > 0. && IsTerrainWalkable( c.First.X, c.First.Y, 10. ) )
c.MaxDistance -= c.Speed * c.interval;
else
c.Return( );
if ( c.UseCasterFacingAngle )
c.First.Angle = GetUnitFacing( c.Caster ) * bj_DEGTORAD;
GroupEnumUnitsInRange( tempGroup, c.First.X, c.First.Y, c.Collision, null );
u = FirstOfGroup( tempGroup );
if ( IsUnitEnemy( u, GetOwningPlayer( c.Caster ) ) && GetWidgetLife( u ) > 0.405 )
{
c.First.Attached = u;
c.Return( );
}
}
}
else
{
for ( 1 <= i2 < c.ChainN )
{
cs[0] = c.ChainSegments[i2];
cs[1] = c.ChainSegments[i2 - 1];
cs[0].XYangle = Atan2( cs[1].Y - cs[0].Y, cs[1].X - cs[0].X );
}
}
if ( c.ChainN == 0 )
c.destroy( );
}
}
private dmChainSegment ChainSegments[dmChain.MAX_CHAIN_SEGMENTS];
private integer ChainN = 0;
private static group tempGroup = CreateGroup( );
private static dmChain C[];
private static integer N = 0;
private static timer T = CreateTimer( );
method onDestroy( )
{
N -= 1;
C[id] = C[N];
C[id].id = id;
if ( N == 0 )
PauseTimer( T );
}
private static method Indexing( dmChain c )
{
if ( N == 0 )
TimerStart( T, DEFAULT_CHAIN_INTERVAL, true, function dmChain.Update );
c.id = N;
C[N] = c;
N += 1;
}
}
struct dmChainSegment extends dmMotion
{
unit Attached = null;
unit Caster = null;
boolean Returning = false;
integer tag = 0;
method onMotion( )
{
if ( Attached != null )
{
SetUnitX( Attached, X );
SetUnitY( Attached, Y );
}
if ( Returning )
if ( IsUnitInRange( Object, Caster, dmChain.DEFAULT_CHAIN_COLLISION ) )
{
dmChain.RemoveLastChainSegment( tag );
destroy( );
}
}
}
}
//! endzinc
//TESH.scrollpos=0
//TESH.alwaysfold=0
//! zinc
library DyMotionMath
{
public constant real dm_2Pi = 2 * bj_PI;
public constant real dm_PiOVER2 = bj_PI / 2;
public constant real dm_3OVER2Pi = 3 / 2 * bj_PI;
//If you want to use this in a condition, to check the distance, use this native function instead IsUnitInRange
public function GetDistance( real x1, real y1, real x2, real y2 ) -> real
{ real dx = x2 - x1, dy = y2 - y1; return Pow( dx * dx + dy * dy, 0.5 ); }
public function GetRandomRealInRingRegion( real maxRadius, real minRadius, real centerN ) -> real
{
real n, min = minRadius, max = maxRadius;
n = centerN;
if ( maxRadius < minRadius )
min = maxRadius;
while ( n >= centerN - min && n <= centerN + min )
n = GetRandomReal( centerN - max, centerN + max );
return n;
}
public function GetRandomPointInRingRegion( real maxRadius, real minRadius, real centerX, real centerY ) -> location
{
return Location( GetRandomRealInRingRegion( maxRadius, minRadius, centerX ),
GetRandomRealInRingRegion( maxRadius, minRadius, centerY ) );
}
}
//! endzinc
//TESH.scrollpos=0
//TESH.alwaysfold=0
//! zinc
library DyMotionDamage requires DyMotionMain
{
//_______________________________________________
//***********************************************
// *****Globals*****
//-----------------------------------------------
constant integer dm_MAX_DAMAGE_FACTORS = 5;
constant damagetype dm_DEFAULT_DAMAGE_TYPE = DAMAGE_TYPE_UNKNOWN;
constant attacktype dm_DEFAULT_ATTACK_TYPE = ATTACK_TYPE_NORMAL;
constant weapontype dm_DEFAULT_WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS;
//-----------------------------------------------
// *****Globals End*****
//_______________________________________________
//***********************************************
public struct dmDamage
{
boolean DamageSelf = false;
boolean DamageAllies = true;
boolean DamageEnemies = false;
boolean VisibleOnly = true;
boolean DamageTrees = false;
damagetype DmgType = dm_DEFAULT_DAMAGE_TYPE;
attacktype AtkType = dm_DEFAULT_ATTACK_TYPE;
weapontype WpnType = dm_DEFAULT_WEAPON_TYPE;
unittype ForcedUnitType = null;
unittype IgnoreUnitType = null;
integer ForcedUnitId = 0;
integer IgnoreUnitId = 0;
string FxPath = null;
string FxPoint = "origin";
method DamageTarget( unit source, unit target, real dmg )
{
real f = GetDamageFactor( source, target );
if ( GetWidgetLife( target ) > 0.405 )
UnitDamageTarget( source, target, dmg * f, true, false, AtkType, DmgType, WpnType );
if ( FxPath != null ) DestroyEffect( AddSpecialEffectTarget( FxPath, target, FxPoint ) );
}
method DamageGroup( unit source, group g, real dmg )
{
CopyGroup( g, tempGroup );
tempUnit = FirstOfGroup( tempGroup );
while ( tempUnit != null )
{ DamageTarget( source, tempUnit, dmg ); GroupRemoveUnit( tempGroup, tempUnit ); tempUnit = FirstOfGroup( tempGroup ); }
}
method DamageAoE( unit source, real x, real y, real radius, real dmg )
{
tempUnit = source;
tempReal = dmg;
instance = this;
GroupEnumUnitsInRange( tempGroup, x, y, radius, function( ) -> boolean {
instance.DamageTarget( tempUnit, GetFilterUnit( ), tempReal ); return false; } );
}
method AddUnitTypeFactor( unittype ut, real fct )
{
if ( unitFctN == dm_MAX_DAMAGE_FACTORS ) return;
unitFctType[unitFctN] = ut;
unitFct[unitFctN] = fct;
unitFctN += 1;
}
method AddBuffTypeFactor( integer buffId, real fct )
{
if ( buffFctN == dm_MAX_DAMAGE_FACTORS ) return;
buffFctId[buffFctN] = buffId;
buffFct[buffFctN] = fct;
buffFctN += 1;
}
//_______________________________________________
//***********************************************
// *****Private Stuff*****
//-----------------------------------------------
private method GetDamageFactor( unit s, unit t ) -> real
{
player p = GetOwningPlayer( s );
boolean isEnemy = IsUnitEnemy( t, p );
boolean isAlly = IsUnitAlly( t, p );
integer i = 0;
real f = 1.;
if ( !DamageSelf && s == t ) return 0.;
else if ( !DamageEnemies && isEnemy ) return 0.;
else if ( !DamageAllies && isAlly ) return 0.;
else if ( VisibleOnly && !IsUnitVisible( t, p ) ) return 0.;
if ( ForcedUnitType != null && !IsUnitType( t, ForcedUnitType ) ) return 0.;
else if ( IgnoreUnitType != null && IsUnitType( t, IgnoreUnitType ) ) return 0.;
else if ( ForcedUnitId != 0 && GetUnitTypeId( t ) != ForcedUnitId ) return 0.;
else if ( IgnoreUnitId != 0 && GetUnitTypeId( t ) == IgnoreUnitId ) return 0.;
while ( unitFctType[i] != null && i < dm_MAX_DAMAGE_FACTORS )
{
if ( IsUnitType( t, unitFctType[i] ) )
{
if ( unitFct[i] > 1. ) f += ( unitFct[i] - 1. );
else if ( unitFct[i] == 0. ) { f -= 1.; if ( f < 0. ) f = 0.; }
else f -= buffFct[i];
}
i += 1;
}
i = 0;
while ( buffFctId[i] != 0 && i < dm_MAX_DAMAGE_FACTORS )
{
if ( GetUnitAbilityLevel( t, buffFctId[i] ) > 0 )
{
if ( buffFct[i] > 1. ) f += ( buffFct[i] - 1. );
else if ( buffFct[i] == 0. ) { f -= 1.; if ( f < 0. ) f = 0.; }
else f -= buffFct[i];
}
i += 1;
}
return f;
}
private unittype unitFctType[dm_MAX_DAMAGE_FACTORS];
private real unitFct[dm_MAX_DAMAGE_FACTORS];
private integer unitFctN = 0;
private integer buffFctId[dm_MAX_DAMAGE_FACTORS];
private real buffFct[dm_MAX_DAMAGE_FACTORS];
private integer buffFctN = 0;
private static group tempGroup = CreateGroup( );
private static unit tempUnit = null;
private static real tempReal = 0.;
private static dmDamage instance = 0;
}
}
//! endzinc
//TESH.scrollpos=67
//TESH.alwaysfold=0
//! zinc
library DyMotionMain
{
constant integer FPS = 30;
public constant integer dm_DUMMY_ID = 'n003';
public constant integer dm_UNTOUCHABLE = 'Aloc';
public constant integer dm_FLYING = 'Amrf';
public constant integer dm_TREE_DETECTION = 'Aeat';
public constant real dm_UPDATE_INTERVAL = 1.0 / FPS;
public function CopyGroup( group gIn, group gOut )
{
bj_groupAddGroupDest = CreateGroup( );
ForGroup( gIn, function( ) { GroupAddUnit( bj_groupAddGroupDest, GetEnumUnit( ) ); } );
gOut = bj_groupAddGroupDest;
}
/*_____________________________________________
***********************************************
*****Dummy Recycle Struct*****
---------------------------------------------*/
public struct Recycle
{
private static group DeadDummies;
private static unit u;
static method operator Dummy( ) -> unit
{
u = FirstOfGroup( DeadDummies );
if ( u == null )
{
u = CreateUnit( Player( 15 ), dm_DUMMY_ID, 0.0, 0.0, 0.0 );
UnitAddAbility( u, dm_UNTOUCHABLE );
UnitAddAbility( u, dm_FLYING );
UnitRemoveAbility( u, dm_FLYING );
PauseUnit( u, true );
}
else
GroupRemoveUnit( DeadDummies, u );
return u;
}
static method operator Dummy=( unit value )
{
SetUnitOwner( value, Player(15), true );
PauseUnit( value, true );
SetUnitScale( value, 1., 1., 1. );
SetUnitTimeScale( value, 1. );
GroupAddUnit( DeadDummies, value );
}
private static method onInit( )
{
integer i;
DeadDummies = CreateGroup( );
for ( 1 <= i <= 200 )
{
u = CreateUnit( Player( 15 ), dm_DUMMY_ID, 0.0, 0.0, 0.0 );
UnitAddAbility( u, dm_UNTOUCHABLE );
UnitAddAbility( u, dm_FLYING );
UnitRemoveAbility( u, dm_FLYING );
PauseUnit( u, true );
GroupAddUnit( DeadDummies, u );
}
}
}
}
//! endzinc
/*_____________________________________________
***********************************************
*****Is Terrain Walkable Lib*****
---------------------------------------------*/
library IsTerrainWalkable initializer Init
globals
public real X = 0.0
public real Y = 0.0
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, real maxrange returns boolean
call MoveRectTo(r, x,y)
call EnumItemsInRect(r,null,function HideBothersomeItem)
call SetItemPosition(check,x,y)
set X = GetItemX(check)
set Y = GetItemY(check)
call SetItemVisible(check,false)
loop
exitwhen hiddenMax<=0
set hiddenMax=hiddenMax-1
call SetItemVisible(hidden[hiddenMax],true)
set hidden[hiddenMax]=null
endloop
return (x-X)*(x-X)+(y-Y)*(y-Y) < maxrange*maxrange
endfunction
endlibrary
/*_____________________________________________
***********************************************
*****Bound Sentinel Lib*****
---------------------------------------------*/
library BoundSentinel initializer init
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=9
//TESH.alwaysfold=0
//! zinc
library DyMotionCollision requires DyMotionMain
{
//_______________________________________________
//***********************************************
// *****Globals*****
//-----------------------------------------------
constant real dm_DEFAULT_COLLISION_RADIUS = 90.;
//-----------------------------------------------
// *****Globals End*****
//_______________________________________________
//***********************************************
interface CollisionSettings
{ method EnumUnits( ) = null; }
public struct dmCollision extends CollisionSettings
{
player Owner = Player( 15 );
real Radius = dm_DEFAULT_COLLISION_RADIUS; //the collision radius
boolean Alive = true;
boolean HeroesOnly = false;
method operator EnemiesOnly ( ) -> boolean
{ return enemiesOnly; }
method operator EnemiesOnly= ( boolean value )
{ enemiesOnly = value; alliesOnly = false; }
method operator AlliesOnly ( ) -> boolean
{ return alliesOnly; }
method operator AlliesOnly= ( boolean value )
{ alliesOnly = value; enemiesOnly = false; }
private boolean enemiesOnly = true;
private boolean alliesOnly = true;
method EnumUnits( )
{
p = Owner;
c = this;
GroupEnumUnitsInRange( Group, tX, tY, Radius, function( ) -> boolean
{
f = GetFilterUnit( );
if ( c.HeroesOnly )
return IsUnitEnemy( f, p ) == c.enemiesOnly && IsUnitAlly( f, p ) == c.alliesOnly &&
IsUnitType( f, UNIT_TYPE_HERO ) && ( GetWidgetLife( f ) > 0.405 ) == c.Alive;
else
return IsUnitEnemy( f, p ) == c.enemiesOnly && IsUnitAlly( f, p ) == c.alliesOnly &&
( GetWidgetLife( f ) > 0.405 ) == c.Alive;
} );
}
method CheckCollisions( real X, real Y ) -> boolean
{
tX = X; tY = Y;
EnumUnits( );
b = false;
if ( FirstOfGroup( Group ) != null )
b = true;
GroupClear( Group );
p = null;
c = 0;
return b;
}
private static real tX, tY;
private static group Group = CreateGroup( );
private static unit f;
private static player p;
private static dmCollision c;
private static boolean b;
}
}
//! endzinc
//TESH.scrollpos=3
//TESH.alwaysfold=0
//! zinc
library DyMotionProjectile requires DyMotionMain
{
public struct dmProjectile
{
private unit object;
private effect fx = null;
private boolean IsDummy = true;
static method create( real x, real y ) -> dmProjectile
{
dmProjectile msl = dmProjectile.allocate( );
msl.object = Recycle.Dummy;
msl.X = x;
msl.Y = y;
return msl;
}
static method createWithUnit( unit u ) -> dmProjectile
{
dmProjectile msl;
if ( GetUnitTypeId( u ) != dm_DUMMY_ID )
{
msl = dmProjectile.allocate( );
msl.object = u;
msl.IsDummy = false;
return msl;
}
debug BJDebugMsg( "The Unit is a Dummy Unit! Not allowed for these effects" );
return 0;
}
method operator FxPath= ( string value )
{
if ( fx != null ) DestroyEffect( fx ); fx = null;
if ( value == "" ) fx = null;
else fx = AddSpecialEffectTarget( value, object, "origin" );
}
method operator Owner ( ) -> player
{ return GetOwningPlayer( object ); }
method operator Owner= ( player value )
{ SetUnitOwner( object, value, true ); }
method operator Size= ( real value )
{ SetUnitScale( object, value, value, value ); }
method operator AnimationSpeed= ( real value )
{ SetUnitTimeScale( object, value ); }
method operator X ( ) -> real
{ return GetUnitX( object ); }
method operator X= ( real value )
{ SetUnitX( object, value ); }
method operator Y ( ) -> real
{ return GetUnitY( object ); }
method operator Y= ( real value )
{ SetUnitY( object, value ); }
method operator Z ( ) -> real
{ return GetUnitFlyHeight( object ); }
method operator Z= ( real value )
{ SetUnitFlyHeight( object, value, 0.0 ); }
method operator XYangle ( ) -> real
{ return GetUnitFacing( object ) * bj_DEGTORAD; }
method operator XYangle= ( real value )
{ SetUnitFacing( object, value * bj_RADTODEG ); }
method operator Object ( ) -> unit
{ return object; }
method onDestroy( )
{
DestroyEffect( fx );
if ( IsDummy )
Recycle.Dummy = object;
}
}
}
//! endzinc
//TESH.scrollpos=0
//TESH.alwaysfold=0
//! zinc
library DyMotionMotion requires DyMotionMain, DyMotionMath, DyMotionProjectile
{
//_______________________________________________
//***********************************************
// *****Globals*****
//-----------------------------------------------
constant real dm_DEFAULT_MAX_SPEED = 1800.;
constant real dm_DEFAULT_LIFE_TIME = 6.;
//-----------------------------------------------
// *****Globals End*****
//_______________________________________________
//***********************************************
interface MotionEvents
{
method onMotion( ) = null;
method onLoop( ) = null;
}
public struct dmMotion extends MotionEvents
{
real LifeTime = dm_DEFAULT_LIFE_TIME;
boolean Paused = false;
boolean AutoFacing = true;
static method create( real x, real y, real angle, unit u ) -> dmMotion
{
dmMotion m = dmMotion.allocate( );
dmMotion.Indexing( m );
if ( u == null ) m.msl = dmProjectile.create( x, y );
else m.msl = dmProjectile.createWithUnit( u );
m.Angle = angle;
return m;
}
/*_____________________________________________
***********************************************
*****Operators*****
---------------------------------------------*/
method operator Angle ( ) -> real
{ return Atan2( spd * sin, spd * cos ); }
method operator Angle= ( real value )
{ cos = Cos( value ); sin = Sin( value ); msl.XYangle = value; }
method operator Speed ( ) -> real
{ return spd / dm_UPDATE_INTERVAL; }
method operator Speed= ( real value )
{ spd = value * dm_UPDATE_INTERVAL; }
method operator Acceleration ( ) -> real
{ return acc / dm_UPDATE_INTERVAL; }
method operator Acceleration= ( real value )
{ acc = value * dm_UPDATE_INTERVAL; }
method operator AngleSpeed ( ) -> real
{ return angspd / dm_UPDATE_INTERVAL; }
method operator AngleSpeed= ( real value )
{ angspd = value * dm_UPDATE_INTERVAL; }
method operator MaxSpeed ( ) -> real
{ return maxspd / dm_UPDATE_INTERVAL; }
method operator MaxSpeed= ( real value )
{ maxspd = value * dm_UPDATE_INTERVAL; }
method operator MinSpeed ( ) -> real
{ return minspd / dm_UPDATE_INTERVAL; }
method operator MinSpeed= ( real value )
{ minspd = value * dm_UPDATE_INTERVAL; }
method operator OrbitRadius( ) -> real
{ return orbRadius; }
method operator OrbitRadius= ( real value )
{ orbRadius = value; }
/*---------------------------------------------
*****Operators End*****
_______________________________________________
**********************************************/
method SetHomingPoint( real x, real y )
{ hmX = x; hmY = y; homing = true; }
method SetHomingUnit( unit t )
{ HomingUnit = t; homing = true; }
method StopHoming( )
{ HomingUnit = null; homing = false; }
method SetOrbitingPoint( real x, real y, real radius, real anglespeed )
{ orbX = x; orbY = y; orbRadius = radius; AngleSpeed = anglespeed; orbiting = true; }
method SetOrbitingUnit( unit t, real radius, real anglespeed )
{ orbUnit = t; orbRadius = radius; AngleSpeed = anglespeed; orbiting = true; }
method StopOrbiting( )
{ orbUnit = null; orbRadius = 0.; angspd = 0.; orbiting = false; }
method Bounce( )
{
if ( Angle > dm_PiOVER2 && Angle < dm_3OVER2Pi )
Angle = -Angle;
else
Angle = bj_PI - Angle;
}
/*_____________________________________________
***********************************************
*****Internal Stuff*****
---------------------------------------------*/
private real maxspd = dm_DEFAULT_MAX_SPEED * dm_UPDATE_INTERVAL;
private real minspd = 0.;
private real spd = 0.; //speed
private real acc = 0.; //acceleration
private real angspd = 0.; //angle speed
private real cos = 0., sin = 0.;
private boolean homing = false; //homing flag
unit HomingUnit = null; //homing unit
private real hmX = 0., hmY = 0.; //homing coordinates
private boolean orbiting = false; //orbiting flag
private unit orbUnit = null; //orbits around this unit
private real orbX = 0., orbY = 0.; //orbits around this point
private real orbRadius = 0.;
private delegate dmProjectile msl;
private integer id;
private static timer Timer;
private static integer N = 0;
private static dmMotion M[];
private static code update;
static group tempGroup = CreateGroup( );
private static method Update( )
{
dmMotion m;
integer i;
real a;
for ( 0 <= i < dmMotion.N )
{
m = dmMotion.M[i];
if ( !m.Paused )
{
if ( m.angspd != 0.0 )
{
if ( m.AutoFacing )
m.Angle = m.Angle + m.angspd;
else
{
a = m.Angle + m.angspd;
m.cos = Cos( a );
m.sin = Sin( a );
}
}
if ( m.homing )
{
if ( m.HomingUnit != null )
{
m.hmX = GetUnitX( m.HomingUnit );
m.hmY = GetUnitY( m.HomingUnit );
}
if ( m.AutoFacing )
m.Angle = Atan2( m.hmY - m.Y, m.hmX - m.X );
else
{
a = Atan2( m.hmY - m.Y, m.hmX - m.X );
m.cos = Cos( a );
m.sin = Sin( a );
}
}
else if ( m.orbiting )
{
if ( m.orbUnit != null ) { m.orbX = GetUnitX( m.orbUnit ); m.orbY = GetUnitY( m.orbUnit ); }
m.X = m.orbX + m.orbRadius * m.cos;
m.Y = m.orbY + m.orbRadius * m.sin;
}
m.X = m.X + m.spd * m.cos;
m.Y = m.Y + m.spd * m.sin;
if ( m.spd < m.maxspd && m.spd >= m.minspd )
m.spd += m.acc;
if ( m.onMotion.exists ) m.onMotion( );
if ( m.LifeTime > 0. )
m.LifeTime -= dm_UPDATE_INTERVAL;
else
m.destroy( );
}
if ( m.onLoop.exists ) m.onLoop( );
}
}
private static method Indexing( dmMotion m )
{
if ( dmMotion.N == 0 ) TimerStart( dmMotion.Timer, dm_UPDATE_INTERVAL, true, dmMotion.update );
m.id = dmMotion.N;
dmMotion.M[dmMotion.N] = m;
dmMotion.N += 1;
}
method onDestroy( )
{
msl.destroy( );
dmMotion.N -= 1;
dmMotion.M[id] = dmMotion.M[dmMotion.N];
dmMotion.M[id].id = id;
if ( dmMotion.N == 0 ) PauseTimer( dmMotion.Timer );
}
private static method onInit( )
{ dmMotion.Timer = CreateTimer( ); dmMotion.update = function dmMotion.Update; }
}
}
//! endzinc
//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=71
//TESH.alwaysfold=0
library Init initializer Set
globals
private real MAP_MIN_X
private real MAP_MAX_X
private real MAP_MIN_Y
private real MAP_MAX_Y
endglobals
function IsInMapXY takes real x , real y returns boolean
return x > MAP_MIN_X and x < MAP_MAX_X and y > MAP_MIN_Y and y < MAP_MAX_Y
endfunction
private function Set takes nothing returns nothing
set MAP_MIN_X = GetRectMinX(bj_mapInitialPlayableArea)
set MAP_MAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
set MAP_MIN_Y = GetRectMinY(bj_mapInitialPlayableArea)
set MAP_MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
endfunction
endlibrary
//***************************************************************************
//*
//* SetUnitZ - By TriggerHappy187
//*
//***************************************************************************
//*
//* Installation
//* * All you need to do is copy this script into your map and you can use
//* the provided functions.
//*
//***************************************************************************
//*
//* Requirements
//* * This requires no external systems, all it requires is JassHelper.
//*
//***************************************************************************
//
// Precautions
// * If this function is used on a point with a terarin deformation
// A desync may occur.
//
//***************************************************************************
library SetUnitZ
globals
private location heightFixer = Location(0,0)
endglobals
function GetCoordZ takes real x, real y returns real
call MoveLocation(heightFixer, x, y)
return GetLocationZ(heightFixer)
endfunction
function SetUnitZ takes unit u, real h returns nothing
local location loc = GetUnitLoc(u)
local real z = GetLocationZ(loc)
call RemoveLocation(loc)
set loc = null
call SetUnitFlyHeight(u,h-z,0.)
endfunction
//function SetUnitZ takes unit whichUnit, real height, real rate returns nothing
// if GetUnitFlyHeight(whichUnit) == 0 then
// if UnitAddAbility(whichUnit, 'Arav') then
// call UnitRemoveAbility(whichUnit, 'Arav')
// endif
// endif
// //call MoveLocation(heightFixer, GetUnitX(whichUnit), GetUnitY(whichUnit))
// call SetUnitFlyHeight(whichUnit, height-GetCoordZ(GetUnitX(whichUnit), GetUnitY(whichUnit)), rate)
//endfunction
function GetUnitZ takes unit whichUnit returns real
call MoveLocation(heightFixer, GetUnitX(whichUnit), GetUnitY(whichUnit))
return GetUnitFlyHeight(whichUnit)+GetLocationZ(heightFixer)
endfunction
endlibrary
library GetTerrainZ
// How to Implement:
//
// by D.V.D
//
// Copy this code
// Create a trigger in your map
// Change the trigger to custom script
// Paste the code into the trigger
globals
location GL = Location(0,0)
endglobals
function GetTerrainZ takes real x, real y returns real
call MoveLocation(GL, x, y)
return GetLocationZ(GL)
endfunction
function GetTerrainZLoc takes location loc returns real
call MoveLocation(GL, GetLocationX(loc), GetLocationY(loc))
return GetLocationZ(GL)
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
scope Grenade initializer Init
private keyword Data
globals
// Editable Globals
private constant integer GRENADE_ID = 'n000' // Grenade unit
private constant integer GRENADE_SFX1 = 'n001' // SFX 1
private constant integer GRENADE_SFX2 = 'n002' // SFX 2
private constant integer SPELL_ID = 'A014' // Ability ID
private constant real MAX_RANGE = 1000
private constant real MIN_RANGE = 400
private constant real MAX_HEIGHT = 400
private constant attacktype AT = ATTACK_TYPE_NORMAL
private constant damagetype DT = DAMAGE_TYPE_NORMAL
private constant weapontype WT = WEAPON_TYPE_WHOKNOWS
private constant boolean DAMAGE_SELF = false// Can it hurt player units ?
private constant boolean DAMAGE_ALLY = false// Can it hurt ally units ?
// Editable Globals
// Don't change...
private constant real PERIOD = 0.04 // Depends on what period you like ... don't moan at me if your .0001 period lags though...
private constant real SPEED = 200 * PERIOD// How fast the grenade travels per second
private Data DATA //Temp Globals
private real X //Temp Globals
private real Y //Temp Globals
private real DIST //Temp Globals
private integer COUNT = 0
private Data array GData
private timer TIMER = CreateTimer()
private location LOC = Location(0,0)
//Don't change
endglobals
private constant function AOE_Range takes integer lvl returns real
return 150 + lvl*50 *1.0
endfunction
private function MinMax takes real val,real min,real max returns real
if(min>val) then
return min
elseif(val>max) then
return max
else
return val
endif
endfunction
private function GetParabolaZ takes real x,real d,real h returns real
return 4 * h * x * (d - x) / (d * d)
endfunction // By AceHart
private function GetDamage takes integer level returns real
return GetRandomReal (10,20) + 15 * (level-1)
endfunction// I guess Flare @ TH.net helped me with this O_o...
private struct Data
unit Grenade
unit caster
player p
real x
real y
real DistCur
real DistMax
real baseH
real aoe
integer level
real cos
real sin
static group GROUP = CreateGroup()
static method Damage takes nothing returns boolean
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(u)
local Data d = DATA
local real damage = GetDamage(d.level)
local boolean dmg = false
if(DAMAGE_SELF and p==d.p)then
set dmg = true
elseif(DAMAGE_ALLY and IsPlayerAlly(p,d.p))then
set dmg = true
elseif(IsPlayerEnemy(p,d.p))then
set dmg = true
endif
if(dmg) then
call UnitDamageTarget(d.caster,u,damage,true,true,AT,DT,WT)
endif
set u = null
return false
endmethod
static method InCircle takes nothing returns boolean
local destructable d = GetFilterDestructable()
local real x = DATA.x - GetDestructableX(d)
local real y = DATA.y - GetDestructableY(d)
local real dist = x*x+y*y
set d = null
if(dist>DATA.aoe*DATA.aoe)then// or SquareRoot(dist) > AOE_RANGE either workz...
return false
else
return true
endif
endmethod
static method TreeDestroy takes nothing returns nothing
local destructable d = GetEnumDestructable()
set d = null
endmethod
method KillTrees takes real x,real y returns nothing
local rect r = Rect(x-.aoe,y-.aoe,x+.aoe,y+.aoe)
call EnumDestructablesInRect(r,Filter(function Data.InCircle),function Data.TreeDestroy)
call RemoveRect(r)
set r = null
endmethod
method Explode takes nothing returns nothing
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX1,.x,.y,0),0,1)
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX2,.x,.y,0),0,1)
set DATA = this
call GroupEnumUnitsInRange(.GROUP,.x,.y,this.aoe,Filter(function Data.Damage))
call .KillTrees(.x,.y)
call .destroy()
endmethod
method onDestroy takes nothing returns nothing
call ShowUnit(.Grenade,false)// Don't know wether this is neccesary ?
call RemoveUnit(.Grenade)
endmethod
endstruct
private function Execute takes nothing returns nothing
local integer i = 0
local Data d
local unit u
local boolean zhit
loop
exitwhen i == COUNT
set zhit = false
set d = GData[i]
set u = d.Grenade
set d.DistCur = d.DistCur + SPEED
set d.x = d.x + SPEED * d.cos
set d.y = d.y + SPEED * d.sin
if IsInMapXY(d.x,d.y) == true then
call SetUnitX(u,d.x)
call SetUnitY(u,d.y)
call SetUnitZ(u,d.baseH+GetParabolaZ(d.DistCur,d.DistMax,MAX_HEIGHT))
call MoveLocation(LOC,d.x,d.y)
if(R2I(GetUnitZ(u))==R2I(GetLocationZ(LOC)))then
// R2I because it gives me '0.001' and stuff ... so it isn't 'equal' unit height
set zhit=true
endif
if zhit==true then
set COUNT = COUNT - 1
set GData[i] = GData[COUNT]
call d.Explode()
else
set i = i + 1
endif
else
set COUNT = COUNT - 1
set GData[i] = GData[COUNT]
call d.destroy()
endif
endloop
set u = null
if COUNT == 0 then
call PauseTimer(TIMER)
endif
endfunction
private function Run takes nothing returns nothing
local Data d = Data.create()
local location l = GetSpellTargetLoc()
local real x = GetLocationX(l)
local real y = GetLocationY(l)
local real dist = 0
local real facing
call RemoveLocation(l)// do I need to 'set l = null' ?
set d.caster = GetTriggerUnit()
set l = GetUnitLoc(d.caster)
set d.baseH = GetLocationZ(l)
call RemoveLocation(l)
set l = null
set d.p = GetOwningPlayer(d.caster)
set d.x = GetUnitX(d.caster)
set d.y = GetUnitY(d.caster)
set d.level = GetUnitAbilityLevel(d.caster,SPELL_ID)
set d.aoe = AOE_Range(d.level)
set x = x - d.x
set y = y - d.y
set facing = Atan2(y,x)
set d.cos = Cos(facing)
set d.sin = Sin(facing)
set d.Grenade = CreateUnit(d.p,GRENADE_ID,d.x,d.y,facing)
call UnitAddAbility(d.Grenade,'Amrf')// I have to do this or else it goes buggy over raised terrain
call UnitRemoveAbility(d.Grenade,'Amrf')
set d.DistMax = MinMax(SquareRoot(x*x+y*y),MIN_RANGE,MAX_RANGE)
set d.DistCur = 0
set GData[COUNT] = d
set COUNT = COUNT + 1
if COUNT == 1 then
call TimerStart(TIMER,PERIOD,true,function Execute)
endif
endfunction
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call Run()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t,Condition(function Cond))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
//
//
// To Implement the spell
//
//
// Copy the following : UNITS
//
// Explosion -> 'xdum'
// Explosion SFX -> 'xsfx''
// Grenade -> ' gdum''
//
//
//
// Copy the following : ABILITy
//
// Grenade -> 'GAId'
//
//
// Copy the following : Triggers
//
// Regrow Trees
// IsDestructableTree
// InitLibrary
//
//
//
// You can change many of the grenades features, such as :
//
// max height , max/min range , aoe range
// damage , wether it can hurt allied or player units
//
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Table
//***************************************************************
//* Table object 3.1
//* ------------
//*
//* set t=Table.create() - instanceates a new table object
//* call t.destroy() - destroys it
//* t[1234567] - Get value for key 1234567
//* (zero if not assigned previously)
//* set t[12341]=32 - Assigning it.
//* call t.flush(12341) - Flushes the stored value, so it
//* doesn't use any more memory
//* t.exists(32) - Was key 32 assigned? Notice
//* that flush() unassigns values.
//* call t.reset() - Flushes the whole contents of the
//* Table.
//*
//* call t.destroy() - Does reset() and also recycles the id.
//*
//* If you use HandleTable instead of Table, it is the same
//* but it uses handles as keys, the same with StringTable.
//*
//* You can use Table on structs' onInit if the struct is
//* placed in a library that requires Table or outside a library.
//*
//* You can also do 2D array syntax if you want to touch
//* mission keys directly, however, since this is shared space
//* you may want to prefix your mission keys accordingly:
//*
//* set Table["thisstring"][ 7 ] = 2
//* set Table["thisstring"][ 5 ] = Table["thisstring"][7]
//*
//***************************************************************
//=============================================================
globals
private constant integer MAX_INSTANCES=8100 //400000
//Feel free to change max instances if necessary, it will only affect allocation
//speed which shouldn't matter that much.
//=========================================================
private hashtable ht = InitHashtable()
endglobals
private struct GTable[MAX_INSTANCES]
method reset takes nothing returns nothing
call FlushChildHashtable(ht, integer(this) )
endmethod
private method onDestroy takes nothing returns nothing
call this.reset()
endmethod
endstruct
//Hey: Don't instanciate other people's textmacros that you are not supposed to, thanks.
//! textmacro Table__make takes name, type, key
struct $name$ extends GTable
method operator [] takes $type$ key returns integer
return LoadInteger(ht, integer(this), $key$)
endmethod
method operator []= takes $type$ key, integer value returns nothing
call SaveInteger(ht, integer(this) ,$key$, value)
endmethod
method flush takes $type$ key returns nothing
call RemoveSavedInteger(ht, integer(this), $key$)
endmethod
method exists takes $type$ key returns boolean
return HaveSavedInteger( ht, integer(this) ,$key$)
endmethod
static method flush2D takes string firstkey returns nothing
call $name$(- StringHash(firstkey)).reset()
endmethod
static method operator [] takes string firstkey returns $name$
return $name$(- StringHash(firstkey) )
endmethod
endstruct
//! endtextmacro
//! runtextmacro Table__make("Table","integer","key" )
//! runtextmacro Table__make("StringTable","string", "StringHash(key)" )
//! runtextmacro Table__make("HandleTable","handle","GetHandleId(key)" )
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library MemoryLeakHelper initializer Init requires Table
// ==================================
// Give credits to Mr.Malte when used!
//===========================================================================
// Information:
//==============
//
// There are things called 'memory Leaks'. When you create a group or use a location
// without destroying it, you will cause lag that stays in the whole game.
// If you implement this library into your map it will automatically fix a big part
// of those memory leaks, so reduce the lag extremely.
// This should mainfully be used by GUI-users because the system is designed for them.
//
// Of course no system can work totally automatically.
// But there is only one thing you have to do in order to prevent bugs:
// If you make groups or locations that have to be filled for more than CLEAN_UP_INTERVAL seconds
// you have to save them with the code:
//
// call ProtectHandle(XXX)
//
// Where XXX is filled with your variable. Otherwise that variable gets destroyed
// automatically. You can also fill in XXX with
//
// GetLastCaughtHandle()
//
// But if you save the things in a variable, I'd recommend to directly put the
// variable into the brackets. Note: GUI variables have the prefix 'udg_' in JASS.
//
// This gives the 'Do Nothing' function in GUI a sense!
// When you call DoNothing, all data that were caught by this system
// will be destroyed in CLEAN_UP_INTERVAL seconds, ignoring how big
// the number of caught handles is. This will not work, if the system is
// already cleaning up.
//===========================================================================
// Implementation:
//===============
//
// The easiest thing is to directly implement this thing into your map, when you start making
// it, so you don't have to look over your globals and use ProtectHandle on them.
// These are the steps you have to do to clear the memory leaks:
//
// 1. Download a tool called 'JassNewGen', and unpack it somewhere. You need that
// edit to use this tool. The 'JassNewGen' is used very commonly and offers other
// nice features. You can find it at:
// [url]http://www.wc3c.net/showthread.php?t=90999[/url]
// 2. Make a new trigger, and convert it to custom text. Insert everything
// the library contains into that trigger.
//
// 3. Download a system called 'Table' from this link:
// [url]http://www.wc3c.net/showthread.php?t=101246[/url]
// Do the same installation stuff for 'Table' as for this system.
//
// 4. Save your map and enjoy :-)
//
// Note: Instead of doing 2 and 3 you can also copy and paste the folder 'MemoryLeakHelper'
// from the example map.
//===========================================================================
// How bad are memory leaks?
//==========================
// If you don't remove memory leaks, they suck memory:
//
// Location: 0.361 kb
// Group: 0.62 kb + 0.040 kb for each unit in the group.
// Effect: 11.631 kb
//
// Both, locations and groups are used very frequently. So when you don't fix those memory leaks,
// you will experience lag.
// When you want to see, how useful this is for your map, implement it
// and write 'call DisplayLeaks()' into a custom script that is fired when
// they game ends.
//===========================================================================
// Changelog:
//===========
// v1.00 --- first version
// v1.01 --- able to detect special effects, too now.
// v1.02 --- made the system safer and reduced the number of variables to protect greatly.
// v1.03 --- Gave a sense to 'DoNothing'* GUI function and made the Pass Data part
// more accurate, so the time until data get destroyed are much more explicit
// now.
// v1.04 --- Added the very important constant MAX_LEAK_INSTANCES
//
// *if you don't want it to be hooked, comment line 350.
//===========================================================================
// FAQ:
// ====
// 1. Why don't you hook functions like GetLocationX or the ForGroup without BJ?
//
// Answer: Well, in jass you would never destroy groups, rather have one global group
// and clear/recycle it. But GUI always creates new groups with the functions.
// So actually, jass groups don't have to be destroyed.
// And special effects are mostly instantly destroyed and locations are never used.
// So I don't want to endanger breaking jass systems, I rather make it for GUI, where it is
// really useful and neccessary
//
// 2. Why should I protect my variables instead of killing my leaks?
//
// Answer: In GUI, unitgroup effect and location variables are actually just used
// for destroying stuff. It is rare that you really want to keep the groups.
// So in fact, it is like one-hundred times less frequent that you want to keep
// your data instead of destroying it.
//
// 3. I can't use jass. How can this system be useful for me?
//
// Answer: This system works mainly automatically; You just have to use jass very rarely (and then a simple function).
// The functions you need are:
//
// ProtectVariable(udg_###)
// GetLastCaughtHandle()
//
// where ProtectVariable saves something you want to keep from getting destroyed. Just replace ### with your
// variable name. NOTE: You don't have to protect the variable, when you want to keep the data inside less than
// CLEAN_UP_INTERVAL seconds.
//
// and where GetLastCaughtHandle responses to the handle* that was used lastly.
// That can be for example the point where you just spawned a unit.
//
// * 'handle' means a specialeffect, a location or a unitgroup
//
// 4. If you give functions like 'DelayMMH', why don't you add functions like 'Disable/EnableMMH'?
//
// Answer: Well, I want to protect the user. You do not need Disable/Enable functions.
// To me the danger is too big, that you forget to activate it again or do
// something like that. DelayMMH is totally enough if you don't want this system
// to affect the code that comes next. Also that prevents, that there are
// spells like 'Trojan Horses' that get too much access to this and can
// change it's infrastructure.
//
//===========================================================================
// Functions:
//==========
// ProtectHandle : Saves a handle from getting destroyed
// ProtectVariable : Same.
// DoNothing() : Destroys all data caught by the system right now in X seconds.
// DelayMMD() : Stops the system working until the trigger ends/next wait *
//
// * This is as fast as an automatic memory leak destroyer can get. Why should
// you want to disable the system? Because it offers the possibilty to make things
// more efficient. I don't want to say, this is unefficient, because it is not.
// But this will destroy leaks like 10% slower.
//
//===========================================================================
globals
// The system fires when you do something that creates a leak.
// The data that cause leak are saved in a variable then.
// And every CLEAN_UP_INTERVAL seconds those data are destroyed.
// This shouldn't be too high, or too low.
private constant real CLEAN_UP_INTERVAL = 120.
// If this is set to true, the system will work more slowly (but you wont notice)
// and count, how much memory this system was able to save.
// This value is display by the function DisplayLeaks() then.
// WARNING: This sucks a lot of performance. I would ONLY use it when you want
// to test, if this is useful for your map. Later set it to false.
private constant boolean DISPLAY_SAVED_MEMORY = false
// The Data are only cleaned up, when that many handles were caught
private constant integer MIN_LEAK_NUMBER = 1750
// How often are data passed to the destroyer?
// Leaks stay for a random time between CLEAN_UP_INTERVAL and CLEAN_UP_INTERVAL+PASS_INTERVAL
// in the game
private constant real PASS_INTERVAL = 2.5
// Memory leaks occur pretty frequently. When a leak is caught it is saved in
// an array. But the array can't have more than MAX_LEAK_INSTANCES instances, so
// if more than MAX_LEAK_INSTANCES memory leaks occur during a destroy interval,
// the system fails.
private constant integer MAX_LEAK_INSTANCES = 60000
endglobals
globals
private HandleTable IndexData
private HandleTable IsSaved
//! textmacro MemoryLeakVars takes NAME, TYPE
private integer Caught$NAME$Leaks = 0
private $TYPE$ array $NAME$LeakData[MAX_LEAK_INSTANCES]
private integer $NAME$DestroyCount = 0
private $TYPE$ array $NAME$DestroyData[MAX_LEAK_INSTANCES]
//! endtextmacro
//! runtextmacro MemoryLeakVars("Location","location")
//! runtextmacro MemoryLeakVars("Effect","effect")
//! runtextmacro MemoryLeakVars("Group","group")
private integer DestroyedLeaks = 0
private integer CaughtLeaks = 0
private integer DestroyedLeaksUser = 0
private handle LastCaught
private timer PassTimer = CreateTimer()
private timer CleanTimer = CreateTimer()
private timer DelayTimer = CreateTimer()
private boolean IsDestroying = false
private real SavedMemory = 0.
private real LastCheckedGroupMemoryUsage = 0.
private boolean DestroyThreadRunning = false
private boolean Disabled = false
// These values were found out in a big leak test by gekko.
private constant real LOCATION_MEMORY_USAGE = 0.361
private constant real GROUP_MEMORY_USAGE = 0.62
private constant real GROUP_UNIT_MEMORY_USAGE = 0.040
private constant real EFFECT_MEMORY_USAGE = 11.631
private constant real REMOVED_EFFECT_MEMORY_USAGE = 0.066
endglobals
// ======================================
// ============= Basic Code =============
// ======================================
function GetLastCaughtHandle takes nothing returns handle
return LastCaught
endfunction
function ProtectHandle takes handle h returns nothing
set IsSaved[h] = 1
endfunction
function ProtectVariable takes handle h returns nothing
set IsSaved[h] = 1
endfunction
private function EnableMMH takes nothing returns nothing
set Disabled = false
endfunction
function DelayMMH takes nothing returns nothing
set Disabled = true
call TimerStart(DelayTimer,0.00,false,function EnableMMH)
endfunction
function DisplayLeaks takes nothing returns nothing
call ClearTextMessages()
call BJDebugMsg("======= MemoryLeakHelper =======")
call BJDebugMsg("Destroyed Leaks: "+I2S(DestroyedLeaks))
call BJDebugMsg("Destroyed Leaks by user: "+I2S(DestroyedLeaksUser))
call BJDebugMsg("Percentage System: "+R2S(I2R(DestroyedLeaks)/I2R(DestroyedLeaks+DestroyedLeaksUser)*100.)+"%")
call BJDebugMsg("Percentage User: "+R2S(I2R(DestroyedLeaksUser)/I2R(DestroyedLeaks+DestroyedLeaksUser)*100.)+"%")
call BJDebugMsg("Leaks until next destroy: "+I2S(MIN_LEAK_NUMBER-CaughtLeaks))
call BJDebugMsg(" === In Destroy Queue === ")
call BJDebugMsg(" Group Leaks: "+I2S(GroupDestroyCount))
call BJDebugMsg(" Location Leaks: "+I2S(LocationDestroyCount))
call BJDebugMsg(" Effect Leaks: "+I2S(EffectDestroyCount))
call BJDebugMsg(" === Not in Destroy Queue yet === ")
call BJDebugMsg(" Group Leaks: "+I2S(CaughtGroupLeaks))
call BJDebugMsg(" Location Leaks: "+I2S(CaughtLocationLeaks))
call BJDebugMsg(" Effect Leaks: "+I2S(CaughtEffectLeaks))
call BJDebugMsg("Time until next PassSequence: "+I2S(R2I(TimerGetRemaining(PassTimer)+0.5))+" seconds.")
call BJDebugMsg(" ")
if DISPLAY_SAVED_MEMORY then
call BJDebugMsg("All in all the MemoryLeakHelper could release "+R2S(SavedMemory)+" kb of memory.")
endif
call BJDebugMsg("================================")
endfunction
private function GroupGetMemoryUsageEnum takes nothing returns nothing
set LastCheckedGroupMemoryUsage = LastCheckedGroupMemoryUsage + GROUP_UNIT_MEMORY_USAGE
endfunction
function GroupGetMemoryUsage takes group g returns real
set LastCheckedGroupMemoryUsage = 0.
call ForGroup(g,function GroupGetMemoryUsageEnum)
return LastCheckedGroupMemoryUsage + GROUP_MEMORY_USAGE
endfunction
//! textmacro ResponseOnLeak takes NAME, VALUE
private function Catch$NAME$ takes $VALUE$ l returns nothing
set LastCaught = l
if Disabled then
return
elseif Caught$NAME$Leaks == MAX_LEAK_INSTANCES then
debug call BJDebugMsg("MemoryLeakHelper: Failed to store leak because of size limitations")
return
endif
if IndexData.exists(l) == false then
//call BJDebugMsg("Caught $NAME$")
set Caught$NAME$Leaks = Caught$NAME$Leaks + 1
set $NAME$LeakData[Caught$NAME$Leaks] = l
set IndexData[l] = Caught$NAME$Leaks
endif
endfunction
private function AddTo$NAME$DestroyQueue takes $VALUE$ l returns nothing
set $NAME$DestroyCount = $NAME$DestroyCount + 1
set $NAME$DestroyData[$NAME$DestroyCount] = l
set IndexData[l] = $NAME$DestroyCount*-1 // Put his to negative, so we know that this is used in the DestroyQueue now.
endfunction
private function Release$NAME$ takes $VALUE$ l returns nothing
local integer index
if IsDestroying == false and IndexData.exists(l) then
set index = IndexData[l]
// If this is true, the index wasn't put to a destroy queue yet.
if index > 0 then
set $NAME$LeakData[index] = $NAME$LeakData[Caught$NAME$Leaks]
set Caught$NAME$Leaks = Caught$NAME$Leaks - 1
else
set index = index * -1
set $NAME$DestroyData[index] = $NAME$DestroyData[$NAME$DestroyCount]
set $NAME$DestroyCount = $NAME$DestroyCount - 1
endif
call IndexData.flush(l)
set DestroyedLeaksUser = DestroyedLeaksUser + 1
endif
endfunction
//! endtextmacro
//! runtextmacro ResponseOnLeak("Location","location")
//! runtextmacro ResponseOnLeak("Group","group")
//! runtextmacro ResponseOnLeak("Effect","effect")
private function DestroyMemoryLeaks takes nothing returns nothing
set IsDestroying = true
//call BJDebugMsg("DESTROYING Memory Leaks")
//! textmacro DestroyLeaks takes NAME, DESTROYCALL, MEMORYUSAGE
set DestroyedLeaks = DestroyedLeaks + $NAME$DestroyCount
loop
exitwhen $NAME$DestroyCount == 0
if DISPLAY_SAVED_MEMORY then
set SavedMemory = SavedMemory + $MEMORYUSAGE$
endif
call $DESTROYCALL$($NAME$DestroyData[$NAME$DestroyCount])
call IndexData.flush($NAME$DestroyData[$NAME$DestroyCount])
set $NAME$DestroyCount = $NAME$DestroyCount - 1
endloop
//! endtextmacro
//! runtextmacro DestroyLeaks ("Group","DestroyGroup","GroupGetMemoryUsage(GroupDestroyData[GroupDestroyCount])")
//! runtextmacro DestroyLeaks ("Location","RemoveLocation","LOCATION_MEMORY_USAGE")
//! runtextmacro DestroyLeaks ("Effect","DestroyEffect","EFFECT_MEMORY_USAGE")
set IsDestroying = false
set DestroyThreadRunning = false
//call StartPassTimer.execute() // Strange. This causes bugs sometimes and the function isn't called
// This is slower, but safe.
call ExecuteFunc("StartPassTimer")
endfunction
function StartDestroyThread takes nothing returns nothing
if DestroyThreadRunning == false then
set DestroyThreadRunning = true
call TimerStart(CleanTimer,CLEAN_UP_INTERVAL,false,function DestroyMemoryLeaks)
call PauseTimer(PassTimer)
endif
endfunction
hook DoNothing StartDestroyThread
// We want that the user doesn't have to protect too many variables, but all the variables that are filled longer
// than CLEAN_UP_INTERVAL seconds. But what, when the handle thing is put into the destroy stack and the next destroy is
// in 5 seconds, because the last one was 15 seconds ago? We can simply avoid something like that by using a 2-step-system
// that goes sure, the handle is only destroyed when it passed the CLEAN_UP_INTERVAL twice.
// Having two kinds of variables is simply easier and more efficient than having another variable that refers to
// how many times the handle passed the timer; If it isn't passed/cleared in the Interval then, we can't loop
// that easily through the data and we'd have to fix gaps later; That would suck a lot of performacne.
private function PassMemoryLeaks takes nothing returns nothing
//call BJDebugMsg("PassMemoryLeaks")
//! textmacro PassLeaks takes NAME
set CaughtLeaks = CaughtLeaks + Caught$NAME$Leaks
//call BJDebugMsg("Caught $NAME$s: "+I2S(Caught$NAME$Leaks))
loop
exitwhen Caught$NAME$Leaks < 1
if IsSaved.exists($NAME$LeakData[Caught$NAME$Leaks]) == false and $NAME$LeakData[Caught$NAME$Leaks] != null then
call AddTo$NAME$DestroyQueue($NAME$LeakData[Caught$NAME$Leaks])
endif
set $NAME$LeakData[Caught$NAME$Leaks] = null
set Caught$NAME$Leaks = Caught$NAME$Leaks - 1
endloop
//! endtextmacro
//! runtextmacro PassLeaks ("Group")
//! runtextmacro PassLeaks ("Location")
//! runtextmacro PassLeaks ("Effect")
if CaughtLeaks > MIN_LEAK_NUMBER then
set CaughtLeaks = 0
//call BJDebugMsg("Caught Leaks: "+I2S(MIN_LEAK_NUMBER))
//call BJDebugMsg("Now start Destroy Timer")
set DestroyThreadRunning = true
call TimerStart(CleanTimer,CLEAN_UP_INTERVAL,false,function DestroyMemoryLeaks)
// We have to pause this timer a bit; Otherwise it would break the CLEAN_UP_INTERVAL rule.
call PauseTimer(PassTimer)
endif
endfunction
// =================================
// ============= Usage =============
// =================================
private function PP takes location source, real dist, real angle returns nothing
call CatchLocation(source)
endfunction
private function CU takes integer count, integer unitId, player p, location l, real face returns nothing
call CatchLocation(l)
endfunction
private function IPO takes unit k, string order, location l returns nothing
call CatchLocation(l)
endfunction
private function SUP takes unit who, location l returns nothing
call CatchLocation(l)
endfunction
private function SUF takes unit who, location l, real dur returns nothing
call CatchLocation(l)
endfunction
private function GUR takes real radius, location l, boolexpr filter returns nothing
call CatchLocation(l)
endfunction
private function CUF takes integer count, integer unitId, player whichPlayer, location loc, location lookAt returns nothing
call CatchLocation(loc)
call CatchLocation(lookAt)
endfunction
hook PolarProjectionBJ PP
hook CreateNUnitsAtLoc CU
hook CreateNUnitsAtLocFacingLocBJ CUF
hook IssuePointOrderLocBJ IPO
hook SetUnitPositionLoc SUP
hook SetUnitFacingToFaceLocTimed SUF
hook GetUnitsInRangeOfLocMatching GUR
hook RemoveLocation ReleaseLocation
private function FG takes group g, code callback returns nothing
call CatchGroup(g)
endfunction
hook ForGroupBJ FG // :D This should catch all GUI usages for groups.
hook GroupPickRandomUnit CatchGroup
hook CountUnitsInGroup CatchGroup
hook DestroyGroup ReleaseGroup
private function ASETU takes string bla, widget d, string blu returns nothing
// We can not catch THIS effect, but the effect that was created before.
// So we can destroy all SpecialEffects excpet one.
call CatchEffect(GetLastCreatedEffectBJ())
endfunction
private function ASE takes location where, string modelName returns nothing
call CatchLocation(where)
call CatchEffect(GetLastCreatedEffectBJ())
endfunction
hook AddSpecialEffectLocBJ ASE
hook AddSpecialEffectTargetUnitBJ ASETU
hook DestroyEffect ReleaseEffect
hook DestroyEffectBJ ReleaseEffect
// When I want to make the timer run the PassMemoryLeaks things, I have to use an .execute command which requires an extra func.
function StartPassTimer takes nothing returns nothing
//call BJDebugMsg("Restarting PassTimer")
call TimerStart(PassTimer,PASS_INTERVAL,true,function PassMemoryLeaks)
endfunction
private function Init takes nothing returns nothing
set IndexData = HandleTable.create()
set IsSaved = HandleTable.create()
call StartPassTimer()
endfunction
endlibrary