Name | Type | is_array | initial_value |
ABI_Point_Position | location | Yes | |
Act1_Tele | location | No | |
Act2_Tele | location | No | |
Act3_loc | location | No | |
Act3_Tele | location | No | |
ApocCaster | unit | No | |
Archer_Player | player | No | |
Arma_Hero | unit | No | |
Arrow_DMG | real | No | |
AS | integervar | No | |
AS_Angle | real | Yes | |
AS_Animation | real | No | |
AS_Damage | real | No | |
AS_Defense_fake | integer | Yes | |
AS_Distance | real | Yes | |
AS_Equation | real | Yes | |
AS_FLY | real | Yes | |
AS_Formula | real | Yes | |
AS_Group | group | Yes | |
AS_Hero | unit | Yes | |
AS_Max_Height | real | Yes | |
AS_Off | boolean | Yes | |
AS_Point | location | Yes | |
AS_Skip | integer | No | |
AS_Special | effect | Yes | |
AS_Speed | real | Yes | |
AS_Stable_Distance | real | Yes | |
AS_Times | integer | No | |
AS_X_Special | effect | Yes | |
Ass_dmg | real | No | |
Assassing | group | No | |
AuraAbaddon | unit | No | |
Baal_Group | group | Yes | |
Baal_Killer | unit | Yes | |
BL_Boolean | boolean | Yes | |
BL_Caster | unit | Yes | |
BL_Damage | real | Yes | |
BL_Dummy | unit | Yes | |
BL_Facing | real | Yes | |
BL_Group | group | Yes | |
BL_Height | real | Yes | |
BL_Index | integer | Yes | |
BL_Range | real | Yes | |
BL_SFX | effect | Yes | |
BL_SFXType | string | No | |
BL_Speed | real | Yes | |
BL_Targets | integer | Yes | |
BL_TempPoint | location | Yes | |
BL_Timer | real | Yes | |
Bonus_Amount | integer | No | |
Bonus_Unit | unit | No | |
Boss_loc | location | No | |
BS_Damage | real | No | |
CI_Dummies | group | No | |
CI_Frozen | group | No | |
CI_Group | group | No | |
CI_Hash | hashtable | No | |
CI_Reals | real | Yes | |
CI_SFX_Group | group | No | |
CI_Terrain_Types | terraintype | Yes | |
CItemType | itemcode | Yes | |
Class_List_Array | unitcode | Yes | |
Class_List_Array_BitsRq | integer | No | |
CleanedItem | item | Yes | |
Clear_Text | real | No | |
Corpsegroup | group | No | |
CreepTable | hashtable | No | |
DE_AOE | real | Yes | |
DE_BaseVelocity | real | Yes | |
DE_CurrentDeathTimer | real | Yes | |
DE_CurrentDuration | real | Yes | |
DE_CurrentEffect | effect | Yes | |
DE_CurrentShardDelay | real | Yes | |
DE_CurrentZ | real | Yes | |
DE_Duration | real | Yes | |
DE_GravitatedShard | group | No | |
DE_HealthDamage | real | Yes | |
DE_LastNode | integer | No | |
DE_ManaDamage | real | Yes | |
DE_MapMaxX | real | No | |
DE_MapMaxY | real | No | |
DE_MapMinX | real | No | |
DE_MapMinY | real | No | |
DE_Mass | real | Yes | |
DE_NextNode | integer | Yes | |
DE_NodeNumber | integer | No | |
DE_OriginalCaster | unit | Yes | |
DE_Portal | unit | Yes | |
DE_PortalHeight | real | Yes | |
DE_PortalX | real | Yes | |
DE_PortalY | real | Yes | |
DE_PortalZ | real | Yes | |
DE_PrevNode | integer | Yes | |
DE_Radius | real | Yes | |
DE_RecycleableNodes | integer | No | |
DE_RecycleNodes | integer | Yes | |
DE_ShardAOE | real | Yes | |
DE_ShardScale | real | Yes | |
DE_SpawnRate | real | Yes | |
DE_SpellCounter | integer | No | |
DE_StageID | integer | Yes | |
DE_TempGroup | group | No | |
DE_Unit | unit | Yes | |
DE_XVelocity | real | Yes | |
DE_YVelocity | real | Yes | |
DE_ZLoc | location | No | |
DE_ZVelocity | real | Yes | |
Desert_loc | location | No | |
Door_loc | location | No | |
DR_Dummy_Group | group | No | |
DR_Group | group | No | |
DR_Hash | hashtable | No | |
DR_Reals | real | Yes | |
Dungeon_loc | location | No | |
DW_Effects | group | No | |
DW_Group | group | No | |
DW_Hash | hashtable | No | |
DW_Reals | real | Yes | |
DyingUnit | unit | Yes | |
FD_AoE | real | Yes | |
FD_Caster | unit | Yes | |
FD_Damage | real | Yes | |
FD_DegreeInterval | real | Yes | |
FD_Degrees | real | Yes | |
FD_Dummy | unit | Yes | |
FD_Duration | real | Yes | |
FD_Index | integer | Yes | |
FD_Index_maxSize | integer | No | |
FD_Index_Size | integer | No | |
FD_LOOP | integervar | No | |
FD_Offset | real | Yes | |
FD_TempInt | integer | No | |
FD_TempLoc | location | Yes | |
FD_TempLoc3 | location | Yes | |
Fear | group | No | |
FearNONE | group | No | |
FH_Charge_Group | group | No | |
FH_Group | group | No | |
FH_Hash | hashtable | No | |
FH_Knockback_Group | group | No | |
FH_Loop_Group_1 | group | No | |
FH_Loop_Group_2 | group | No | |
FH_Reals | real | Yes | |
FH_Unit_Type | unitcode | No | |
Floating_Text | location | No | |
Fog_loc | location | No | |
Fok_DMG | real | No | |
fokGroup | group | No | |
fokloc | location | No | |
Frost_Dmg | real | No | |
Frost_group | group | No | |
Frost_loc | location | No | |
Frost_unit | unit | No | |
FS_AoE | real | Yes | |
FS_Caster | unit | Yes | |
FS_CasterPoint | location | Yes | |
FS_Damage | real | Yes | |
FS_Index | integer | Yes | |
FS_TempGroup | group | Yes | |
FW_AoE | real | No | |
FW_Caster | unit | Yes | |
FW_DOT | real | Yes | |
FW_Dur | real | Yes | |
FW_Effect1 | effect | Yes | |
FW_Effect2 | effect | Yes | |
FW_Index | integer | Yes | |
FW_Index_maxSize | integer | No | |
FW_Index_Size | integer | No | |
FW_IntialDamage | real | Yes | |
FW_LOOP | integervar | No | |
FW_TempInt | integer | No | |
group | group | No | |
HashTable | hashtable | Yes | |
Hero | unit | Yes | |
Hero_loc | location | No | |
Hero_One | unit | No | |
HeroAttributeBonus | integer | Yes | |
HeroDied | dialog | No | |
HeroRespawn | unit | No | |
HeroReviveTimer | timer | Yes | |
HEROWAIT | integer | No | |
HL_AttackType | attacktype | No | |
HL_Damage | real | No | |
HL_DamageType | damagetype | No | |
HL_DestroyTrees | boolean | No | |
HL_Heal | real | No | |
HL_Level | integer | No | |
HL_Loop | integer | No | |
HL_Range | real | No | |
HL_TargetPoint | location | No | |
HL_TempGroup | group | No | |
HL_TempPoint | location | No | |
HR_AoE | real | Yes | |
HR_Caster | unit | Yes | |
HR_Damage | real | Yes | |
HR_Degree | real | Yes | |
HR_Dur | real | Yes | |
HR_Index | integer | Yes | |
HR_Index_maxSize | integer | No | |
HR_Index_Size | integer | No | |
HR_LOOP | integervar | No | |
HR_Offset | real | Yes | |
HR_TempLoc1 | location | Yes | |
HR_TempLoc2 | location | Yes | |
HR_TempLoc3 | location | Yes | |
HR_TempLoc4 | location | Yes | |
HR_TempLoc5 | location | Yes | |
HSS_CanUseTheSameHeroes | boolean | No | |
HSS_HeroesLeft | integer | No | |
HSS_Integer | integer | Yes | |
HSS_Player_CurrentIndex | integer | Yes | |
HSS_Player_Multiboard | multiboard | Yes | |
HSS_Player_ViewingMultiboard | boolean | Yes | |
HSS_PlayerGroup | force | No | |
HuntGKills | integer | No | |
IL_Angle | real | Yes | |
IL_AoE | real | Yes | |
IL_Caster | unit | Yes | |
IL_CasterPoint | location | Yes | |
IL_Counter | integer | Yes | |
IL_Damage | real | Yes | |
IL_DestroyTrees | boolean | No | |
IL_End | integer | Yes | |
IL_Index | integer | Yes | |
IL_Size | real | Yes | |
IL_TargetPoint | location | Yes | |
IL_TempGroup | group | Yes | |
IL_TempPoint | location | Yes | |
Interval | real | No | |
Item_List_Array | itemcode | Yes | |
Item_List_Array_BitsRq | integer | No | |
ItemCleanupFlag | boolean | No | |
ItemCleanupTimer | timer | No | |
ItemsToClean | integer | No | |
KnifeDmg | real | No | |
loc | location | No | |
Loop | integervar | No | |
LoopA | integervar | No | |
loopA | integervar | No | |
LoopInt1 | integer | No | |
LoopInt2 | integer | No | |
LoopInt3 | integer | No | |
LS_AoE | real | Yes | |
LS_Caster | unit | Yes | |
LS_Damage | real | Yes | |
LS_DegreeLength | real | Yes | |
LS_Degrees | real | Yes | |
LS_Dur | real | Yes | |
LS_Index | integer | Yes | |
LS_Index_maxSize | integer | No | |
LS_Index_Size | integer | No | |
LS_LOOP | integervar | No | |
LS_Offset | real | Yes | |
LS_TempInt | integer | No | |
LS_TempLoc | location | Yes | |
LS_TempLoc2 | location | Yes | |
M_Boolean | boolean | Yes | |
M_Caster | unit | Yes | |
M_Damage | real | Yes | |
M_Delay | real | Yes | |
M_Index | integer | Yes | |
M_Point | location | Yes | |
M_Radius | real | Yes | |
M_SFX | effect | Yes | |
M_Speed | real | Yes | |
Manyshot | integer | No | |
ManyshotA | integervar | No | |
ManyshotCaster | unit | Yes | |
ManyshotLevel | integer | Yes | |
ManyshotOn | boolean | Yes | |
ManyshotSkip | integer | No | |
Map_Creator_Name | string | No | |
Meteor_group | group | No | |
Meteor_loc | location | No | |
MI_Group | group | No | |
MI_Hash | hashtable | No | |
MI_Lightning | string | No | |
MI_Reals | real | Yes | |
MI_Unit_Type | unitcode | No | |
MultiplierAoePerLevelINT | integer | No | |
MultiplierPerLevelINT | integer | No | |
Nest_Raptor | unitcode | No | |
NPS_Buffer_Bits | string | No | |
NPS_Buffer_Ptr | integer | No | |
NPS_CMap | string | No | |
NPS_CMap_Bits | string | Yes | |
NPS_CMap_BitsRq_Total | integer | No | |
NPS_CMap_Char | string | Yes | |
NPS_CMap_Int | integer | Yes | |
NPS_Data_Bits | string | Yes | |
NPS_Data_EntryCount | integer | No | |
NPS_Data_Error_Bits | integer | No | |
NPS_Data_Int | integer | Yes | |
NPS_Data_Int_BitsRq | integer | Yes | |
NPS_Password | string | No | |
NPS_Password_Color | string | No | |
NW_Dummies | group | No | |
NW_Hash | hashtable | No | |
NW_Lightning | string | No | |
NW_Loop | group | No | |
NW_Reals | real | Yes | |
Oasis_loc1 | location | No | |
Oasis_loc2 | location | No | |
OURTIMER | timer | Yes | |
PE_Chance | integer | No | |
PE_Chance2 | integer | No | |
Player_Rev | player | Yes | |
PlayerNumber | integer | No | |
Quest | quest | Yes | |
QuestEffect | effect | Yes | |
QuestReq | questitem | Yes | |
Raptor_Spawn | unit | No | |
ReadInteger | integer | No | |
RealDmg | real | No | |
Regen_Heal | real | No | |
Regen_Length | timer | No | |
Rep_int | integer | No | |
Rep_int2 | integer | No | |
Rep_Player | player | No | |
Rep_Point | location | No | |
Rep_Unit | unit | No | |
Rep_Unit2 | unit | No | |
RS_Animation_Speed | real | No | |
RS_Attack_Type | attacktype | No | |
RS_Caster | unit | Yes | |
RS_Current_Index | integer | No | |
RS_Damage | real | Yes | |
RS_Damage_Type | damagetype | No | |
RS_Effect | string | Yes | |
RS_Index | integer | Yes | |
RS_Index_Size | integer | No | |
RS_Level | integer | No | |
RS_Loop | integervar | No | |
RS_Max_Index | integer | No | |
RS_Slashes | integer | Yes | |
RS_Target | unit | Yes | |
RS_Transparency | real | No | |
RS_Weapon_Effect | effect | Yes | |
SpiderDen | location | No | |
TauntDmg | real | Yes | |
Tauntgroup | group | No | |
Tauntloc | location | No | |
Temp_Group_1 | group | No | |
Temp_Group_2 | group | No | |
Temp_Integer_1 | integer | No | |
Temp_Integer_2 | integer | No | |
Temp_Lightning_1 | lightning | No | |
Temp_Loc_1 | location | No | |
Temp_Loc_2 | location | No | |
Temp_Loc_3 | location | No | |
Temp_Loc_4 | location | No | |
Temp_Point | location | No | |
Temp_Point2 | location | No | |
Temp_Real_1 | real | No | |
Temp_Real_2 | real | No | |
Temp_Real_3 | real | No | |
Temp_Real_4 | real | No | |
Temp_Real_5 | real | No | |
Temp_Real_6 | real | No | |
Temp_Unit_1 | unit | No | |
Temp_Unit_2 | unit | No | |
Temp_Unit_3 | unit | No | |
TempBoolean | boolean | No | |
TempIndex | integer | No | |
TempInt | integer | No | |
TempInt1 | integer | No | |
TempInt2 | integer | No | |
TempLoc | location | No | |
TempLoc1 | location | No | |
TempLoc2 | location | No | |
TempLoc3 | location | No | |
TempLoc4 | location | No | |
TempLoc6 | location | Yes | |
TempString | string | No | |
Terrain_Hash | hashtable | No | |
Text_Display_Time | real | No | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitIndexLock | integer | Yes | |
Waypoint_Start | location | No | |
Waypoint_Tele | location | No | |
Waypoint_Tele2 | location | No | |
Waypoint_Tele3 | location | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library RespawnSystem initializer Init
globals
//***************************************************************************
/* Edit timers here */
private constant real RESPAWN_TIMER_HERO = 300
private constant real RESPAWN_TIMER_UNIT = 120
/* Do not edit below */
/* If you need anything else changed */
//***************************************************************************
endglobals
globals
private hashtable hash = InitHashtable()
endglobals
private function Revive takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer key = GetHandleId(t)
local player p = LoadPlayerHandle(hash, key, -1)
local integer id = LoadInteger(hash, key, -2)
local real x = LoadReal(hash, key, -3)
local real y = LoadReal(hash, key, -4)
local real a = LoadReal(hash, key, -5)
local unit u
if not (x == 0 and y == 0 and a == 0) then
if LoadBoolean(hash, key, -6) then
call ReviveHero(LoadUnitHandle(hash, key, -7),x,y, false)
else
set u = CreateUnit(p,id,x,y,a)
call SaveReal(hash, GetHandleId(u), 0, x)
call SaveReal(hash, GetHandleId(u), 1, y)
call SaveReal(hash, GetHandleId(u), 2, a)
endif
endif
call DestroyTimer(t)
set t = null
set p = null
set u = null
endfunction
private function TryRevive takes nothing returns nothing
local timer t = CreateTimer()
local unit u = GetTriggerUnit()
local integer key = GetHandleId(t)
call SavePlayerHandle(hash, key, -1, GetOwningPlayer(u))
call SaveInteger(hash, key, -2, GetUnitTypeId(u))
call SaveReal(hash, key, -3, LoadReal(hash, GetHandleId(u), 0))
call SaveReal(hash, key, -4, LoadReal(hash, GetHandleId(u), 1))
call SaveReal(hash, key, -5, LoadReal(hash, GetHandleId(u), 2))
if IsUnitType(u, UNIT_TYPE_HERO) then
call SaveBoolean(hash, key, -6, true)
call SaveUnitHandle(hash, key, -7, u)
call TimerStart(t, RESPAWN_TIMER_HERO, false, function Revive)
else
call SaveBoolean(hash, key, -6, false)
call TimerStart(t, RESPAWN_TIMER_UNIT, false, function Revive)
endif
set t = null
set u = null
endfunction
private function RegisterSystemUnits takes nothing returns nothing
local group g = CreateGroup()
local unit u
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g,u)
if GetOwningPlayer(u) == Player(PLAYER_NEUTRAL_AGGRESSIVE) then
call SaveReal(hash, GetHandleId(u), 0, GetUnitX(u))
call SaveReal(hash, GetHandleId(u), 1, GetUnitY(u))
call SaveReal(hash, GetHandleId(u), 2, GetUnitFacing(u))
endif
endloop
call DestroyTimer(GetExpiredTimer())
call DestroyGroup(g)
set g = null
endfunction
private function Init takes nothing returns nothing
local trigger trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig, Player(PLAYER_NEUTRAL_AGGRESSIVE), EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddAction(trig, function TryRevive)
call TimerStart(CreateTimer(), 0.00, false, function RegisterSystemUnits)
set trig = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
function CheckItemLife takes nothing returns nothing
if GetWidgetLife(GetEnumItem()) == 0.00 then
set udg_ItemsToClean = udg_ItemsToClean + 1
set udg_CleanedItem[udg_ItemsToClean] = GetEnumItem()
endif
endfunction
function RunItemCleanUp takes nothing returns nothing
local integer i = 0
if udg_ItemCleanupFlag then
set udg_ItemCleanupFlag = false
//
// Loop through all dead items and remove them
//
loop
exitwhen i > udg_ItemsToClean
call SetWidgetLife(udg_CleanedItem[i], 1.00)
call RemoveItem( udg_CleanedItem[i] )
set udg_CleanedItem[i] = null
set i = i + 1
endloop
else
//
// Clean up all dead items on the map every 15 seconds
//
set udg_ItemsToClean = -1
call EnumItemsInRect(bj_mapInitialPlayableArea, null, function CheckItemLife)
if udg_ItemsToClean >= 0 then
//
// Start a 1.50 second timer to give time for any death animations to play
//
set udg_ItemCleanupFlag = true
endif
endif
endfunction
//===========================================================================
function InitTrig_Item_Cleanup takes nothing returns nothing
call TimerStart(CreateTimer(), 1.00, true, function RunItemCleanUp)
endfunction
//TESH.scrollpos=35
//TESH.alwaysfold=0
function HeroRevivalCon takes nothing returns boolean
if IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) and not IsUnitIllusion(GetTriggerUnit()) then
return true
endif
return false
endfunction
function HeroRevivalAct takes nothing returns nothing
local unit u = GetTriggerUnit()
local timer t = CreateTimer()
local timerdialog td = CreateTimerDialog(t)
if IsPlayerInForce(GetLocalPlayer(), bj_FORCE_ALL_PLAYERS) then
// Use only local code (no net traffic) within this block to avoid desyncs.
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 10.00, "|cffff0000" + GetPlayerName(GetTriggerPlayer()) + "|r has been killed by a |cffff0000" + GetUnitName(GetKillingUnit()))
endif
call TimerStart(t, 15.00, false, null)
if GetLocalPlayer() == GetTriggerPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call TimerDialogDisplay(td, true)
endif
call TriggerSleepAction( 15.00 )
call DestroyTimerDialog(td)
call DestroyTimer(t)
call ReviveHero( u, GetRectCenterX(gg_rct_Spawn), GetRectCenterY(gg_rct_Spawn), true )
if GetLocalPlayer() == GetTriggerPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call PanCameraToTimed(GetRectCenterX(gg_rct_Spawn), GetRectCenterY(gg_rct_Spawn), 0.00)
endif
set u = null
set t = null
set td = null
endfunction
//===========================================================================
function InitTrig_HeroRevival takes nothing returns nothing
local trigger trig = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
set i = i + 1
exitwhen i == 12
endloop
call TriggerAddCondition( trig, Condition( function HeroRevivalCon ) )
call TriggerAddAction( trig, function HeroRevivalAct )
endfunction
//TESH.scrollpos=345
//TESH.alwaysfold=0
////////////////////////////////////////////////////////////////////
// DEVASTATION ENVOY V1.00 //
// //
// Author: Tank-Commander //
// Requires: Dummy.mdl //
// Purpose: Spam-cast spell //
// //
// Notes: //
// - Read the readme before you try modifying the config //
// - Use the "Helpful files" to help you import the spell //
// //
// Credits: //
// - (Dummy.mdl) Vexorian //
// //
// //
// If you have used this spell in your map, you are required //
// to give credits to Tank-Commander for the creation of it //
// If you take a snippet from this code for physics reasons //
// or whatever else, if possible, also give credit for its //
// source origin //
// //
// Importing: Remember to import Dummy.mdl and possibly the //
// object data when importing this spell (just the ability and //
// dummy unit) note that importing the dummy unit object should //
// be done AFTER importing Dummy.mdl, if not, then you will //
// need to set the model of the dummy to Dummy.mdl yourself, if //
// you would like to change what your dummy unit is you can, //
// but it will still need Dummy.mdl for this spell to work //
// If you have problems, make sure you read the readme first //
// and follow it to the best of your abilities before posting //
// comments //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// README: //
// Before modifying this spell a few things need to be //
// understood and read, this is one of those things, while //
// most modification can be considered intuitive, it still //
// helps to read through these intstructions, as they will //
// inform you about how to configure this spell to your //
// desire. //
//----------------------------------------------------------------//
// Initial importing: The variable creator trigger can be //
// imported first and if you have the correct settings (file, //
// preferences, General, automatically create unknown variables //
// checked, then when you pasta in the variable creator it //
// will automatically give you all the variables you need for //
// this spell //
//----------------------------------------------------------------//
// This configuration is ordered by category of use, and not //
// alphabetically, the ones you're most likely to want to //
// change, are earlier in the readme, the most essential being //
// first. These categories are: //
// //
// - Data Values: The most essential to change, otherwise the //
// spell will simply not function //
// //
// - ChronoKinetic: Fancy word for affecting the flow of time //
// Contains things like the duration of the //
// spell, the Timer speed and Shard Spawn rate //
// //
// - Power: Controls the aspects of the speed of the shards //
// based on the Mass, and Radius of the Portal //
// //
// - Damage: Controls the AOE and damage (health and mana) //
// values each individual Shard has //
// //
// - Aesthetics: Controls the Appearences of the ability - the //
// models used, the scales of those models and //
// so on //
// //
// - Damage Information: Contains things like weapontypes and //
// damage types, etc. //
// //
// - Other Attributes: Contains the world gravity, death timer //
// Height let and the celestial Gravitational //
// constant. //
//----------------------------------------------------------------//
// DATA VALUES //
//----------------------------------------------------------------//
// Dummy ID: This is the raw data of the dummy unit, to see //
// raw data in the object editor, press Ctrl + D, doing this //
// again will switch it back, if you want to change this dummy //
// unit, follow as displayed (use the first 4 characters in //
// the raw data and put them in ' markers) //
constant function DE_DummyID takes nothing returns integer
return 'ude0'
endfunction
//----------------------------------------------------------------//
// Spell ID: This is done in the same manner as the Dummy ID //
// except that this time, you're doing it with ability raw //
// data, see the dummy unit if you do not know already how to //
// view raw data //
constant function DE_SpellID takes nothing returns integer
return 'Ade0'
endfunction
//----------------------------------------------------------------//
// CHRONOKINETIC //
//----------------------------------------------------------------//
// Timer Speed: The default for this is 0.03, it determines how //
// many times per second these triggers are ran, normally you //
// want to leave this at 0.03, but 0.04 and prehaps 0.05 //
// would be good options if you computer lags a bit. //
constant function DE_TimerSpeed takes nothing returns real
return 0.03
endfunction
//----------------------------------------------------------------//
// Duration Base: Determines how long each cast will last as a //
// base value - this is to help give better control when //
// scaling abilities while not having to change values for each //
// level, cutting out a lot of configuration time, the value is //
// in seconds (1.00 = 1second) //
constant function DE_DurationBase takes nothing returns real
return 1.00
endfunction
//----------------------------------------------------------------//
// Duration Per Level: Deter,omes jpw ;pmg eacj casy wo;; as a //
// per level value - at level one this will be applied once, //
// twice at level two and so forth, it is added on to the base //
// value to come to the actual duration of the spell instance //
constant function DE_DurationPerLevel takes nothing returns real
return 1.00
endfunction
//----------------------------------------------------------------//
// Spawn Rate Base: A base value, this controls how many //
// seconds there are between each Shard being created, if this //
// is the same or lower (the sum total of the Base and Per //
// Level) is lower or equal to the timer speed, then one Shard //
// will be made every Timer Speed seconds (Time is a decimal //
// value, 0.5 is half a second) //
constant function DE_SpawnRateBase takes nothing returns real
return 0.10
endfunction
//----------------------------------------------------------------//
// Spawn Rate Per Level: The other part to the spawn rate //
// remember that it's a decimal value and the lower it is, the //
// faster Shards are created, so for this per level you'll //
// normally either want a negative value, or 0.00, though you //
// are not limited to such values //
constant function DE_SpawnRatePerLevel takes nothing returns real
return -0.03
endfunction
//----------------------------------------------------------------//
// POWER //
//----------------------------------------------------------------//
// Radius Base: This Base value determines how far out from the //
// center the shards are created, it also affects the gravity //
// strength of the Portal - the smaller the radius in relation //
// to it's Mass, the higher the gravitational effect and the //
// more volatile the Shards will be //
constant function DE_RadiusBase takes nothing returns real
return 100.00
endfunction
//----------------------------------------------------------------//
// Radius Per Level: The per level component to the Radius, //
// works the same all the other per level factors, giving this //
// a negative value will make your Portal smaller but more //
// volatile each level, and a positive value will make it large //
// and more stable //
constant function DE_RadiusPerLevel takes nothing returns real
return 0.00
endfunction
//----------------------------------------------------------------//
// Mass Base: the Mass within the Portal, the main strength of //
// the gravitational pull, larger numbers will decrease //
// stability and increase the speed the Shards move, lowering //
// it makes it more stable, but unlike the Radius, it does not //
// affect the size of your Portal, works well for a baseline //
// when testing different levels of instability or stability //
// when getting your preferences for the spell //
constant function DE_MassBase takes nothing returns real
return 800.00
endfunction
//----------------------------------------------------------------//
// Mass Per Level: the Per level component of the Mass can make //
// the spell more stable or volatile as it levels up without //
// changing it's size, remember that it is applied once at level //
// one, so the values 800 and 400 (the defaults) yeild 1200 //
// Mass at level one //
constant function DE_MassPerLevel takes nothing returns real
return 800.00
endfunction
//----------------------------------------------------------------//
// DAMAGE //
//----------------------------------------------------------------//
// Shard AOE Base: Determines the area of effect of the shards //
// 90 is melee range, 40 is directly on top, 20 is probably too //
// small an area to work and 400 to large, try different values //
// and see what you like //
constant function DE_ShardAOEBase takes nothing returns real
return 90.00
endfunction
//----------------------------------------------------------------//
// Shard AEO Per Level: Normally not used, but here for your //
// preferences, allows you to adjust the area of effect of your //
// shards as they level up, normally only making the area larger //
// makes logical sense, or not changing it at all //
constant function DE_ShardAOEPerLevel takes nothing returns real
return 0.10
endfunction
//----------------------------------------------------------------//
// Health Damage Base: This is the damage the spell deals to //
// all the units within the AOE on impact with a shard, you'll //
// want to make this fairly relative to the number of shards //
// you have, 75 shards with 100 damage each is 7500 damage in //
// one cast of the spell - that's a lot of potential damage in //
// a spell which has no cooldown by default, note that this //
// damage is not true damage - enemies will have their armour //
// applied and reduce this damage based on their armour type //
// vs your damage type //
constant function DE_HealthDamageBase takes nothing returns real
return 150.00
endfunction
//----------------------------------------------------------------//
// Health Damage Per Level: For changing the amount of damage //
// you want to deal with each shard as you level up, normally //
// this is your main source of increased damage as the spell //
// levels up rather than the other factors, it makes little //
// sense to not have this as a positive value of some number //
// (25% of your total level 1 damage seems like a good number, //
// i.e. if your combined level one damage is 100, roughly 25 of //
// that damage should probably be coming from this per level //
// value //
constant function DE_HealthDamagePerLevel takes nothing returns real
return 300.00
endfunction
//----------------------------------------------------------------//
// Mana Damage Base: Unlike Health damage the mana damage is //
// true damage - no matter how much armour they have, exactly //
// these values will be subtracted from their mana, normally //
// this is 0 as mana damage is mostly useless except vs certain //
// enemies, but it's still good to have the option to be able //
// to have it if you want //
constant function DE_ManaDamageBase takes nothing returns real
return 500.00
endfunction
//----------------------------------------------------------------//
// Mana Damage Per Level: Per level component of the normally //
// disused mana damage, not any real sense in having a below 0 //
// amount here, since it'll only make it weaker, like the //
// health damage I suggest this to be 25% of your total mana //
// damage of your level 1 version //
constant function DE_ManaDamagePerLevel takes nothing returns real
return 100.00
endfunction
//----------------------------------------------------------------//
// AESTHETICS //
//----------------------------------------------------------------//
// Portal Model: This determines the model used for your //
// main portal, you want to use the model path and paste it //
// into the double quotes or " markers, if the path has only //
// single slashes (\) you'll need to changeb it to double slash //
// (\\) before you save, the spell will not work if you do not //
// do this (if you acidentally save with the single slash (\) //
// it will still save but you may find yourself having a //
// lingering Progress bar at full percentage, you can ignore it //
// for the most part, but if you have it, you probably haven't //
// entered this field correctly. Get the model paths from the //
// Object editor - find the model you want (the model, not the //
// unit, in the models list, select it and hit enter twice, //
// then select the path (will look similar to this default //
// value, and paste in it here) I suggest doing this with a //
// unit of no value (changing the model to get the model path) //
// and then reset the field afterwards to get the unit back to //
// normal //
constant function DE_PortalModel takes nothing returns string
return "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdl"
endfunction
//----------------------------------------------------------------//
// Shard Model: The model used for your individual shards, //
// follow the steps in the "Portal Model" section if you need //
// information on how to change these values successfully //
constant function DE_ShardModel takes nothing returns string
return "Abilities\\Weapons\\WitchDoctorMissile\\WitchDoctorMissile.mdl"
endfunction
//----------------------------------------------------------------//
// Impact Model: The model used for your individual shards, //
// follow the steps in the "Portal Model" section if you need //
// information on how to change these values successfully //
constant function DE_ImpactModel takes nothing returns string
return "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl"
endfunction
//----------------------------------------------------------------//
// Attachment Point: This determines where on the unit the //
// model is placed, "origin", "chest", "head", "overhead" are //
// all good places to put the model, switch them around to see //
// which you prefer the most, "foot" and "hand" are less so as //
// they're offsetted from the center //
constant function DE_AttachmentPoint takes nothing returns string
return "origin"
endfunction
//----------------------------------------------------------------//
// Portal Height Base: This is how height the portal is off the //
// floor (it is added onto the terrain Z) you'll want it a good //
// distance off the ground (unles you want Shards to smack into //
// the ground while the spell is still going off, which is a //
// viable thing to do for this spell) but not so high as to //
// send the Shards halfway across the map, 400 is default //
constant function DE_PortalHeightBase takes nothing returns real
return 400.00
endfunction
//----------------------------------------------------------------//
// Portal Height Per Level: The per level for the height of the //
// portal, generally this'll be set at 0 as the spell changes //
// more on functionality, than on effectiveness depending on //
// height - so changing this value as it levels up will not //
// necessarily make it any stronger or weaker //
constant function DE_PortalHeightPerLevel takes nothing returns real
return 0.00
endfunction
//----------------------------------------------------------------//
// Portal Scale Base: this is the scale of the portal model //
// it's a decimal percentage (1.00 = 100%) as the largest part //
// of the spell you'll normally want this at, at least 100% //
// depending on the model, generally a good idea to try to line //
// it up with your portal radius as to get the best effect out //
// of it //
constant function DE_PortalScaleBase takes nothing returns real
return 2.00
endfunction
//----------------------------------------------------------------//
// Portal Scale Per Level: Used for changing the portal scale //
// as it levels up - good in combination with radius change per //
// level as to stay correct relatively //
constant function DE_PortalScalePerLevel takes nothing returns real
return 1.00
endfunction
//----------------------------------------------------------------//
// Shard Scale Base: Scales the Shards that are created by the //
// portal, normally you'll want them significantly smaller that //
// the portal 10% (0.10) is a good size, but for some models a //
// bit bigger might be good, be sure to play around with this //
// to get the size you want and looks best in your opinion //
constant function DE_ShardScaleBase takes nothing returns real
return 0.10
endfunction
//----------------------------------------------------------------//
// Shard Scale Per Level: Also for use with making the portal //
// seem relatively the same size as it levels up - or simply //
// to make them bigger to show increased AOE, Damage, more or //
// less to show anything about the spell being stronger as it //
// levels up and becomes more powerful //
constant function DE_ShardScalePerLevel takes nothing returns real
return 0.00
endfunction
//----------------------------------------------------------------//
// DAMAGE INFORMATION //
//----------------------------------------------------------------//
// Damage Type: These determine the damagetypes, changing this //
// will modify the damage multiplyers vs certain enemies //
// the standard is DAMAGE_TYPE_MAGIC, note that this spell //
// automatically discludes magic immunes, so changing this //
// damage type will not make them start taking damage //
constant function DE_AttackType takes nothing returns attacktype
return ATTACK_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// Attack Type: This is very much so basically the same as //
// Damage Type, generally you'll want this to match with it //
// as such the default is ATTACK_TYPE_MAGIC, though Damagetype //
// is a key factor for determining bonuses rather than this //
// but unlike weapontype, you cannot have null as a setting //
constant function DE_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
// Weapon Type: This alters what kind of weapon type is used by //
// the spell, those without knowledge of weapontypes don't //
// worry, you're not missing much, this spell doesn't really //
// use it, hence the default of null, but if you want to use //
// them, no reason to not. //
constant function DE_WeaponType takes nothing returns weapontype
return null
endfunction
//----------------------------------------------------------------//
// OTHER ATTRIBUTES //
//----------------------------------------------------------------//
// Gravity: Determines the worldly gravity strength used to //
// pull the shards back to the ground after they have been //
// freed from the portal, having a lower gravity increases the //
// spread range, higher lowers it, the default is 1/8 of the //
// earthly gravity of 9.81, beng 1.22625 //
constant function DE_Gravity takes nothing returns real
return 1.22625
endfunction
//----------------------------------------------------------------//
// Gravitational Constant: This is the constant reprisented by //
// G in Celestial Physics and Mechanics. Normally it's //
// 6.67384 x 10^-11 N (m/kg)^2 but for Warcraft purposes I //
// cranked it up a bit, (x 10^11 to be exact) changing it may //
// yeild interesting results, but I take no responcibility if //
// you do something silly and crash the game by making it //
// really high //
constant function DE_GravitationalConstant takes nothing returns real
return 6.67384
endfunction
//----------------------------------------------------------------//
// Height Let: This is a small let so that projectiles nearly //
// touching the floor, will be treated as actually touching it //
// This is to prevent graphical errors because models cannot //
// sink into the floor by reducing their fly height //
// 5 is default 10 is probably the max you can reasonably give //
// this //
constant function DE_HeightLet takes nothing returns real
return 5.00
endfunction
//----------------------------------------------------------------//
// Death Timer: Determines how long after the death of a dummy //
// will it be removed from the game completely, this is so //
// death effects, if any can finish playing before the unit is //
// removed, 1.8 is default, 2 is probably excessive and in some //
// cases it's possible that 1 could be too little //
constant function DE_DeathTimer takes nothing returns real
return 1.80
endfunction
//----------------------------------------------------------------//
// You have now reached the end of the configuration, below are //
// the functions used to run the spell, beyond this point if //
// you find any constant values (indicated in Blue like the //
// other constants here if you have standard syntax highlighting //
// they're there for a reason and don't fiddle with them, to //
// actually make any modifications I hope you're an experienced //
// programmer, though do not hassle for help because I don't //
// take responcibility for other people's programming skills //
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function used for finding the Z height of a location, since //
// it cannot be done with co-ordinates, a recycled location is //
// used constantly. //
////////////////////////////////////////////////////////////////////
function DE_GetZ takes real x, real y returns real
//Gets the location Z of the selected location
call MoveLocation(udg_DE_ZLoc, x, y)
return GetLocationZ(udg_DE_ZLoc)
endfunction
////////////////////////////////////////////////////////////////////
// Target filter function - passed units and players and checks //
// if the unit is allowed to be targetted by this spell //
////////////////////////////////////////////////////////////////////
function DE_TargetFilter takes unit u, player pl returns boolean
//Checks if the unit can be used as a target
if (IsUnitType(u, UNIT_TYPE_GROUND)) and (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != DE_DummyID()) and (not IsUnitType(u, UNIT_TYPE_DEAD)) then
return true
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// Function for running the main parts of the spell, creates //
// new shards and destroys old portals, and does all the //
// recycling and damaging of targets, as well as shard movement //
////////////////////////////////////////////////////////////////////
function DE_Loop takes nothing returns nothing
//Sets up all the locals needed for this section
local integer TempInt = 0
local integer TempInt2 = 0
local integer TempNode = 0
local integer Node = 0
local real Angle
local real Angle2
local real Distance
local real x
local real x2
local real dx
local real y
local real y2
local real dy
local real z
local unit u
local player pl
loop
//Moves to the next node
set TempInt = TempInt + 1
exitwhen TempInt > udg_DE_SpellCounter
set Node = udg_DE_NextNode[Node]
if (udg_DE_StageID[Node] == 2) then
//Initialises data required for movement
set x = GetUnitX(udg_DE_Unit[Node])
set y = GetUnitY(udg_DE_Unit[Node])
set udg_DE_CurrentZ[Node] = udg_DE_CurrentZ[Node] + udg_DE_ZVelocity[Node]
set z = DE_GetZ(x, y)
set dy = udg_DE_PortalY[Node] - y
set dx = udg_DE_PortalX[Node] - x
set Angle = Atan2(dy, dx)
set Angle2 = Atan2(udg_DE_PortalZ[Node] - udg_DE_CurrentZ[Node], SquareRoot(dx * dx + dy * dy))
//Checks if the projectile has crashed
if (udg_DE_CurrentZ[Node] - z < DE_HeightLet()) then
//Yes it crashed, deassociating the unit
set udg_DE_StageID[Node] = 3
set pl = GetOwningPlayer(udg_DE_OriginalCaster[Node])
call DestroyEffect(udg_DE_CurrentEffect[Node])
call DestroyEffect(AddSpecialEffect(DE_ImpactModel(), x, y))
//Select Units to damage
call GroupEnumUnitsInRange(udg_DE_TempGroup, x, y, udg_DE_ShardAOE[Node], null)
loop
//Scanning through
set u = FirstOfGroup(udg_DE_TempGroup)
exitwhen u == null
//Select all the units which are to be damaged
if DE_TargetFilter(u, pl) then
//Dealing health and mana damage
call UnitDamageTarget(udg_DE_OriginalCaster[Node], u, udg_DE_HealthDamage[Node], true, false, DE_AttackType(), DE_DamageType(), DE_WeaponType())
call SetUnitState(u, UNIT_STATE_MANA, (GetUnitState(u,UNIT_STATE_MANA) - udg_DE_ManaDamage[Node]))
endif
//Remove the unit from the unit group
call GroupRemoveUnit(udg_DE_TempGroup, u)
endloop
//Removes the projectile
call KillUnit(udg_DE_Unit[Node])
//Nulls variables
set u = null
set pl = null
else
//Setting the new locations X and Y for this instance
set x2 = x + udg_DE_XVelocity[Node]
set y2 = y + udg_DE_YVelocity[Node]
if (IsUnitInGroup(udg_DE_Unit[Node], udg_DE_GravitatedShard)) then
//Calculating the new velocities (will be used next time this runs)
set udg_DE_ZVelocity[Node] = udg_DE_ZVelocity[Node] + udg_DE_BaseVelocity[Node] * Sin(Angle2)
set udg_DE_XVelocity[Node] = udg_DE_XVelocity[Node] + udg_DE_BaseVelocity[Node] * Cos(Angle) * Cos(Angle2)
set udg_DE_YVelocity[Node] = udg_DE_YVelocity[Node] + udg_DE_BaseVelocity[Node] * Sin(Angle) * Cos(Angle2)
else
set udg_DE_ZVelocity[Node] = udg_DE_ZVelocity[Node] - DE_Gravity()
endif
//Makes sure the new location is within the map bounds
if ((udg_DE_MapMinX <= x2) and (x2 <= udg_DE_MapMaxX) and (udg_DE_MapMinY <= y2)and (y2 <= udg_DE_MapMaxY)) then
call SetUnitX(udg_DE_Unit[Node], x2)
call SetUnitY(udg_DE_Unit[Node], y2)
endif
//Sets the correct fly height
call SetUnitFlyHeight(udg_DE_Unit[Node], udg_DE_CurrentZ[Node] - z, 0.00)
endif
elseif (udg_DE_StageID[Node] == 1) then
//Increases the duration of both artificial wait timers
set udg_DE_CurrentShardDelay[Node] = udg_DE_CurrentShardDelay[Node] + DE_TimerSpeed()
set udg_DE_CurrentDuration[Node] = udg_DE_CurrentDuration[Node] + DE_TimerSpeed()
//Checks if the spell has ran out of duration
if(udg_DE_CurrentDuration[Node] >= udg_DE_Duration[Node]) then
set udg_DE_StageID[Node] = 3
call DestroyEffect(udg_DE_CurrentEffect[Node])
//Finds all the affected Shards and releases them
loop
set TempInt2 = TempInt2 + 1
exitwhen TempInt2 > udg_DE_SpellCounter
set TempNode = udg_DE_NextNode[TempNode]
if (udg_DE_Portal[TempNode] == udg_DE_Unit[Node]) then
call GroupRemoveUnit (udg_DE_GravitatedShard, udg_DE_Unit[TempNode])
endif
endloop
//Checks if it's time to make a new shard
elseif (udg_DE_CurrentShardDelay[Node] >= udg_DE_SpawnRate[Node]) then
//Resets the timer
set udg_DE_CurrentShardDelay[Node] = 0.00
//Sets up a random place to put the new Shard
set Angle = GetRandomReal(0, 360)
set Angle2 = GetRandomReal(0, 180)
set Distance = Cos(Angle2) * udg_DE_Radius[Node]
if (Distance < 0) then
set Distance = Distance * -1
endif
set udg_DE_SpellCounter = udg_DE_SpellCounter + 1
set x = udg_DE_PortalX[Node] + Distance * Cos(Angle * bj_DEGTORAD)
set y = udg_DE_PortalY[Node] + Distance * Sin(Angle * bj_DEGTORAD)
set z = Sin(Angle2) * udg_DE_Radius[Node] + udg_DE_PortalZ[Node]
//Checking for recycleable Nodes
if (udg_DE_RecycleableNodes == 0) then
set udg_DE_NodeNumber = udg_DE_NodeNumber + 1
set TempNode = udg_DE_NodeNumber
else
set udg_DE_RecycleableNodes = udg_DE_RecycleableNodes - 1
set TempNode = udg_DE_RecycleNodes[udg_DE_RecycleableNodes]
endif
//Sets up this Node
set udg_DE_NextNode[TempNode] = 0
set udg_DE_NextNode[udg_DE_LastNode] = TempNode
set udg_DE_PrevNode[TempNode] = udg_DE_LastNode
set udg_DE_LastNode = TempNode
//Sets up the data for the Shard
set udg_DE_HealthDamage[TempNode] = udg_DE_HealthDamage[Node]
set udg_DE_ManaDamage[TempNode] = udg_DE_ManaDamage[Node]
set udg_DE_Portal[TempNode] = udg_DE_Unit[Node]
set udg_DE_PortalX[TempNode] = udg_DE_PortalX[Node]
set udg_DE_PortalY[TempNode] = udg_DE_PortalY[Node]
set udg_DE_PortalZ[TempNode] = udg_DE_PortalZ[Node]
set udg_DE_ShardAOE[TempNode] = udg_DE_ShardAOE[Node]
set udg_DE_OriginalCaster[TempNode] = udg_DE_OriginalCaster[Node]
set udg_DE_BaseVelocity[TempNode] = udg_DE_BaseVelocity[Node]
set udg_DE_CurrentZ[TempNode] = z
set udg_DE_StageID[TempNode] = 2
//Sets up initialisation Velocities (this is to give the shards a bit of a kick of instability in their orbit)
set udg_DE_ZVelocity[TempNode] = udg_DE_BaseVelocity[TempNode] * Sin(Angle2)
set udg_DE_XVelocity[TempNode] = udg_DE_BaseVelocity[TempNode] * Cos(Angle) * Cos(Angle2)
set udg_DE_YVelocity[TempNode] = udg_DE_BaseVelocity[TempNode] * Sin(Angle) * Cos(Angle2)
//Creates the unit and applies Aesthetics
set udg_DE_Unit[TempNode] = CreateUnit(Player(14), DE_DummyID(), x, y, 0.00)
if UnitAddAbility(udg_DE_Unit[TempNode], 'Amrf') and UnitRemoveAbility(udg_DE_Unit[TempNode], 'Amrf') then
endif
set udg_DE_CurrentEffect[TempNode] = AddSpecialEffectTarget(DE_ShardModel(), udg_DE_Unit[TempNode], DE_AttachmentPoint())
call SetUnitScale(udg_DE_Unit[TempNode], udg_DE_ShardScale[Node], 0.00, 0.00)
call SetUnitFlyHeight(udg_DE_Unit[TempNode], z, 0.00)
//Adds them to the group of Gravitated Shards
call GroupAddUnit(udg_DE_GravitatedShard, udg_DE_Unit[TempNode])
endif
elseif (udg_DE_CurrentDeathTimer[Node] < DE_DeathTimer()) then
set udg_DE_CurrentDeathTimer[Node] = 0.00
//Removes the projectile
call RemoveUnit(udg_DE_Unit[Node])
if (udg_DE_LastNode == Node) then
set udg_DE_LastNode = udg_DE_PrevNode[Node]
endif
//Recycles the node
set udg_DE_RecycleNodes[udg_DE_RecycleableNodes] = Node
set udg_DE_RecycleableNodes = udg_DE_RecycleableNodes + 1
set udg_DE_NextNode[udg_DE_PrevNode[Node]] = udg_DE_NextNode[Node]
set udg_DE_PrevNode[udg_DE_NextNode[Node]] = udg_DE_PrevNode[Node]
set udg_DE_SpellCounter = udg_DE_SpellCounter - 1
set TempInt = TempInt - 1
//Destroys the timer when not in use
if (udg_DE_SpellCounter == 0) then
call DestroyTimer(GetExpiredTimer())
endif
else
set udg_DE_CurrentDeathTimer[Node] = udg_DE_CurrentDeathTimer[Node] + DE_TimerSpeed()
endif
endloop
endfunction
////////////////////////////////////////////////////////////////////
// Function runs when a new instance is to be created - runs //
// as a condition but always returns false, creates a new //
// portal if the correct spell was cast //
////////////////////////////////////////////////////////////////////
function DE_NewInstance takes nothing returns boolean
//Sets up locals
local unit u
local integer Node
local real rLevel
local real x
local real y
//Checks if the spell cast is the correct spell
if (GetSpellAbilityId() == DE_SpellID()) then
set u = GetTriggerUnit()
set x = GetSpellTargetX()
set y = GetSpellTargetY()
set rLevel = I2R(GetUnitAbilityLevel(u, DE_SpellID()))
//Checking for recycleable Nodes
if (udg_DE_RecycleableNodes == 0) then
set udg_DE_NodeNumber = udg_DE_NodeNumber + 1
set Node = udg_DE_NodeNumber
else
set udg_DE_RecycleableNodes = udg_DE_RecycleableNodes - 1
set Node = udg_DE_RecycleNodes[udg_DE_RecycleableNodes]
endif
//Sets up this Node
set udg_DE_NextNode[Node] = 0
set udg_DE_NextNode[udg_DE_LastNode] = Node
set udg_DE_PrevNode[Node] = udg_DE_LastNode
set udg_DE_LastNode = Node
//Sets up the portal data
set udg_DE_PortalHeight[Node] = DE_PortalHeightBase() + (DE_PortalHeightPerLevel() * rLevel)
set udg_DE_Mass[Node] = DE_MassBase() + (DE_MassPerLevel() * rLevel)
set udg_DE_Radius[Node] = DE_RadiusBase() + (DE_RadiusPerLevel() * rLevel)
set udg_DE_BaseVelocity[Node] = ((DE_GravitationalConstant() * udg_DE_Mass[Node]) / udg_DE_Radius[Node]) * DE_TimerSpeed()
set udg_DE_HealthDamage[Node] = DE_HealthDamageBase() + (DE_HealthDamagePerLevel() * rLevel)
set udg_DE_ManaDamage[Node] = DE_ManaDamageBase() + (DE_ManaDamagePerLevel() * rLevel)
set udg_DE_SpawnRate[Node] = DE_SpawnRateBase() + (DE_SpawnRatePerLevel() * rLevel)
set udg_DE_Duration[Node] = DE_DurationBase() + (DE_DurationPerLevel() * rLevel)
set udg_DE_ShardScale[Node] = DE_ShardScaleBase() + (DE_ShardScalePerLevel() * rLevel)
set udg_DE_ShardAOE[Node] = DE_ShardAOEBase() + (DE_ShardAOEPerLevel() * rLevel)
set udg_DE_PortalX[Node] = x
set udg_DE_PortalY[Node] = y
set udg_DE_PortalZ[Node] = udg_DE_PortalHeight[Node] + DE_GetZ(x, y)
set udg_DE_CurrentShardDelay[Node] = 0.00
set udg_DE_CurrentDuration[Node] = 0.00
set udg_DE_OriginalCaster[Node] = u
set udg_DE_StageID[Node] = 1
set udg_DE_SpellCounter = udg_DE_SpellCounter + 1
//Creates the unit and applies Aesthetics
set udg_DE_Unit[Node] = CreateUnit(Player(14), DE_DummyID(), x, y, 0.00)
if UnitAddAbility(udg_DE_Unit[Node], 'Amrf') and UnitRemoveAbility(udg_DE_Unit[Node], 'Amrf') then
endif
set udg_DE_CurrentEffect[Node] = AddSpecialEffectTarget(DE_PortalModel(), udg_DE_Unit[Node], DE_AttachmentPoint())
call SetUnitScale(udg_DE_Unit[Node], DE_PortalScaleBase() + (DE_PortalScalePerLevel() * rLevel), 0.00, 0.00)
call SetUnitFlyHeight(udg_DE_Unit[Node], udg_DE_PortalHeight[Node], 0.00)
//Checks if it's the only portal on the map
if (udg_DE_SpellCounter == 1) then
call TimerStart(CreateTimer(), DE_TimerSpeed(), true, function DE_Loop)
endif
//Nulls variables
set u = null
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// Function for setting up the other functions and initialising //
// the map bounds variables and Z finder for locations //
////////////////////////////////////////////////////////////////////
function InitTrig_DE_DevastationEnvoy takes nothing returns nothing
//Sets up locals
local trigger DE = CreateTrigger()
local integer index = 0
//Initialise the event for every player
loop
call TriggerRegisterPlayerUnitEvent(DE, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(DE, Condition(function DE_NewInstance))
//Sets up the map bounds the spell with use
set udg_DE_MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set udg_DE_MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
set udg_DE_MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set udg_DE_MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
//Sets up the Z location finder
set udg_DE_ZLoc = Location(0,0)
//Nulls variables
set DE = null
endfunction
////////////////////////////////////////////////////////////////////
// End of the spell //
////////////////////////////////////////////////////////////////////
//TESH.scrollpos=49
//TESH.alwaysfold=0
scope CorruptedArrows //version 1.05
/*******************************************************************************************************************
* Requires:
* -CTL (By Nestharus)
* -WorldBounds (By Nestharus)
* -Table (By Bribe)
* -GroupUtils (By Rising_Dusk)
* -IsDestructableTree (PitzerMike)
* -SpellEffectEvent (By Bribe)
* -RegisterPlayerUnitEvent (By Magtheridon96)
*
* How to Import:
* -Copy both abilities from object editor (Abilities)
* -Copy Multishot - Dummy from object editor (Units)
* -Copy Corrupted arrows from object editor (Buffs/Effects)
* -Copy Multishot trigger
* -Copy Libraries Folder
*
* Give credits if use :)
*
***********************************************************************************************************************/
/**************************************************************************************
* *
* CONFIGURATION *
* *
**************************************************************************************/
globals
//Main ability rawcode
private constant integer SPELL_CODE = 'Aca0'
//Armor debuff ability rawcode
private constant integer DEBUF_CODE = 'aca1'
//Dummy rawcode
private constant integer DUMMY_CODE = 'hca0'
//Ammout of arrows shotted
private constant integer AMMOUT = 15
//Angle at which arrows are shooted. You can set it to 360 to make nova spell
private constant real ANGLE_ARC = 90
//Arrows dize
private constant real DUMMY_SCALE = 100
//Arrows height
private constant real DUMMY_HEIGHT = 70
//Range to pick units to damage
private constant real DAMAGE_RANGE = 40
//Move effect cooldown
private constant integer MOVE_CD = 3
//Effect that appear on damaged units
private constant string DAMAGE_EFFECT = "Abilities\\Spells\\Other\\BlackArrow\\BlackArrowMissile.mdl"
//Damage and attack type
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_DEATH
//Should arrows destroy trees?
private constant boolean DESTROY_TREE = false
endglobals
//Damage function
private function GetDamage takes integer level returns real
return level * 150.00
endfunction
//Total distance function
private function GetDistance takes integer level returns real
return level * 50.00 + 650.00
endfunction
//Speed function
private function GetSpeed takes integer level returns real
return level * 3.00 + 23.00
endfunction
/**************************************************************************************
* *
* DAMAGE FILTER FUNCTIOn *
* *
**************************************************************************************/
private function TargetFilter takes unit u, player p returns boolean
return IsUnitEnemy(u, p) and not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(u, UNIT_TYPE_FLYING)
endfunction
/**************************************************************************************
* *
* CONFIGURATION END *
* *
**************************************************************************************/
private function Tree_Kill takes nothing returns boolean
local destructable dummy = GetFilterDestructable()
if IsDestructableTree(dummy) then
call KillDestructable(dummy)
endif
set dummy = null
return false
endfunction
private struct CorruptedArrows extends array
private static unit array caster
private static unit array dummy
private static player array owner
private static real array distance
private static real array speed
private static real array damage
private static rect array tree_rect
private static integer array moveCD
private static integer array moveCCD
private static group array ignoreGroup
static Table array missiles
implement CTL
local unit u
local unit t
local unit e
local real x
local real y
local real a
local real dx
local real dy
local group d
local integer index
local integer i
implement CTLExpire
set distance[this] = distance[this] - speed[this]
set index = 0
set i = 0
loop
set u = missiles[this].unit[index]
set a = missiles[this].real[index]
set dx = GetUnitX(u)
set dy = GetUnitY(u)
set x = dx + speed[this] * Cos(a)
set y = dy + speed[this] * Sin(a)
if (x < WorldBounds.maxX and x > WorldBounds.minX and y < WorldBounds.maxY and y > WorldBounds.minY ) then
call SetUnitX(u, x)
call SetUnitY(u, y)
set moveCCD[this] = moveCCD[this] + 1
if moveCCD[this] == moveCD[this] then
set e = CreateUnit(owner[this], DUMMY_CODE, x, y, a * bj_RADTODEG)
call SetUnitFlyHeight(e, DUMMY_HEIGHT, 0)
call SetUnitScale(e, DUMMY_SCALE * 0.01, 0, 0)
call UnitApplyTimedLife(e, 'BTLF', 0.50)
call SetUnitAnimation(e, "death")
set moveCCD[this] = moveCCD[this] - moveCD[this]
set e = null
endif
else
call KillUnit(u)
endif
set d = NewGroup()
call GroupUnitsInArea(d, x, y, DAMAGE_RANGE)
loop
set t = FirstOfGroup(d)
exitwhen t == null
if TargetFilter(t, owner[this]) and not IsUnitInGroup(t, ignoreGroup[this]) then
call UnitDamageTarget(caster[this], t, damage[this], false, true, ATTACK_TYPE, DAMAGE_TYPE, null)
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_EFFECT, t, "chest"))
call IssueTargetOrder(dummy[this], "faeriefire", t)
call GroupAddUnit(ignoreGroup[this], t)
endif
call GroupRemoveUnit(d, t)
endloop
call ReleaseGroup(d)
set d = null
static if DESTROY_TREE then
call SetRect(tree_rect[this], x - DAMAGE_RANGE, y - DAMAGE_RANGE, x + DAMAGE_RANGE, y + DAMAGE_RANGE)
call EnumDestructablesInRect(tree_rect[this],function Tree_Kill,null)
endif
set u = null
set index = index + 1
exitwhen index == AMMOUT
endloop
if distance[this] <= 0 then
loop
call UnitApplyTimedLife(missiles[this].unit[i], 'BTLF', 0.50)
call SetUnitAnimation(missiles[this].unit[i], "death")
exitwhen i == AMMOUT
set i = i + 1
endloop
call missiles[this].destroy()
call KillUnit(dummy[this])
set caster[this] = null
set dummy[this] = null
set owner[this] = null
call ReleaseGroup(ignoreGroup[this])
set ignoreGroup[this] = null
call destroy()
endif
implement CTLNull
implement CTLEnd
private static method onCast takes nothing returns nothing
local thistype this = create()
local unit u
local real cx
local real cy
local real tx
local real ty
local real a
local real ainc
local real arc
local integer level
local integer index = 0
set caster[this] = GetTriggerUnit()
set owner[this] = GetTriggerPlayer()
set level = GetUnitAbilityLevel(caster[this], SPELL_CODE)
set cx = GetUnitX(caster[this])
set cy = GetUnitY(caster[this])
set tx = GetSpellTargetX()
set ty = GetSpellTargetY()
set distance[this] = GetDistance(level)
set speed[this] = GetSpeed(level)
set damage[this] = GetDamage(level)
set ignoreGroup[this] = NewGroup()
set moveCD[this] = MOVE_CD
set moveCCD[this] = 0
set arc = ANGLE_ARC * bj_DEGTORAD
set a = Atan2(ty - cy, tx - cx) - (arc/ 2)
set ainc = arc / AMMOUT
set missiles[this] = Table.create()
loop
set u = CreateUnit(owner[this], DUMMY_CODE, cx, cy, a * bj_RADTODEG)
set missiles[this].unit[index] = u
set missiles[this].real[index] = a
call SetUnitScale(u, DUMMY_SCALE * 0.01, 0, 0)
call SetUnitFlyHeight(u, DUMMY_HEIGHT, 0)
set a = a + ainc
exitwhen index == AMMOUT
set index = index + 1
endloop
set u = null
static if DESTROY_TREE then
set tree_rect[this] = Rect(0, 0, 0, 0)
endif
set dummy[this] = CreateUnit(owner[this], DUMMY_CODE, cx, cy, 0)
call ShowUnit(dummy[this], false)
call UnitAddAbility(dummy[this], DEBUF_CODE)
call SetUnitAbilityLevel(dummy[this], DEBUF_CODE, level)
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_CODE,function thistype.onCast)
endmethod
endstruct
endscope
//TESH.scrollpos=3
//TESH.alwaysfold=0
//Holy Shock by Hanky aka OrkOfMordor aka MDZ-OrkOfMordor
scope HolyShock initializer init
//===================================================================================================================
//Constants
globals
private constant integer SpellId ='A040' //Ability Rawcode: Holy Shock
private constant integer DummyId ='e006' //Unit Rawcode: Dummy
private constant real distance =600. //Maximal distance the missiles will move
private constant string MissileExplFunc="HolyShockEnd"//The endfunction of the missile move (better you don't change this)
private constant string MissileMdl ="Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"//The model of the missile 1#
private constant string MissileMdl2 ="Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl"//The model of the missile 2#
private constant string MissileAttach ="origin"//The models attachpoint
private constant real MissileSpeed =10. //The speed of the missiles
private constant real DamageRange =90. //The collision range of the missiles
private constant real MissileZ =45. //The flyheight of the missiles
private constant real periodic =0.03 //The periodic motion time
private rect MaxArea =null //The maximal movearea of the missiles
endglobals
private constant function Amount takes integer lvl returns real
//The maximal amount of shock missiles
return 10.
endfunction
private constant function Chance takes integer lvl returns real
//The chance that missiles will be released
return 10.+(2.5*lvl)
endfunction
private constant function Damage takes integer lvl returns real
//Damage the units get when they collide with missiles
return lvl*25.+250.
endfunction
private function UnitFilter takes unit c,unit u returns boolean
//The unit filter for the units who get damage
if IsUnitEnemy(u,GetOwningPlayer(c)) then
if GetUnitState(u,UNIT_STATE_LIFE)>0. then
if IsUnitType(u,UNIT_TYPE_FLYING)==false then
if GetUnitAbilityLevel(u,invulnerable_id)<=0 then
if IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)==false then
return IsUnitType(u,UNIT_TYPE_STRUCTURE)==false
endif
endif
endif
endif
endif
return false
endfunction
//End Constants
//===================================================================================================================
//Conditions
private function Holy_Shock_Conditions takes nothing returns boolean
return GetUnitAbilityLevel(GetTriggerUnit(),SpellId) > 0
endfunction
//Actions
private struct HolyShockMissile
unit u
unit caster
effect gfx
effect mgfx
real x
real y
real max
real min
real tdistance
real dmg
method motion takes nothing returns nothing
local group g
local unit a
local real angle=GetRandomReal(.min,.max)*deg2rad
set .x=.x+MissileSpeed*Cos(angle)
set .y=.y+MissileSpeed*Sin(angle)
if RectContainsCoords(MaxArea,.x,.y) then
call SetUnitX(.u,.x)
call SetUnitY(.u,.y)
else
set .active=false
endif
set g=GetUnitsInRange(DamageRange,.x,.y)
call GroupRemoveUnit(g,.u)
loop
set a=FirstOfGroup(g)
exitwhen a==null
call GroupRemoveUnit(g,a)
if UnitFilter(.caster,a) then
call E2Null(AddSpecialEffectTarget(MissileMdl2,a,MissileAttach),0.5)
call UnitDamageTarget(.caster,a,.dmg,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
set .active=false
endif
endloop
if .tdistance>distance then
set .active=false
endif
set .tdistance=.tdistance+MissileSpeed
set g=null
endmethod
method endmotion takes nothing returns nothing
call U2Null(.u,0.5)
call DestroyEffect(.gfx)
call DestroyEffect(.mgfx)
set .caster =null
set .u =null
set .gfx =null
set .mgfx =null
call .destroy()
endmethod
//! runtextmacro CostumMotion("HolyShockMissile","motion","endmotion","periodic")
endstruct
private function HolyShockBegin takes nothing returns boolean
local integer i =1
local integer lvl =GetUnitAbilityLevel(DamageSkill_attacked,SpellId)
local real x =GetUnitX(DamageSkill_attacked)
local real y =GetUnitY(DamageSkill_attacked)
local real angle =360./Amount(lvl)
local real tangle =GetRandomReal(0,360)
local HolyShockMissile dat
call E2Null(AddSpecialEffectTarget(MissileMdl2,DamageSkill_attacked,MissileAttach),0.5)
loop
exitwhen i>Amount(lvl)
set dat =HolyShockMissile.create()
set dat.caster =DamageSkill_attacked
set dat.u =CreateUnit(Player(14),DummyId,x,y,tangle)
set dat.mgfx =AddSpecialEffectTarget(MissileMdl,dat.u,MissileAttach)
set dat.gfx =AddSpecialEffectTarget(MissileMdl2,dat.u,MissileAttach)
set dat.min =tangle-angle
set dat.max =tangle+angle
set dat.x =x
set dat.y =y
set dat.tdistance=0.
set dat.dmg =Damage(lvl)
call UnitAddFly(dat.u)
call SetUnitFlyHeight(dat.u,MissileZ,0.)
call HolyShockMissile.addMotion(dat)
set tangle=tangle+angle
set i=i+1
endloop
return true
endfunction
private function Holy_Shock_Actions takes nothing returns nothing
local real rndm =GetRandomReal(0,100)
local unit a =GetAttacker()
local unit u =GetTriggerUnit()
if Chance(GetUnitAbilityLevel(u,SpellId))>=rndm then
call TriggerAddDamageEvent(u,a,function HolyShockBegin)
endif
set a=null
set u=null
endfunction
//===========================================================================
private function init takes nothing returns nothing
local integer i=0
set gg_trg_Holy_Shock = CreateTrigger( )
set MaxArea = bj_mapInitialPlayableArea
loop
call TriggerRegisterPlayerUnitEvent(gg_trg_Holy_Shock, Player(i),EVENT_PLAYER_UNIT_ATTACKED, MainFunctions_filter)
set i=i+1
exitwhen i==bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition( gg_trg_Holy_Shock, Condition( function Holy_Shock_Conditions ) )
call TriggerAddAction( gg_trg_Holy_Shock, function Holy_Shock_Actions )
//Preload
call Preload(MissileMdl)
call Preload(MissileMdl2)
endfunction
endscope
//TESH.scrollpos=187
//TESH.alwaysfold=0
scope Hoarfrost
// -----
// Start of Configurables
// -----
globals
private constant integer SPELL_ID = 'A9L0' // Hero ability.
private constant integer ORBS_PER_SIDE = 4 // How many orbs make up each side of the triangle. Does NOT count the first one (at the tip of the triangle).
private constant real INTEL_MULTI = 0.5 // How much of the hero's intelligence is taken as damage.
private constant real DAMAGE_AOE = 150.0 // How close enemies must get to the wave to get damaged/knocked back.
private constant real WAVE_DISTANCE = 1000.0 // How far the wave travels.
private constant real FIRST_OFFSET = 300.0 // Distance the first orb is from the caster.
private constant real ORB_DISTANCE = 100.0 // Separation distance between each orb.
private constant real ORB_ANGLE = 30.0 // Angle between first orb and others.
private constant real WAVE_HEIGHT = 50.0 // Height of the wave.
private constant real WAVE_SPEED = 500.0 // Speed of the wave.
// Model of each orb:
private constant string WAVE_EFFECT = "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"
// Effect created on hit units:
private constant string TARGET_EFFECT = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"
private constant string TARGET_ATTACH = "origin"
endglobals
// -----
// End of Configurables
// -----
globals
private constant integer SIZE = (2 * ORBS_PER_SIDE) + 1
private constant real ORB_ANGLE_RAD = Deg2Rad(ORB_ANGLE)
private constant real WAVE_INCREMENT = WAVE_SPEED * T32_PERIOD
private constant real WAVE_DURATION = WAVE_DISTANCE / WAVE_SPEED
private group enumG = CreateGroup()
private unit enumU
endglobals
private function IsUnitTargetable takes unit whichUnit returns boolean
return (not IsUnitType(whichUnit, UNIT_TYPE_DEAD) and not IsUnitType(whichUnit, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE))
endfunction
private struct SpellData
unit caster
player owner
group hit
xefx array fx[SIZE]
real angle
real cos
real sin
real damage
real time = WAVE_DURATION
private method destroy takes nothing returns nothing
local integer i
for i = 0 to (SIZE - 1)
call fx[i].hiddenDestroy()
endfor
call ReleaseGroup(hit)
set caster = null
set owner = null
set hit = null
call deallocate()
endmethod
/**
* Damage and knock back all enemimes within range.
*/
private method checkNearby takes real x, real y returns nothing
local real ang
call GroupUnitsInArea(enumG, x, y, DAMAGE_AOE)
for enumU in enumG
if (not IsUnitInGroup(enumU, hit) and IsUnitEnemy(enumU, owner) and IsUnitTargetable(enumU)) then
call GroupAddUnit(hit, enumU)
call UnitDamageTarget(caster, enumU, damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
call DestroyEffect(AddSpecialEffectTarget(TARGET_EFFECT, enumU, TARGET_ATTACH))
// If the target is still alive, knock it back:
if (IsUnitTargetable(enumU)) then
set ang = Atan2(GetUnitY(enumU) - y, GetUnitX(enumU) - x)
call Knockback.start(enumU, 150.0, ang, 100.0, "")
endif
endif
endfor
endmethod
/**
* Move all orbs and call checkNearby.
*/
private method periodic takes nothing returns nothing
local integer i
local integer i2
local integer index = 0
local real ang
local real offset = ORB_DISTANCE
/* Move orbs */
set fx[index].x = fx[index].x + cos
set fx[index].y = fx[index].y + sin
call checkNearby(fx[index].x, fx[index].y)
set ang = (bj_PI + angle) - ORB_ANGLE_RAD
for i2 = 0 to 1
for i = 0 to (ORBS_PER_SIDE - 1)
set index = index + 1
set fx[index].x = fx[0].x + offset * Cos(ang)
set fx[index].y = fx[0].y + offset * Sin(ang)
call checkNearby(fx[index].x, fx[index].y)
set offset = offset + ORB_DISTANCE
endfor
set offset = ORB_DISTANCE
set ang = ang + (2.0 * ORB_ANGLE_RAD)
endfor
/****/
set time = time - T32_PERIOD
if (time <= 0.0) then
call stopPeriodic()
call destroy()
endif
endmethod
implement T32x
/**
* Create all orbs and set up spell.
*/
private static method create takes nothing returns thistype
local thistype this = allocate()
local integer i
local integer i2
local integer index = 0
local real tx
local real ty
local real cx
local real cy
local real ang
local real offset = ORB_DISTANCE
set caster = GetTriggerUnit()
set owner = GetTriggerPlayer()
set damage = GetHeroInt(caster, true) * INTEL_MULTI
set hit = NewGroup()
set cx = GetUnitX(caster)
set cy = GetUnitY(caster)
set ang = Atan2(GetSpellTargetY() - cy, GetSpellTargetX() - cx)
set angle = ang
set cos = Cos(ang)
set sin = Sin(ang)
set tx = cx + FIRST_OFFSET * cos
set ty = cy + FIRST_OFFSET * sin
/* Create moving orbs */
set fx[index] = xefx.create(tx, ty, 0.0)
set fx[index].fxpath = WAVE_EFFECT
set fx[index].z = WAVE_HEIGHT
set ang = Atan2(GetUnitY(caster) - ty, GetUnitX(caster) - tx) - ORB_ANGLE_RAD
for i2 = 0 to 1
for i = 0 to (ORBS_PER_SIDE - 1)
set index = index + 1
set fx[index] = xefx.create(tx + offset * Cos(ang), ty + offset * Sin(ang), 0.0)
set fx[index].fxpath = WAVE_EFFECT
set fx[index].z = WAVE_HEIGHT
set offset = offset + ORB_DISTANCE
endfor
set offset = ORB_DISTANCE
set ang = ang + (2.0 * ORB_ANGLE_RAD)
endfor
/****/
set cos = cos * WAVE_INCREMENT
set sin = sin * WAVE_INCREMENT
call startPeriodic()
return this
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.create)
call Preload(WAVE_EFFECT)
call Preload(TARGET_EFFECT)
endmethod
endstruct
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope FireRing
// -----
// Start of Configurables
// -----
globals
private constant integer SPELL_ID = 'A041' // "Fire Ring" hero ability.
private constant integer PURGE_ID = 'A02P' // "Fire Ring - Purge" unit ability.
private constant integer NUM_ORBS = 25 // How many fires make up the ring.
private constant real DISTANCE = 500.0 // How far the ring travels.
private constant real RING_SPEED = 350.0 // How fast the ring travels.
private constant real DAMAGE_AOE = 150.0 // How close enemies must get to be damaged and purged.
private constant real ORB_SCALE = 1.5 // Scale of each fire.
// Model of each fire:
private constant string ORB_EFFECT = "Doodads\\Cinematic\\TownBurningFireEmitter\\TownBurningFireEmitter.mdl"
endglobals
// Configure how the intelligence multiplier is calculated:
// damage = intMultiplier * heroInt
private function GetIntMultiplier takes integer level returns real
return 5.0 * level
endfunction
// -----
// End of Configurables
// -----
globals
private constant real ANGLE_DIV = 360.0 / NUM_ORBS
private constant real RING_INC = RING_SPEED * T32_PERIOD
private group enumG = CreateGroup()
private unit enumU
endglobals
private function IsUnitTargetable takes unit whichUnit returns boolean
return (not IsUnitType(whichUnit, UNIT_TYPE_DEAD) and not IsUnitType(whichUnit, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE))
endfunction
private struct SpellData
unit caster
player owner
group hit = CreateGroup()
integer level
real dist = 0.0
real damage
xefx array orbs[NUM_ORBS]
real array cos[NUM_ORBS]
real array sin[NUM_ORBS]
private method destroy takes nothing returns nothing
local integer i
for i = 0 to (NUM_ORBS - 1)
call orbs[i].destroy()
endfor
set caster = null
call deallocate()
endmethod
private method checkNearby takes nothing returns nothing
local integer i
local Dummy d
for i = 0 to (NUM_ORBS - 1)
call GroupEnumUnitsInRange(enumG, orbs[i].x, orbs[i].y, DAMAGE_AOE, null)
for enumU in enumG
if (not IsUnitInGroup(enumU, hit) and IsUnitEnemy(enumU, owner) and IsUnitTargetable(enumU)) then
call GroupAddUnit(hit, enumU)
call UnitDamageTarget(caster, enumU, damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
set d = Dummy.create(orbs[i].x, orbs[i].y, owner)
call d.addAbility(PURGE_ID, level)
call d.targetOrder("purge", enumU)
call d.release()
endif
endfor
endfor
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local integer i
if (dist >= DISTANCE) then
call stopPeriodic()
call destroy()
else
call checkNearby()
set dist = dist + RING_INC
for i = 0 to (NUM_ORBS - 1)
set orbs[i].x = x + dist * cos[i]
set orbs[i].y = y + dist * sin[i]
endfor
endif
endmethod
implement T32x
private static method create takes nothing returns thistype
local thistype this = allocate()
local integer i
local real x
local real y
set caster = GetTriggerUnit()
set owner = GetTriggerPlayer()
set level = GetUnitAbilityLevel(caster, SPELL_ID)
set damage = GetIntMultiplier(level) * GetHeroInt(caster, true)
set x = GetUnitX(caster)
set y = GetUnitY(caster)
for i = 0 to (NUM_ORBS - 1)
set cos[i] = Cos(Deg2Rad(i * ANGLE_DIV))
set sin[i] = Sin(Deg2Rad(i * ANGLE_DIV))
set orbs[i] = xefx.create(x + dist * cos[i], y + dist * sin[i], 0.0)
set orbs[i].fxpath = ORB_EFFECT
set orbs[i].scale = ORB_SCALE
endfor
call startPeriodic()
return this
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_ID, function thistype.create)
call Preload(ORB_EFFECT)
endmethod
endstruct
endscope
//TESH.scrollpos=99
//TESH.alwaysfold=0
scope LightningHose
// -----
// Start of Configurables
// -----
globals
private constant integer SPELL_ID = 'A042' // "Lightning Hose" hero ability.
private constant real SPRAY_FREQ = 0.1 // How often a lightning bolt is created.
private constant real AREA_OF_EFFECT = 100.0 // Area of effect of the spell.
private constant real DAMAGE_AREA = 250.0 // How close enemies must be to the bolts to get damaged.
private constant real MISSILE_SCALE = 1.0 // Missile model scale.
private constant real MISSILE_SPEED = 1000.0 // Missile speed.
private constant real MISSILE_ARC = 0.3 // Missile arc.
// Lightning bolt model:
private constant string MISSILE_ART = "war3mapImported\\RedZapMissle.mdx"
// Effect created on damaged units:
private constant string TARGET_EFFECT = "Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl"
// Attachment point for TARGET_EFFECT:
private constant string TARGET_ATTACH = "origin"
endglobals
// Configure how the intelligence multiplier is calculated:
// damage = intMultiplier * heroInt
private function GetIntMultiplier takes integer level returns real
return 1.0
endfunction
// -----
// End of Configurables
// -----
globals
private group enumG = CreateGroup()
private unit enumU
endglobals
private function IsUnitTargetable takes unit whichUnit returns boolean
return (not IsUnitType(whichUnit, UNIT_TYPE_DEAD) and not IsUnitType(whichUnit, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE))
endfunction
private struct Bolt extends xemissile
unit caster
player owner
real damage
private method onHit takes nothing returns nothing
call GroupEnumUnitsInRange(enumG, x, y, DAMAGE_AREA, null)
for enumU in enumG
if (IsUnitTargetable(enumU) and IsUnitEnemy(enumU, owner)) then
call UnitDamageTarget(caster, enumU, damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
call DestroyEffect(AddSpecialEffectTarget(TARGET_EFFECT, enumU, TARGET_ATTACH))
endif
endfor
endmethod
static method create takes unit s, real d, real x, real y returns thistype
local thistype this = allocate(GetUnitX(s), GetUnitY(s), 50.0, 0.0, 0.0, 0.0)
local real dist = GetRandomReal(0.0, AREA_OF_EFFECT)
local real ang = GetRandomReal(0.0, bj_PI * 2.0)
local real tx = x + dist * Cos(ang)
local real ty = y + dist * Sin(ang)
set caster = s
set owner = GetOwningPlayer(caster)
set damage = d
set fxpath = MISSILE_ART
set scale = MISSILE_SCALE
call setTargetPoint(tx, ty, 0.0)
call launch(MISSILE_SPEED, MISSILE_ARC)
return this
endmethod
endstruct
private struct SpellData
unit caster
real tx
real ty
real damage
private static method spray takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
// Cancelled order or channel time finished:
if (GetUnitCurrentOrder(caster) != OrderId("flamestrike")) then
call ReleaseTimer(GetExpiredTimer())
set caster = null
call deallocate()
// Still channelling:
else
call Bolt.create(caster, damage, tx, ty)
call TimerStart(GetExpiredTimer(), SPRAY_FREQ, false, function thistype.spray)
endif
endmethod
private static method create takes nothing returns thistype
local thistype this
if (GetSpellAbilityId() == SPELL_ID) then
set this = allocate()
set caster = GetTriggerUnit()
set damage = GetHeroInt(caster, true) * GetIntMultiplier(GetUnitAbilityLevel(caster, SPELL_ID))
set tx = GetSpellTargetX()
set ty = GetSpellTargetY()
call TimerStart(NewTimerEx(this), 0.0, false, function thistype.spray)
endif
return 0
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CHANNEL, function thistype.create)
call Preload(MISSILE_ART)
call Preload(TARGET_EFFECT)
endmethod
endstruct
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library CTL /* v1.1.0.0
*************************************************************************************
*
* CTL or Constant Timer Loop provides a loop for constant merged timers of timeout .03125
*
* Similar to T32 but pauses timer when no structs have instances and removes structs
* from timer trigger when those structs have no instances.
*
* This can also create new timers after destroying a previous timer and generates less
* code in the module. It also generates no triggers so long as the module is implemented
* at the top of the struct.
*
************************************************************************************
*
* static method create takes nothing returns thistype
* - CTL
* - Creates new timer
*
* method destroy takes nothing returns nothing
* - CTL
* - Destroys created timer
*
* Module
*
* module CTL
* - Declare locals in here
* - Run ini code
* module CTLExpire
* - Run timer code
* -
* - thistype this refers to current expiring timer\
* module CTLNull
* - Null locals here
* module CTLEnd
*
* Example of Constant Timer Loop 32
* struct MyTimer extends array
* integer myValue
* implement CTL
* local string s="My value is "
* implement CTLExpire
* call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,s+I2S(myValue))
* call destroy()
* implement CTLNull
* set s=null //pointless, but shows how to use null block
* implement CTLEnd
* endstruct
*
* set MyTimer.create().myValue=16 //will display "My value is 16" in 5 seconds
*
* module CT32
* - A constant running timer. Useful when the timer is pretty much never ever
* - going to stop. Also allows control over loop (just provides an expiring timer).
* - Code goes in between two methods
* module CT32End
*
* Example of Constant Timer 32
*
* //Displays
* // 1
* // 2
* // 3
* struct MyTimers extends array
* integer myValue
* thistype next
* implement CTL2
* local thistype this=thistype(0).next
* loop
* exitwhen 0==this
* call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,s+I2S(myValue))
* set this=next
* endloop
* implement CTL2End
* private static method onInit takes nothing returns nothing
* set thistype(0).next=1
* set thistype(1).next=2
* set thistype(2).next=3
* set thistype(1).myValue=1
* set thistype(2).myValue=2
* set thistype(3).myValue=3
* endmethod
* endstruct
*
************************************************************************************/
globals
private integer ic=0 //instance count
private integer tc=0 //timer count
private integer array rf //root first
private integer array n //next
private integer array p //previous
private integer array th //timer head
private integer array ns //next stack
private trigger t=CreateTrigger()
private timer m=CreateTimer()
private triggercondition array ct
private conditionfunc array rc
endglobals
private function E takes nothing returns nothing
local integer i=ns[0]
set ns[0]=0
loop
exitwhen 0==i
if (0==p[i]) then
if (0==n[i]) then
call TriggerRemoveCondition(t,ct[th[i]])
set ct[th[i]]=null
set tc=tc-1
set rf[th[i]]=0
else
set rf[th[i]]=n[i]
set p[n[i]]=0
endif
else
set p[n[i]]=p[i]
set n[p[i]]=n[i]
endif
set n[i]=n[0]
set n[0]=i
set i=ns[i]
endloop
if (0==tc) then
call PauseTimer(m)
else
call TriggerEvaluate(t)
endif
endfunction
private function CT takes integer r returns integer
local integer i
local integer f
if (0==n[0]) then
set i=ic+1
set ic=i
else
set i=n[0]
set n[0]=n[i]
endif
set th[i]=r
set ns[i]=-1
set f=rf[r]
if (0==f) then
set n[i]=0
set p[i]=0
set rf[r]=i
set ct[r]=TriggerAddCondition(t,rc[r])
if (0==tc) then
call TimerStart(m,.031250000,true,function E)
endif
set tc=tc+1
else
set n[i]=f
set p[i]=0
set p[f]=i
set rf[r]=i
endif
return i
endfunction
private function DT takes integer t returns nothing
debug if (0>ns[t]) then
set ns[t]=ns[0]
set ns[0]=t
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"TIMER LOOP ERROR: ATTEMPT TO DESTROY NULL TIMER")
debug endif
endfunction
private keyword r
private keyword e
module CTL
static integer r
static method create takes nothing returns thistype
return CT(r)
endmethod
method destroy takes nothing returns nothing
call DT(this)
endmethod
static method e takes nothing returns boolean
local thistype this=rf[r]
endmodule
module CTLExpire
loop
exitwhen 0==this
endmodule
module CTLNull
set this=n[this]
endloop
endmodule
module CTLEnd
return false
endmethod
private static method onInit takes nothing returns nothing
set r=ic+1
set ic=r
set rc[r]=Condition(function thistype.e)
endmethod
endmodule
module CT32
static method e takes nothing returns boolean
endmodule
module CT32End
return false
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(t,Condition(function thistype.e))
if (0==tc) then
call TimerStart(m,.031250000,true,function E)
endif
set tc=tc+1
endmethod
endmodule
endlibrary
//TESH.scrollpos=30
//TESH.alwaysfold=0
//* ****************************************************************************************************
//*
//* struct Dummy
//*
//* static method create takes real x, real y, player forPlayer returns thistype
//* // Creates a dummy at a point.
//*
//* method addAbility takes integer abilityId, integer abilityLevel returns nothing
//* // Adds an ability and sets the level.
//*
//* method setHeight takes real height returns nothing
//* // Sets the height of the dummy.
//*
//* method instantOrder takes string orderId returns nothing
//* // Issues an immediate order (like "stomp").
//*
//* method targetOrder takes string orderId, widget target returns nothing
//* // Issues a target order (like "charm").
//*
//* method pointOrder takes string orderId, real x, real y returns nothing
//* // Issues a point order (like "silence").
//*
//* method setDuration takes real duration returns nothing
//* // Adds a custom expiration timer to the dummy.
//* // Note that release() must not be called after this.
//*
//* method release takes nothing returns nothing
//* // Releases the dummy.
//* // Note that setDuration() must not be called after this.
//*
//* ****************************************************************************************************
library DummyTools
globals
private constant integer DUMMY_ID = 'e006' // Raw ID of "Dummy" unit.
private constant real TIMER_DURATION = 0.5 // Expiration timer duration.
endglobals
struct Dummy
private unit d // Actual unit.
private real t // Expiration timer value.
private boolean r // Whether it has been released.
method release takes nothing returns nothing
if (not r) then
call UnitApplyTimedLife(d, 'BTLF', t)
set d = null
call deallocate()
else
call BJDebugMsg("|cffff0000DummyTools|r: Used release when dummy is already released.")
endif
endmethod
method setDuration takes real duration returns nothing
if (r) then
call BJDebugMsg("|cffff0000DummyTools|r: Used setDuration when dummy is already released.")
elseif (duration >= 0.0) then
set t = duration
call release()
set r = true
else
call BJDebugMsg("|cffff0000DummyTools|r: Cannot pass a negative duration to setDuration.")
endif
endmethod
method pointOrder takes string orderId, real x, real y returns nothing
call IssuePointOrder(d, orderId, x, y)
endmethod
method targetOrder takes string orderId, widget target returns nothing
call IssueTargetOrder(d, orderId, target)
endmethod
method instantOrder takes string orderId returns nothing
call IssueImmediateOrder(d, orderId)
endmethod
method setHeight takes real height returns nothing
call UnitAddAbility(d, 'Amrf')
call UnitRemoveAbility(d, 'Amrf')
call SetUnitFlyHeight(d, height, 99999.0)
endmethod
method addAbility takes integer abilityId, integer abilityLevel returns nothing
call UnitAddAbility(d, abilityId)
call SetUnitAbilityLevel(d, abilityId, abilityLevel)
endmethod
static method create takes real x, real y, player forPlayer returns thistype
local thistype this = allocate()
set d = CreateUnit(forPlayer, DUMMY_ID, x, y, 0.0)
set t = TIMER_DURATION
set r = false
return this
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/***************************************
*
* GroupTools
* v1.1.2.2
* By Magtheridon96
*
* - Original version by Rising_Dusk
*
* - Recycles groups, and allows the
* enumeration of units while taking
* into account collision.
*
* API:
* ----
*
* - group ENUM_GROUP
*
* - function NewGroup takes nothing returns group
* - function ReleaseGroup takes group g returns nothing
* - Get and release group handles
*
* - function GroupRefresh takes group g returns nothing
* - Refresh a group so that null units are removed
*
* - function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
* - Groups units while taking into account collision
*
***************************************/
library GroupTools
globals
// The highest collision size you're using in your map.
private constant real MAX_COLLISION_SIZE = 197.
// Data Variables
private group array groups
private group gT = null
private integer gN = 0
private boolean f = false
// Global Group (Change it to CreateGroup() if you want)
group ENUM_GROUP = bj_lastCreatedGroup
endglobals
static if DEBUG_MODE then
private struct V extends array
debug static hashtable ht = InitHashtable()
endstruct
endif
private function AE takes nothing returns nothing
if (f) then
call GroupClear(gT)
set f = false
endif
call GroupAddUnit(gT,GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
debug if null==g then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"[GroupUtils]Error: Attempt to refresh null group!")
debug return
debug endif
set f = true
set gT = g
call ForGroup(gT,function AE)
if (f) then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if 0==gN then
return CreateGroup()
endif
set gN = gN - 1
debug call SaveBoolean(V.ht,GetHandleId(groups[gN]),0,false)
return groups[gN]
endfunction
function ReleaseGroup takes group g returns nothing
debug if null==g then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"[GroupUtils]Error: Attempt to release null group!")
debug return
debug endif
debug if LoadBoolean(V.ht,GetHandleId(g),0) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"[GroupUtils]Error: Double free!")
debug return
debug endif
debug call SaveBoolean(V.ht,GetHandleId(g),0,true)
call GroupClear(g)
set groups[gN] = g
set gN = gN + 1
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local unit u
debug if null==whichGroup then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"[GroupUtils]Error: Null group passed to GroupUnitsInArea!")
debug return
debug endif
call GroupEnumUnitsInRange(ENUM_GROUP,x,y,radius+MAX_COLLISION_SIZE,null)
loop
set u = FirstOfGroup(ENUM_GROUP)
exitwhen null==u
if IsUnitInRangeXY(u,x,y,radius) then
call GroupAddUnit(whichGroup,u)
endif
call GroupRemoveUnit(ENUM_GROUP,u)
endloop
endfunction
endlibrary
//TESH.scrollpos=33
//TESH.alwaysfold=0
library IsDestructableTree initializer init /* v1.2
*************************************************************************************
*
* Detect whether a destructable is a tree or not.
*
***************************************************************************
*
* Credits
*
* To PitzerMike
* -----------------------
*
* for IsDestructableTree
*
*************************************************************************************
*
* Functions
*
* function IsDestructableTree takes destructable which returns boolean
*
* function IsDestructableAlive takes destructable which returns boolean
*
* function IsDestructableDead takes destructable which returns boolean
*
* function IsTreeAlive takes destructable which returns boolean
* - May only return true for trees
*
* function KillTree takes destructable which returns nothing
* - May only kill trees
*
*/
globals
private constant integer UNIT_DUMMY_HARVESTER = 'hpea'//human peasant
private constant integer HARVEST_ABILITY = 'Ahrl'//ghoul harvest
private constant integer HARVEST = 0xD0032//harvest order, could also be 852018
private constant player PLAYER_OWNER = Player(PLAYER_NEUTRAL_PASSIVE)
private unit HARVESTER = null
endglobals
function IsDestructableTree takes destructable d returns boolean
debug if (d == null) then
debug call BJDebugMsg("ERROR: library IsDestructableTree, function IsDestructableTree, INVALID DESTRUCTABLE")
debug return false
debug endif
//851973 is the order id for stunned, it will interrupt the preceding harvest order.
return (IssueTargetOrderById(HARVESTER, HARVEST, d)) and (IssueImmediateOrderById(HARVESTER, 851973))
endfunction
function IsDestructableAlive takes destructable d returns boolean
return (GetWidgetLife(d) > 0.405)
endfunction
function IsTreeAlive takes destructable d returns boolean
return IsDestructableAlive(d) and IsDestructableTree(d)
endfunction
function KillTree takes destructable d returns nothing
if IsTreeAlive(d) then
call KillDestructable(d)
endif
endfunction
function IsDestructableDead takes destructable d returns boolean
return (GetWidgetLife(d) <= 0.405)
endfunction
private function init takes nothing returns nothing
set HARVESTER=CreateUnit(PLAYER_OWNER,UNIT_DUMMY_HARVESTER,0,0,0)
call UnitAddAbility(HARVESTER, HARVEST_ABILITY)
call UnitAddAbility(HARVESTER, 'Aloc')
call ShowUnit(HARVESTER, false)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//* ****************************************************************************************************
//*
//* Requires the "Lumberjack" library if you want knockbacked units to destroy trees (optional).
//*
//* struct Knockback
//*
//* static method start takes unit whichUnit, real distance, real angle, real speed, string effectPath returns Knockback
//* // Begins the knockback of the unit.
//* // NOTE: angle is in radians!
//*
//* ****************************************************************************************************
library Knockback requires T32, TerrainPathability, optional Lumberjack
globals
private constant real KILL_TREE_AOE = 150.0 // Kill all trees within this distance. Only applicable if "Lumberjack" library is present.
private constant real EFFECT_FREQ = 0.1 // How often knockback effects are created.
private constant string EFFECT_ATTACH = "origin" // Attachment point for the effects.
endglobals
struct Knockback
unit target
real dist
real cos
real sin
real inc
real ticker
string eff
private method destroy takes nothing returns nothing
call PauseUnit(target, false)
call SetUnitPathing(target, true)
set target = null
call deallocate()
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(target) + inc * cos
local real y = GetUnitY(target) + inc * sin
if (not IsUnitType(target, UNIT_TYPE_DEAD) and IsTerrainWalkable(x, y) and dist > 0.0) then
call SetUnitX(target, x)
call SetUnitY(target, y)
set dist = dist - inc
// Create effect if necessary:
if (ticker >= EFFECT_FREQ) then
call DestroyEffect(AddSpecialEffectTarget(eff, target, EFFECT_ATTACH))
set ticker = 0.0
else
set ticker = ticker + T32_PERIOD
endif
static if (LIBRARY_Lumberjack) then
call KillTrees(x, y, KILL_TREE_AOE)
endif
else
call stopPeriodic()
call destroy()
endif
endmethod
implement T32x
static method start takes unit whichUnit, real distance, real angle, real speed, string effectPath returns thistype
local thistype this = allocate()
set target = whichUnit
set dist = distance
set cos = Cos(angle)
set sin = Sin(angle)
set inc = speed * T32_PERIOD
set ticker = 999.0 // So that effect is created on first tick.
set eff = effectPath
call PauseUnit(target, true)
call SetUnitPathing(target, false)
call startPeriodic()
return this
endmethod
endstruct
endlibrary
//TESH.scrollpos=51
//TESH.alwaysfold=0
// ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
// Û Û
// Û Û
// ßßßßßÛ Ûßßßßß
// Û Û
// Û Û ÜÜÜÜÜÜ ÜÜÜÜÜÜÜ
// Û Û Û Û Û Û
// Û Û Û Ü Û Û Ûßßßßßß
// Û Û Û ÛÛ Û Û Û
// Û Û Û Û Û Û Û Û ÜÜÜ
// Û Û Û Û Û Û Û Û Û Û
// Û Û Û ßßß Û Û ÛÜÜÛ Û
// Û Û Û Û Û Û
// ßßßß ßßßßßßßß ßßßßßßß
// ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
// ³ Clan TDG @ Azeroth ¸ ³
// ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
// Screen Solution: 1280x1024 Visit www.jx3.net/TDG!
// ++++++++++++++++++++++++++++++++++++++++++ INFO ++++++++++++++++++++++++++++++++++++++++
// Type........................................ : .....................................Random
// Language.................................... : ......................................vJass
// Coder....................................... : ......................................Hanky
// MUI......................................... : ........................................Yes
// ++++++++++++++++++++++++++++++++++++++++++ CREDITS ++++++++++++++++++++++++++++++++++++++++
// Thanks for the JassGenNewPack: .............pipedream
// .............xttocs
// .............Pitzermike
// .............Vexorian
// .............MindWorx
// .............Scio
// .............Starcraftfreak
// .............FyreDaug
// .............KDEWolf
// ++++++++++++++++++++++++++++++++++++++++++ NOTES ++++++++++++++++++++++++++++++++++++++++
// Greetz fly out to: NgO . BuranX . JonNny . Darkt3mpl3r . WaRadius . Fireeye
// TDG . WC3C . HIVE . Toadcop . xxdingo93xx . Dynasti . TheBlooddancer
// Paladon
//================================================================================================
//Loop - Costum Motion
//================================================================================================
//A very useful system for looping structs. If you want to know more about this small system
//then check out our website. ("www.ngo.clan.su")
//! textmacro CostumMotion takes type,run,end,periodic
static timer loopExe=CreateTimer()
static integer size =0
static $type$ array runStruct[maxIndex]
boolean active
boolean paused
static method loopRun takes nothing returns nothing
local integer index=0
loop
exitwhen index==$type$.size
if not $type$.runStruct[index].paused then
if $type$.runStruct[index].active then
call $type$.runStruct[index].$run$()
set index=index+1
else
call $type$.runStruct[index].$end$()
set $type$.size=$type$.size-1
set $type$.runStruct[index]=$type$.runStruct[$type$.size]
endif
else
set index=index+1
endif
endloop
if $type$.size==0 then
call PauseTimer($type$.loopExe)
endif
endmethod
static method addMotion takes $type$ data returns integer
if $type$.size==0 then
call TimerStart($type$.loopExe,$periodic$,true,function $type$.loopRun)
endif
set $type$.runStruct[$type$.size] =data
set $type$.runStruct[$type$.size].active=true
set $type$.runStruct[$type$.size].paused=false
set $type$.size =$type$.size+1
return $type$.size
endmethod
//! endtextmacro
//================================================================================================
//Hashtable Index System
//================================================================================================
library HIS
globals
//Config Part
private constant integer size=8190
private constant integer pos =0
//Hashtable Var
private hashtable tempcache=InitHashtable()
//Important SystemVars
private integer array inUse[size]
private integer array last [size]
private integer indexsize=0
private integer lastsize =0
endglobals
//System Code
function AddHandleIndex takes handle h returns nothing
local integer id=GetHandleId(h)
local integer qi
if HaveSavedInteger(tempcache,id,pos) then
set qi=LoadInteger(tempcache,id,pos)
set inUse[qi]=inUse[qi]+1
elseif lastsize>0 then
set lastsize =lastsize-1
set inUse[last[lastsize]]=1
call SaveInteger(tempcache,id,pos,last[lastsize])
else
set inUse[indexsize]=1
call SaveInteger(tempcache,id,pos,indexsize)
set indexsize=indexsize+1
endif
endfunction
function GetHandleIndex takes handle h returns integer
debug if not HaveSavedInteger(tempcache,GetHandleId(h),pos) then
debug call BJDebugMsg("Error: No index attached to handle [#100]")
debug endif
return LoadInteger(tempcache,GetHandleId(h),pos)
endfunction
function ClearHandleIndex takes handle h returns nothing
local integer id=GetHandleId(h)
local integer qi=LoadInteger(tempcache,id,pos)
debug if HaveSavedInteger(tempcache,id,pos) then
set inUse[qi]=inUse[qi]-1
if inUse[qi]==0 then
set last[lastsize]=qi
set lastsize =lastsize+1
call FlushChildHashtable(tempcache,id)
endif
debug else
debug call BJDebugMsg("Error: No index attached to handle [#101]")
debug endif
endfunction
endlibrary
//================================================================================================
//Functions - Standart Functions
//================================================================================================
library MainFunctions initializer init
globals
constant real deg2rad =0.017453 //Set the degree to radians value
constant real rad2deg =57.2957795//Set the radians to degree value
constant integer maxIndex =8190 //Set the maximal index number
constant real PreX =700. //Preload X
constant real PreY =700. //Preload Y
public group loopG =null
public item getWalkable =null
public location loc =null
public boolexpr filter =null
constant integer invulnerable_id ='Avul'
constant integer purge_buff_id ='Bprg'
public constant integer getWalkable_id ='sehr'
public constant integer flyHack ='Amrf'
endglobals
function GetProVal takes real value returns real
if value<0. then
return value*-1
endif
return value
endfunction
//Little helpful functions
function ClearTextMessagesForPlayer takes player p returns nothing
if (GetLocalPlayer()==p) then
call ClearTextMessages()
endif
endfunction
function UnitAddFly takes unit u returns nothing
call UnitAddAbility(u,flyHack)
call UnitRemoveAbility(u,flyHack)
endfunction
function A2PXY takes real x,real y,real xt,real yt returns real
return ModuloReal(rad2deg*Atan2(yt-y,xt-x),360.)
endfunction
function D2PXY takes real x,real y,real xt,real yt returns real
local real dx=xt-x
local real dy=yt-y
return SquareRoot(dx*dx+dy*dy)
endfunction
function IsPointWalkable takes real x,real y returns boolean
call SetItemPosition(getWalkable,x,y)
call SetItemVisible(getWalkable,false)
return GetItemX(getWalkable)==x and GetItemY(getWalkable)==y
endfunction
function GetPointWalkableX takes real x,real y returns real
call SetItemPosition(getWalkable,x,y)
call SetItemVisible(getWalkable,false)
return GetItemX(getWalkable)
endfunction
function GetPointWalkableY takes real x,real y returns real
call SetItemPosition(getWalkable,x,y)
call SetItemVisible(getWalkable,false)
return GetItemY(getWalkable)
endfunction
function DebugFilter takes nothing returns boolean
return true
endfunction
function GetUnitsInRange takes real radius,real x,real y returns group
call GroupEnumUnitsInRange(loopG,x,y,radius,filter)
return loopG
endfunction
function GetClonedGroup takes group g returns group
set bj_groupAddGroupDest = loopG
call ForGroup(g, function GroupAddGroupEnum)
return loopG
endfunction
function RangedReal takes real v,real min,real max returns real
if v<min then
// return min
elseif v>max then
// return max
endif
return v
endfunction
function GetZ takes real x,real y returns real
call MoveLocation(loc,x,y)
return GetLocationZ(loc)
endfunction
//Credits to JonNny for the Parabula
function GetFlyParabula takes real maxheight , real zs , real zt , real q returns real
return (maxheight * Sin(q*bj_PI))+ q * (zt-zs)
endfunction
//Generic unit filter
function IsUnitNotImmun takes unit c,unit u returns boolean
if IsUnitEnemy(u,GetOwningPlayer(c)) then
if GetUnitState(u,UNIT_STATE_LIFE)>0. then
if GetUnitAbilityLevel(u,invulnerable_id)<=0 then
if IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)==false then
return IsUnitType(u,UNIT_TYPE_STRUCTURE)==false
endif
endif
endif
endif
return false
endfunction
function IsUnitNotBuffImmune takes unit u returns boolean
if IsUnitType(u,UNIT_TYPE_RESISTANT)==false then
if IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)==false then
if GetUnitState(u,UNIT_STATE_LIFE)>0. then
if GetUnitAbilityLevel(u,invulnerable_id)<=0 then
return GetUnitAbilityLevel(u,purge_buff_id)<=0
endif
endif
endif
endif
return false
endfunction
function TerrainDeformationRippleXY takes real duration, boolean limitNeg, real x,real y, real startRadius, real endRadius, real depth, real wavePeriod, real waveWidth returns terraindeformation
local real spaceWave
local real timeWave
local real radiusRatio
if (endRadius <= 0 or waveWidth <= 0 or wavePeriod <= 0) then
return null
endif
set timeWave = 2.0 * duration / wavePeriod
set spaceWave = 2.0 * endRadius / waveWidth
set radiusRatio = startRadius / endRadius
set bj_lastCreatedTerrainDeformation = TerrainDeformRipple(x,y, endRadius, depth, R2I(duration * 1000), 1, spaceWave, timeWave, radiusRatio, limitNeg)
return bj_lastCreatedTerrainDeformation
endfunction
//Clearing Handles
function AB_DestroyTrigger takes trigger trig returns nothing
if trig!=null then
call TriggerClearActions(trig)
call TriggerClearConditions(trig)
call DestroyTrigger(trig)
endif
endfunction
function AB_DestroyTimer takes timer t returns nothing
if t!=null then
call PauseTimer(t)
call DestroyTimer(t)
endif
endfunction
function AB_DestroyGroup takes group g returns nothing
if g!=null then
call GroupClear(g)
call DestroyGroup(g)
endif
endfunction
function AB_DialogDestroy takes dialog log returns nothing
if log!=null then
call DialogClear(log)
call DialogDestroy(log)
endif
endfunction
function AB_DestroyMultiboard takes multiboard lb returns nothing
if lb!=null then
call MultiboardClear(lb)
call DestroyMultiboard(lb)
endif
endfunction
//Initialization of the varibales
private function init takes nothing returns nothing
set getWalkable=CreateItem(getWalkable_id,0,0)
set loc =Location(0,0)
set loopG =CreateGroup()
set filter =Filter(function DebugFilter)
call SetItemVisible(getWalkable,false)
endfunction
endlibrary
//Count function for rects in a area
library CountDestructable requires MainFunctions
globals
private rect dat_prove=Rect(0,0,0,0)
endglobals
private function EnumCountDestructables takes nothing returns nothing
if GetDestructableLife(GetEnumDestructable())>0 then
set bj_forLoopAIndex=bj_forLoopAIndex+1
endif
endfunction
function CountDestructableInRangeOfXY takes real x,real y,real range returns integer
call SetRect(dat_prove,x-range,y-range,x+range,y+range)
set bj_forLoopAIndex=0
call EnumDestructablesInRect(dat_prove,MainFunctions_filter,function EnumCountDestructables)
return bj_forLoopAIndex
endfunction
endlibrary
//================================================================================================
//Loop - Buff Check (Debug for some spells)
//================================================================================================
//This is just made for this spellpack. If you have questions about this system just ask me.
library BuffCheck requires MainFunctions
private struct BuffCheckData
integer buffid
real time
real max
unit u
method check takes nothing returns nothing
set .time=.time+0.5
set .active=.time<=.max and GetUnitAbilityLevel(.u,.buffid)>0
endmethod
method endcheck takes nothing returns nothing
call UnitRemoveAbility(.u,.buffid)
set .u=null
call .destroy()
endmethod
//! runtextmacro CostumMotion("BuffCheckData","check","endcheck","0.5")
endstruct
function DestroyBuffAfterTime takes unit u,integer buffid,real maxtime returns nothing
local BuffCheckData bc
if GetUnitAbilityLevel(u,buffid)>0 then
call UnitRemoveAbility(u,buffid)
else
set bc=BuffCheckData.create()
set bc.u =u
set bc.buffid=buffid
set bc.time =0.
set bc.max =maxtime
call BuffCheckData.addMotion(bc)
endif
endfunction
endlibrary
//================================================================================================
//Loop - Buff Effects
//================================================================================================
//This is just made for this spellpack. If you have questions about this system just ask me.
//! textmacro BuffEffect takes abilityId,periodic,prefix
private struct $prefix$BuffData
static timer loopExe=CreateTimer()
static integer size =0
static integer array executer [maxIndex]
static $prefix$BuffData array runStruct[maxIndex]
unit victim
real duration
real time
static method BuffCheck takes nothing returns nothing
local integer index=0
local integer id
loop
exitwhen index==$prefix$BuffData.size
set id=$prefix$BuffData.executer[index]
set $prefix$BuffData.runStruct[id].time=$prefix$BuffData.runStruct[id].time+$periodic$
if $prefix$BuffData.runStruct[id].time>=$prefix$BuffData.runStruct[id].duration then
call UnitRemoveAbility($prefix$BuffData.runStruct[id].victim,$abilityId$)
call ClearHandleIndex($prefix$BuffData.runStruct[id].victim)
set $prefix$BuffData.runStruct[id].victim=null
call $prefix$BuffData.runStruct[id].destroy()
set $prefix$BuffData.size=$prefix$BuffData.size-1
set $prefix$BuffData.executer[index]=$prefix$BuffData.executer[$prefix$BuffData.size]
elseif not IsUnitNotBuffImmune($prefix$BuffData.runStruct[id].victim) then
call UnitRemoveAbility($prefix$BuffData.runStruct[id].victim,$abilityId$)
call ClearHandleIndex($prefix$BuffData.runStruct[id].victim)
set $prefix$BuffData.runStruct[id].victim=null
call $prefix$BuffData.runStruct[id].destroy()
set $prefix$BuffData.size=$prefix$BuffData.size-1
set $prefix$BuffData.executer[index]=$prefix$BuffData.executer[$prefix$BuffData.size]
else
set index=index+1
endif
endloop
if $prefix$BuffData.size==0 then
call PauseTimer($prefix$BuffData.loopExe)
endif
endmethod
endstruct
private function UnitAdd$prefix$Buff takes unit victim,real duration,integer lvl returns nothing
local integer index
if $prefix$BuffData.size==0 then
call TimerStart($prefix$BuffData.loopExe,$periodic$,true,function $prefix$BuffData.BuffCheck)
endif
if GetUnitAbilityLevel(victim,$abilityId$)>0 then
set index=GetHandleIndex(victim)
call UnitRemoveAbility(victim,$abilityId$)
else
call AddHandleIndex(victim)
set index =GetHandleIndex(victim)
set $prefix$BuffData.runStruct[index] =$prefix$BuffData.create()
set $prefix$BuffData.executer[$prefix$BuffData.size]=index
set $prefix$BuffData.size =$prefix$BuffData.size+1
endif
set $prefix$BuffData.runStruct[index].victim =victim
set $prefix$BuffData.runStruct[index].duration =duration
set $prefix$BuffData.runStruct[index].time =0.
call UnitAddAbility(victim,$abilityId$)
call SetUnitAbilityLevel(victim,$abilityId$,lvl)
endfunction
//! endtextmacro
//================================================================================================
//Loop - Motion System
//================================================================================================
//This is a easy motion system which make some basic motions.
//It's helpful if you don't want to write some stuff again and
//again.
library MotionDatabase initializer init requires MainFunctions
globals
private constant real MinimalChaseRange=10.
public unit tm //Temp Missle
public unit tc //Temp Caster
public unit tv //Temp Victim
public integer tdata //Temp Data
private rect MaxArea =null
public real periodic =0.03
endglobals
struct JumpDatabase
unit u
real distance
real maxdistance
real angle
real speed
real x
real y
real mx
real my
real array z[3]
method motion takes nothing returns nothing
local real curv
local real x
local real y
local real z
set .distance=.distance+.speed
if .distance>.maxdistance then
call SetUnitFlyHeight(.u,GetUnitDefaultFlyHeight(.u),0)
set .active=false
else
set x=.x+.mx
set y=.y+.my
set z=GetZ(x,y)
set curv=GetFlyParabula(.z[1],.z[0],.z[2],.distance/.maxdistance) + (.z[0]-z)
if RectContainsCoords(MaxArea,x,y) then
call SetUnitPosition(.u,x,y)
set .x=x
set .y=y
endif
call SetUnitFlyHeight(.u,curv,0)
endif
endmethod
method endmotion takes nothing returns nothing
set .u=null
call .destroy()
endmethod
//! runtextmacro CostumMotion("JumpDatabase","motion","endmotion","periodic")
endstruct
struct ChaseDatabase
unit u
unit target
unit attacker
real speed
real z
real Rz
string endfunc
integer data
integer loopMember
method motion takes nothing returns nothing
local real Ux =GetUnitX(.u)
local real Uy =GetUnitY(.u)
local real Tx =GetUnitX(.target)
local real Ty =GetUnitY(.target)
local real distance =D2PXY(Ux,Uy,Tx,Ty)
local real angle
if distance>MinimalChaseRange then
set angle=Atan2(Ty-Uy,Tx-Ux)
set Ux=Ux+.speed*Cos(angle)
set Uy=Uy+.speed*Sin(angle)
call SetUnitPosition(.u,Ux,Uy)
call SetUnitFlyHeight(.u,.z,.Rz)
else
set .active=false
endif
endmethod
method endmotion takes nothing returns nothing
set tv =.target
set tm =.u
set tc =.attacker
set tdata=.data
call ExecuteFunc(.endfunc)
set .u =null
set .target =null
set .attacker=null
call .destroy()
endmethod
//! runtextmacro CostumMotion("ChaseDatabase","motion","endmotion","periodic")
endstruct
struct CollisionDatabase
unit u
unit attacker
real speed
real angle
real z
real Rz
real range
real distance
real x
real y
string endfunc
integer data
integer loopMember
method motion takes nothing returns nothing
local unit a
local group g
local integer c
set .distance=.distance-.speed
if .distance>0. then
set .x=.x+.speed*Cos(.angle)
set .y=.y+.speed*Sin(.angle)
call SetUnitPosition(.u,.x,.y)
call SetUnitFlyHeight(.u,.z,.Rz)
set g=GetUnitsInRange(.range,.x,.y)
set c=0
loop
set a=FirstOfGroup(g)
exitwhen a==null
call GroupRemoveUnit(g,a)
if IsUnitNotImmun(.attacker,a) and a!=.u then
set c=c+1
endif
endloop
call GroupClear(g)
set g=null
set .active=c<=0
else
set .active=false
endif
endmethod
method endmotion takes nothing returns nothing
set tc =.attacker
set tm =.u
set tdata=.data
call ExecuteFunc(.endfunc)
set .u =null
set .attacker=null
call .destroy()
endmethod
//! runtextmacro CostumMotion("CollisionDatabase","motion","endmotion","periodic")
endstruct
function LaunchMissileAtPointEx takes unit u,real x1,real y1,real bZ,real maxZ,real x2,real y2,real endz,real speed returns nothing
local JumpDatabase JD =JumpDatabase.create()
set JD.u =u
set JD.z[0] =GetZ(x1,y1)+bZ
set JD.z[1] =maxZ
set JD.z[2] =GetZ(x2,y2)+endz
set JD.x =x1
set JD.y =y1
set JD.speed =speed
set JD.distance =0.
set JD.maxdistance =D2PXY(x1,y1,x2,y2)
set JD.angle =Atan2(y2-y1,x2-x1)
set JD.mx =speed*Cos(JD.angle)
set JD.my =speed*Sin(JD.angle)
call UnitAddFly(u)
call SetUnitX(u,x1)
call SetUnitY(u,y1)
call JumpDatabase.addMotion(JD)
endfunction
function LaunchNormalChaseMissileAtPointEx takes unit attacker,unit missile,real x1,real y1,real z,unit victim,real speed,real Zrate,string colfunc,integer data returns nothing
local ChaseDatabase CD =ChaseDatabase.create()
set CD.u =missile
set CD.z =z
set CD.attacker =attacker
set CD.target =victim
set CD.speed =speed
set CD.endfunc =colfunc
set CD.Rz =Zrate
set CD.data =data
call UnitAddFly(missile)
call SetUnitX(missile,x1)
call SetUnitY(missile,y1)
call ChaseDatabase.addMotion(CD)
endfunction
function LaunchNormalCollisionMissileAtPointEx takes unit attacker,unit missile,real x1,real y1,real z,real x2,real y2,real speed,real range,string colfunc,integer data returns nothing
local CollisionDatabase CD =CollisionDatabase.create()
set CD.u =missile
set CD.attacker =attacker
set CD.z =z
set CD.Rz =0.
set CD.x =x1
set CD.y =y1
set CD.range =range
set CD.speed =speed
set CD.endfunc =colfunc
set CD.distance =D2PXY(x1,y1,x2,y2)
set CD.angle =Atan2(y2-y1,x2-x1)
set CD.data =data
call UnitAddFly(missile)
call SetUnitX(missile,x1)
call SetUnitY(missile,y1)
call CollisionDatabase.addMotion(CD)
endfunction
private function init takes nothing returns nothing
set MaxArea=bj_mapInitialPlayableArea
endfunction
endlibrary
//================================================================================================
//Timer - Timer Recycler
//================================================================================================
//This is a standart timer recycler. It's so fast like TimerUtils and some benchmark tests
//showed that this system seems to be sometimes faster than both TimerUtil versions.
//But try it out yourself.
library TimerRecycler requires MainFunctions,HIS
globals
private constant integer pos =0
private hashtable hs =InitHashtable()
private integer lastsize =0
private timer array last[maxIndex]
endglobals
//! textmacro NextTimer takes name,type,func
function GetNextTimer$name$ takes $type$ dat returns timer
local integer index
local timer temp
if lastsize>0 then
set lastsize=lastsize-1
set temp =last[lastsize]
else
set temp =CreateTimer()
endif
call AddHandleIndex(temp)
call Save$func$(hs,GetHandleIndex(temp),pos,dat)
return temp
endfunction
//! endtextmacro
//! runtextmacro NextTimer("Int","integer","Integer")
//! runtextmacro NextTimer("Agent","agent","AgentHandle")
//! runtextmacro NextTimer("TextTag","texttag","TextTagHandle")
//! runtextmacro NextTimer("Lightning","lightning","LightningHandle")
//! textmacro GetType takes name,type,func
function GetTimerData$name$ takes timer t returns $type$
return Load$func$(hs,GetHandleIndex(t),pos)
endfunction
//! endtextmacro
//! runtextmacro GetType("Int","integer","Integer")
//! runtextmacro GetType("Unit","unit","UnitHandle")
//! runtextmacro GetType("Effect","effect","EffectHandle")
//! runtextmacro GetType("Lightning","lightning","LightningHandle")
//! runtextmacro GetType("TextTag","texttag","TextTagHandle")
function RecycleTimer takes timer t returns nothing
local integer index=GetHandleIndex(t)
call PauseTimer(t)
call ClearHandleIndex(t)
set last[lastsize]=t
set lastsize =lastsize+1
endfunction
endlibrary
//================================================================================================
//Group - Group Recycler
//================================================================================================
//A standart group recycler.
library GroupRecycler requires MainFunctions,HIS
globals
private integer max =0
private integer cmax =0
private group array rGroup
private integer array rInt[maxIndex]
endglobals
function GetNextGroup takes nothing returns group
set cmax=cmax+1
if max<cmax then
set rGroup[cmax]=CreateGroup()
set max =cmax
endif
call AddHandleIndex(rGroup[cmax])
set rInt[GetHandleIndex(rGroup[cmax])]=cmax
return rGroup[cmax]
endfunction
function RecycleGroup takes group g returns nothing
local integer index=GetHandleIndex(g)
call ClearHandleIndex(g)
set rGroup[rInt[index]] =rGroup[cmax]
set rInt[GetHandleIndex(rGroup[cmax])]=rInt[index]
set rGroup[cmax] =g
set cmax=cmax-1
endfunction
endlibrary
//================================================================================================
//Timed - Handle Destroy
//================================================================================================
//Some small useful functions.
library TimedHandleDead requires MainFunctions,TimerRecycler
function U2Death takes nothing returns nothing
local timer t = GetExpiredTimer()
call RemoveUnit(GetTimerDataUnit(t))
call RecycleTimer(t)
set t=null
endfunction
function U2Null takes unit u,real duration returns nothing
local timer t = GetNextTimerAgent(u)
call TimerStart(t,duration,false,function U2Death)
set t = null
endfunction
function E2Death takes nothing returns nothing
local timer t = GetExpiredTimer()
call DestroyEffect(GetTimerDataEffect(t))
call RecycleTimer(t)
set t=null
endfunction
function E2Null takes effect e,real duration returns nothing
local timer t = GetNextTimerAgent(e)
call TimerStart(t,duration,false,function E2Death)
set t = null
endfunction
function L2Death takes nothing returns nothing
local timer t = GetExpiredTimer()
call DestroyLightning(GetTimerDataLightning(t))
call RecycleTimer(t)
set t=null
endfunction
function L2Null takes lightning l,real duration returns nothing
local timer t = GetNextTimerLightning(l)
call TimerStart(t,duration,false,function L2Death)
set t = null
endfunction
function TT2Death takes nothing returns nothing
local timer t = GetExpiredTimer()
call DestroyTextTag(GetTimerDataTextTag(t))
call RecycleTimer(t)
set t=null
endfunction
function TT2Null takes texttag tt,real duration returns nothing
local timer t = GetNextTimerTextTag(tt)
call TimerStart(t,duration,false,function L2Death)
set t = null
endfunction
endlibrary
//================================================================================================
//Passiv - Damage Skill
//================================================================================================
//This system will be useful for skills like my Crush or Holy Shock spell. For more
//informations just ask me.
library DamageSkill initializer init requires MainFunctions,TimerRecycler
globals
private boolexpr array ExecuteFunction[maxIndex]
private unit array Attacker[maxIndex]
private unit array Attacked[maxIndex]
private trigger DamageDetect=null
private trigger EventExecute=null
private group InUseCache =null
private group RegisterCache =null
public unit attacker=null
public unit attacked=null
public real damage =0.
endglobals
function TriggerAddDamageEvent takes unit a,unit b,code func returns nothing
local integer id
if not IsUnitInGroup(a,RegisterCache) then
call TriggerRegisterUnitEvent(DamageDetect,a,EVENT_UNIT_DAMAGED)
call GroupAddUnit(RegisterCache,a)
endif
if not IsUnitInGroup(b,InUseCache) then
call AddHandleIndex(b)
set id=GetHandleIndex(b)
call GroupAddUnit(InUseCache,b)
else
set id=GetHandleIndex(b)
call DestroyBoolExpr(ExecuteFunction[id])
endif
set ExecuteFunction[id]=Filter(func)
set Attacker[id] =b
set Attacked[id] =a
endfunction
private function CheckRegister takes nothing returns boolean
return IsUnitInGroup(GetEventDamageSource(),InUseCache)
endfunction
private function GetDamage takes nothing returns nothing
local integer id =GetHandleIndex(GetEventDamageSource())
local triggercondition tc
set attacker=Attacker[id]
set attacked=Attacked[id]
set damage =GetEventDamage()
set tc=TriggerAddCondition(EventExecute,ExecuteFunction[id])
call TriggerEvaluate(EventExecute)
call TriggerRemoveCondition(EventExecute,tc)
call DestroyBoolExpr(ExecuteFunction[id])
call GroupRemoveUnit(InUseCache,Attacker[id])
call ClearHandleIndex(Attacker[id])
set ExecuteFunction[id]=null
set Attacker[id] =null
set Attacked[id] =null
set tc =null
endfunction
private function init takes nothing returns nothing
set InUseCache =CreateGroup()
set RegisterCache =CreateGroup()
set DamageDetect =CreateTrigger()
set EventExecute =CreateTrigger()
call TriggerAddAction(DamageDetect,function GetDamage)
call TriggerAddCondition(DamageDetect,Condition(function CheckRegister))
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/**************************************************************
*
* RegisterPlayerUnitEvent
* v4.2.0.0
* By Magtheridon96
*
* I would like to give a special thanks to Bribe, azlier
* and BBQ for improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must
* return false. They can return nothing as well.
*
* Disclaimer:
* -----------
*
* - Don't use TriggerSleepAction inside registered code.
*
* API:
* ----
*
* function RegisterPlayerUnitEvent
* takes
* playerunitevent whichEvent : The event you would like to register
* code whichFunction : The code you would like to register
* returns
* nothing
*
* - Registers code that will execute when an event fires.
*
**************************************************************/
library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
globals
private trigger array t
endglobals
function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
local integer i = GetHandleId(p)
local integer k = 15
if t[i] == null then
set t[i] = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
exitwhen k == 0
set k = k - 1
endloop
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//============================================================================
// SpellEffectEvent by Bribe
// - Version 1.1.0.0
//
// API
// ---
// RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
// RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
// Table: hiveworkshop.com/forums/showthread.php?t=188084
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
//============================================================================
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable ht = InitHashtable()
endif
static method onCast takes nothing returns nothing
static if LIBRARY_Table then
call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
else
call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
endif
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set .tb = Table.create()
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
//============================================================================
private struct S extends array
implement M
endstruct
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
static if LIBRARY_Table then
if not S.tb.handle.has(abil) then
set S.tb.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
else
if not HaveSavedHandle(S.ht, 0, abil) then
call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.1.0
One map, one hashtable. Welcome to NewTable 3.1
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Timer32 ~~ By Jesus4Lyf ~~ Version 1.06 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Timer32?
// - Timer32 implements a fully optimised timer loop for a struct.
// - Instances can be added to the loop, which will call .periodic every
// PERIOD until .stopPeriodic() is called.
//
// =Pros=
// - Efficient.
// - Simple.
//
// =Cons=
// - Only allows one period.
// - The called method must be named ".periodic".
//
// Methods:
// - struct.startPeriodic()
// - struct.stopPeriodic()
//
// - private method periodic takes nothing returns nothing
//
// This must be defined in structs that implement Periodic Module.
// It will be executed by the module every PERIOD until .stopPeriodic() is called.
// Put "implement T32x" BELOW this method.
//
// Modules:
// - T32x
// Has no safety on .stopPeriodic or .startPeriodic (except debug messages
// to warn).
//
// - T32xs
// Has safety on .stopPeriodic and .startPeriodic so if they are called
// multiple times, or while otherwise are already stopped/started respectively,
// no error will occur, the call will be ignored.
//
// - T32
// The original, old version of the T32 module. This remains for backwards
// compatability, and is deprecated. The periodic method must return a boolean,
// false to continue running or true to stop.
//
// Details:
// - Uses one timer.
//
// - Do not, within a .periodic method, follow a .stopPeriodic call with a
// .startPeriodic call.
//
// How to import:
// - Create a trigger named T32.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Infinitegde for finding a bug in the debug message that actually altered
// system operation (when in debug mode).
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library T32 initializer OnInit
globals
public constant real PERIOD=0.03125
public constant integer FPS=R2I(1/PERIOD)
public integer Tick=0 // very useful.
//==============================================================================
private trigger Trig=CreateTrigger()
endglobals
//==============================================================================
// The standard T32 module, T32x.
//
module T32x
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
method stopPeriodic takes nothing returns nothing
debug if this.prev==0 and thistype(0).next!=this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had stopPeriodic called while not running!")
debug endif
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The standard T32 module with added safety checks on .startPeriodic() and
// .stopPeriodic(), T32xs.
//
module T32xs
private thistype next
private thistype prev
private boolean runningPeriodic
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
if not this.runningPeriodic then
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
set this.runningPeriodic=true
endif
endmethod
method stopPeriodic takes nothing returns nothing
if this.runningPeriodic then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
set this.runningPeriodic=false
endif
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The original T32 module, for backwards compatability only.
//
module T32 // deprecated.
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
if this.periodic() then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endif
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// System Core.
//
private function OnExpire takes nothing returns nothing
set Tick=Tick+1
call TriggerEvaluate(Trig)
endfunction
private function OnInit takes nothing returns nothing
call TimerStart(CreateTimer(),PERIOD,true,function OnExpire)
endfunction
endlibrary
//TESH.scrollpos=72
//TESH.alwaysfold=0
library TerrainPathability initializer Init
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script can be used to detect the type of pathing at a specific point.
//* It is valuable to do it this way because the IsTerrainPathable is very
//* counterintuitive and returns in odd ways and aren't always as you would
//* expect. This library, however, facilitates detecting those things reliably
//* and easily.
//*
//******************************************************************************
//*
//* > function IsTerrainDeepWater takes real x, real y returns boolean
//* > function IsTerrainShallowWater takes real x, real y returns boolean
//* > function IsTerrainLand takes real x, real y returns boolean
//* > function IsTerrainPlatform takes real x, real y returns boolean
//* > function IsTerrainWalkable takes real x, real y returns boolean
//*
//* These functions return true if the given point is of the type specified
//* in the function's name and false if it is not. For the IsTerrainWalkable
//* function, the MAX_RANGE constant below is the maximum deviation range from
//* the supplied coordinates that will still return true.
//*
//* The IsTerrainPlatform works for any preplaced walkable destructable. It will
//* return true over bridges, destructable ramps, elevators, and invisible
//* platforms. Walkable destructables created at runtime do not create the same
//* pathing hole as preplaced ones do, so this will return false for them. All
//* other functions except IsTerrainWalkable return false for platforms, because
//* the platform itself erases their pathing when the map is saved.
//*
//* After calling IsTerrainWalkable(x, y), the following two global variables
//* gain meaning. They return the X and Y coordinates of the nearest walkable
//* point to the specified coordinates. These will only deviate from the
//* IsTerrainWalkable function arguments if the function returned false.
//*
//* Variables that can be used from the library:
//* [real] TerrainPathability_X
//* [real] TerrainPathability_Y
//*
globals
private constant real MAX_RANGE = 10.
private constant integer DUMMY_ITEM_ID = 'wolg'
endglobals
globals
private item Item = null
private rect Find = null
private item array Hid
private integer HidMax = 0
public real X = 0.
public real Y = 0.
endglobals
function IsTerrainDeepWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
function IsTerrainShallowWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
function IsTerrainLand takes real x, real y returns boolean
return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
endfunction
function IsTerrainPlatform takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
private function HideItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set Hid[HidMax] = GetEnumItem()
call SetItemVisible(Hid[HidMax], false)
set HidMax = HidMax + 1
endif
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
//Hide any items in the area to avoid conflicts with our item
call MoveRectTo(Find, x, y)
call EnumItemsInRect(Find ,null, function HideItem)
//Try to move the test item and get its coords
call SetItemPosition(Item, x, y) //Unhides the item
set X = GetItemX(Item)
set Y = GetItemY(Item)
static if LIBRARY_IsTerrainWalkable then
//This is for compatibility with the IsTerrainWalkable library
set IsTerrainWalkable_X = X
set IsTerrainWalkable_Y = Y
endif
call SetItemVisible(Item, false)//Hide it again
//Unhide any items hidden at the start
loop
exitwhen HidMax <= 0
set HidMax = HidMax - 1
call SetItemVisible(Hid[HidMax], true)
set Hid[HidMax] = null
endloop
//Return walkability
return (X-x)*(X-x)+(Y-y)*(Y-y) <= MAX_RANGE*MAX_RANGE and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
private function Init takes nothing returns nothing
set Find = Rect(0., 0., 128., 128.)
set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
call SetItemVisible(Item, false)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=20
//TESH.alwaysfold=0
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
// use the dummy.mdx model, so remember to import it as
// well, just use copy&paste to copy the dummy from the
// xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
// this rawcode to another spell that morphs into a flier
// in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
// raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
// timer that depends on it, if you put a low value
// the movement will look good but it may hurt your
// performance, if instead you use a high value it
// will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
// you got a unit bigger than 197.0 it would be
// a good idea to update this constant, since some
// enums will not find it. Likewise, if none of
// your units can go bellow X and X is much smaller
// than 197.0, it would be a good idea to update
// as well, since it will improve the performance
// those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************
//===========================================================================
globals
constant integer XE_DUMMY_UNITID = 'e006'
constant integer XE_HEIGHT_ENABLER = 'Amrf'
constant integer XE_TREE_RECOGNITION = 'Aeat'
constant real XE_ANIMATION_PERIOD = 0.025
constant real XE_MAX_COLLISION_SIZE = 197.0
endglobals
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library xefx initializer init requires xebasic, optional xedummy
//**************************************************
// xefx 0.9
// --------
// Recommended: ARGB (adds ARGBrecolor method)
// For your movable fx needs
//
//**************************************************
//==================================================
globals
private constant integer MAX_INSTANCES = 8190 //change accordingly.
//Delay in order to show the death animation of the effect correctly when xefx is destroyed.
//You may need to increase this if you are using effects with longer death animations.
private constant real MIN_RECYCLE_DELAY = 4.0
//The delay does not need to be exact so we do cleanup in batches instead of individually.
//This determines how often the recycler runs, should be less than MIN_RECYCLE_DELAY.
private constant real RECYCLE_INTERVAL = 0.5
//if this is true and the xedummy library is present, units will be recycled instead of removed.
private constant boolean RECYCLE_DUMMY_UNITS = true
private timer recycler
endglobals
private struct recyclebin
unit u
private recyclebin next=0
private static recyclebin array list
private static integer readindex=1
private static integer writeindex=0
private static integer count=0
static method Recycle takes nothing returns nothing
local recyclebin this = .list[readindex]
loop
exitwhen this==0
static if RECYCLE_DUMMY_UNITS and LIBRARY_xedummy then
call XE_ReleaseDummyUnit(this.u)
else
call RemoveUnit(this.u)
endif
set this.u=null
set .count=.count-1
call this.destroy()
set this=this.next
endloop
set .list[readindex]=0
set .writeindex=.readindex
set .readindex=.readindex+1
if .readindex>R2I(MIN_RECYCLE_DELAY/RECYCLE_INTERVAL+1.0) then
set .readindex=0
endif
if count!=0 then
call TimerStart(recycler, RECYCLE_INTERVAL, false, function recyclebin.Recycle)
endif
endmethod
static method create takes unit u returns recyclebin
local recyclebin this=recyclebin.allocate()
if .count==0 then
call TimerStart(recycler, RECYCLE_INTERVAL, false, function recyclebin.Recycle)
endif
set .count=.count+1
set .u=u
call SetUnitOwner(u,Player(15),false)
set .next=.list[.writeindex]
set .list[.writeindex]=this
return this
endmethod
endstruct
private function init takes nothing returns nothing
set recycler=CreateTimer()
endfunction
struct xefx[MAX_INSTANCES]
public integer tag=0
private unit dummy
private effect fx=null
private real zang=0.0
private integer r=255
private integer g=255
private integer b=255
private integer a=255
private integer abil=0
static method create takes real x, real y, real facing returns xefx
local xefx this=xefx.allocate()
static if RECYCLE_DUMMY_UNITS and LIBRARY_xedummy then
set this.dummy= XE_NewDummyUnit(Player(15), x,y, facing*bj_RADTODEG)
else
set this.dummy= CreateUnit(Player(15), XE_DUMMY_UNITID, x,y, facing*bj_RADTODEG)
call UnitAddAbility(this.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(this.dummy,'Aloc')
call UnitRemoveAbility(this.dummy,XE_HEIGHT_ENABLER)
call SetUnitX(this.dummy,x)
call SetUnitY(this.dummy,y)
endif
return this
endmethod
method operator owner takes nothing returns player
return GetOwningPlayer(this.dummy)
endmethod
method operator owner= takes player p returns nothing
call SetUnitOwner(this.dummy,p,false)
endmethod
method operator teamcolor= takes playercolor c returns nothing
call SetUnitColor(this.dummy,c)
endmethod
method operator scale= takes real value returns nothing
call SetUnitScale(this.dummy,value,value,value)
endmethod
//! textmacro XEFX_colorstuff takes colorname, colorvar
method operator $colorname$ takes nothing returns integer
return this.$colorvar$
endmethod
method operator $colorname$= takes integer value returns nothing
set this.$colorvar$=value
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
//! endtextmacro
//! runtextmacro XEFX_colorstuff("red","r")
//! runtextmacro XEFX_colorstuff("green","g")
//! runtextmacro XEFX_colorstuff("blue","b")
//! runtextmacro XEFX_colorstuff("alpha","a")
method recolor takes integer r, integer g , integer b, integer a returns nothing
set this.r=r
set this.g=g
set this.b=b
set this.a=a
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
implement optional ARGBrecolor
method operator abilityid takes nothing returns integer
return this.abil
endmethod
method operator abilityid= takes integer a returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(a!=0) then
call UnitAddAbility(this.dummy,a)
endif
set this.abil=a
endmethod
method operator abilityLevel takes nothing returns integer
return GetUnitAbilityLevel( this.dummy, this.abil)
endmethod
method operator abilityLevel= takes integer newLevel returns nothing
call SetUnitAbilityLevel(this.dummy, this.abil, newLevel)
endmethod
method flash takes string fx returns nothing
call DestroyEffect(AddSpecialEffectTarget(fx,this.dummy,"origin"))
endmethod
method operator xyangle takes nothing returns real
return GetUnitFacing(this.dummy)*bj_DEGTORAD
endmethod
method operator xyangle= takes real value returns nothing
call SetUnitFacing(this.dummy,value*bj_RADTODEG)
endmethod
method operator zangle takes nothing returns real
return this.zang
endmethod
method operator zangle= takes real value returns nothing
local integer i=R2I(value*bj_RADTODEG+90.5)
set this.zang=value
if(i>=180) then
set i=179
elseif(i<0) then
set i=0
endif
call SetUnitAnimationByIndex(this.dummy, i )
endmethod
method operator x takes nothing returns real
return GetUnitX(this.dummy)
endmethod
method operator y takes nothing returns real
return GetUnitY(this.dummy)
endmethod
method operator z takes nothing returns real
return GetUnitFlyHeight(this.dummy)
endmethod
method operator z= takes real value returns nothing
call SetUnitFlyHeight(this.dummy,value,0)
endmethod
method operator x= takes real value returns nothing
call SetUnitX(this.dummy,value)
endmethod
method operator y= takes real value returns nothing
call SetUnitY(this.dummy,value)
endmethod
method operator fxpath= takes string newpath returns nothing
if (this.fx!=null) then
call DestroyEffect(this.fx)
endif
if (newpath=="") then
set this.fx=null
else
set this.fx=AddSpecialEffectTarget(newpath,this.dummy,"origin")
endif
endmethod
method hiddenReset takes string newfxpath, real newfacing returns nothing
local real x = GetUnitX(this.dummy)
local real y = GetUnitY(this.dummy)
local real z = this.z
local real za = this.zangle
local integer level = this.abilityLevel
set .fxpath=null
static if RECYCLE_DUMMY_UNITS and LIBRARY_xedummy then
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
call recyclebin.create(this.dummy)
set this.dummy=XE_NewDummyUnit(Player(15), x,y, newfacing*bj_RADTODEG)
else
call RemoveUnit(this.dummy)
set this.dummy= CreateUnit(Player(15), XE_DUMMY_UNITID, x,y, newfacing*bj_RADTODEG)
call UnitAddAbility(this.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(this.dummy,'Aloc')
call UnitRemoveAbility(this.dummy,XE_HEIGHT_ENABLER)
call SetUnitX(this.dummy,x)
call SetUnitY(this.dummy,y)
endif
set .fxpath=newfxpath
if(level != 0) then
call UnitAddAbility(this.dummy, this.abil)
call SetUnitAbilityLevel(this.dummy, this.abil, level)
endif
set this.z = z
set zangle = za
endmethod
method destroy takes nothing returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(this.fx!=null) then
call DestroyEffect(this.fx)
set this.fx=null
endif
call recyclebin.create(this.dummy)
set this.dummy=null
call this.deallocate()
endmethod
method hiddenDestroy takes nothing returns nothing
call ShowUnit(dummy,false)
call destroy()
endmethod
endstruct
endlibrary
//TESH.scrollpos=60
//TESH.alwaysfold=0
library xemissile requires xefx, xebasic
//****************************************************************
//*
//* xemissile 0.9
//* -------------
//* A xemissile object is a special effect that moves like a
//* WC3's attack or spell missile.
//*
//* Please use .terminate() instead of .destroy() this ensures
//* that it will be safe to destroy it (else you would have to
//* worry about destroying it during the animation loop/etc.)
//*
//* This struct is used similarly to xecollider. Instead of just
//* creating the xemissile (which works, but it would only be a
//* xefx that can move like a missile) you probably need to make
//* it do something special when it reaches its target...
//* For this reason, you need to make a new struct extending
//* xemissile that declares an onHit method, you may also declare
//* a loopControl method.
//*
//****************************************************************
//===========================================================================
// So, this exists merely so you can declare your own event handler methods
// if interfaces make your brain blow out, please skip the next four lines.
//
private interface eventHandler
method onHit takes nothing returns nothing defaults nothing
method loopControl takes nothing returns nothing defaults nothing
endinterface
//===========================================================================
private struct missile extends eventHandler
private delegate xefx fx
// movement duration parameter.
private real time
// xy movement parameters.
private real mx
private real my
private real mvx
private real mvy
private real mvxy = 1.0
// z movement parameters.
private real mz
private real mvz
private real maz
private static location l = Location(0.0,0.0)
// target parameters.
private real tx = 0.0
private real ty = 0.0
private real tz = 0.0
private unit tu = null
public real zoffset = 0.0
private boolean update = true
private boolean launched = false
private boolean dead = false
public method operator x takes nothing returns real
return .mx
endmethod
public method operator y takes nothing returns real
return .my
endmethod
public method operator z takes nothing returns real
call MoveLocation(.l, .mx,.my)
return mz-GetLocationZ(.l)
endmethod
public method operator x= takes real r returns nothing
set .update=true
set .mx=r
endmethod
public method operator y= takes real r returns nothing
set .update=true
set .my=r
endmethod
public method operator z= takes real r returns nothing
set .update=true
call MoveLocation(.l, .mx,.my)
set .mz=r+GetLocationZ(.l)
endmethod
public method operator speed takes nothing returns real
return .mvxy/XE_ANIMATION_PERIOD
endmethod
public method operator speed= takes real newspeed returns nothing
local real factor=newspeed*XE_ANIMATION_PERIOD/.mvxy
if newspeed<=0.0 then
debug call BJDebugMsg("xemissile speed error: speed must be a non-zero positive value.")
return
endif
set .mvxy=newspeed*XE_ANIMATION_PERIOD
if .launched then
set .time=.time/factor
set .mvx=.mvx*factor
set .mvy=.mvy*factor
set .mvz=.mvz*factor
set .maz=.maz*factor*factor
endif
endmethod
public method operator targetUnit takes nothing returns unit
return this.tu
endmethod
public method operator targetUnit= takes unit u returns nothing
set .update=true
set .tu=u
set .tx=GetUnitX(u)
set .ty=GetUnitY(u)
call MoveLocation(.l, .tx,.ty)
set .tz=GetUnitFlyHeight(u)+GetLocationZ(.l)+.zoffset
endmethod
public method setTargetPoint takes real x, real y, real z returns nothing
set .update=true
set .tu=null
set .tx=x
set .ty=y
call MoveLocation(.l, .tx,.ty)
set .tz=z+GetLocationZ(.l)
endmethod
//-------- Missile launcher
public method launch takes real speed, real arc returns nothing
local real dx=.tx-.mx
local real dy=.ty-.my
local real d=SquareRoot(dx*dx+dy*dy)
local real a=Atan2(dy, dx)
local real dz=.tz-.mz
set .mvxy=speed*XE_ANIMATION_PERIOD
if speed<=0.0 then
debug call BJDebugMsg("xemissile launch error: speed must be a non-zero positive value.")
return
elseif d>0.0 then
set .time=d/speed
else
set .time=XE_ANIMATION_PERIOD
endif
set .mvz=( (d*arc)/(.time/4.0) + dz/.time )*XE_ANIMATION_PERIOD // Do some mathemagics to get a proper arc.
set .dead=.dead and not(.launched) // In case this is called from the onHit method to bounce the missile.
if not .dead and not .launched then
set .launched=true
set .V[.N]=this
set .N=.N+1
if(.N==1) then
call TimerStart(.T, XE_ANIMATION_PERIOD, true, xemissile.timerLoopFunction )
endif
endif
endmethod
//-------- Constructors and destructors
static method create takes real x, real y, real z, real a returns missile
local missile this=missile.allocate()
set .mx=x
set .my=y
call MoveLocation(.l, x,y)
set .mz=z+GetLocationZ(.l)
set .fx = xefx.create(x,y,a)
set .fx.z = z
return this
endmethod
private boolean silent=false
private method destroy takes nothing returns nothing
if(this.silent) then
call this.fx.hiddenDestroy()
else
call this.fx.destroy()
endif
call .deallocate()
endmethod
method terminate takes nothing returns nothing
set this.dead=true
set this.fx.zangle=0.0
set this.fxpath=""
endmethod
// declare hiddenDestroy so people don't call directly on the delegate xefx
method hiddenDestroy takes nothing returns nothing
set silent = true
call terminate()
endmethod
//-------- Main engine
private static timer T
private static integer N=0
private static xemissile array V
private static code timerLoopFunction //I use a code var so create can be above the timerloop function, more readable
private static method timerLoop takes nothing returns nothing
local integer i=0
local integer c=0
local thistype this
local real dx
local real dy
local real d
local real a
loop
exitwhen (i==.N )
set this=.V[i] //adopt-a-instance
if .dead then
set .launched=false
set this.fx.zangle=0.0
call .destroy()
else
if .tu!=null and GetUnitTypeId(.tu)!=0 then
set .update=true
set .tx=GetUnitX(.tu)
set .ty=GetUnitY(.tu)
call MoveLocation(.l, .tx,.ty)
set .tz=GetUnitFlyHeight(.tu)+GetLocationZ(.l)+.zoffset
endif
if .update then
set .update=false
set dx=.tx-.mx
set dy=.ty-.my
set d=SquareRoot(dx*dx+dy*dy)
set a=Atan2(dy,dx)
if d>0.0 then
set .time=d/.mvxy*XE_ANIMATION_PERIOD
else
set .time=XE_ANIMATION_PERIOD
endif
set .mvx=Cos(a)*.mvxy
set .mvy=Sin(a)*.mvxy
set .fx.xyangle=a
set .maz=2*((.tz-.mz)/.time/.time*XE_ANIMATION_PERIOD*XE_ANIMATION_PERIOD-(.mvz*XE_ANIMATION_PERIOD)/.time)
endif
set .mx=.mx+.mvx
set .my=.my+.mvy
set a=.maz/2.0
set .mvz=.mvz+a
set .mz=.mz+.mvz
set .mvz=.mvz+a
set .fx.x=.mx
set .fx.y=.my
call MoveLocation(.l, .mx,.my)
set .fx.z=.mz-GetLocationZ(.l)
set .fx.zangle=Atan2(.mvz, .mvxy)
set .time=.time-XE_ANIMATION_PERIOD
if .time<=0.0 then
set .dead=true
call this.onHit()
if .dead then
set .fxpath=""
endif
endif
set .V[c]=this
set c=c+1
if( this.loopControl.exists and not this.dead ) then
call this.loopControl()
endif
endif
set i=i+1
endloop
set .N=c
if(c==0) then
call PauseTimer(.T)
endif
endmethod
static method onInit takes nothing returns nothing
set .timerLoopFunction = (function missile.timerLoop)
set .T=CreateTimer()
endmethod
endstruct
//===========================================================================
struct xemissile extends missile
public static method create takes real x,real y,real z, real tx,real ty,real tz returns xemissile
local xemissile xm = xemissile.allocate(x,y,z, Atan2(ty-y,tx-x))
call xm.setTargetPoint(tx,ty,tz)
return xm
endmethod
endstruct
struct xehomingmissile extends xemissile
public static method create takes real x,real y,real z, unit target,real zoffset returns xehomingmissile
local xehomingmissile xm = xehomingmissile.allocate(x,y,z, GetUnitX(target), GetUnitY(target), 0.0)
set xm.zoffset=zoffset
set xm.targetUnit=target
return xm
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library_once WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
* readonly static integer centerX
* readonly static integer centerY
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX=R2I(GetRectMaxX(world))
set maxY=R2I(GetRectMaxY(world))
set minX=R2I(GetRectMinX(world))
set minY=R2I(GetRectMinY(world))
set centerX=R2I((maxX+minX)/2)
set centerY=R2I((minY+maxY)/2)
set worldRegion=CreateRegion()
call RegionAddRect(worldRegion,world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DDItemCombineBasic initializer Init
globals
// *** Edit to your own will ***
private constant string ITEM_COMBINE_EFFECT = "Abilities\\Spells\\Items\\AIlm\\AIlmTarget.mdl"
private constant string ATTACH_POINT = "origin"
// *** End edit ***
private sound ItemCombineSound = null
private integer array CType[8191]
private integer ItemN = 0
endglobals
function NewItemGroup takes nothing returns nothing
local integer i = ItemN*6 + 7
local integer h = 1
set ItemN = ItemN + 1
loop
exitwhen (h == 7)
set udg_CItemType[i] = udg_CItemType[h]
set udg_CItemType[h] = 0
set h = h + 1
set i = i + 1
endloop
set CType[ItemN-1] = udg_CItemType[0]
set udg_CItemType[0] = 0
endfunction
private function UnitRemoveItemById takes unit whichUnit, integer itemId returns nothing
local integer i = 0
local item it
loop
exitwhen (i >= bj_MAX_INVENTORY)
set it = UnitItemInSlot(whichUnit, i)
if GetItemTypeId(it) == itemId then
call RemoveItem(it)
exitwhen (true)
endif
set i = i + 1
endloop
set it = null
endfunction
private function Actions takes nothing returns nothing
local integer n = 0
local integer array it
local integer i = 7
local integer h = 0
local integer x = 0
local unit u = GetTriggerUnit()
local boolean b = true
local integer y = 0
local integer z = 0
local integer array hero_item_type
// Get hero items
loop
exitwhen (x >= bj_MAX_INVENTORY)
set hero_item_type[x] = GetItemTypeId(UnitItemInSlot(u, x))
set x = x + 1
endloop
loop
exitwhen (n >= ItemN)
set h = i + 6
set x = 0
set it[x] = hero_item_type[x]
set x = x + 1
set it[x] = hero_item_type[x]
set x = x + 1
set it[x] = hero_item_type[x]
set x = x + 1
set it[x] = hero_item_type[x]
set x = x + 1
set it[x] = hero_item_type[x]
set x = x + 1
set it[x] = hero_item_type[x]
set x = x + 1
set y = 0 // N of items that hero has ()
set z = 0 // N of items needed ()
loop
exitwhen (i >= h or udg_CItemType[i] == 0)
set z = z + 1
// Does unit contain item n
set x = 0
loop
exitwhen (x >= bj_MAX_INVENTORY)
if (it[x] == udg_CItemType[i]) then
// Kick out the item
set it[x] = 0
set y = y + 1
// And increase by 1
exitwhen (true)
endif
set x = x + 1
endloop
set i = i + 1
endloop
set i = h
if (y == z) then
set h = i
set i = i-6
loop
exitwhen (i > h or udg_CItemType[i] == 0)
call UnitRemoveItemById(u, udg_CItemType[i])
set i = i + 1
endloop
call UnitAddItemById(u, CType[n])
call SetSoundPosition(ItemCombineSound, GetUnitX(u), GetUnitY(u), 0.)
call StartSound(ItemCombineSound)
call DestroyEffect(AddSpecialEffectTarget(ITEM_COMBINE_EFFECT, u, ATTACH_POINT))
set u = null
return
endif
set n = n + 1
endloop
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( t, function Actions )
call Preload(ITEM_COMBINE_EFFECT)
set ItemCombineSound = CreateSound( "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImage.wav", false, true, true, 10, 10, "" )
call SetSoundParamsFromLabel( ItemCombineSound, "MirrorImage" )
call SetSoundDuration( ItemCombineSound, 1756 )
call SetSoundPitch(ItemCombineSound, 1.2)
call SetSoundVolume(ItemCombineSound, 100)
endfunction
endlibrary