• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Triggers

sealing the keyhole.w3m
Variables
Variables
Initialization
Melee Initialization
Systems
Unit Indexer
DummyCaster
Instant Kill
Spell
Sealing the Keyhole
Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code except Custom Script Item. Custom Script Item will merge into map script after globals variables declaration with the list order in trigger view.
Name Type is_array initial_value
IsUnitPreplaced boolean Yes
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
Default melee game initialization for all players
Melee Initialization
Events
Map initialization
Conditions
Actions
Melee Game - Use melee time of day (for all players)
Melee Game - Limit Heroes to 1 per Hero-type (for all players)
Melee Game - Give trained Heroes a Scroll of Town Portal (for all players)
Melee Game - Set starting resources (for all players)
Melee Game - Remove creeps and critters from used start locations (for all players)
Melee Game - Create starting units (for all players)
Melee Game - Run melee AI scripts (for computer players)
Melee Game - Enforce victory/defeat conditions (for all players)
Visibility - Disable fog of war
Visibility - Disable black mask
Hero - Set Paladin 0001 <gen> Hero-level to 10 , Hide level-up graphics
This trigger works in two key phases:

1) During map initialization, enumerate all existing units of all players to give them an index.
2) Adds a second event to itself to index new units as they enter the map.

As a unit enters the map, check for any old units that may have been removed at some point in order to free their index.
Unit Indexer
Events
Map initialization
Conditions
Actions
Custom script: call ExecuteFunc("InitializeUnitIndexer")
Custom script: endfunction
-------- --------
-------- This is the core function - it provides an index all existing units and for units as they enter the map --------
-------- --------
Custom script: function IndexUnit takes nothing returns boolean
Custom script: local integer pdex = udg_UDex
Custom script: local integer ndex
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
IsUnitPreplaced[0] Equal to False
Then - Actions
-------- --------
-------- Check for removed units for every (32) new units created --------
-------- --------
Set Variable Set UDexWasted = (UDexWasted + 1)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
UDexWasted Equal to 32
Then - Actions
Set Variable Set UDexWasted = "0"
Set Variable Set UDex = UDexNext[0]
Custom script: loop
Custom script: exitwhen udg_UDex == 0
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Custom value of UDexUnits[UDex]) Equal to 0
Then - Actions
-------- --------
-------- Remove index from linked list --------
-------- --------
Custom script: set ndex = udg_UDexNext[udg_UDex]
Custom script: set udg_UDexNext[udg_UDexPrev[udg_UDex]] = ndex
Custom script: set udg_UDexPrev[ndex] = udg_UDexPrev[udg_UDex]
Set Variable Set UDexPrev[UDex] = "0"
Set Variable Set IsUnitPreplaced[UDex] = "false"
-------- --------
-------- Fire deindex event for UDex --------
-------- --------
Set Variable Set UnitIndexEvent = "2.00"
Set Variable Set UnitIndexEvent = "0.00"
-------- --------
-------- Recycle the index for later use --------
-------- --------
Set Variable Set UDexUnits[UDex] = No unit
Set Variable Set UDexNext[UDex] = UDexRecycle
Set Variable Set UDexRecycle = UDex
Custom script: set udg_UDex = ndex
Else - Actions
Set Variable Set UDex = UDexNext[UDex]
Custom script: endloop
Else - Actions
Else - Actions
-------- --------
-------- You can use the boolean UnitIndexerEnabled to protect some of your undesirable units from being indexed --------
-------- - Example: --------
-------- -- Set UnitIndexerEnabled = False --------
-------- -- Unit - Create 1 Dummy for (Triggering player) at TempLoc facing 0.00 degrees --------
-------- -- Set UnitIndexerEnabled = True --------
-------- --------
-------- You can also customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
-------- --------
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
UnitIndexerEnabled Equal to True
(Custom value of (Matching unit)) Equal to 0
Then - Actions
-------- --------
-------- Generate a unique integer index for this unit --------
-------- --------
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
UDexRecycle Equal to 0
Then - Actions
Set Variable Set UDex = (UDexGen + 1)
Set Variable Set UDexGen = UDex
Else - Actions
Set Variable Set UDex = UDexRecycle
Set Variable Set UDexRecycle = UDexNext[UDex]
-------- --------
-------- Link index to unit, unit to index --------
-------- --------
Set Variable Set UDexUnits[UDex] = (Matching unit)
Unit - Set the custom value of UDexUnits[UDex] to UDex
Set Variable Set IsUnitPreplaced[UDex] = IsUnitPreplaced[0]
-------- --------
-------- Use a doubly-linked list to store all active indexes --------
-------- --------
Set Variable Set UDexPrev[UDexNext[0]] = UDex
Set Variable Set UDexNext[UDex] = UDexNext[0]
Set Variable Set UDexNext[0] = UDex
-------- --------
-------- Fire index event for UDex --------
-------- --------
Set Variable Set UnitIndexEvent = "0.00"
Set Variable Set UnitIndexEvent = "1.00"
Set Variable Set UnitIndexEvent = "0.00"
Else - Actions
Custom script: set udg_UDex = pdex
Custom script: return false
Custom script: endfunction
-------- --------
-------- The next function initializes the core of the system --------
-------- --------
Custom script: function InitializeUnitIndexer takes nothing returns nothing
Custom script: local integer i = 0
Custom script: local region re = CreateRegion()
Custom script: local rect r = GetWorldBounds()
Custom script: local boolexpr b = Filter(function IndexUnit)
Set Variable Set UnitIndexEvent = "-1.00"
Set Variable Set UnitIndexerEnabled = "true"
Set Variable Set IsUnitPreplaced[0] = "true"
Custom script: call RegionAddRect(re, r)
Custom script: call TriggerRegisterEnterRegion(CreateTrigger(), re, b)
Custom script: call RemoveRect(r)
Custom script: set re = null
Custom script: set r = null
Custom script: loop
Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), b)
Custom script: set i = i + 1
Custom script: exitwhen i == bj_MAX_PLAYER_SLOTS
Custom script: endloop
Custom script: set b = null
-------- --------
-------- This is the "Unit Indexer Initialized" event, use it instead of "Map Initialization" for best results --------
-------- --------
Set Variable Set IsUnitPreplaced[0] = "false"
Set Variable Set UnitIndexEvent = "3.00"
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DummyCaster /* v2.0.0.1
*************************************************************************************
*
*   Dummy caster for casting spells
*
*   Spells must have 0 cooldown, 92083 range, and cost 0 mana. Spells must be instant and
*   can't share the same order as other spells on the dummy caster.
*
*************************************************************************************
*
*   */uses/*
*       */ optional UnitIndexer, /*       hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*
************************************************************************************
*   SETTINGS
*/
globals
    constant integer UNITS_DUMMY_CASTER = 'h001'
    
    /*************************************************************************************
    *
    *                                   PLAYER_OWNER
    *
    *   Owner of dummy caster
    *
    *************************************************************************************/
    private constant player PLAYER_OWNER = Player(15)
