Name | Type | is_array | initial_value |
A_AoE | real | No | |
A_Bool | boolean | No | |
A_Bool2 | boolean | No | |
A_Damage | real | No | |
A_Duration | real | No | |
A_Int | integer | No | |
A_Real | real | No | |
A_Real2 | real | No | |
A_Speed | real | No | |
A_UType | unitcode | No | |
AGI | integer | No | |
Amount | integer | No | |
ArgosQ | integer | No | |
AuraDummy | unit | No | |
BE_Ability | abilcode | No | |
BE_AbilityIndex | integer | Yes | |
BE_Angle | real | Yes | |
BE_AttackType | attacktype | No | |
BE_Bounces | integer | Yes | |
BE_Caster | unit | Yes | |
BE_CDamage | real | Yes | |
BE_CHeal | real | Yes | |
BE_CSizeIncrement | real | No | |
BE_CurrentBounces | integer | Yes | |
BE_Damage | real | Yes | |
BE_DamageAddition | real | Yes | |
BE_DamageType | damagetype | No | |
BE_Distance | real | Yes | |
BE_DistanceTravelled | real | Yes | |
BE_Dummy | unit | Yes | |
BE_DummyType | unitcode | No | |
BE_FX | effect | Yes | |
BE_Group | group | No | |
BE_Heal | real | Yes | |
BE_HealAddition | real | Yes | |
BE_Height | real | Yes | |
BE_MaxIndex | integer | No | |
BE_Model | string | No | |
BE_NegAbility | abilcode | No | |
BE_NegSpecialEffect | string | No | |
BE_PickedUnits | unit | No | |
BE_Player | player | Yes | |
BE_PosAbility | abilcode | No | |
BE_PosSpecialEffect | string | No | |
BE_PreloadUnit | unit | No | |
BE_SearchAoE | real | Yes | |
BE_SizeIncrement | real | Yes | |
BE_Speed | real | Yes | |
BE_Target | unit | Yes | |
BE_TempIndex | integervar | No | |
BE_TempPoint | location | No | |
BE_TempPoint2 | location | No | |
BE_TempPoint3 | location | No | |
BE_TotalDistance | real | No | |
BloodBolt | timer | No | |
BossMusic | timer | No | |
CalloftheDivine | timer | No | |
Caster | unit | No | |
Color | string | Yes | |
ContinueToProtect | button | No | |
CorruptedAbomination | unit | No | |
Counter | integer | No | |
Damage | real | No | 300.00 |
DamageGroup | group | No | |
Difficulty | dialog | No | |
Distance | real | No | |
DP_Angles | real | No | |
DP_AoEAngle | real | No | |
DP_AoEGroup | group | No | |
DP_AoEKey | integer | No | |
DP_AoELoc | location | No | |
DP_AoEMaxHeightX | real | No | |
DP_AoEOffset | location | No | |
DP_AoEOrbitSpeed | real | Yes | |
DP_AoEs | unit | No | |
DP_AoESpeed | real | No | |
DP_AoEStage | integer | No | |
DP_AoETemp | unit | No | |
DP_AoETempKey | integer | No | |
DP_AoETimer | real | No | |
DP_Arc | real | No | |
DP_ArcHex | real | No | |
DP_ArcMax | real | No | |
DP_ArcMin | real | No | |
DP_Blue | real | No | |
DP_Caster | unit | No | |
DP_CurrentHeight | real | No | |
DP_CurrentSize | real | No | |
DP_DistanceHex | real | No | |
DP_DistanceMax | real | No | |
DP_DistanceMin | real | No | |
DP_Green | real | No | |
DP_Hash | hashtable | No | |
DP_Interval | real | No | |
DP_Intervals | real | No | |
DP_Levels | integer | No | |
DP_Lightning | lightning | No | |
DP_LModel | string | No | |
DP_MaxHeight | real | No | |
DP_MaxSize | real | No | |
DP_MissileDistance | real | No | |
DP_MissileHeight | real | No | |
DP_MissileKey | integer | No | |
DP_MissileLoc | location | No | |
DP_MissileOffset | location | No | |
DP_MissileTemp | unit | No | |
DP_MissileTempKey | integer | No | |
DP_MissileTravelled | real | No | |
DP_Owner | player | No | |
DP_Portal | unit | No | |
DP_PortalDeathSFx | string | No | |
DP_PortalDuration | real | Yes | |
DP_PortalDurationGeneral | real | Yes | |
DP_PortalGroup | group | No | |
DP_PortalGrow | real | No | |
DP_PortalKey | integer | No | |
DP_Radius | real | No | |
DP_Red | real | No | |
DP_Sides | integer | No | |
DP_SizeInterval | real | No | |
DP_Soul | unit | No | |
DP_SoulDamage | real | Yes | |
DP_SoulGroup | group | No | |
DP_SoulHex | integer | No | |
DP_SoulMax | integer | Yes | |
DP_SoulMin | integer | Yes | |
DP_SoulSFX | string | No | |
DP_Stage | integer | No | |
DP_TargetLoc | location | No | |
DP_TempGroup | group | No | |
DP_TempInteger | integervar | No | |
DP_TempLoc | location | No | |
DP_Timer | real | No | |
DP_U | unit | No | |
DP_UKey | integer | No | |
DP_ULoc | location | No | |
DropHero | unit | No | |
DummyCaster | unit | No | |
DyingHero | unit | Yes | |
EarthArmour | group | No | |
Easy | button | No | |
EasyCounter | integer | No | |
EclipseTimer | timer | No | |
EnchantedArmorUnits | group | No | |
Epicmobky | timer | No | |
Events | timer | No | |
Evil | group | No | |
ForestSpirit | timer | No | |
GameMode | dialog | No | |
GhostShip | timer | No | |
GoblinSappers | group | No | |
GodOfConstruction | unitcode | No | n009 |
Hard | button | No | |
HardCounter | integer | No | |
Hashtable | hashtable | No | |
HealingCircle | timer | No | |
HellPortal | destructable | No | |
HellTowers | group | No | |
HolyWater | timer | No | |
HydroJetCasters | group | No | |
HydroJetProjectiles | group | No | |
InfermusTimer | timer | No | |
INT | integer | No | |
Katalyzator | location | No | |
KatalyzatorPosition | integer | Yes | |
Life | integer | No | |
Life2 | integer | No | |
LivingFire | timer | No | |
LivingFireDmg | timer | No | |
LizarpytheTimer | timer | No | |
Medium | button | No | |
MediumCounter | integer | No | |
Merchant | unit | No | |
MerchantTimer | timer | No | |
MeteoriteDummy | unit | Yes | |
MeteoriteTimer | timer | No | |
OwlCourrier | unitcode | No | n00F |
Player1 | timer | No | |
Player2 | timer | No | |
Player3 | timer | No | |
Player4 | timer | No | |
Player5 | timer | No | |
Player6 | timer | No | |
Player_Owner | player | No | |
PlayerGroup | force | No | |
Point1 | location | No | |
Point2 | location | No | |
Point3 | location | No | |
Point4 | location | No | |
Point5 | location | No | |
Poklad | location | No | |
PokladPosition | integer | Yes | |
ProtectMode | button | No | |
ProtectVoteTimer | timer | No | |
PvPMode | button | No | |
RainOfHolyWater | timer | No | |
Random | integer | No | |
Random2 | integer | No | |
RPGDefeat | button | No | |
RPGDefeatDialog | dialog | No | |
RPGEvents | timer | No | |
RPGEvents2 | timer | No | |
RPGMode | button | No | |
RPGTimer | timer | No | |
RPGTimer2 | timer | No | |
RPGVoteTimer | timer | No | |
SandboxMode | button | No | |
SandStorm | group | No | |
ShootingStars | timer | No | |
SnowflowerTimer | timer | No | |
SoulEnergy | timer | No | |
SpellLevel | integer | No | |
SpellLevel2 | integer | No | |
SpellLevel3 | integer | No | |
SpellLevel4 | integer | No | |
SpellLevel5 | integer | No | |
SpiritWyvern | unit | No | |
STR | integer | No | |
TempGroup | group | No | |
TempHandle | handle | No | |
TempInteger | integer | No | |
TempPoint | location | No | |
TempPoint2 | location | No | |
TempPoint3 | location | No | |
TempUnit | unit | No | |
TempUnit2 | unit | No | |
TempUnit3 | unit | No | |
TempUnit4 | unit | No | |
TempX | real | No | |
TempY | real | No | |
Tentacles | group | No | |
TenTaecTul | unit | No | |
Thunderwing | unit | No | |
ToD_Ability | integer | No | |
ToD_Area_of_Effect | real | No | |
ToD_Base_Chance | integer | No | |
ToD_Base_Heal | real | No | |
ToD_Caster | unit | No | |
ToD_Dummy_Ability | abilcode | No | |
ToD_Dummy_Ability_Frenzy | abilcode | No | |
ToD_Heal_Group | group | No | |
ToD_Owner | player | No | |
ToD_Position | location | No | |
ToD_Target_Location | location | No | |
ToD_Unit_Counter | integer | No | |
TrapDamage | group | No | |
Whirlpools | group | No | |
WooderlockTimer | timer | No |
//**********************************************************************************
//* xDModules v1.1 by xD.Schurke - 16.04.2009
//* --------------------------------------------
//*
//* Requires:
//* * JNGP (JassHelper v0.9.G.0)
//*
//*
//* * Implement the module in your structs, which need timers.
//* * The struct needs a method called actions
//*
//* Example:
//*
//* struct Data
//* integer count = 0
//* method actions takes nothing returns nothing
//* call BJDebugMsg("Hello World")
//* if count == 5 then
//* set .active = false
//* endif
//* endmethod
//* implement structStack
//* endstruct
//*
//* If you want to destroy the struct just the this.active = false (.active = false).
//* But don't forget to clear all leaks before
//*
//* Changelog:
//* * Now the timer interval are commited by the create parameters
//*
//*
//**********************************************************************************
library xDModules
module structStack
boolean active = true
private integer i
private static integer Total = 0
private static thistype array Data
private static timer Tim = CreateTimer()
private static method callback takes nothing returns nothing
local thistype dat
local integer i = 0
loop
exitwhen i >= thistype.Total
set dat = thistype.Data[i]
if dat.active == true then
call dat.actions()
else
call thistype.destroy(dat)
set i = i - 1
endif
set i = i + 1
endloop
if thistype.Total == 0 then
call PauseTimer(thistype.Tim)
endif
endmethod
static method create takes real interval returns thistype
local thistype dat = thistype.allocate()
if thistype.Total == 0 then
call TimerStart(thistype.Tim,interval,true,function thistype.callback)
endif
set thistype.Data[thistype.Total] = dat
set dat.i = thistype.Total
set thistype.Total = thistype.Total + 1
return dat
endmethod
private method onDestroy takes nothing returns nothing
set thistype.Total=thistype.Total-1
set thistype.Data[.i]=thistype.Data[thistype.Total]
set thistype.Data[.i].i=.i
endmethod
endmodule
endlibrary
library GroupRecycler
//*********************************************************************
//* Group Recycler 1.0 by xD.Schurke
//* --------------------------------
//*
//* To implement just create a custom text trigger and paste the script
//* there.
//*
//* This script requires vJass (JassNewGenPack)
//*
//* Usage of the scriot:
//* - Recycle Groups
//*
//* set group g = NewGroup() : Get a group (alternative to CreateGroup)
//* call ReleaseGroup(g) : Releases a group (alternative to
//* DestroyGroup)
//*
//*********************************************************************
globals
private constant integer MAX_GROUPS = 8191
private group array rG
private integer rN = 0
endglobals
function NewGroup takes nothing returns group
if (rN == 0) then
set rG[0] = CreateGroup()
else
set rN = rN - 1
endif
return rG[rN]
endfunction
function ReleaseGroup takes group g returns nothing
if(g == null) then
debug call BJDebugMsg("Warning: Try to release a null group")
return
endif
if (rN == MAX_GROUPS) then
debug call BJDebugMsg("Warning: Limit reached, Destroying Group")
call DestroyGroup(g)
else
call GroupClear(g)
set rG[rN] = g
set rN = rN + 1
endif
endfunction
endlibrary
//**********************************************************************************************
//* Fire Disc v1.2d By xD.Schurke - 17.04.2009
//* --------------------------------------------
//*
//* Requires:
//* * xDModules (are needed for struct stacking issues)
//* * JNGP (JassHelper v0.9.G.1)
//*
//* This is my first spell created with my struct stacking module. I wanted to test this new
//* feature and for that I created this spell.
//*
//* Fire Disc is a spell which damages all enemies it hits. Also it can cut through trees.
//*
//*
//* How to implement this spell?
//* * Copy this trigger and the xDModules library to your map
//* * Copy the spell to your map (object editor) but don't forget to adjust the Raw-Code
//* * Adjust the rawcodes to your map specific ones
//* * Now you are done
//*
//* Credits:
//* *PitzerMike for TreeFilter function
//* *Vexorian for vJass
//*
//*
//*
//* Changelog:
//* v1.2
//* * Fixed leak for TriggerRegisterPlayerUnitEvent
//* * Added GroupRecycler
//*
//* v1.2b
//* * Added more documentation
//*
//* v1.2c
//* * Forgot to destroy DummyFilter boolexpr in the init function :(
//*
//* v1.2d
//* * Decreased damage delt by the part missiles
//* * Increased range of part missile damage
//*
//**********************************************************************************************
library FireDisc initializer init requires xDModules,GroupRecycler
//Setup change the Variables you want to change, but better don't change the spell script
globals
private constant integer dummyID = 'n012'
private constant integer spellID = 'A03P'
private constant integer flyID = 'Amrf'
private constant integer partMissiles = 8 //Number of disc parts (I choosed 8, because it looks realy good that way)
private constant integer alphaDec = 51 //255/5 = 51 the number for slowly hiding the missiles, should not look to instant (the end of spell)
private constant real interval = 0.03125
private constant real alphaDecStart = 900. //The distance when the hiding process should start
private constant real speed = 20. //The speed of the main missile => always has to be a multipler of maxDis and effectDis and also alphaDecStart
private constant real speedPart = 10. //The speed of the part missile (needed for angle calculation, creates a rotation)
private constant real maxDeg = 360.
private constant real maxDis = 1000. //The distance the disc can fly
private constant real effectDis = 860. //At this distance the effect for the last explosion spawns
private constant real partMisDist = 80. //The distance between the main missile and the part missiles
private constant real treeKillRange = 0. //Radius where Trees get killed
private constant real pDamage = 15. //Damage of the part missiles
private constant real mDamage = 70. //Damage of the main missile
private constant real mDamageRange = 300. //Radius of main missile Damage
private constant real pDamageRange = 50. //Radius of part missile Damage
//The following strings are the effect strings
private constant string mainEffect = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
private constant string partEffect = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl"
private constant string partEffect2 = "Abilities\\Spells\\Other\\ImmolationRed\\ImmolationRedDamage.mdl"
private constant string explodeEffect = "Abilities\\Spells\\Human\\MarkOfChaos\\MarkOfChaosTarget.mdl"
//Following Variables should not be changed
private group tmpG = CreateGroup()
private player tmpP
private boolexpr Cond = null
private boolexpr condTree = null
endglobals
//Setup end
//constantFunctionPart
private function partDamage takes integer lvl returns real
return lvl*pDamage
endfunction
private function mainDamage takes integer lvl returns real
return lvl*mDamage
endfunction
//endconstantFunctionPart
//Do not change anything below!
private function DummyFilter takes nothing returns boolean
return true
endfunction
private function GroupFilter takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(),tmpP) and (GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0) and IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and (GetUnitTypeId(GetFilterUnit())!=dummyID)
endfunction
private function TreeFilter takes nothing returns boolean
local destructable d = GetFilterDestructable()
local boolean i = IsDestructableInvulnerable(d)
local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), dummyID, GetWidgetX(d), GetWidgetY(d), 0)
local boolean result = false
call UnitAddAbility(u, 'Ahrl')
if i then
call SetDestructableInvulnerable(d, false)
endif
set result = IssueTargetOrder(u, "harvest", d)
call RemoveUnit(u)
if i then
call SetDestructableInvulnerable(d, true)
endif
set u = null
set d = null
return result
endfunction
private function KillTree takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
//Following struct is used for the single parts of the disc, so each part of the disc works for its own
private struct discPart
integer alpha = 255 //Alpha-Channel
unit caster
unit missile
unit tarMissile //The mainMissile
real angle = 0. //Angle, needed for the speed of rotation
real x = 0. //x-point of the end
real y = 0. //y-point of the end
real dis = 0. //how far the missile got
group g //Is the unit already hit?
method actions takes nothing returns nothing
local real x = 0.
local real y = 0.
local rect r
local unit u
local integer i = 0
//Moving Part of the missile
set .angle = .angle + speedPart
set x = GetUnitX(.tarMissile) + partMisDist * Cos(.angle * bj_DEGTORAD)
set y = GetUnitY(.tarMissile) + partMisDist * Sin(.angle * bj_DEGTORAD)
call SetUnitFacing(.missile,.angle)
call SetUnitPosition(.missile,x,y)
//endmovingpart
//TreeFilter part
set r = Rect(x-treeKillRange,y-treeKillRange,x+treeKillRange,y+treeKillRange)
call EnumDestructablesInRect(r,condTree,function KillTree)
//end TreeFilter part
//Unit damaging part
set tmpP = GetOwningPlayer(.caster)
call GroupEnumUnitsInRange(tmpG,x,y,pDamageRange,Cond)
loop
set u = FirstOfGroup(tmpG)
exitwhen u == null
if IsUnitInGroup(u,.g) != true then
call UnitDamageTarget(.caster,u,partDamage(GetUnitAbilityLevel(.caster,spellID)),false,false,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
call GroupAddUnit(.g,u)
endif
call GroupRemoveUnit(tmpG,u)
endloop
//end unit damaging part
//hiding part => alpha-channel manipulation
set .dis = .dis + speed
if .dis >= alphaDecStart then
set .alpha = .alpha - alphaDec
call SetUnitVertexColor(.missile,255,255,255,.alpha)
endif
//end hiding part
//destroying part of the struct + clear leaks
if .dis >= maxDis then
call RemoveUnit(.missile)
call ReleaseGroup(.g)
set .missile = null
set .g = null
set .caster = null
set .active = false
endif
call RemoveRect(r)
set u = null
set r = null
endmethod
implement structStack
endstruct
//Following struct is used for the mainPart of the disc (this missile in the middle, where all partMissiles will fly aroung
private struct discMain
integer alpha = 255 //Alpha-Channel
unit caster
unit missile
real x = 0. //X-Point of the end
real y = 0. //Y-Point of the end
real angle = 0. //Angle between caster and SpellTargetPoint
real dis = 0. //how far the missile got
method actions takes nothing returns nothing
//moving part of the missile
local real x = GetUnitX(.missile) + speed * Cos(.angle * bj_DEGTORAD)
local real y = GetUnitY(.missile) + speed * Sin(.angle * bj_DEGTORAD)
local unit u
call SetUnitPosition(.missile,x,y)
set .dis = .dis + speed
//endmovingpart
//part for the last effect => AOE damage and hiding part by manipulating the alpha-channels
if .dis == effectDis then
call DestroyEffect(AddSpecialEffect(explodeEffect,.x,.y))
elseif .dis >= alphaDecStart then
set .alpha = .alpha - alphaDec
call SetUnitVertexColor(.missile,255,255,255,.alpha)
endif
//end effect/hiding part
//destroying part of the struct + clear leaks
if .dis >= maxDis then
set tmpP = GetOwningPlayer(.caster)
call GroupEnumUnitsInRange(tmpG,x,y,mDamageRange,Cond)
loop
set u = FirstOfGroup(tmpG)
exitwhen u == null
call UnitDamageTarget(.caster,u,mainDamage(GetUnitAbilityLevel(.caster,spellID)),false,false,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(tmpG,u)
endloop
call RemoveUnit(.missile)
set .missile = null
set .caster = null
set .active = false
endif
set u = null
endmethod
implement structStack
endstruct
private function cond takes nothing returns boolean
return GetSpellAbilityId() == spellID
endfunction
private function action takes nothing returns nothing
local discMain dM = discMain.create(interval)
local discPart dP
local location tmpLoc = GetSpellTargetLoc()
local integer i = 0
local real x = 0
local real y = 0
//initialize mainMissile
set dM.caster = GetTriggerUnit()
set dM.missile = CreateUnit(GetOwningPlayer(dM.caster),dummyID,GetUnitX(dM.caster),GetUnitY(dM.caster),0)
call UnitAddAbility(dM.missile,flyID)
call UnitRemoveAbility(dM.missile,flyID)
call SetUnitFlyHeight(dM.missile,100,0)
call AddSpecialEffectTarget(mainEffect,dM.missile,"origin")
set dM.angle = bj_RADTODEG * Atan2(GetLocationY(tmpLoc) - GetUnitY(dM.caster), GetLocationX(tmpLoc) - GetUnitX(dM.caster))
set dM.x = GetUnitX(dM.caster) + maxDis * Cos(dM.angle * bj_DEGTORAD)
set dM.y = GetUnitY(dM.caster) + maxDis * Sin(dM.angle * bj_DEGTORAD)
//mainMissile initialization finished
//initialize partMissile
loop
exitwhen i >= partMissiles
set dP = discPart.create(interval)
set dP.caster = dM.caster
set dP.tarMissile = dM.missile
set dP.angle = (maxDeg/partMissiles)*i
set x = GetUnitX(dP.tarMissile) + partMisDist * Cos(dP.angle * bj_DEGTORAD)
set y = GetUnitY(dP.tarMissile) + partMisDist * Sin(dP.angle * bj_DEGTORAD)
set dP.missile = CreateUnit(GetOwningPlayer(dP.caster),dummyID,x,y,0)
call UnitAddAbility(dP.missile,flyID)
call UnitRemoveAbility(dP.missile,flyID)
call SetUnitFlyHeight(dP.missile,100,0)
call AddSpecialEffectTarget(partEffect,dP.missile,"origin")
set dP.x = dM.x
set dP.y = dM.y
set dP.g = NewGroup()
set i = i + 1
endloop
//partMissile initialization finished
call RemoveLocation(tmpLoc)
set tmpLoc = null
endfunction
private function init takes nothing returns nothing
local trigger int = CreateTrigger()
local integer i = 0
local boolexpr boolTemp = Filter(function DummyFilter)
loop
call TriggerRegisterPlayerUnitEvent(int,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,boolTemp)
set i = i + 1
exitwhen i >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(int,Condition(function cond))
call TriggerAddAction(int,function action)
set int = null
//Setup the filters
set condTree = Filter(function TreeFilter)
set Cond = Filter(function GroupFilter)
//Preload
call Preload(mainEffect)
call Preload(partEffect)
call Preload(partEffect2)
call Preload(explodeEffect)
call DestroyBoolExpr(boolTemp)
set boolTemp = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DuneWorm initializer onInit requires TimerUtils, UnitStatus
//===========================================================================
// Dune Worm v1.05b by TriggerHappy
//============================================================================
//
// How to Install:
// 1. Copy the Dune Worm folder over to your map.
// 2. In the object editor, copy the Dune Worm ability
// and the SUMMON unit (unless you'd like to use your own)
// 3. Once copied, change ABILITY_ID and WORM_DUMMY
// to the raw codes that fit your map.
//
// Notes:
// Created for the Zephyr Contest #6 at THW.
// Credits to Vexorian and Rising_Dusk for their systems
// and everyone who has helped improve this.
//===========================================================================
//===========================================================================
// Configurables
//===========================================================================
globals
private constant integer WORM_DUMMY = 'h00Y' // The worm dummy raw code
private constant integer ABILITY_ID = 'A025' // The raw code of the spell
private constant integer CIRCLE_DIST = 10 // How far apart each effect created in the circle is (increase if lag)
private constant integer LOCUST_ID = 'Aloc'
private constant real WAIT_TIME = 3.0 // The worm timer interval
private constant real WORM_DISTANCE = 150 // How far away from the target the worm spawns
private constant real CIRLCE_INT = 0.05 // The timer interval for the circle effect
private constant string UPRISE_ANIM = "Morph Alternate" // The animation to while when the worm rises
private constant string DIG_ANIM = "Morph" // The animation to while when the worm rises
private constant string CIRCLE_FX = "Abilities\\Spells\\Undead\\Impale\\ImpaleMissTarget.mdl" // The fx on cast
private constant string BLOOD_FX = "Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl" // The effect when the worm impales the enemy
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS // The weapon type
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL // The damage type
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC // The attack type
endglobals
private constant function GetDamage takes integer lvl returns real
return lvl*(150.00)
endfunction
// Level 1: 300
// Level 2: 400
// Level 3: 500
private constant function GetAOE takes integer lvl returns real
return 200. + (lvl * 100)
endfunction
private constant function AttackCount takes integer lvl returns integer
return lvl
endfunction
//==============================
// Do not edit past this line
//==============================
globals
private group GLOBAL_GROUP = CreateGroup()
private player TempPlayer
endglobals
native UnitAlive takes unit id returns boolean
private struct data
unit worm
unit caster
unit target = null
unit last
real castX
real castY
real aoe
real dmg
player p
integer level
integer max
integer tick = 0
boolean b = false
string nextAnim = UPRISE_ANIM
static method PickUnit takes nothing returns boolean
return IsPlayerEnemy(GetOwningPlayer(GetFilterUnit()), TempPlayer) and UnitAlive(GetFilterUnit())
endmethod
method onDestroy takes nothing returns nothing
set this.worm = null
set this.caster = null
set this.target = null
set this.last = null
endmethod
static method callback takes nothing returns nothing
local real x = 0
local real y
local real f
local timer t = GetExpiredTimer()
local data this = GetTimerData(t)
if this.tick >= this.max then
call RemoveUnit(this.worm)
call ReleaseTimer(t)
call this.destroy()
return
endif
if this.target == null then
set TempPlayer = this.p
call GroupEnumUnitsInRange(GLOBAL_GROUP, this.castX, this.castY, this.aoe, Filter(function data.PickUnit))
call ForGroup(GLOBAL_GROUP, function GroupPickRandomUnitEnum) // The BJ is completely fine.
set this.target = FirstOfGroup(GLOBAL_GROUP)
if not UnitAlive(this.target) or this.target == null then
set this.target = null
set this.last = null
set this.tick = this.tick + 1
return
endif
set this.last = this.target
endif
if this.target != null then
if this.nextAnim == UPRISE_ANIM then
set f = GetRandomReal(0, 360)
set x = GetUnitX(this.target) + WORM_DISTANCE * Cos(f* bj_DEGTORAD)
set y = GetUnitY(this.target) + WORM_DISTANCE * Sin(f* bj_DEGTORAD)
call SetUnitFacing(this.worm, f+180)
call StunUnitTimed(this.target, WAIT_TIME)
call SetUnitX(this.worm, x)
call SetUnitY(this.worm, y)
else
call UnitDamageTarget(this.caster, this.last, this.dmg, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
call DestroyEffect(AddSpecialEffectTarget(BLOOD_FX, this.target, "origin"))
endif
call SetUnitAnimation(this.worm, this.nextAnim)
set x = WAIT_TIME
if this.nextAnim == UPRISE_ANIM then
set this.nextAnim = DIG_ANIM
set x = WAIT_TIME-1
elseif this.nextAnim == DIG_ANIM then
set this.nextAnim = UPRISE_ANIM
set this.tick = this.tick + 1
set this.target = null
endif
call PauseTimer(t)
call TimerStart(t, x, true, function data.callback)
endif
endmethod
static method create takes unit u, integer lvl, unit c returns data
local data this = data.allocate()
local timer tmr = NewTimer()
local real x
local real y
local integer i = 0
set this.caster = c
set this.worm = u
set this.level = lvl
set this.castX = GetSpellTargetX()
set this.castY = GetSpellTargetY()
set this.aoe = GetAOE(lvl)
set this.p = GetOwningPlayer(u)
set this.dmg = GetDamage(lvl)
set this.max = AttackCount(lvl)
loop
exitwhen i > 360
set x = this.castX + this.aoe * Cos(i*bj_DEGTORAD)
set y = this.castY + this.aoe * Sin(i*bj_DEGTORAD)
call DestroyEffect(AddSpecialEffect(CIRCLE_FX, x, y))
set i = i + CIRCLE_DIST
endloop
call UnitAddAbility(u, LOCUST_ID)
call SetTimerData(tmr, this)
call TimerStart(tmr, 0, true, function data.callback)
return this
endmethod
endstruct
private function Actions takes nothing returns boolean
local unit u
if GetSpellAbilityId() == ABILITY_ID then
set u = GetTriggerUnit()
call data.create(CreateUnit(GetOwningPlayer(u), WORM_DUMMY, 0, 0, 0), GetUnitAbilityLevel(u, ABILITY_ID), u)
set u = null
endif
return false
endfunction
//===========================================================================
private function onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Filter(function Actions))
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
set tT[0]=CreateTimer()
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitStatus initializer Init requires TimerUtils, AutoIndex, optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library exists because oftentimes, a mapmaker needs to apply a specific
//* status effect to a unit. If he were to do it on his own, he'd need to find a
//* way to get the status effects to stack properly with one another and with
//* multiple instances of themselves. This script does just that with the five
//* most useful status options in WC3 that cannot be reproduced perfectly with
//* just code and not actual in-game buffs.
//*
//* WARNING: This library uses the following buffs. If you use any of the listed
//* buffs in your map, they will not stack with this script's buffs and
//* it may not work. If you need these effects, then only use this
//* script to achieve them.
//* - Drunken Haze
//* - Soul Burn
//* - Ensnare
//* - Storm Bolt
//* - Hurl Boulder
//*
//******************************************************************************
//*
//* The following status effects are supported by this library.
//*
//* - Silence
//* This status disables a given unit's ability to cast spells. This works
//* properly on spell immune and normal units.
//*
//* Example Usage:
//* call SilenceUnit(u, true) //Silences a unit
//* call SilenceUnit(u, false) //Removes silence from a unit
//* call SilenceUnitTimed(u, 4.0) //Adds a timed silence to a unit
//* call RemoveSilence(u) //Totally removes silence from a unit
//*
//* - Disarm
//* This status disables a given unit's ability to attack and attack ground.
//* This will not work properly on spell immune units because of a Blizzard
//* bug. The function calls will return false when used on units that are
//* spell immune. This status disables both ranged and melee attacks.
//*
//* Example Usage:
//* call DisarmUnit(u, true) //Disarms a unit
//* call DisarmUnit(u, false) //Removes disarm from a unit
//* call DisarmUnitTimed(u, 4.0) //Adds a timed disarm to a unit
//* call RemoveDisarm(u) //Totally removes disarm from a unit
//*
//* - Ensnare
//* This status disables a given unit's ability to move. This works properly
//* on spell immune and normal units. Because of the nature of the ability
//* this is based upon, it will exhibit strange behavior on flying units. If
//* this is used on flying units, they will retain their flying height, but
//* be treated as ground units by the game. There is unfortunately no
//* workaround for this behavior. It is recommended to not use it on flying
//* units because of that behavior.
//*
//* Example Usage:
//* call EnsnareUnit(u, true) //Ensnares a unit
//* call EnsnareUnit(u, false) //Removes ensnare from a unit
//* call EnsnareUnitTimed(u, 4.0) //Adds a timed ensnare to a unit
//* call RemoveEnsnare(u) //Totally removes ensnare from a unit
//*
//* - Stun
//* This status is identical in nature to the standard melee stun. A stunned
//* unit cannot move, attack, or cast spells. Both spell immune and normal
//* units can be stunned.
//*
//* Example Usage:
//* call StunUnit(u, true) //Ensnares a unit
//* call StunUnit(u, false) //Removes stun from a unit
//* call StunUnitTimed(u, 4.0) //Adds a timed ensnare to a unit
//* call RemoveStun(u) //Totally removes stun from a unit
//*
//* - Disable
//* Disable is a unique status meant to be used as a replacement for pausing a
//* unit using the PauseUnit native. Pausing a unit has the negative side
//* effects of removing the unit's command card and not preserving queued
//* orders. Disabling a unit retains both of those sought features. Disable is
//* a non-graphical stun at its core that is always 'underneath' stun when
//* both are applied on a unit at once as listed below.
//*
//* Disable also interacts with stun in a unique way.
//* - If stun is used on a disabled unit, the unit becomes stunned instead.
//* - If stun ends on a disabled unit, the unit is disabled until the disable
//* ends.
//* - If disable is used on a stunned unit, the unit remains visibly stunned.
//*
//* Example Usage:
//* call DisableUnit(u, true) //Disables a unit
//* call DisableUnit(u, false) //Removes disable from a unit
//* call DisableUnitTimed(u, 4.0) //Adds a timed disable to a unit
//* call RemoveDisable(u) //Totally removes disable from a unit
//*
//* WARNING: These status effects, when used on invulnerable units, will have
//* absolutely no effect.
//*
//******************************************************************************
//*
//* There is a textmacro call below that runs a series of ObjectMerger calls
//* inside of an embedded .lua script. This sub-script generates all of the
//* abilities and buffs required by this library automatically for you. Enable
//* it by uncommenting the textmacro, saving your map, closing your map,
//* reopening your map, and commenting the macro again.
//*
//* Note that you, as the user, may edit any of the buff icons or tooltips to
//* your liking. It is not recommended to edit the data fields for the spells,
//* though. They are the way they are so that they will work.
//*
//* WARNING: The ObjectMerger call for Disarm's ability seems to be unable to
//* properly configure the "Data - Attacks Prevented" field. If you
//* find that the DisarmUnit call isn't functioning as intended, then
//* set that field to "None", save your map, set the field back to
//* "Melee, Ranged", and then save your map again. It should now work
//* properly.
//*
//* You may change the raw ids of any of the generated abilities as needed for
//* your map. (If there are conflicts) If you want to do so, then make sure that
//* you change the raw ids inside all affected ObjectMerger calls and the
//* constants in the globals block below.
//*
//* WARNING: If you choose to change the raw id for the Silence ability, do NOT
//* let the buff raw id match the ability raw id. If you do, the buff's
//* special effect fields will not show in-game. (This may or may not
//* even affect you, but it is worth noting regardless)
//*
//* xebasic is an optional requirement. If you have xebasic in your map, this
//* script will use xebasic's dummy unit id instead of the constant below. If
//* you do not have xebasic in your map, for this to work you will need to make
//* (if you have not already) a dummy unit caster for your map. Put its raw id
//* below in the DUMMY_UNITID constant field.
//*
//* Enjoy!
//*
//* Uncomment the following textmacro to create the abilities.
////! runtextmacro GenerateAbilities()
//! textmacro GenerateAbilities
//! externalblock extension=lua ObjectMerger $FILENAME$
//! i
//! i function set(field, value)
//! i makechange(current, field, value)
//! i end
//! i function setl(field, level, value)
//! i makechange(current, field, level, value)
//! i end
//! i
//! i setobjecttype("abilities")
//! i
//! i createobject("AHtb", "stun"); set("anam", "Stun Ability")
//! i set ("aani", "") ; set ("aart", "") ; set ("amat", "") ; set ("amsp", 0) ; setl("Htb1", 1, 0.0);
//! i setl("aran", 1, 99999.0); setl("acdn", 1, 0.0); setl("ahdu", 1, 0.0) ; setl("adur", 1, 0.0) ; set ("arlv", 6) ;
//! i set ("alev", 1) ; setl("amcs", 1, 0) ; set ("arac", "other"); setl("atar", 1, "notself");
//! i
//! i createobject("ANso", "&sil"); set("anam", "Silence Ability")
//! i set ("aart", "") ; setl("Nso1", 1, 0.0); setl("Nso3", 1, 0.0) ; setl("Nso2", 1, 99999.0) ; setl("aran", 1, 99999.0);
//! i setl("abuf", 1, "&SIL"); setl("acdn", 1, 0.0); setl("ahdu", 1, 0.0) ; setl("adur", 1, 0.0) ; set ("arlv", 1);
//! i set ("alev", 1) ; setl("amcs", 1, 0) ; set ("arac", "other"); setl("atar", 1, "notself");
//! i
//! i createobject("ANdh", "&arm"); set("anam", "Disarm Ability")
//! i set ("aart", "") ; set ("amat", "") ; set ("amac", 0.0) ; set ("amsp", 0) ; setl("Nsi1", 1, 3) ;
//! i setl("Nsi2", 1, 0.0) ; setl("Nsi3", 1, 0.0) ; setl("aare", 1, 0.0); setl("aran", 1, 99999.0); setl("abuf", 1, "&ARM");
//! i setl("acdn", 1, 0.0) ; setl("ahdu", 1, 0.0) ; setl("adur", 1, 0.0); set ("arlv", 6) ; set ("alev", 1) ;
//! i setl("amcs", 1, 0) ; set ("arac", "other") ; setl("atar", 1, "notself");
//! i
//! i createobject("ACen", "&ens"); set("anam", "Ensnare Ability")
//! i set ("aart", "") ; set ("amat", "") ; set ("amsp", 0) ; setl("Ens1", 1, -1.0); setl("Ens2", 1, -1.0);
//! i setl("aran", 1, 99999.0) ; setl("abuf", 1, "&EN1,&EN2"); setl("acdn", 1, 0.0); setl("ahdu", 1, 0.0) ; set ("aher", 1) ;
//! i setl("adur", 1, 0.0) ; set ("arlv", 6) ; set ("alev", 1) ; setl("amcs", 1, 0) ; set ("arac", "other");
//! i setl("atar", 1, "notself"); set ("areq", "") ; set("ansf", "") ;
//! i
//! i createobject("ACtb", "&dis"); set("anam", "Disable Ability")
//! i set ("aani", "") ; set ("aart", "") ; set ("amat", "") ; set ("amsp", 0) ; setl("Ctb1", 1, 0.0) ;
//! i setl("aran", 1, 99999.0) ; setl("abuf", 1, "&DIS"); setl("acdn", 1, 0.0); setl("ahdu", 1, 0.0); setl("adur", 1, 0.0) ;
//! i set ("aher", 1) ; set ("arlv", 6) ; set ("alev", 1) ; setl("amcs", 1, 0) ; set ("arac", "other");
//! i setl("atar", 1, "notself");
//! i
//! i setobjecttype("buffs")
//! i
//! i createobject("BNso", "&SIL"); set("fnam", "Disabled (Spells)")
//! i set("ftip", "Disabled (Spells)") ; set("fube", "This unit cannot cast spells.");
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "") ; set("fta0", "");
//! i
//! i createobject("BNdh", "&ARM"); set("fnam", "Disabled (Attacks)")
//! i set("ftip", "Disabled (Attacks)") ; set("fube", "This unit cannot attack.");
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "") ; set("fta0", "");
//! i
//! i createobject("Beng", "&EN1"); set("fnam", "Disabled (Movement)")
//! i set("ftip", "Disabled (Movement)") ; set("fube", "This unit cannot move." );
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "") ; set("frac", "other");
//! i
//! i createobject("Bena", "&EN2"); set("fnam", "Disabled (Movement)")
//! i set("ftip", "Disabled (Movement)") ; set("fube", "This unit cannot move.");
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "") ; set("fta0", "");
//! i set("frac", "other");
//! i
//! i createobject("BPSE", "&DIS"); set("fnam", "Disabled")
//! i set("ftip", "Disabled") ; set("fube", "This unit cannot do anything.");
//! i set("fart", "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"); set("ftat", "") ; set("fta0", "")
//! i
//! endexternalblock
//! endtextmacro GenerateAbilities
globals
//General constants
private constant integer DUMMY_UNITID = 'e000' //Replace this with your dummy's id
//Stun constants
private constant integer STUN_ID = 'stun' //This needs to match the ObjectMerger call above
private constant integer STUN_ORDER_ID = 852095 //Order id to stun a unit
private constant integer STUN_BUFF_ID = 'BPSE' //Normal storm bolt stun buff
//Silence constants
private constant integer SILENCE_ID = '&sil' //This needs to match the ObjectMerger call above
private constant integer SILENCE_ORDER_ID = 852668 //Order id to soul burn a unit
private constant integer SILENCE_BUFF_ID = '&SIL' //Generated soul burn based buff
//Disarm constants
private constant integer DISARM_ID = '&arm' //This needs to match the ObjectMerger call above
private constant integer DISARM_ORDER_ID = 852585 //Order id to drunken haze a unit
private constant integer DISARM_BUFF_ID = '&ARM' //Generated drunken haze based buff
//Ensnare constants
private constant integer ENSNARE_ID = '&ens' //This needs to match the ObjectMerger call above
private constant integer ENSNARE_ORDER_ID = 852106 //Order id to ensnare a unit
private constant integer ENSNARE_BUFF_ID = '&EN1' //Generated ensnare based buff (ground)
private constant integer ENSNARE_BUFF_ID2 = '&EN2' //Generated ensnare based buff (air)
//Disable constants
private constant integer DISABLE_ID = '&dis' //This needs to match the ObjectMerger call above
private constant integer DISABLE_ORDER_ID = 852252 //Order id to hurl boulder at a unit
private constant integer DISABLE_BUFF_ID = '&DIS' //Generated hurl boulder based buff
endglobals
globals
private unit Caster = null //Dummy caster
private timer Temp = null //For callback referencing
endglobals
//******************************************************************************
//! textmacro UnitStatus_GenerateBase takes TYPE, CONSTANT, STRUCTNAME, INJECTPOSTBUFF, INJECTCHECK, INJECTPREBUFF
private struct clear$TYPE$
unit u = null
//Exists only for clearing on Add/Remove situations
static method create takes unit t returns thistype
local thistype c = thistype.allocate()
set c.u = t
return c
endmethod
endstruct
private function TimerRemove$TYPE$ takes nothing returns nothing
local clear$TYPE$ c = clear$TYPE$(GetTimerData(GetExpiredTimer()))
local unit whichUnit = c.u
if $TYPE$Counter[GetUnitId(c.u)] == 0 then
//Make sure we should still remove it
call UnitRemoveAbility(c.u, $CONSTANT$_BUFF_ID)
$INJECTPOSTBUFF$
endif
call ReleaseTimer(GetExpiredTimer())
call c.destroy()
set whichUnit = null
endfunction
function $TYPE$Unit takes unit whichUnit, boolean flag returns boolean
local integer id = GetUnitId(whichUnit)
local boolean b = true
if whichUnit == null then
//Target can't be null
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null unit given to $TYPE$Unit")
return false
endif
if flag then
if $TYPE$Counter[id] == 0 $INJECTCHECK$ then
//Buff the unit
$INJECTPREBUFF$
call UnitShareVision(whichUnit, GetOwningPlayer(Caster), true)
set b = IssueTargetOrderById(Caster, $CONSTANT$_ORDER_ID, whichUnit)
call UnitShareVision(whichUnit, GetOwningPlayer(Caster), false)
endif
if not b then
//Cast failed somehow
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Unit could not be buffed ($TYPE$Unit)")
return false
endif
set $TYPE$Counter[id] = $TYPE$Counter[id] + 1
elseif $TYPE$Counter[id] > 0 then //Only run this if unit is buffed at all
//Decrement Counter
set $TYPE$Counter[id] = $TYPE$Counter[id] - 1
if $TYPE$Counter[id] == 0 then
//Clear the buff
if GetUnitAbilityLevel(whichUnit, $CONSTANT$_BUFF_ID) == 0 then
//Remove it in a 0.01s callback because it hasn't been applied yet
set Temp = NewTimer()
call SetTimerData(Temp, integer(clear$TYPE$.create(whichUnit)))
call TimerStart(Temp, 0.01, false, function TimerRemove$TYPE$)
else
call UnitRemoveAbility(whichUnit, $CONSTANT$_BUFF_ID)
$INJECTPOSTBUFF$
endif
endif
else
//Unit doesn't have the buff we're trying to remove
return false
endif
return true
endfunction
private struct $STRUCTNAME$
timer t
unit tar
real dur
private static method end takes nothing returns nothing
call thistype(GetTimerData(GetExpiredTimer())).destroy()
endmethod
static method start takes unit target, real duration returns boolean
local thistype s
local boolean b = $TYPE$Unit(target, true)
if not b then
//Failed, return false
return false
endif
set s = thistype.allocate()
set s.tar = target
set s.dur = duration
set s.t = NewTimer()
call SetTimerData(s.t, integer(s))
call TimerStart(s.t, duration, false, function $STRUCTNAME$.end)
return true
endmethod
private method onDestroy takes nothing returns nothing
call $TYPE$Unit(.tar, false)
call ReleaseTimer(.t)
endmethod
endstruct
function $TYPE$UnitTimed takes unit whichUnit, real duration returns boolean
if duration <= 0.01 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Less than 0.01 duration given to $TYPE$UnitTimed")
return false
endif
return $STRUCTNAME$.start(whichUnit, duration)
endfunction
function Remove$TYPE$ takes unit whichUnit returns boolean
local integer id = GetUnitId(whichUnit)
if $TYPE$Counter[id] > 0 then
set $TYPE$Counter[id] = 0
//Clear the buff
if GetUnitAbilityLevel(whichUnit, $CONSTANT$_BUFF_ID) == 0 then
//Remove it in a 0.01s callback because it hasn't been applied yet
set Temp = NewTimer()
call SetTimerData(Temp, integer(clear$TYPE$.create(whichUnit)))
call TimerStart(Temp, 0.01, false, function TimerRemove$TYPE$)
else
call UnitRemoveAbility(whichUnit, $CONSTANT$_BUFF_ID)
$INJECTPOSTBUFF$
endif
return true
endif
return false
endfunction
//! endtextmacro
//******************************************************************************
//Declare all necessary globals first
globals
private integer array StunCounter
private integer array SilenceCounter
private integer array DisarmCounter
private integer array EnsnareCounter
private integer array DisableCounter
endglobals
//Special functions for Stun
private function StunLingeringDisable takes unit u returns nothing
local integer id = GetUnitId(u)
if DisableCounter[id] > 0 then
//Add the disabled buff because it lingers on
call UnitShareVision(u, GetOwningPlayer(Caster), true)
call IssueTargetOrderById(Caster, DISABLE_ORDER_ID, u)
call UnitShareVision(u, GetOwningPlayer(Caster), false)
endif
endfunction
private function StunFinishDisable takes unit u returns nothing
local integer id = GetUnitId(u)
if DisableCounter[id] > 0 then
//Remove the disable buff for first refcount stun
call UnitRemoveAbility(u, DISABLE_BUFF_ID)
endif
endfunction
//Generates all of the base code
//! runtextmacro UnitStatus_GenerateBase("Stun" , "STUN" , "stun" , "call StunLingeringDisable(whichUnit)", "", "call StunFinishDisable(whichUnit)")
//! runtextmacro UnitStatus_GenerateBase("Silence", "SILENCE", "silence", "", "", "")
//! runtextmacro UnitStatus_GenerateBase("Disarm" , "DISARM" , "disarm" , "", "", "")
//! runtextmacro UnitStatus_GenerateBase("Ensnare", "ENSNARE", "ensnare", "call UnitRemoveAbility(whichUnit, ENSNARE_BUFF_ID2)", "", "")
//! runtextmacro UnitStatus_GenerateBase("Disable", "DISABLE", "disable", "", "and StunCounter[id] == 0", "")
private function Init takes nothing returns nothing
static if LIBRARY_xebasic then
set Caster = CreateUnit(Player(15), XE_DUMMY_UNITID, 0., 0., 0.)
else
set Caster = CreateUnit(Player(15), DUMMY_UNITID , 0., 0., 0.)
endif
call UnitRemoveAbility(Caster, 'Amov')
if GetUnitAbilityLevel(Caster, 'Aloc') == 0 then
call UnitAddAbility(Caster, 'Aloc') //xe dummies don't have this automatically
endif
//Add the abilities
call UnitAddAbility(Caster, STUN_ID)
call UnitAddAbility(Caster, SILENCE_ID)
call UnitAddAbility(Caster, DISARM_ID)
call UnitAddAbility(Caster, ENSNARE_ID)
call UnitAddAbility(Caster, DISABLE_ID)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AutoIndex
//===========================================================================
// Information:
//==============
//
// AutoIndex is a very simple script to utilize. Just call GetUnitId(unit) to
// get get the unique value assigned to a particular unit. AutoIndex differs from
// other unit indexing libraries because it automatically assigns an ID to each
// unit as it enters the map, and automatically frees that ID as the unit leaves
// the map. This gives you several advantages as the user:
//
// 1.) The GetUnitId function inlines directly to a GetUnitUserData call (or a
// LoadInteger call if UseUnitUserData is disabled.)
// 2.) You don't need to manually free IDs as units leave the map.
// 3.) Detecting removing units to free their indexes is O(1), and less costly
// performance-wise than a timer scanning the map for removed units.
//
// If you turn on debug mode, AutoIndex will become slower, but it will show
// you a variety of helpful error messages. It can detect the following problems:
// -Passing a null unit to GetUnitId
// -Passing a removed or decayed unit to GetUnitId
// -Code outside of AutoIndex has overwritten a unit's UserData value.
// -GetUnitId was used on a filtered unit (a unit you don't want indexed).
//
// AutoIndex also provides events upon indexing or deindexing units. This
// effectively allows you to notice when units enter or leave the game, and
// handle the creation or destruction of attached data or other things.
//
//===========================================================================
// How to install AutoIndex:
//===========================
//
// 1.) Copy and paste this script into your map.
// 2.) Save it to allow the ObjectMerger macro to generate the "Leave Detect"
// ability for you. Close and re-open the map. After that, disable the macro
// to prevent the save delay.
//
//===========================================================================
// How to use AutoIndex:
//=======================
//
// So you can get a unique integer for each unit, but how do you use that to
// attach data to a unit? GetUnitId will always return a number in the range of
// 1-8190. This means it can be used as an array index, as demonstrated below:
//
// globals
// integer array IntegerData
// real array RealData
// SomeStruct array SomeStructData
// englobals
//
// function Example takes nothing returns nothing
// local unit u = CreateUnit(...)
// local integer id = GetUnitId(u)
// //You now have a unique index for the unit, so you can
// //attach or retrieve data about the unit using arrays.
// set IntegerData[id] = 5
// set RealData[id] = 25.0
// set SomeStructData[id] = SomeStruct.create()
// //If you have access to the same unit in another function, you can
// //retrieve the data by using GetUnitId() and reading the arrays.
// endfunction
//
// The UnitFilter function in the config section is provided so that you can
// make AutoIndex completely ignore any unit-types that don't want to be indexed.
// You may want to ignore dummy casters or system-private units, especially ones
// that use UnitUserData internally. You don't need to worry about xe dummy units,
// as those are automatically filtered.
//
//===========================================================================
// How to use OnUnitIndexed / OnUnitDeindexed:
//=============================================
//
// AutoIndex will fire the OnUnitIndexed event when a unit enters the map,
// and the OnUnitDeindexed event when a unit leaves the map. Functions used
// as events must take a unit and return nothing. An example is given below:
//
// function UnitEntersMap takes unit u returns nothing
// call BJDebugMsg(GetUnitName(u)+" was indexed with the ID "+I2S(GetUnitId(u)))
// endfunction
//
// function UnitLeavesMap takes unit u returns nothing
// call BJDebugMsg(GetUnitName(u)+" was deindexed with the ID "+I2S(GetUnitId(u)))
// endfunction
//
// function Init takes nothing returns nothing
// call OnUnitIndexed(UnitEntersMap)
// call OnUnitDeindexed(UnitLeavesMap)
// endfunction
//
// As you can see, it works perfectly fine to call GetUnitId() on a unit
// during either of these events.
//
// If you call OnUnitIndexed during map initialization, every existing
// unit will be considered as entering the map. This saves you from needing
// to manually enumerate preplaced units (or units created by initialization
// code that ran before OnUnitIndexed was called).
//
// OnUnitDeindexed runs while a unit still exists, which means you can
// still do things such as destroy special effects attached to the unit.
// The unit will cease to exist immediately after the event is over.
//
//===========================================================================
// AutoIndex API:
//================
//
// GetUnitId(unit) -> integer
// This function returns a unique ID in the range of 1-8190 for the
// specified unit. Use it to attach data to the unit. This function
// inlines directly to GetUnitUserData or LoadInteger if debug mode
// is disabled. If debug mode is enabled, it can display error mess-
// ages when passed a null, decayed or filtered unit.
//
// IsUnitIndexed(unit) -> boolean
// This function returns a boolean indicating whether the specified
// unit is indexed or not. A unit would not be indexed if you ignored
// it using the UnitFilter function, or if it is a xe dummy unit.
//
// OnUnitIndexed(IndexFunc)
// This function accepts an IndexFunc, which must take a unit and
// return nothing. The IndexFunc will be fired instantly whenever
// a unit enters the map. You may use GetUnitId on the unit. When
// you call this function during map initialization, every existing
// unit will be considered as entering the map.
//
// OnUnitDeindexed(IndexFunc)
// Same as above, but runs whenever a unit is leaving the map. When
// this event runs, the unit still exists, but it will cease to exist
// as soon as the event ends. You may use GetUnitId on the unit.
//
//===========================================================================
// Configuration:
//================
///! external ObjectMerger w3a Adef lvdt anam "Leave Detect" aart "" arac 0
//Save your map with this Object Merger call enabled, then close and reopen your
//map. Disable it by removing the exclamation to remove the delay while saving.
globals
private constant integer LeaveDetectAbilityID = 'lvdt'
//This rawcode must match the parameter after "Adef" in the
//ObjectMergermacro above. You can change both if you want.
private constant boolean UseUnitUserData = true
//If this is set to true, UnitUserData will be used. You should only set
//this to false if something else in your map already uses UnitUserData.
//A hashtable will be used instead, but it is about 60% slower.
endglobals
public function UnitFilter takes nothing returns boolean
return true
endfunction
//Any units you filter out in this function will not be indexed.
//Use GetFilterUnit() to refer to the filtered unit. You do not
//need to filter out xe dummy units; they are already filtered.
//===========================================================================
// User functions:
//=================
function GetUnitId takes unit u returns integer
static if DEBUG_MODE then
return AutoIndex.getIndexDebug(u)
else
return AutoIndex.getIndex(u)
endif
endfunction
function IsUnitIndexed takes unit u returns boolean
return AutoIndex.isUnitIndexed(u)
endfunction
function interface IndexFunc takes unit u returns nothing
function OnUnitIndexed takes IndexFunc func returns nothing
call AutoIndex.onUnitIndexed(func)
endfunction
function OnUnitDeindexed takes IndexFunc func returns nothing
call AutoIndex.onUnitDeindexed(func)
endfunction
//===========================================================================
hook RemoveUnit AutoIndex.hook_RemoveUnit
hook ReplaceUnitBJ AutoIndex.hook_ReplaceUnitBJ
debug hook SetUnitUserData AutoIndex.hook_SetUnitUserData
struct AutoIndex
private static trigger enter = CreateTrigger()
private static trigger status = CreateTrigger()
private static trigger creepdeath = CreateTrigger()
private static group preplaced = CreateGroup()
private static timer allowdecay = CreateTimer()
private static hashtable ht
private static boolean array dead
private static boolean array summoned
private static boolean array animated
private static boolean array nodecay
private static boolean array removing
private static IndexFunc array indexfuncs
private static integer indexfuncs_n = -1
private static IndexFunc array deindexfuncs
private static integer deindexfuncs_n = -1
private static IndexFunc indexfunc
private static unit array allowdecayunit
private static integer allowdecay_n = -1
private static boolean duringinit = true
private static boolean array altered
private static unit array idunit
//===========================================================================
static method getIndex takes unit u returns integer
static if UseUnitUserData then
return GetUnitUserData(u)
else
return LoadInteger(ht, 0, GetHandleId(u))
endif
endmethod
//Resolves to an inlinable one-liner after the static if.
static method getIndexDebug takes unit u returns integer
local integer index = getIndex(u)
if u == null then
call BJDebugMsg("AutoIndex error: Null unit passed to GetUnitId.")
elseif GetUnitTypeId(u) == 0 then
call BJDebugMsg("AutoIndex error: Removed or decayed unit passed to GetUnitId.")
elseif idunit[index] != u then
call BJDebugMsg("AutoIndex error: "+GetUnitName(u)+" is a filtered unit.")
endif
return index
endmethod
//If debug mode is enabled, use the getIndex method that shows errors.
static method setIndex takes unit u, integer index returns nothing
static if UseUnitUserData then
call SetUnitUserData(u, index)
else
call SaveInteger(ht, 0, GetHandleId(u), index)
endif
endmethod
//Resolves to an inlinable one-liner after the static if.
//===========================================================================
static method isUnitAnimateDead takes unit u returns boolean
return animated[getIndex(u)]
endmethod
//Don't use this; use IsUnitAnimateDead from StatusEvents instead.
static method isUnitIndexed takes unit u returns boolean
return u != null and idunit[getIndex(u)] == u
endmethod
//===========================================================================
private static method onUnitIndexed_sub takes nothing returns nothing
call indexfunc.evaluate(GetEnumUnit())
endmethod
//During initialization, evaluate the indexfunc for every preplaced unit.
static method onUnitIndexed takes IndexFunc func returns nothing
set indexfuncs_n = indexfuncs_n + 1
set indexfuncs[indexfuncs_n] = func
if duringinit then
set indexfunc = func
call ForGroup(preplaced, function AutoIndex.onUnitIndexed_sub)
endif
endmethod
static method onUnitDeindexed takes IndexFunc func returns nothing
set deindexfuncs_n = deindexfuncs_n + 1
set deindexfuncs[deindexfuncs_n] = func
endmethod
//===========================================================================
private static method hook_RemoveUnit takes unit whichUnit returns nothing
set removing[getIndex(whichUnit)] = true
endmethod
private static method hook_ReplaceUnitBJ takes unit whichUnit, integer newUnitId, integer unitStateMethod returns nothing
set removing[getIndex(whichUnit)] = true
endmethod
//Intercepts whenever RemoveUnit or ReplaceUnitBJ is called and sets a flag.
private static method hook_SetUnitUserData takes unit whichUnit, integer data returns nothing
static if UseUnitUserData then
if IsUnitIndexed(whichUnit) then
if getIndex(whichUnit) == data then
call BJDebugMsg("AutoIndex error: Code outside AutoIndex attempted to alter "+GetUnitName(whichUnit)+"'s index.")
else
call BJDebugMsg("AutoIndex error: Code outside AutoIndex altered "+GetUnitName(whichUnit)+"'s index.")
if idunit[data] != null then
call BJDebugMsg("AutoIndex error: "+GetUnitName(whichUnit)+" and "+GetUnitName(idunit[data])+" now have the same index.")
endif
set altered[data] = true
endif
endif
endif
endmethod
//In debug mode, intercepts whenever SetUnitUserData is used on an indexed unit.
//Displays an error message if outside code tries to alter a unit's index.
//===========================================================================
private static method allowDecay takes nothing returns nothing
local integer n = allowdecay_n
loop
exitwhen n < 0
set nodecay[getIndex(allowdecayunit[n])] = false
set allowdecayunit[n] = null
set n = n - 1
endloop
set allowdecay_n = -1
endmethod
//Iterate through all the units in the stack and allow them to decay again.
private static method detectStatus takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer index = getIndex(u)
local integer n
if idunit[index] == u then //Ignore non-indexed units.
if not IsUnitType(u, UNIT_TYPE_DEAD) then
if dead[index] then //The unit was dead, but now it's alive.
set dead[index] = false //The unit has been resurrected.
//! runtextmacro optional RunStatusEvent("Resurrect")
//If StatusEvents is in the map, run the resurrection events.
if IsUnitType(u, UNIT_TYPE_SUMMONED) and not summoned[index] then
set summoned[index] = true //If the unit gained the summoned flag,
set animated[index] = true //it's been raised with Animate Dead.
//! runtextmacro optional RunStatusEvent("AnimateDead")
//If StatusEvents is in the map, run the Animate Dead events.
endif
endif
else
if not removing[index] and not dead[index] and not animated[index] then
set dead[index] = true //The unit was alive, but now it's dead.
set nodecay[index] = true //A dead unit can't decay for at least 0. seconds.
set allowdecay_n = allowdecay_n + 1 //Add the unit to a stack. After the timer
set allowdecayunit[allowdecay_n] = u //expires, allow the unit to decay again.
call TimerStart(allowdecay, 0., false, function AutoIndex.allowDecay)
//! runtextmacro optional RunStatusEvent("Death")
//If StatusEvents is in the map, run the Death events.
//! runtextmacro optional TransportUnload()
//If TransportEvents is in the map, remove the dead unit from whatever transport it's in.
elseif removing[index] or (dead[index] and not nodecay[index]) or (not dead[index] and animated[index]) then
//If .nodecay was false and the unit is dead and was previously dead, the unit decayed.
//If .animated was true and the unit is dead, the unit died and exploded.
//If .removing was true, the unit is being removed or replaced.
//! runtextmacro optional TransportUnload()
//If TransportEvents is in the map, remove the leaving unit from whatever transport it's in.
set n = deindexfuncs_n
loop //Run the OnUnitDeindexed events.
exitwhen n < 0
call deindexfuncs[n].evaluate(u)
set n = n - 1
endloop
//! runtextmacro optional TransportClean()
//If TransportEvents is in the map, and the leaving unit is a
//transport, clean the transport- related data from the unit.
call AutoIndex(index).destroy() //Free the index by destroying the AutoIndex struct.
set idunit[index] = null //Null this unit reference to prevent a leak.
endif
endif
endif
set u = null
return false
endmethod
private static method isUndefendOrder takes nothing returns boolean
//! runtextmacro optional TransportUnloadCheck()
//If TransportEvents is in the map, check whether a unit is unloading.
return GetIssuedOrderId() == 852056
endmethod
//===========================================================================
private static method unitEntersMap takes unit u returns nothing
local integer index
local integer n = 0
if getIndex(u) != 0 then //If a unit already has an ID, don't assign a new one.
return //This only happens if a unit leaves the entire map area.
endif
set index = create()
call setIndex(u, index) //Assign an index to the entering unit.
call UnitAddAbility(u, LeaveDetectAbilityID) //Add the leave detect ability to the entering unit.
call UnitMakeAbilityPermanent(u, true, LeaveDetectAbilityID) //Prevent it from disappearing on morph.
set dead[index] = IsUnitType(u, UNIT_TYPE_DEAD) //Reset all of the flags for the entering
set summoned[index] = IsUnitType(u, UNIT_TYPE_SUMMONED) //unit. These flags are necessary to detect
set animated[index] = false //when the unit leaves the map.
set nodecay[index] = false
set removing[index] = false
debug set altered[index] = false //In debug mode, this flag tracks wheter a unit's index was altered.
set idunit[index] = u //Attach the unit that is supposed to have this index to the index.
loop //Run the OnUnitIndexed events.
exitwhen n > indexfuncs_n
call indexfuncs[n].evaluate(u)
set n = n + 1
endloop
endmethod
private static method initPreplacedUnit takes nothing returns nothing
static if LIBRARY_xebasic then
if GetUnitTypeId(GetEnumUnit()) == XE_DUMMY_UNITID then
return //Don't index xe dummy units, and don't add
endif //them to the group of preplaced units.
endif
call GroupAddUnit(preplaced, GetEnumUnit()) //Assemble a group of all the preplaced units.
call unitEntersMap(GetEnumUnit()) //Initialize each preplaced unit.
return
endmethod
private static method initEnteringUnit takes nothing returns boolean
static if LIBRARY_xebasic then
if GetUnitTypeId(GetFilterUnit()) == XE_DUMMY_UNITID then
return false //Don't index xe dummy units, and don't add
endif //them to the group of preplaced units.
endif
if duringinit then
call GroupAddUnit(preplaced, GetFilterUnit())
//Add units that are created during initialization to the preplaced units group.
//This ensures that all units are noticed by OnUnitIndexed during initialization.
endif
call unitEntersMap(GetFilterUnit()) //Initialize each unit that enters the map.
return false
endmethod
//===========================================================================
private static method afterInit takes nothing returns nothing
set duringinit = false //Initialization is over; set a flag.
call DestroyTimer(GetExpiredTimer()) //Destroy the timer.
call GroupClear(preplaced) //The preplaced units group is
call DestroyGroup(preplaced) //no longer needed, so clean it.
set preplaced = null
endmethod
private static method onInit takes nothing returns nothing
local region maparea = CreateRegion()
local rect bounds = GetWorldBounds()
local group g = CreateGroup()
local integer i = 15
static if not UseUnitUserData then
set ht = InitHashtable() //Only create a hashtable if it will be used.
endif
loop
exitwhen i < 0
call SetPlayerAbilityAvailable(Player(i), LeaveDetectAbilityID, false)
//Make the LeaveDetect ability unavailable so that it doesn't show up on the command card of every unit.
call TriggerRegisterPlayerUnitEvent(status, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, function UnitFilter)
//Register the "EVENT_PLAYER_UNIT_ISSUED_ORDER" event to notice Undefend orders. Ignore filtered units.
call GroupEnumUnitsOfPlayer(g, Player(i), Condition(function UnitFilter))
call ForGroup(g, function AutoIndex.initPreplacedUnit)
//Enum every non-filtered unit on the map during initialization and assign it a unique
//index. By using GroupEnumUnitsOfPlayer, even units with Locust can be detected.
set i = i - 1
endloop
call TriggerAddCondition(status, And(function AutoIndex.isUndefendOrder, function AutoIndex.detectStatus))
//The detectStatus method will fire every time a non-filtered unit recieves an undefend order.
//And() is used here to avoid using a trigger action, which starts a new thread and is slower.
call TriggerRegisterPlayerUnitEvent(creepdeath, Player(12), EVENT_PLAYER_UNIT_DEATH, function UnitFilter)
call TriggerAddCondition(creepdeath, function AutoIndex.detectStatus)
//The detectStatus method must also fire when a neutral hostile creep dies, in case it was
//sleeping. Sleeping creeps don't fire undefend orders on non-damaging deaths.
call RegionAddRect(maparea, bounds) //GetWorldBounds() contains the entire map area, including the shaded boundry areas.
call TriggerRegisterEnterRegion(enter, maparea, And(function UnitFilter, function AutoIndex.initEnteringUnit))
//Only the filter function of an EnterRegion trigger runs instantly when a unit is created.
//Using And() lets both the UnitFilter and indexing function run when a unit enters the map.
call TimerStart(CreateTimer(), 0., false, function AutoIndex.afterInit)
//After any time elapses, perform after-initialization actions.
call GroupClear(g)
call DestroyGroup(g)
call RemoveRect(bounds)
set g = null
set bounds = null
endmethod
endstruct
endlibrary
library MultiShock initializer Init
globals
private constant integer ACTIVATOR_RAWCODE = 'A03V'
private constant integer DUMMY_RAWCODE = 'h00K'
private constant string DUMMY_STRING = "carrionswarm"
private constant real TARGET_ARC = 300
private constant integer WAVE_NUMBER_PER_LEVEL = 3
private constant integer WAVE_NUMBER_BASE = 0
private constant real TARGET_ARC_CUTOFF = TARGET_ARC/6.28319
private constant real TARGET_OFFSET = 150
private constant real DUMMY_DURATION = 1
endglobals
private function MSCondition takes nothing returns boolean
return GetSpellAbilityId() == ACTIVATOR_RAWCODE
endfunction
private constant function DummyFilter takes nothing returns boolean
return true
endfunction
private function MultiShock takes nothing returns nothing
local unit tu = GetTriggerUnit()
local location tl = GetSpellTargetLoc()
local unit lu
local player p = GetOwningPlayer(tu)
local integer im = WAVE_NUMBER_BASE + GetUnitAbilityLevel(tu,ACTIVATOR_RAWCODE) * WAVE_NUMBER_PER_LEVEL
local integer i = 0
local real x = GetUnitX(tu)
local real y = GetUnitY(tu)
local real tx = GetLocationX(tl)
local real ty = GetLocationY(tl)
local real distance = SquareRoot((x-tx)*(x-tx)+(y-ty)*(y-ty))
local real circum
local real r
call RemoveLocation(tl)
set tl = null
if distance > TARGET_ARC_CUTOFF then
set circum = TARGET_ARC/distance
set r = Atan2(ty-y,tx-x) - circum/2
else
set circum = 6.28319
set r = GetUnitFacing(tu)*bj_DEGTORAD
endif
set circum = circum/im
loop
exitwhen i == im
set lu = CreateUnit(p,DUMMY_RAWCODE,x,y,r*bj_RADTODEG)
call UnitApplyTimedLife(lu,'BTLF',DUMMY_DURATION)
call IssuePointOrder(lu,DUMMY_STRING,x+TARGET_OFFSET*Cos(r),y+TARGET_OFFSET*Sin(r))
set r = r + circum
set i = i + 1
endloop
set tu = null
set lu = null
set p = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local filterfunc ff = Filter(function DummyFilter)
loop
exitwhen (i >= bj_MAX_PLAYER_SLOTS)
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, ff)
set i = i + 1
endloop
call TriggerAddCondition(t,Condition(function MSCondition))
call TriggerAddAction(t,function MultiShock)
call DestroyFilter(ff)
set ff = null
endfunction
endlibrary
library DemonSlash requires RegisterPlayerUnitEvent, T32
// Demon Slash by The_Witcher
// The hero slashes through numerous enemys dealing aoe damage.
// When the hero crashes into an obstacle he stops.
//
// well not much to say look through/edit the setup part for your wishes
//
// The SETUP part
globals
// the rawcode of the ghost/demon appearing behind the caster when channeling
private constant integer DEMON_DUMMY_ID = 'h00N'
// the rawcode and the order string of the Demon Slash ability
private constant integer ABILITY_ID = 'A042'
private constant string ORDER_STRING = "absorb"
// the size the dummy will be when fully grown (2 = 200%)
private constant real MAX_SIZE = 2.5
//the effect created when a unit is hit
private constant string BLOOD_EFFECT = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
//the effect created on the weapon of the caster
private constant string WEAPON_EFFECT = "Abilities\\Weapons\\ZigguratMissile\\ZigguratMissile.mdl"
//the effect created on the body of the caster
private constant string BODY_EFFECT = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilMissile.mdl"
//the effect created when the dummy disappears cause of abort
private constant string ABORT_EFFECT = "Abilities\\Spells\\Undead\\CarrionSwarm\\CarrionSwarmDamage.mdl"
endglobals
private function GetDamage takes integer level returns real
return 100.00 + 50 * (level - 1) //120 on level 1, 170 level 2, 220 level 3, ...
endfunction
private function GetAOE takes integer level returns real
return 100.00 + 20 * level //120 on level 1, 140 level 2, 160 level 3, ...
endfunction
private function GetSlashDistance takes integer level returns real
return 700.0 + 100 * level //600 on level 1, 700 level 2, 800 level 3, ...
endfunction
private function GetSlashSpeed takes integer level returns real
return 700.0 + 100 * level //800 on level 1, 900 level 2, 1000 level 3, ...
endfunction
private function GetChannelTime takes integer level returns real
return 6.00 - level //3, 5 on level 1, 3 level 2, 2, 5 level 3, ...
endfunction
//==============================================================================
//========================= SETUP END ======================================
//==============================================================================
private struct spell
static group g
static item ite
static unit Temp
static boolexpr BoolExpr
unit u
unit dummy
real v
real d
real vx
real vy
real phase
real temp
integer level
effect bodyFX
effect weaponFX
group damaged
method IsCoordPathable takes real x, real y returns boolean
local real xx
local real yy
call SetItemVisible(.ite, true)
call SetItemPosition(.ite, x, y)
set xx = GetItemX( .ite ) - x
set yy = GetItemY( .ite ) - y
call SetItemVisible(.ite, false)
if xx < 1 and xx > -1 and yy < 1 and yy > -1 then
return true
endif
return false
endmethod
method periodic takes nothing returns nothing
local unit k = null
if .phase == 0 then // phase 1
if GetUnitCurrentOrder(.u) == OrderId(ORDER_STRING) then
call SetUnitVertexColor(.dummy, 255, 255, 255, R2I(.temp / 100 * 255))
call SetUnitScalePercent(.dummy, .temp * MAX_SIZE, .temp * MAX_SIZE, .temp * MAX_SIZE)
set .temp = .temp + 100 / GetChannelTime(.level) * T32_PERIOD
if .temp >= 100 then
set .phase = 1
set .temp = 0
set .weaponFX = AddSpecialEffectTarget(WEAPON_EFFECT, .u, "weapon")
set .bodyFX = AddSpecialEffectTarget(BODY_EFFECT, .u, "chest")
call IssueImmediateOrder(.u,"stop")
call PauseUnit(.u, true)
call SetUnitInvulnerable(.u, true)
call SetUnitAnimation(.u, "attack")
call SetUnitAnimation(.dummy, "attack")
call QueueUnitAnimation(.dummy,"stand")
endif
else
call DestroyEffect(AddSpecialEffect(ABORT_EFFECT, GetUnitX(.dummy), GetUnitY(.dummy)))
call RemoveUnit(.dummy)
call DestroyGroup(.damaged)
call .stopPeriodic()
call .destroy()
endif
else // phase 2
call SetUnitVertexColor(.dummy, 255, 255, 255, R2I((100 - .temp) / 100 * 255))
set .temp = .temp + 400 / GetChannelTime(.level) * T32_PERIOD
if .d > 0 and IsCoordPathable(GetUnitX(.u) + .vx, GetUnitY(.u) + .vy) then
call SetUnitX(.u, GetUnitX(.u) + .vx )
call SetUnitY(.u, GetUnitY(.u) + .vy )
set .d = .d - .v
set .Temp = .u
call GroupEnumUnitsInRange(.g, GetUnitX(.u), GetUnitY(.u), GetAOE(.level), .BoolExpr)
loop
set k = FirstOfGroup(.g)
exitwhen k == null
call GroupRemoveUnit(.g, k)
if not IsUnitInGroup(k, .damaged) then
call GroupAddUnit(.damaged, k)
call UnitDamageTarget( .u, k, GetDamage(.level), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS )
call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT, k, "chest"))
endif
endloop
else
call PauseUnit(.u, false)
call SetUnitAnimation(.u, "stand")
call SetUnitInvulnerable(.u, false)
call DestroyEffect(.weaponFX)
call DestroyEffect(.bodyFX)
call RemoveUnit(.dummy)
call DestroyGroup(.damaged)
call .stopPeriodic()
call .destroy()
endif
endif
endmethod
implement T32x
private static method create takes unit caster, real tx, real ty returns spell
local spell this = spell.allocate()
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local real r = Atan2(ty - y, tx - x)
set .u = caster
set .level = GetUnitAbilityLevel(.u, ABILITY_ID)
set .v = GetSlashSpeed(.level) * T32_PERIOD
set .vx = .v * Cos(r)
set .vy = .v * Sin(r)
set x = x + 200 * Cos(r - bj_PI)
set y = y + 200 * Sin(r - bj_PI)
set .dummy = CreateUnit(GetOwningPlayer(caster), DEMON_DUMMY_ID, x, y, r * bj_RADTODEG)
call PauseUnit(.dummy, true)
call SetUnitVertexColor(.dummy, 255, 255, 255, 0)
set .phase = 0
set .temp = 0
set .d = GetSlashDistance(.level)
set .damaged = CreateGroup()
call .startPeriodic()
return this
endmethod
private static method cast takes nothing returns nothing
if GetSpellAbilityId() == ABILITY_ID then
call spell.create(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
endif
endmethod
private static method AllyFilter takes nothing returns boolean
return ( IsUnitAlly(GetFilterUnit(), GetOwningPlayer(.Temp)) == false ) and not (IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) or GetUnitTypeId(GetFilterUnit()) == 0 )
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent( EVENT_PLAYER_UNIT_SPELL_CAST, function spell.cast )
set .BoolExpr = Condition(function spell.AllyFilter)
set .ite = CreateItem( 'wolg', 0, 0 )
call SetItemVisible(.ite, false)
set .g = CreateGroup()
endmethod
endstruct
endlibrary
//Code indented using The_Witcher's Script Language Aligner
//Download the newest version and report bugs at www.hiveworkshop.com
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ 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
/**************************************************************
*
* RegisterPlayerUnitEvent
* v5.0.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. (Which is a Pro)
*
* Warning:
* --------
*
* - 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.
*
* - function RegisterPlayerUnitEventForPlayer
* takes
* playerunitevent whichEvent : The event you would like to register
* code whichFunction : The code you would like to register
* player whichPlayer : The player you would like to register the event for
* returns
* nothing
*
* - Registers code that will execute when an event fires for a certain player.
*
**************************************************************/
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
function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
local integer i = 260 + 16 * GetHandleId(p) + GetPlayerId(pl)
if t[i] == null then
set t[i] = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
endlibrary