endglobals
/*
************************************************************************************
*
*   Dummy at position 32256,32256
*
*    struct DummyCaster extends array
*
*       method cast takes player castingPlayer, integer abilityLevel, integer order, real x, real y returns boolean
*           -   call DummyCaster[abilityId].cast(...)
*       method castTarget takes player castingPlayer, integer abilityLevel, integer order, widget t returns boolean
*           -   call DummyCaster[abilityId].castTarget(...)
*       method castPoint takes player castingPlayer, integer abilityLevel, integer order, real x, real y returns boolean
*           -   call DummyCaster[abilityId].castPoint(...)
*
************************************************************************************/
    globals
        private unit u
    endglobals
    private module N
        private static method onInit takes nothing returns nothing
            static if LIBRARY_UnitIndexer then
                set UnitIndexer.enabled=false
                set u=CreateUnit(PLAYER_OWNER,UNITS_DUMMY_CASTER,0,0,0)
                set UnitIndexer.enabled=true
            else
                set u=CreateUnit(PLAYER_OWNER,UNITS_DUMMY_CASTER,0,0,0)
            endif
            call SetUnitPosition(u,32256,32256)
        endmethod
    endmodule
    struct DummyCaster extends array
        implement N
        private static method prep takes integer a, player p, integer l returns nothing
            call UnitAddAbility(u, a)
            if (1 < l) then
                call SetUnitAbilityLevel(u, a, l)
            endif
            if (null != p) then
                call SetUnitOwner(u, p, false)
            endif
        endmethod
        private static method finish takes integer a returns nothing
            call SetUnitOwner(u, PLAYER_OWNER, false)
            call UnitRemoveAbility(u, a)
        endmethod
        method unit takes nothing returns unit
            return u
        endmethod
        method cast takes player p, integer level, integer order, real x, real y returns boolean
            local boolean b
            call SetUnitX(u, x)
            call SetUnitY(u, y)
            call prep(this, p, level)
            set b = IssueImmediateOrderById(u,order)
            call finish(this)
            call SetUnitPosition(u, 32256, 32256)
            return b
        endmethod
        method castTarget takes player p, integer level, integer order, widget t returns boolean
            local boolean b
            call SetUnitX(u, GetWidgetX(t))
            call SetUnitY(u, GetWidgetY(t))
            call prep(this, p, level)
            set b = IssueTargetOrderById(u,order,t)
            call finish(this)
            call SetUnitPosition(u, 32256, 32256)
            return b
        endmethod
        method castPoint takes player p, integer level, integer order, real px, real py, real x, real y returns boolean
            local boolean b
            call SetUnitX(u, px)
            call SetUnitY(u, py)
            call prep(this, p, level)
            set b = IssuePointOrderById(u,order,x,y)
            call finish(this)
            call SetUnitPosition(u, 32256, 32256)
            return b
        endmethod
    endstruct
endlibrary
//A simple library for killing a unit while still giving kill credit to another unit
//Author: KitsuneTailsPrower

library InstantKill requires optional DamageEngine

native UnitAlive takes unit u returns boolean

globals

integer killertypeid = 'h001' //set this to a dummy unit

unit killer=null

endglobals

function InstantKill takes player p, unit target, real x, real y returns nothing
	if not UnitAlive(killer) then
		set killer = CreateUnit(p, killertypeid, x, y, 0.0)
	else
		call SetUnitOwner(killer,p,false)
		call SetUnitX(killer,x)
		call SetUnitY(killer,y)
	endif
	static if LIBRARY_DamageEngine then
		set udg_NextDamageType = udg_DamageTypePure
	endif
	call UnitRemoveBuffs(target,true,true)
	call SetWidgetLife(target,1.0)
	call UnitDamageTarget(killer, target, 100000000., true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
endfunction

endlibrary
scope SealingTheKeyHole initializer onInit

    globals
	//configuration
        private constant integer AID = 'A000' //Ability ID of the main spell
	private constant integer OID = 852600 //OrderID of the main spell
	private constant string VOID_EFFECT_PATH = "Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdl" //Model of the initial effect
	private constant real VOID_EFFECT_SCALE = 4.0 //Scale of the initial effect
	private constant string GATE_EFFECT_PATH = "Doodads\\Icecrown\\Terrain\\IceCrownThroneGate\\IceCrownThroneGate.mdl" //Model of the door effect
	private constant real GATE_EFFECT_SCALE = 1.0 //Scale of the initial effect
	private constant string EXPLOSION_EFFECT_PATH = "Objects\\Spawnmodels\\Human\\HCancelDeath\\HCancelDeath.mdl" //Model of the explosion effect
	private constant real EXPLOSION_EFFECT_SCALE = 3.0 //Scale of the explosion effect
	private constant real INITIAL_DAMAGE_BASE = 10.0 //Base damage when the spell is first cast
	private constant real INITIAL_DAMAGE_PER_LEVEL = 10.0 //Bonus damage per level when the spell is first cast
	private constant real AOE = 200.0 //Area of effect of the spell, set equal to the AoE in the object editor
	private constant real KILL_PERCENT_HERO = 33.0 //Heroes at or below this life percent will die instantly when the door apears. KILL_PERCENT values are in % not decimal. Set to a negative value to always kill
	private constant real KILL_PERCENT_UNIT = -1.0 //Non hero units at or below this life percent will die instantly when the door apears. KILL_PERCENT values are in % not decimal. Set to a negative value to always kill
	private constant real END_DAMAGE_BASE = 50.0 //Base damage when the door appears (Not included in KILL_PERCENT caculations)
	private constant real END_DAMAGE_PER_LEVEL = 50.0 //Bonus damage per level when the door appears (Not included in KILL_PERCENT caculations)
	private constant integer STUN_AID = 'A001' //Abilty ID of the spell used to perform the stun, feel free to comment out and use an existing stun system
	private constant integer STUN_OID = 852095 //Order ID of the spell used to perform the stun, feel free to comment out and use an existing stun system

	//don't touch
	private group array targets
	private real array facingangles
	private real array targetx
	private real array targety
    endglobals

    private function FilterTarget takes unit u, unit c returns boolean
    	return IsUnitEnemy(u, GetOwningPlayer(c)) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not BlzIsUnitInvulnerable(u) and UnitAlive(u) and not IsUnitType(u,UNIT_TYPE_STRUCTURE)
    endfunction

    private function onCast takes nothing returns nothing
	local unit c = GetTriggerUnit()
	local unit u = null
	local group g = CreateGroup()
	local effect fx = null
	local real initialdamage = INITIAL_DAMAGE_BASE + (INITIAL_DAMAGE_PER_LEVEL * GetUnitAbilityLevel(c,AID))
	local integer userdata = GetUnitUserData(c)

	if GetSpellAbilityId() != AID then
		call DestroyGroup(g)
		set c = null
		set g = null
		return
	endif
	if targets[userdata] == null then
		set targets[userdata] = CreateGroup()
	endif
	call GroupClear(targets[userdata])
	set facingangles[userdata] = GetUnitFacing(c)
	set targetx[userdata] = GetUnitX(GetSpellTargetUnit())
	set targety[userdata] = GetUnitY(GetSpellTargetUnit())
	set fx=AddSpecialEffect(VOID_EFFECT_PATH,targetx[userdata],targety[userdata])	
	call BlzSetSpecialEffectScale(fx,VOID_EFFECT_SCALE)
	call DestroyEffect(fx)
        call GroupEnumUnitsInRange(g, targetx[userdata],targety[userdata], AOE, null)
	loop
        	set u = FirstOfGroup(g)
       	 	exitwhen u == null
		if FilterTarget(u,c) then
			call UnitDamageTarget(c, u, initialdamage, false, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
			call GroupAddUnit(targets[userdata],u)
		endif
		call GroupRemoveUnit(g, u)
	endloop
	call DestroyGroup(g)
	set g=null
	set fx=null
	set c=null
    endfunction
    private function onFinish takes nothing returns nothing
	local unit c = GetTriggerUnit()
	local unit u=null
	local effect fx = null
	local real enddamage = END_DAMAGE_BASE + (END_DAMAGE_PER_LEVEL * GetUnitAbilityLevel(c,AID))
	local integer userdata = GetUnitUserData(c)
	if GetSpellAbilityId() == AID then
		set fx=AddSpecialEffect(GATE_EFFECT_PATH,targetx[userdata],targety[userdata])
		call BlzSetSpecialEffectScale(fx,GATE_EFFECT_SCALE)
		call BlzSetSpecialEffectOrientation(fx,(facingangles[userdata] * 3.14) / 180,0.0,0.0)
		call DestroyEffect(fx)
		set fx=AddSpecialEffect(EXPLOSION_EFFECT_PATH,targetx[userdata],targety[userdata])
		call BlzSetSpecialEffectScale(fx,EXPLOSION_EFFECT_SCALE)
		call DestroyEffect(fx)
		loop
        		set u = FirstOfGroup(targets[GetUnitUserData(c)])
       	 		exitwhen u == null
			if (IsUnitType(u,UNIT_TYPE_HERO) and (KILL_PERCENT_HERO < 0.0 or GetUnitLifePercent(u) <= KILL_PERCENT_HERO)) or /*
			*/ (not IsUnitType(u,UNIT_TYPE_HERO) and (KILL_PERCENT_UNIT < 0.0 or GetUnitLifePercent(u) <= KILL_PERCENT_UNIT)) then
    				call SetUnitX(u,targetx[userdata])
    				call SetUnitY(u,targety[userdata])
    				call InstantKill(GetOwningPlayer(c),u,GetUnitX(c),GetUnitY(c))
			else
				call DummyCaster['A001'].castTarget(GetOwningPlayer(c),GetUnitAbilityLevel(c,AID),STUN_OID,u) //Comment this out and use your own stuns system here if desired
				call UnitDamageTarget(c, u, enddamage, false, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
			endif
			call GroupRemoveUnit(targets[GetUnitUserData(c)], u)
		endloop
	endif
	call GroupClear(targets[GetUnitUserData(c)])
	set fx=null
	set c = null
    endfunction

    private function onInit takes nothing returns nothing
	local trigger t = CreateTrigger()
	call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    	call TriggerAddCondition( t, Condition(function onCast) )
	set t = CreateTrigger()
	call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_FINISH )
    	call TriggerAddCondition( t, Condition(function onFinish) )
	set t = null
    endfunction
endscope
Top