• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Human Race Alternate Spells

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
cjass is required for ghostwalk, and possibly other spells. or at least knowledge to convert cjass to vjass/whatever.

Human is the race required to for the custom spells. check heroes, and casters.

i plan to eventually make some sort of custom melee set...but for now it can be a hero spell pack, i suppose...even though most of the content is seemingly somewhat unoriginal.

off the top of my head, credits can go to mc ! for his awesome blood elf model, and as for other arts, i probably did not make them... b17rider made an icon i think is in there...and there's other stuff too i suppose that i don't quite remember.

i figure the ghostwalk spell alone is enough of an accomplishment that it should be shared with others. the rest wasn't really all that special, if i do say so myself.

Code:
//===========================================================================
// 
// Terenas Stand
// 
//   Warcraft III map script
//   Generated by the Warcraft III World Editor
//   Date: Tue Dec 06 14:06:56 2011
//   Map Author: Blizzard Entertainment
// 
//===========================================================================

//***************************************************************************
//*
//*  Global Variables
//*
//***************************************************************************

globals
    // Generated
    trigger                 gg_trg_Custom_Initialization = null
    trigger                 gg_trg_paladin             = null
    trigger                 gg_trg_notes               = null
    trigger                 gg_trg_timerloops          = null
    trigger                 gg_trg_yojimbo             = null
    trigger                 gg_trg_coin_drops          = null
    trigger                 gg_trg_GT                  = null
    trigger                 gg_trg_MSGS                = null
    trigger                 gg_trg_DebugS              = null
    trigger                 gg_trg_Sorter              = null
    trigger                 gg_trg_jBoard              = null
    trigger                 gg_trg_jasscault           = null
    trigger                 gg_trg_Skeleton_Lord       = null
    trigger                 gg_trg_Untitled_Trigger_005 = null
    trigger                 gg_trg_fudo                = null
    trigger                 gg_trg_STM                 = null
    trigger                 gg_trg_TTG                 = null
    trigger                 gg_trg_TimerEvents         = null
    trigger                 gg_trg_pool                = null
    trigger                 gg_trg_SimError            = null
    trigger                 gg_trg_jumpy               = null
    trigger                 gg_trg_quests              = null
    trigger                 gg_trg_GUI_BLANK_TRIGGER   = null
    trigger                 gg_trg_testing             = null
    trigger                 gg_trg_xecollider_Copy     = null
    trigger                 gg_trg_xefx_Copy_Copy      = null
    trigger                 gg_trg_SomeNeatFunctions   = null
    trigger                 gg_trg_Black_Hole          = null
    trigger                 gg_trg_SithDebilitate      = null
    trigger                 gg_trg_Maelstrom           = null
    trigger                 gg_trg_Passive_Polymorph   = null
    trigger                 gg_trg_forceshield         = null
    trigger                 gg_trg_Demon_Slash         = null
    trigger                 gg_trg_kathy_windwood      = null
    trigger                 gg_trg_korg_lighthorn      = null
    trigger                 gg_trg_Birds               = null
    trigger                 gg_trg_Aquatic_Blast__NoLightning_Version = null
    trigger                 gg_trg_Water_Spirits       = null
    trigger                 gg_trg_Water_Strike        = null
    trigger                 gg_trg_Hydro_Rings         = null
    trigger                 gg_trg_Web                 = null
    trigger                 gg_trg_AquaCrush           = null
    trigger                 gg_trg_Unleash_Liquid      = null
    trigger                 gg_trg_Egg_Shack           = null
    trigger                 gg_trg_Drown               = null
    trigger                 gg_trg_apocalypse          = null
    trigger                 gg_trg_angelskiss          = null
    trigger                 gg_trg_coloritems          = null
    trigger                 gg_trg_mercenaries         = null
    trigger                 gg_trg_recipesinstructions = null
    trigger                 gg_trg_recipesTAF          = null
    trigger                 gg_trg_itemfunctions       = null
    trigger                 gg_trg_getissuedorderitem  = null
    trigger                 gg_trg_mbSTM               = null
    trigger                 gg_trg_leap                = null
    trigger                 gg_trg_TT                  = null
    trigger                 gg_trg_Geometry_Funcs      = null
    trigger                 gg_trg_recipesys           = null
    trigger                 gg_trg_table               = null
    trigger                 gg_trg_spellevents         = null
    trigger                 gg_trg_timereffects        = null
    trigger                 gg_trg_GroupUtils          = null
    trigger                 gg_trg_TimerUtils          = null
    trigger                 gg_trg_SoundUtils          = null
    trigger                 gg_trg_Stack               = null
    trigger                 gg_trg_PolarProjection     = null
    trigger                 gg_trg_oct_09_damage_stuff_by_anitarf = null
    trigger                 gg_trg_GetNearest          = null
    trigger                 gg_trg_DestructableLib     = null
    trigger                 gg_trg_TerrainPathabilitynew = null
    trigger                 gg_trg_LineSegment_Copy    = null
    trigger                 gg_trg_xebasic_Copy        = null
    trigger                 gg_trg_xedamage_Copy       = null
    trigger                 gg_trg_BoundSentinel       = null
    trigger                 gg_trg_xepreload_Copy_Copy = null
    trigger                 gg_trg_xecast_Copy_Copy    = null
    trigger                 gg_trg_KT                  = null
    trigger                 gg_trg_ABuff_Copy          = null
    trigger                 gg_trg_LightLeaklessDamageDetect = null
endglobals

function InitGlobals takes nothing returns nothing
endfunction

//***************************************************************************
//*
//*  Unit Item Tables
//*
//***************************************************************************

function Unit000012_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000015_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000018_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000021_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 2 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000022_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000024_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 2 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000025_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000032_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_CHARGED, 2 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

        // Item set 1
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000033_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 4 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000034_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 2 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000038_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 4 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000039_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 2 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000043_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_CHARGED, 3 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000044_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000048_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_CHARGED, 3 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000049_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000055_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 2 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000060_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 2 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000063_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000066_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000069_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000072_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000075_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000078_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000084_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_CHARGED, 2 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

        // Item set 1
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_POWERUP, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Unit000087_DropItems takes nothing returns nothing
    local widget  trigWidget = null
    local unit    trigUnit   = null
    local integer itemID     = 0
    local boolean canDrop    = true

    set trigWidget = bj_lastDyingWidget
    if (trigWidget == null) then
        set trigUnit = GetTriggerUnit()
    endif

    if (trigUnit != null) then
        set canDrop = not IsUnitHidden(trigUnit)
        if (canDrop and GetChangingUnit() != null) then
            set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE))
        endif
    endif

    if (canDrop) then
        // Item set 0
        call RandomDistReset(  )
        call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, 1 ), 100 )
        set itemID = RandomDistChoose(  )
        if (trigUnit != null) then
            call UnitDropItem( trigUnit, itemID )
        else
            call WidgetDropItem( trigWidget, itemID )
        endif

    endif

    set bj_lastDyingWidget = null
    call DestroyTrigger(GetTriggeringTrigger())
endfunction


//***************************************************************************
//*
//*  Unit Creation
//*
//***************************************************************************

//===========================================================================
function CreateNeutralHostile takes nothing returns nothing
    local player p = Player(PLAYER_NEUTRAL_AGGRESSIVE)
    local unit u
    local integer unitID
    local trigger t
    local real life

    set u = CreateUnit( p, 'nkot', -21.8, -5279.9, 119.087 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000015_DropItems )
    set u = CreateUnit( p, 'nkob', -147.8, -5293.0, 106.136 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nkob', 72.3, -5184.0, 133.033 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nkot', -256.2, 4663.8, 291.705 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000018_DropItems )
    set u = CreateUnit( p, 'nkob', -371.4, 4716.6, 306.763 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nkob', -126.4, 4698.3, 260.185 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwzg', 4551.8, -4770.4, 203.110 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000021_DropItems )
    set u = CreateUnit( p, 'nrog', 4551.2, -4944.0, 166.440 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000022_DropItems )
    set u = CreateUnit( p, 'nrog', 4547.5, -4605.6, 227.156 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwzg', -4443.9, 4402.4, 359.305 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000024_DropItems )
    set u = CreateUnit( p, 'nrog', -4444.6, 4228.9, 24.344 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000025_DropItems )
    set u = CreateUnit( p, 'nrog', -4448.2, 4567.2, 335.827 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nftr', 1795.9, -5095.8, 129.902 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nftr', 1382.4, -5102.7, 95.950 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nftr', 1819.1, -4981.9, 141.410 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nfsp', 1587.8, -4996.6, 115.882 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nsqt', 1497.7, -4910.3, 101.491 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000084_DropItems )
    set u = CreateUnit( p, 'nwiz', 3006.7, -5007.9, 34.696 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwzg', 301.5, 2219.1, 138.380 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000033_DropItems )
    set u = CreateUnit( p, 'nenf', 140.9, 2084.0, 120.120 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000034_DropItems )
    set u = CreateUnit( p, 'nenf', 351.5, 2438.3, 152.894 )
    set u = CreateUnit( p, 'nbrg', 292.0, 1994.3, 125.337 )
    set u = CreateUnit( p, 'nbrg', 487.2, 2337.3, 151.028 )
    set u = CreateUnit( p, 'nwzg', -606.3, -3127.7, 297.070 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000038_DropItems )
    set u = CreateUnit( p, 'nenf', -442.5, -3023.2, 278.810 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000039_DropItems )
    set u = CreateUnit( p, 'nenf', -757.8, -3247.2, 311.584 )
    set u = CreateUnit( p, 'nbrg', -550.6, -2884.9, 284.026 )
    set u = CreateUnit( p, 'nbrg', -904.0, -3150.6, 309.717 )
    set u = CreateUnit( p, 'nkol', -4476.2, -925.1, 318.360 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000043_DropItems )
    set u = CreateUnit( p, 'nkog', -4699.8, -990.4, 340.140 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000044_DropItems )
    set u = CreateUnit( p, 'nkog', -4381.6, -747.4, 293.253 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'ngrk', -4567.6, -1076.3, 345.548 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'ngrk', -4349.0, -918.8, 300.637 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nkol', 4464.3, 346.0, 138.360 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000048_DropItems )
    set u = CreateUnit( p, 'nkog', 4687.9, 411.3, 160.140 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000049_DropItems )
    set u = CreateUnit( p, 'nkog', 4369.7, 168.3, 113.253 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'ngrk', 4555.6, 497.2, 165.548 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'ngrk', 4337.0, 339.7, 120.637 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nass', 4189.6, 4143.1, 211.390 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000055_DropItems )
    set u = CreateUnit( p, 'nwiz', 4092.1, 4331.7, 239.425 )
    set u = CreateUnit( p, 'nwiz', 4340.3, 4090.7, 194.918 )
    set u = CreateUnit( p, 'nban', 4008.9, 4224.8, 238.044 )
    set u = CreateUnit( p, 'nban', 4216.3, 3988.8, 185.357 )
    set u = CreateUnit( p, 'nwiz', -4571.3, -4512.7, 29.694 )
    set u = CreateUnit( p, 'nwiz', -4313.5, -4743.3, 62.318 )
    set u = CreateUnit( p, 'nass', -4418.7, -4558.9, 42.422 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000060_DropItems )
    set u = CreateUnit( p, 'nban', -4234.8, -4633.1, 64.554 )
    set u = CreateUnit( p, 'nban', -4451.6, -4405.8, 25.565 )
    set u = CreateUnit( p, 'nkog', 247.9, -1803.5, 94.954 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000063_DropItems )
    set u = CreateUnit( p, 'nkob', 101.0, -1766.8, 77.577 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nkob', 403.3, -1724.9, 115.048 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nkog', -719.0, 799.6, 313.978 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000066_DropItems )
    set u = CreateUnit( p, 'nkob', -832.9, 679.5, 329.964 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nkob', -571.2, 721.9, 286.804 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwzr', -3455.1, -2573.0, 315.980 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000069_DropItems )
    set u = CreateUnit( p, 'nwiz', -3559.3, -2655.4, 340.475 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwiz', -3418.3, -2406.1, 291.552 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwzr', 2775.4, 1602.1, 139.581 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000072_DropItems )
    set u = CreateUnit( p, 'nwiz', 2671.1, 1519.8, 126.255 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwiz', 2812.1, 1769.1, 156.516 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nmrm', 5055.2, 2393.2, 176.310 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000075_DropItems )
    set u = CreateUnit( p, 'nmrr', 4923.6, 2527.9, 190.169 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nmrr', 4908.0, 2254.1, 160.165 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nmrm', -5164.0, -3390.4, 23.567 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000078_DropItems )
    set u = CreateUnit( p, 'nmrr', -4996.2, -3310.6, 37.426 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nmrr', -5143.9, -3149.0, 7.422 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwiz', 3203.6, -5000.8, 72.973 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwiz', 3108.3, -5102.7, 19.480 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000087_DropItems )
    set u = CreateUnit( p, 'nwiz', -2958.5, 4397.3, 214.696 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwiz', -3264.0, 4424.7, 252.973 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nsqt', -1508.4, 4324.3, 281.491 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000032_DropItems )
    set u = CreateUnit( p, 'nfsp', -1598.5, 4410.6, 295.882 )
    call SetUnitState( u, UNIT_STATE_MANA, 0 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nftr', -1829.8, 4395.9, 321.410 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nftr', -1393.1, 4516.8, 275.950 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nftr', -1806.6, 4509.8, 309.902 )
    call SetUnitAcquireRange( u, 200.0 )
    set u = CreateUnit( p, 'nwiz', -3121.1, 4376.6, 199.480 )
    call SetUnitAcquireRange( u, 200.0 )
    set t = CreateTrigger(  )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
    call TriggerAddAction( t, function Unit000012_DropItems )
endfunction

//===========================================================================
function CreateNeutralPassiveBuildings takes nothing returns nothing
    local player p = Player(PLAYER_NEUTRAL_PASSIVE)
    local unit u
    local integer unitID
    local trigger t
    local real life

    set u = CreateUnit( p, 'ngol', -4544.0, -4864.0, 270.000 )
    call SetResourceAmount( u, 12500 )
    set u = CreateUnit( p, 'ngol', 4736.0, -2560.0, 270.000 )
    call SetResourceAmount( u, 12500 )
    set u = CreateUnit( p, 'ngol', -4800.0, 2048.0, 270.000 )
    call SetResourceAmount( u, 12500 )
    set u = CreateUnit( p, 'ngol', 4416.0, 4352.0, 270.000 )
    call SetResourceAmount( u, 12500 )
    set u = CreateUnit( p, 'ngol', 512.0, 2048.0, 270.000 )
    call SetResourceAmount( u, 12500 )
    set u = CreateUnit( p, 'ngol', -768.0, -2944.0, 270.000 )
    call SetResourceAmount( u, 12500 )
    set u = CreateUnit( p, 'ntav', -256.0, -576.0, 270.000 )
    call SetUnitColor( u, ConvertPlayerColor(0) )
    set u = CreateUnit( p, 'ngme', -1600.0, 4608.0, 270.000 )
    set u = CreateUnit( p, 'ngme', 1600.0, -5248.0, 270.000 )
    set u = CreateUnit( p, 'nmer', -4672.0, -704.0, 270.000 )
    call SetUnitColor( u, ConvertPlayerColor(0) )
    set u = CreateUnit( p, 'ngad', 4864.0, -4864.0, 270.000 )
    set u = CreateUnit( p, 'ngad', -4736.0, 4480.0, 270.000 )
    set u = CreateUnit( p, 'nmer', 4672.0, 128.0, 270.000 )
    call SetUnitColor( u, ConvertPlayerColor(0) )
endfunction

//===========================================================================
function CreatePlayerBuildings takes nothing returns nothing
endfunction

//===========================================================================
function CreatePlayerUnits takes nothing returns nothing
endfunction

//===========================================================================
function CreateAllUnits takes nothing returns nothing
    call CreateNeutralPassiveBuildings(  )
    call CreatePlayerBuildings(  )
    call CreateNeutralHostile(  )
    call CreatePlayerUnits(  )
endfunction

//***************************************************************************
//*
//*  Custom Script Code
//*
//***************************************************************************
//TESH.scrollpos=0
//TESH.alwaysfold=0


//***************************************************************************
//*
//*  Triggers
//*
//***************************************************************************

//===========================================================================
// Trigger: Custom Initialization
//
// Default melee game initialization for all players
//===========================================================================
//TESH.scrollpos=-1
//TESH.alwaysfold=0
void CustomGrantItemsToHero (unit whichUnit){
integer owner   = GetPlayerId(GetOwningPlayer(whichUnit))
if (bj_meleeTwinkedHeroes[owner] < bj_MELEE_MAX_TWINKED_HEROES) then
if GetUnitRace(whichUnit)==RACE_HUMAN then
UnitAddItemById(whichUnit, 'mcri');UnitAddItemById(whichUnit, 'stwp')
elseif GetUnitRace(whichUnit)==RACE_NIGHTELF then
UnitAddItemById(whichUnit, 'moon');UnitAddItemById(whichUnit, 'stwp')
elseif GetUnitRace(whichUnit)==RACE_UNDEAD then    
UnitAddItemById(whichUnit, 'skul');UnitAddItemById(whichUnit, 'stwp')
elseif GetUnitRace(whichUnit)==RACE_ORC then
UnitAddItemById(whichUnit, 'shas');UnitAddItemById(whichUnit, 'stwp')
else;UnitAddItemById(whichUnit, 'I001');UnitAddItemById(whichUnit, 'tret')
endif;set bj_meleeTwinkedHeroes[owner] = bj_meleeTwinkedHeroes[owner] + 1;endif}
void CustomGrantItemsToTrainedHero(){CustomGrantItemsToHero(GetTrainedUnit())}
void CustomGrantItemsToHiredHero(){CustomGrantItemsToHero(GetSoldUnit())}

void CustomGrantHeroItems(){integer index;trigger trig;index = 0;loop;bj_meleeTwinkedHeroes[index] = 0
index = index + 1;exitwhen index == bj_MAX_PLAYER_SLOTS;endloop;index = 0;loop
trig = CreateTrigger();TriggerRegisterPlayerUnitEvent(trig, Player(index), EVENT_PLAYER_UNIT_TRAIN_FINISH, filterMeleeTrainedUnitIsHeroBJ)
TriggerAddAction(trig, function CustomGrantItemsToTrainedHero);index = index + 1;exitwhen index == bj_MAX_PLAYERS
endloop;trig = CreateTrigger();TriggerRegisterPlayerUnitEvent(trig, Player(PLAYER_NEUTRAL_PASSIVE), EVENT_PLAYER_UNIT_SELL, filterMeleeTrainedUnitIsHeroBJ)
TriggerAddAction(trig, function CustomGrantItemsToHiredHero);bj_meleeGrantHeroItems = true}


unit CustomRandomHeroLoc(player p, integer id1, integer id2, integer id3, integer id4, integer id5, location loc){
unit hero = null;integer roll,pick;version v;v = VersionGet();if (v == VERSION_REIGN_OF_CHAOS) then
roll = GetRandomInt(1,3);else;roll = GetRandomInt(1,5);endif;if roll == 1 then;pick = id1
elseif roll == 2 then;pick = id2;elseif roll == 3 then;pick = id3;elseif roll == 4 then
pick = id4;elseif roll == 5 then;pick = id5;else;pick = id1;endif;hero = CreateUnitAtLoc(p, pick, loc, bj_UNIT_FACING)
if bj_meleeGrantHeroItems then;MeleeGrantItemsToHero(hero);endif;return hero}

void CustomStartingUnitsHuman(player whichPlayer, location startLoc, boolean doHeroes, boolean doCamera, boolean doPreload)
{boolean  useRandomHero = IsMapFlagSet(MAP_RANDOM_HERO)
real unitSpacing   = 64.00;unit nearestMine,townHall = null;location nearMineLoc,heroLoc
real peonX,peonY;if (doPreload) then;Preloader( "scripts\\HumanMelee.pld" );endif
nearestMine = MeleeFindNearestMine(startLoc, bj_MELEE_MINE_SEARCH_RADIUS)
if(nearestMine!=null)then;townHall=CreateUnitAtLoc(whichPlayer,'htow',startLoc,bj_UNIT_FACING)
nearMineLoc = MeleeGetProjectedLoc(GetUnitLoc(nearestMine), startLoc, 320, 0)
peonX = GetLocationX(nearMineLoc);peonY = GetLocationY(nearMineLoc)
CreateUnit(whichPlayer, 'hpea', peonX + 0.00 * unitSpacing, peonY + 1.00 * unitSpacing, bj_UNIT_FACING)
CreateUnit(whichPlayer, 'hpea', peonX + 1.00 * unitSpacing, peonY + 0.15 * unitSpacing, bj_UNIT_FACING)
CreateUnit(whichPlayer, 'hpea', peonX - 1.00 * unitSpacing, peonY + 0.15 * unitSpacing, bj_UNIT_FACING)
CreateUnit(whichPlayer, 'hpea', peonX + 0.60 * unitSpacing, peonY - 1.00 * unitSpacing, bj_UNIT_FACING)
CreateUnit(whichPlayer, 'hpea', peonX - 0.60 * unitSpacing, peonY - 1.00 * unitSpacing, bj_UNIT_FACING)
heroLoc = MeleeGetProjectedLoc(GetUnitLoc(nearestMine), startLoc, 384, 45);else;
townHall = CreateUnitAtLoc(whichPlayer, 'htow', startLoc, bj_UNIT_FACING)
peonX = GetLocationX(startLoc);peonY = GetLocationY(startLoc) - 224.00
CreateUnit(whichPlayer, 'hpea', peonX + 2.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
CreateUnit(whichPlayer, 'hpea', peonX + 1.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
CreateUnit(whichPlayer, 'hpea', peonX + 0.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
CreateUnit(whichPlayer, 'hpea', peonX - 1.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
CreateUnit(whichPlayer, 'hpea', peonX - 2.00 * unitSpacing, peonY + 0.00 * unitSpacing, bj_UNIT_FACING)
heroLoc = Location(peonX, peonY - 2.00 * unitSpacing);endif;if (townHall != null) then
UnitAddAbilityBJ('Amic', townHall);UnitMakeAbilityPermanentBJ(true, 'Amic', townHall);endif
if (doHeroes) then;if useRandomHero then
CustomRandomHeroLoc(whichPlayer, 'Hamg', 'Hmkg', 'Hpal', 'Hblm', 'E007', heroLoc);else
SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_HERO_TOKENS, bj_MELEE_STARTING_HERO_TOKENS)
endif;endif;if (doCamera) then;SetCameraPositionForPlayer(whichPlayer, peonX, peonY)
SetCameraQuickPositionForPlayer(whichPlayer, peonX, peonY);endif}



void CustomStartingUnits(){integer index;player indexPlayer;location indexStartLoc
race indexRace;Preloader( "scripts\\SharedMelee.pld" );index = 0;loop;
indexPlayer = Player(index);if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
indexStartLoc = GetStartLocationLoc(GetPlayerStartLocation(indexPlayer));indexRace = GetPlayerRace(indexPlayer)
if (indexRace == RACE_HUMAN) then;CustomStartingUnitsHuman(indexPlayer, indexStartLoc, true, true, true)
elseif (indexRace == RACE_ORC) then;MeleeStartingUnitsOrc(indexPlayer, indexStartLoc, true, true, true)
elseif (indexRace == RACE_UNDEAD) then;MeleeStartingUnitsUndead(indexPlayer, indexStartLoc, true, true, true)
elseif (indexRace == RACE_NIGHTELF) then;MeleeStartingUnitsNightElf(indexPlayer, indexStartLoc, true, true, true)
else;MeleeStartingUnitsUnknownRace(indexPlayer, indexStartLoc, true, true, true);endif;endif
set index = index + 1;exitwhen index == bj_MAX_PLAYERS;endloop}


void Trig_Custom_Initialization_Actions(){MeleeStartingVisibility();MeleeStartingHeroLimit()
CustomGrantHeroItems();MeleeStartingResources();MeleeClearExcessUnits();CustomStartingUnits()
MeleeStartingAI();MeleeInitVictoryDefeat()}
//==
void InitTrig_Custom_Initialization(){gg_trg_Custom_Initialization=CreateTrigger()
TriggerAddAction( gg_trg_Custom_Initialization, function Trig_Custom_Initialization_Actions )}
//===========================================================================
// Trigger: paladin
//===========================================================================
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//'AIpr'
scope shieldpala initializer I
struct divineShield;    unit x;    integer y
    private method onTimedLoop takes nothing returns boolean
    y++;if y>=160 then//160 is 4 seconds
            SetUnitInvulnerable(x,false);return false;        endif;SetUnitInvulnerable(x,true);     return true;    endmethod
    implement TimedLoop 
    static method create takes unit u returns divineShield
     local divineShield m= divineShield.allocate()
        set m.x = u;set m.y=0
        call m.startTimedLoop() 
     return m
    endmethod
endstruct

private function Actions takes nothing returns boolean;call divineShield.create(GetSpellTargetUnit());return false;endfunction
private void I (){effectstartGT(Actions, 'AIpr')};endscope
//===========================================================================
// Trigger: timerloops
//===========================================================================
//TESH.scrollpos=108
//TESH.alwaysfold=0
library TimedLoop
// *******************************************************
//  TimedLoop
//  ---------
// 
//  Requires jasshelper 0.9.G.1 or greater.
// 
//    A library + module that are meant to make those
//  array + timer loops easy, yet still faster than
//  other alternatives meant to be easy (In other words
//  no TriggerEvaluate is involved).
// 
//  The OOPness is interesting.
// 
//   Before implementing TimedLoop
//  your struct needs an onTimedLoop method that takes
//  nothing and returns boolean, if the method
//  returns false, the instance will get removed
//  from the loop and destroyed, else it will continue,
//  think of it as if the call asks the method a
//  question: "Should I continue the loop afterwards?"
// 
//  Alternatively, if you are not convinced, you may
//  use the TimedLoop_CONTINUE and TimedLoop_STOP
//  constants in the method's returns.
//  
//    After implementing TimedLoop, you can call
//  the startTimedLoop method to add the periodic event
//  to that instance, only call it once per instance.
// 
//  I recommend to call implement just bellow the
//  declaration of the onLoop method, else it will
//  actually use TriggerEvaluate, which is lame. Remind
//  me to implement a topsort in jasshelper.
// 
//   If you feel the need to destroy the struct outside
//  the loop, well, you'll have to add a flag to it so
//  you send a message to onLoop to make it return false.
//  A more complicated module to allow that easily would
//  come later.
// 
// *******************************************************

//========================================================
// config:

    globals
     public constant real    PERIOD = 0.025
     // A lower value and everything using the module will
     // look better, yet performance will drop.
    endglobals

//========================================================
// implementation:
//
   globals
    public constant boolean STOP     = false
    public constant boolean CONTINUE = true
   endglobals
   
   
   //===========================  
   module TimedLoop
   // god bless private module members.
   //
      private static thistype array V        // The array
      private static integer        N = 0    // The count
      private static timer          T = null // the timer, one per
                                             // struct that implements this
      
      private static method onExpire takes nothing returns nothing
       local integer  n    = 0
       local thistype this // yay for odd-sounding syntax constructs
       local integer  i    = 0
       
          loop
              exitwhen (i== thistype.N)
              set this = .V[i]
              if ( this.onTimedLoop() == CONTINUE ) then
                  set .V[n] = this
                  set n=n+1
              else
                  call this.destroy()
              endif
              set i=i+1
          endloop
          set thistype.N = n
          if (n== 0) then
              call PauseTimer(.T)
          endif
                 
      endmethod
      
      public method startTimedLoop takes nothing returns nothing
         set .V[.N] = this
         set .N=.N + 1
         if (.N == 1) then
             if (.T == null) then
                 set .T = CreateTimer()
             endif
             call TimerStart(.T, PERIOD, true, function thistype.onExpire)
         endif
      endmethod
     
   endmodule


endlibrary
//example
/*struct moveUnit

    unit u

    //=====================================================
    // You need to code an onTimedLoop method before
    // implementing the module.
    //
    private method onTimedLoop takes nothing returns boolean
        //instance's timer expired:
        // This will just move a unit's x coordinate with
        // a speed of 100 until it reaches 5000.0

        call SetUnitX(u, GetUnitX(u) + 100.0* TimedLoop_PERIOD )
        // notice the use of the TimedLoop_PERIOD constant
        // since it may be tweaked by the user...


        if ( GetUnitX(u) >= 5000) then
            return TimedLoop_STOP
        endif

     return TimedLoop_CONTINUE

     //You are free to/should use false and true instead of the
     //constants.
    endmethod

    implement TimedLoop //This does the module magic

    static method create takes unit u returns moveUnit
     local moveUnit m= moveUnit.allocate()
        set m.u = u
        call m.startTimedLoop() //The module works by
        // creating a startTimedLoop method that will
        // do all the dirty work and end up calling
        // .onTimedLoop...
        //
     return m
    endmethod

endstruct
//call moveUnit.create(GetTriggerUnit()) and see...
*///===========================================================================
// Trigger: yojimbo
//===========================================================================
//TESH.scrollpos=-1
//TESH.alwaysfold=0
// Ice Trap by BRUTAL.
// Requires GT, and KT2.
// Credits are welcome but not necessary.
// October 12th 2009.
//
// Modified to be Fire Barrier for Valkyrie Hero by SanKakU
// My memories are a little fuzzy of the Xena episodes but
// from what i remember, Odin's top blonde valkyrie cursed
// Gabrielle by putting her in a fire trap much like this one.
// In further research it can be found that  in the tv show
// Bleach, the Captain Commander Yamamoto uses an ability
// like this.
//
// the spell now enables countering of escape spells.

scope FireBarrier initializer I
define{private ID='A00E';private IMMO_ID='A00F';private DUMMY_ID='h000';;private PATH_BLOCK='YTpb'
private PERIOD=.04;private SCALE=1. ;private ALPHA=75 ;private MAX_UNITS=36;private DISTANCE=350.}
private struct Data;unit caster, target;real x, y;real angle;integer pbInt=0, ticks, maxTicks
destructable array pathBlock[MAX_UNITS];unit array a[MAX_UNITS]
static method create takes unit u, unit z returns Data
local Data data=Data.allocate()
set data.caster=u
set data.target=z
set data.x=GetUnitX(data.target)
set data.y=GetUnitY(data.target)
set data.angle=GetUnitFacing(u)+140
set data.ticks=R2I(45*(GetUnitAbilityLevel(data.caster,ID))/PERIOD)+10
set data.maxTicks=data.ticks
return data
endmethod
method circle takes nothing returns nothing
integer level=GetUnitAbilityLevel(.caster,ID)
real dis=DISTANCE
//==AS AN ULTIMATE, THIS SPELL LASTS 45 SECONDS AT LEVEL 1, 90 SECONDS AT LEVEL 2, AND 135 SECONDS AT LEVEL 3
real x=.x+dis*Cos(.angle*bj_DEGTORAD)
real y=.y+dis*Sin(.angle*bj_DEGTORAD)
.a[.pbInt]=CreateUnit(GetOwningPlayer(.caster),DUMMY_ID,x,y,bj_RADTODEG*Atan2(y-.y,x-.x))
call SetUnitScale(.a[pbInt],SCALE,SCALE,1.75)
call SetUnitVertexColor(.a[pbInt],255,255,255,R2I(2.55*ALPHA))
call UnitAddAbility(.a[pbInt],IMMO_ID)
call SetUnitAbilityLevel(.a[pbInt],IMMO_ID,level)
call IssueImmediateOrder(.a[pbInt],"immolation")
set .angle=.angle+360./MAX_UNITS
set .pathBlock[.pbInt]=CreateDestructable(PATH_BLOCK,x,y,0,1,0)
set .pbInt=.pbInt+1
endmethod
method end takes nothing returns nothing
integer i=-1;whilenot(i++>MAX_UNITS){RemoveUnit(.a[i]);KillDestructable(.pathBlock[i])};endmethod
endstruct 
private function PeriodicFunc takes nothing returns boolean
local Data data=KT_GetData()
if getdisr(data.x,data.y,data.target)>=DISTANCE then
call SetUnitX(data.target,data.x)
call SetUnitY(data.target,data.y)
endif
set data.ticks=data.ticks-1
if data.ticks<=0 then  
call data.end()
return true
else
if data.ticks>=data.maxTicks-MAX_UNITS then
call data.circle()
endif
return false
endif  
endfunction 
private function actions takes nothing returns nothing
call KT_Add(function PeriodicFunc,Data.create(GetTriggerUnit(),GetSpellTargetUnit()),PERIOD)
endfunction
private function I takes nothing returns nothing
XE_PreloadAbility(IMMO_ID)
call TriggerAddAction(GT_RegisterStartsEffectEvent(CreateTrigger(),ID),function actions)
endfunction
endscope

scope Cloudarchmage initializer I
private function f takes nothing returns boolean
location tl = GetSpellTargetLoc();real tx = GetLocationX(tl),ty = GetLocationY(tl)
unit ut = GetTriggerUnit(),u = CreateUnit(GetOwningPlayer(ut), 'e005', tx, ty, 270.00)
integer lvl = GetUnitAbilityLevel(ut,'A008')
UnitAddAbility(u, 'Aclf')
SetUnitAbilityLevel(u, 'Aclf', lvl)
IssuePointOrder(u, "cloudoffog", tx,ty)
UnitApplyTimedLife(u, 'BTLF', 20. )
RemoveLocation(tl);tl = null;u = null;ut = null;return false;endfunction
public function I takes nothing returns nothing
effectstartGT(f,'A008')
XE_PreloadAbility('Aclf')
endfunction
endscope

scope banishher initializer I;globals;private boolean ya=false;private integer za=0;endglobals
//define private {HEROABI = 'AOsf';DUMMABI = 'AHbn';TEMPABI = 'AHpx';DUMMID='e000';PURGABI='A006'}

struct banaaa;unit x,u;integer y,z
private method onTimedLoop takes nothing returns boolean;SetUnitX(u,gux(x));SetUnitY(u,guy(x));if ya==false then;KillUnit(u);
return false;endif;y++;if y>=1280 then;KillUnit(u);return false;else;y++;if y>=1200 then;if z>0 then;return true;endif;z++;
if ya==true then;ya=false;UnitRemoveAbility(x,'A001');UnitAddAbility(x, 'AOsf');SetUnitAbilityLevel(x, 'AOsf', za);
UnitAddAbility(u, 'A006');IssueTargetOrder(u, "purge", x);endif;else;;endif;endif;
return true;endmethod;implement TimedLoop ;static method create takes unit x returns banaaa
local banaaa m= banaaa.allocate();set m.x = x;set m.y=0;set m.z=0
m.u = CreateUnit(GetOwningPlayer(m.x), 'e004', gux(m.x), guy(m.x), 270.00)
UnitRemoveAbility(m.x,'AOsf');UnitAddAbility(m.x, 'A001');UnitAddAbility(m.u, 'AHbn');SetUnitAbilityLevel(m.u, 'AHbn', za)
IssueTargetOrder(m.u, "banish", m.x);ya=true;call m.startTimedLoop() ; return m;endmethod;endstruct
private boolean e(){unit u=CreateUnit(GetOwningPlayer(gtu), 'e004', gux(gtu), guy(gtu), 270.00)
;ya=false;UnitRemoveAbility(gtu,'A001');UnitAddAbility(gtu, 'AOsf');SetUnitAbilityLevel(gtu, 'AOsf', za);
UnitAddAbility(u, 'A006');IssueTargetOrder(u, "purge", gtu);UnitApplyTimedLife(u,'BTLF',2.);return false}
private boolean g (){za++;return false};private boolean Actions (){call banaaa.create(gtu);return false}
private void I (){effectstartGT(Actions, 'AOsf');effectstartGT(e, 'A001');skillGT(g,'AOsf')
call XE_PreloadAbility('A006');call XE_PreloadAbility('AHbn');XE_PreloadAbility('AOsf');XE_PreloadAbility('A001')};endscope
//
scope projectora initializer I;struct propur;unit x,d,p,t;integer y;real a,b
private method onTimedLoop takes nothing returns boolean;b=getdis(t,p);a=b-10.0
SetDistanceToUnit(t,p,a);if b<129.0 then;KillUnit(p);KillUnit(d);
UnitDamageTarget(x,t,100.0,false,false,ATTACK_TYPE_HERO,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS);return false;
endif;y++;if y>=400 then;KillUnit(p);KillUnit(d);return false;endif;SetUnitX(d,gux(p));SetUnitY(d,guy(p));
UnitAddAbility(d, 'A006');IssueTargetOrder(d, "purge", p);return true
endmethod;implement TimedLoop ;static method create takes unit x, unit w returns propur
local propur m= propur.allocate();set m.t = w;m.x = x;set m.y=0;m.a=0.0;m.b=0.0
m.d = CreateUnit(GetOwningPlayer(m.x), 'e004', gux(m.x), guy(m.x), 270.00)
m.p = CreateUnit(GetOwningPlayer(m.x), 'e006', gux(m.x), guy(m.x), 270.00)
call m.startTimedLoop() ; return m;endmethod;endstruct
private boolean Actions (){call propur.create(gtu,GetSpellTargetUnit());return false}
private void I (){effectstartGT(Actions, 'A009')};endscope

//
//function SetDistanceToUnit takes unit y, unit x, real dist returns nothing
//extension to snippet.
//function getdis takes unit x, unit y returns real
//

scope SpinBash initializer Init

// Spin Bash by The_Witcher

// The Blademaster spins the target around, 
// damaging all enemies in range.
// After some time he releases his target, throwing it away.

globals
// the rawcode of your ability(press CTRL + D in object editor)
private constant integer SpellID = 'A0C5'

// the interval of the timer (increase if laggy)
private constant real interval = 0.01

// the distance between the target and the caster when
// spinnig around
private constant real SpinDistance = 150

// the curve is a constant used by the parabola forumla
private constant real Curve = 1.5

// this is the range in where units have to be around the target
// to get damaged
private constant real DamageRange = 80
endglobals

private function GetRotateTime takes integer lvl returns real
local real lowest  = IMaxBJ(4-lvl,0)
local real highest = lowest + 2
return GetRandomReal(lowest,highest)  // on lvl 1 between 4 and 6 seconds
endfunction

private function GetThrowDistance takes integer lvl returns real
return 200.*lvl  //100 on lvl 1, 200 on lvl 2,...
endfunction

private function GetRotateSpeed takes integer lvl returns real
return 4.*lvl// +4 degree every interval
endfunction

private function GetSpinDamage takes  integer lvl  returns real
return 30.*lvl   // every unit hit by the spinning/thrown unit takes this damage (here 30/60/90)
endfunction

private function GetTargetDamage takes  integer lvl  returns real
return 40.*lvl  // the damage the target takes (here 40/80/120)
endfunction

//-----------Don't modify anything below this line---------

private struct data
unit u
unit v
real a
real d
real s
real maxd
integer lvl
integer mode = 1
real dmg1
real dmg2
group DamageOnceGroup
endstruct

globals
private data array DATAS
private integer total = 0
private timer tim = CreateTimer()
private group g = CreateGroup()
private item ite
private player TempPlayer
private data TempDat
endglobals

private function 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
endfunction

private function JumpParabola takes real dist, real maxdist, real curve returns real
local real t = (dist * 2) / maxdist - 1
return (- t * t + 1) * (maxdist / curve)
endfunction

private function EnemiesOnly takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(),TempPlayer) and not (IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) or GetUnitTypeId(GetFilterUnit()) == 0 )
endfunction

private function Damage takes nothing returns nothing
if not IsUnitInGroup(GetEnumUnit(),TempDat.DamageOnceGroup) then
call UnitDamageTarget(TempDat.u,GetEnumUnit(),TempDat.dmg1,true,false,ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
call GroupAddUnit(TempDat.DamageOnceGroup,GetEnumUnit())
endif
endfunction

private function execute takes nothing returns nothing
local data dat
local integer i = 0
local real x
local real y
local unit u
loop
exitwhen i >= total
set dat = DATAS[i]
if dat.mode == 1 then
// Spinning around
set x = GetUnitX(dat.u) + SpinDistance * Cos(dat.a*bj_DEGTORAD)
set y = GetUnitY(dat.u) + SpinDistance * Sin(dat.a*bj_DEGTORAD)
call SetUnitX(dat.v,x)
call SetUnitY(dat.v,y)
call SetUnitFacing(dat.v,dat.a-180)
set dat.a = dat.a + dat.s
set dat.d = dat.d - interval
set TempPlayer = GetOwningPlayer(dat.u)
call GroupEnumUnitsInRange(g,GetUnitX(dat.v),GetUnitY(dat.v), DamageRange,Condition(function EnemiesOnly))
call GroupRemoveUnit(g,dat.v)
set TempDat = dat
call ForGroup(g, function Damage)
call GroupClear(g)
if dat.a > 360 then
set dat.a = dat.a - 360
call GroupClear(dat.DamageOnceGroup)
endif
if dat.d <= 0 then
set dat.d = 0 
set dat.maxd = GetThrowDistance(dat.lvl)
set dat.mode = 2
call PauseUnit(dat.u,false)
call SetUnitAnimation(dat.u,"stand")
call GroupClear(dat.DamageOnceGroup)
endif
else
// throw
set x = GetUnitX(dat.v) + dat.s * Cos(dat.a*bj_DEGTORAD)
set y = GetUnitY(dat.v) + dat.s * Sin(dat.a*bj_DEGTORAD)
if IsCoordPathable(x,y) then
call SetUnitX(dat.v,x)
call SetUnitY(dat.v,y)
call GroupEnumUnitsInRange(g,GetUnitX(dat.v),GetUnitY(dat.v), DamageRange,Condition(function EnemiesOnly))
call GroupRemoveUnit(g,dat.v)
set TempDat = dat
call ForGroup(g, function Damage)
call GroupClear(g)
endif
set dat.d = dat.d + dat.s
if dat.mode == 3 then
call SetUnitFlyHeight(dat.v,JumpParabola(dat.d,dat.maxd,Curve),0)
else
call SetUnitFlyHeight(dat.v,JumpParabola(dat.d,dat.maxd,Curve*3),0)
endif
if dat.d >= dat.maxd and dat.mode == 2 then
set dat.d = 0 
set dat.maxd = GetThrowDistance(dat.lvl) / 3
set dat.mode = 3
call GroupClear(dat.DamageOnceGroup)
call UnitDamageTarget(dat.u,dat.v,dat.dmg2,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
elseif dat.d >= dat.maxd and dat.mode == 3 then
call SetUnitFlyHeight(dat.v,0,0)
call PauseUnit(dat.v,false)
call SetUnitTimeScale(dat.v,1)
call DestroyGroup(dat.DamageOnceGroup)
set total = total - 1
set DATAS[i] = DATAS[total]
call dat.destroy()
set i = i - 1
endif
endif
set i = i + 1
endloop
if total == 0 then
call PauseTimer(tim)
endif
endfunction

private function start takes nothing returns boolean
local data dat
if GetSpellAbilityId() == SpellID then
set dat = data.create()
set dat.u = GetTriggerUnit()
set dat.v = GetSpellTargetUnit()
set dat.a = bj_RADTODEG * Atan2(GetUnitY(dat.v) - GetUnitY(dat.u), GetUnitX(dat.v) - GetUnitX(dat.u))
set dat.lvl = GetUnitAbilityLevel(dat.u,SpellID)
set dat.d = GetRotateTime(dat.lvl)
set dat.s = GetRotateSpeed(dat.lvl)
set dat.dmg1 = GetSpinDamage(dat.lvl)
set dat.dmg2 = GetTargetDamage(dat.lvl)
set dat.DamageOnceGroup = CreateGroup()
call IssueImmediateOrder(dat.u,"stop")
call PauseUnit(dat.u,true)
call PauseUnit(dat.v,true)
call SetUnitTimeScale(dat.v,0)
call SetUnitAnimation(dat.u,"spin")
call UnitAddAbility(dat.v,'Amrf')
call UnitRemoveAbility(dat.v,'Amrf')
set DATAS[total] = dat
set total = total + 1
if total == 1 then
call TimerStart(tim,interval,true, function execute)
endif
endif
return false
endfunction

private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerAddCondition(t,Condition(function start))
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
set ite = CreateItem('wolg',0,0)
call SetItemVisible(ite,false)
call SetItemInvulnerable( ite, true)
endfunction

endscope//===========================================================================
// Trigger: GT
//===========================================================================
//TESH.scrollpos=74
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ GT ~~ GTrigger ~~ By Jesus4Lyf ~~ Version 1.05 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is GTrigger?
//               - GTrigger is an event system that replaces the cumbersome WC3
//                 event system.
//               - GTrigger only launches the necessary threads instead of x threads,
//                 where x is the number of times the event type occurs in the map.
//
//      =Pros=
//               - Instead of having 16 events (for "16" players) per use of an,
//                 event type, you have 0 per use and 16 total for that event type.
//               - If you have 100 events of one type in your map, instead of firing
//                 100 triggers each time any spell is cast, you fire only what's needed.
//               - GTrigger is faster to code with, more efficient to execute, and just
//                 better programming practises and nicer code all round.
//
//      =Cons=
//               - If a trigger with a GTrigger event is destroyed, it must have its
//                 event unregistered first or it will leak an event (slows firing down).
//               - Shouldn't use "wait" actions anywhere in the triggers.
//
//      Functions:
//                 // General
//               - GT_UnregisterTriggeringEvent()
//
//                 // Ability events
//               - GT_RegisterStartsEffectEvent(trigger, abilityid)       (returns the trigger passed in)
//               - GT_RegisterBeginsChanellingEvent(trigger, abilityid)   (returns the trigger passed in)
//               - GT_RegisterBeginsCastingEvent(trigger, abilityid)      (returns the trigger passed in)
//               - GT_RegisterStopsCastingEvent(trigger, abilityid)       (returns the trigger passed in)
//               - GT_RegisterFinishesCastingEvent(trigger, abilityid)    (returns the trigger passed in)
//               - GT_RegisterLearnsAbilityEvent(trigger, abilityid)       (returns the trigger passed in)
//                 // Order events // (can use String2OrderIdBJ("OrderString") for orderid
//               - GT_RegisterTargetOrderEvent(trigger, orderid)          (returns the trigger passed in)
//               - GT_RegisterPointOrderEvent(trigger, orderid)           (returns the trigger passed in)
//               - GT_RegisterNoTargetOrderEvent(trigger, orderid)        (returns the trigger passed in)
//                 // Item events
//               - GT_RegisterItemUsedEvent(trigger, itemtypeid)          (returns the trigger passed in)
//               - GT_RegisterItemAcquiredEvent(trigger, itemtypeid)      (returns the trigger passed in)
//               - GT_RegisterItemDroppedEvent(trigger, itemtypeid)       (returns the trigger passed in)
//                 // Unit events
//               - GT_RegisterUnitDiesEvent(trigger, unittypeid)          (returns the trigger passed in)
//
//                 // Ability Events
//               - GT_UnregisterSpellEffectEvent(trigger, abilityid)      (returns the trigger passed in)
//               - GT_UnregisterBeginsChanellingEvent(trigger, abilityid) (returns the trigger passed in)
//               - GT_UnregisterBeginsCastingEvent(trigger, abilityid)    (returns the trigger passed in)
//               - GT_UnregisterStopsCastingEvent(trigger, abilityid)     (returns the trigger passed in)
//               - GT_UnregisterFinishesCastingEvent(trigger, abilityid)  (returns the trigger passed in)
//               - GT_UnregisterLearnsAbilityEvent(trigger, abilityid)     (returns the trigger passed in)
//                 // Order events // (can use String2OrderIdBJ("OrderString") for orderid
//               - GT_UnregisterTargetOrderEvent(trigger, orderid)        (returns the trigger passed in)
//               - GT_UnregisterPointOrderEvent(trigger, orderid)         (returns the trigger passed in)
//               - GT_UnregisterNoTargetOrderEvent(trigger, orderid)      (returns the trigger passed in)
//                 // Item events
//               - GT_UnregisterItemUsedEvent(trigger, itemtypeid)        (returns the trigger passed in)
//               - GT_UnregisterItemAcquiredEvent(trigger, itemtypeid)    (returns the trigger passed in)
//               - GT_UnregisterItemDroppedEvent(trigger, itemtypeid)     (returns the trigger passed in)
//                 // Unit events
//               - GT_UnregisterUnitDiesEvent(trigger, unittypeid)        (returns the trigger passed in)
//
//      Alternative interface (not recommended):
//              If you aren't familiar with how this works, you shouldn't use it.
//              All funcs must return false. (That is the only reason it isn't recommended.)
//                 // General
//               - GT_RemoveTriggeringAction() // Use this to remove actions.
//                 // Ability Events
//               - GT_AddStartsEffectAction(func, abilityid)
//               - GT_AddBeginsChanellingActon(func, abilityid)
//               - GT_AddBeginsCastingAction(func, abilityid)
//               - GT_AddStopsCastingAction(func, abilityid)
//               - GT_AddFinishesCastingAction(func, abilityid)
//               - GT_AddLearnsAbilityAction(func, abilityid)
//                 // Order events // (can use String2OrderIdBJ("OrderString") for orderid
//               - GT_AddTargetOrderAction(func, orderid)
//               - GT_AddPointOrderAction(func, orderid)
//               - GT_AddNoTargetOrderAction(func, orderid)
//                 // Item events
//               - GT_AddItemUsedAction(func, itemtypeid)
//               - GT_AddItemAcquiredAction(func, itemtypeid)
//               - GT_AddItemDroppedAction(func, itemtypeid)
//                 // Unit events
//               - GT_AddUnitDiesAction(func, unittypeid)
//
//  Details:
//               - Due to the storage method, only 8191 GTrigger events are possible at any one time.
//
//  Thanks:
//               - Daxtreme: For voluntarily testing this system and the UnitDies event idea.
//               - kenny!: For the Order and Learns Ability event ideas.
//
//  How to import:
//               - Create a trigger named GT.
//               - Convert it to custom text and replace the whole trigger text with this.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library GT initializer Init
    //////////////
    // Pointers //
    ////////////////////////////////////////////////////////////////////////////
    // Assigned to abilities, and point to trigger grouping linked lists.
    //
    // Use:
    //  GetPointer --> int (pointer)
    //  FreePointer(int (pointer))
    //  set PointerTarget[int (pointer)]=int (list link)
    //  PointerTarget[int (pointer)] --> int (list link)
    globals
        // Pointer
        private integer array PointerTarget
        private integer PointerMax=0
        // Spare Pointer Stack
        private integer array NextPointer
        private integer NextPointerMaxPlusOne=1
    endglobals
    
    private function GetPointer takes nothing returns integer
        if NextPointerMaxPlusOne==1 then
            set PointerMax=PointerMax+1
            return PointerMax
        endif
        set NextPointerMaxPlusOne=NextPointerMaxPlusOne-1
        return NextPointer[NextPointerMaxPlusOne]
    endfunction
    private function FreePointer takes integer pointer returns nothing
        set PointerTarget[pointer]=0
        set NextPointer[NextPointerMaxPlusOne]=pointer
        set NextPointerMaxPlusOne=NextPointerMaxPlusOne+1
    endfunction
    
    ///////////////////////////////////
    // Trigger Grouping Linked Lists //
    ////////////////////////////////////////////////////////////////////////////
    // Contains a chain of triggers to be executed together.
    //
    // Use:
    //  GetMem() --> int (mem)
    //  FreeMem(int (mem))
    //  Link(int (pointer), int (mem))
    //  Unlink(int (pointer), int (mem))
    globals
        // Spare Link Stack
        private integer array NextMem
        private integer NextMemMaxPlusOne=1
        // Linked list
        private trigger array Trig
        private integer array Next
        private integer array Prev
        private integer TrigMax=0
    endglobals
    
    private function GetMem takes nothing returns integer
        if NextMemMaxPlusOne==1 then
            set TrigMax=TrigMax+1
            return TrigMax
        endif
        set NextMemMaxPlusOne=NextMemMaxPlusOne-1
        return NextMem[NextMemMaxPlusOne]
    endfunction
    private function FreeMem takes integer i returns nothing
        set Trig[i]=null
        set NextMem[NextMemMaxPlusOne]=i
        set NextMemMaxPlusOne=NextMemMaxPlusOne+1
    endfunction
    
    // Linked list functionality
    // NOTE: This means "Next" must be loaded BEFORE executing the trigger, which could delete the current link.
    private function Link takes integer pointer, integer new returns nothing
        set Prev[new]=0
        set Next[new]=PointerTarget[pointer]
        set Prev[PointerTarget[pointer]]=new
        set PointerTarget[pointer]=new
    endfunction
    private function Unlink takes integer pointer, integer rem returns nothing
        if Prev[rem]==0 then
            set PointerTarget[pointer]=Next[rem]
            set Prev[Next[rem]]=0
        endif
        set Next[Prev[rem]]=Next[rem]
        set Prev[Next[rem]]=Prev[rem]
    endfunction
    
    //////////////////////
    // GTrigger General //
    ////////////////////////////////////////////////////////////////////////////
    // Only contains the UnregisterTriggeringEvent action for public use.
    globals
        boolean UnregisterLastEvent=false
    endglobals
    public function UnregisterTriggeringEvent takes nothing returns nothing
        set UnregisterLastEvent=true
    endfunction
    
    /////////////////////////////////////
    // GTrigger Ability Implementation //
    ////////////////////////////////////////////////////////////////////////////
    // The nasty textmacro implementation of special "All Players" events.
    //! textmacro SetupSpecialAllPlayersEvent takes NAME, EVENT, GETSPECIAL
        globals
            private trigger $NAME$Trigger=CreateTrigger()
            // Extendable arrays
            private integer array $NAME$AbilityIdA
            private integer array $NAME$ListPointerA
            private integer array $NAME$AbilityIdB
            private integer array $NAME$ListPointerB
            private integer array $NAME$AbilityIdC
            private integer array $NAME$ListPointerC
            private integer array $NAME$AbilityIdD
            private integer array $NAME$ListPointerD
            private integer array $NAME$AbilityIdE
            private integer array $NAME$ListPointerE
        endglobals
        
        globals//locals
            private integer GetOrCreateListPointer$NAME$AbilHashed
        endglobals
        private function GetOrCreate$NAME$ListPointer takes integer abil returns integer
            set GetOrCreateListPointer$NAME$AbilHashed=abil-(abil/8191)*8191
            if $NAME$AbilityIdA[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerA[GetOrCreateListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdA[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
                set $NAME$AbilityIdA[GetOrCreateListPointer$NAME$AbilHashed]=abil
                set $NAME$ListPointerA[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
                return $NAME$ListPointerA[GetOrCreateListPointer$NAME$AbilHashed]
            endif
            if $NAME$AbilityIdB[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerB[GetOrCreateListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdB[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
                set $NAME$AbilityIdB[GetOrCreateListPointer$NAME$AbilHashed]=abil
                set $NAME$ListPointerB[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
                return $NAME$ListPointerB[GetOrCreateListPointer$NAME$AbilHashed]
            endif
            if $NAME$AbilityIdC[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerC[GetOrCreateListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdC[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
                set $NAME$AbilityIdC[GetOrCreateListPointer$NAME$AbilHashed]=abil
                set $NAME$ListPointerC[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
                return $NAME$ListPointerC[GetOrCreateListPointer$NAME$AbilHashed]
            endif
            if $NAME$AbilityIdD[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerD[GetOrCreateListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdD[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
                set $NAME$AbilityIdD[GetOrCreateListPointer$NAME$AbilHashed]=abil
                set $NAME$ListPointerD[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
                return $NAME$ListPointerD[GetOrCreateListPointer$NAME$AbilHashed]
            endif
            if $NAME$AbilityIdE[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerE[GetOrCreateListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdE[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
                set $NAME$AbilityIdE[GetOrCreateListPointer$NAME$AbilHashed]=abil
                set $NAME$ListPointerE[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
                return $NAME$ListPointerE[GetOrCreateListPointer$NAME$AbilHashed]
            endif
            call BJDebugMsg("GTrigger Error: Ran out of storage locations for pointers on object "+GetObjectName(abil)+"!")
            set PointerTarget[0]=0
            return 0
        endfunction
        
        globals//locals
            private integer GetListPointer$NAME$AbilHashed
        endglobals
        private function Get$NAME$ListPointer takes integer abil returns integer
            set GetListPointer$NAME$AbilHashed=abil-(abil/8191)*8191
            if $NAME$AbilityIdA[GetListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerA[GetListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdA[GetListPointer$NAME$AbilHashed]<1 then // Empty
                set PointerTarget[0]=0 // Make sure.
                return 0
            endif
            if $NAME$AbilityIdB[GetListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerB[GetListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdB[GetListPointer$NAME$AbilHashed]<1 then // Empty
                set PointerTarget[0]=0 // Make sure.
                return 0
            endif
            if $NAME$AbilityIdC[GetListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerC[GetListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdC[GetListPointer$NAME$AbilHashed]<1 then // Empty
                set PointerTarget[0]=0 // Make sure.
                return 0
            endif
            if $NAME$AbilityIdD[GetListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerD[GetListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdD[GetListPointer$NAME$AbilHashed]<1 then // Empty
                set PointerTarget[0]=0 // Make sure.
                return 0
            endif
            if $NAME$AbilityIdE[GetListPointer$NAME$AbilHashed]==abil then // Correct
                return $NAME$ListPointerE[GetListPointer$NAME$AbilHashed]
            elseif $NAME$AbilityIdE[GetListPointer$NAME$AbilHashed]<1 then // Empty
                set PointerTarget[0]=0 // Make sure.
                return 0
            endif
            call BJDebugMsg("GTrigger Error: Ran out of storage locations for pointers at ability "+GetObjectName(abil)+"!")
            set PointerTarget[0]=0
            return 0
        endfunction
        
        globals//locals
            private integer Register$NAME$Mem
        endglobals
        public function Register$NAME$Event takes trigger t, integer abil returns trigger
            set Register$NAME$Mem=GetMem()
            set Trig[Register$NAME$Mem]=t
            call Link(GetOrCreate$NAME$ListPointer(abil),Register$NAME$Mem)
            return t
        endfunction
        
        globals//locals
            private integer Unregister$NAME$Pointer
            private integer Unregister$NAME$Mem
        endglobals
        public function Unregister$NAME$Event takes trigger t, integer abil returns trigger
            set Unregister$NAME$Pointer=Get$NAME$ListPointer(abil)
            set Unregister$NAME$Mem=PointerTarget[Unregister$NAME$Pointer]
            loop
                exitwhen Trig[Unregister$NAME$Mem]==t
                if Unregister$NAME$Mem==0 then
                    return t // Not found.
                endif
                set Unregister$NAME$Mem=Next[Unregister$NAME$Mem]
            endloop
            call Unlink(Unregister$NAME$Pointer,Unregister$NAME$Mem)
            call FreeMem(Unregister$NAME$Mem)
            return t
        endfunction
        
        private function Trigger$NAME$Event takes nothing returns boolean
            local integer Trigger$NAME$Pointer=Get$NAME$ListPointer($GETSPECIAL$)
            local integer Trigger$NAME$Mem=PointerTarget[Trigger$NAME$Pointer]
            local integer Trigger$NAME$NextMem
            set UnregisterLastEvent=false
            loop
                exitwhen Trigger$NAME$Mem<1
                set Trigger$NAME$NextMem=Next[Trigger$NAME$Mem]
                if TriggerEvaluate(Trig[Trigger$NAME$Mem]) then
                    call TriggerExecute(Trig[Trigger$NAME$Mem])
                endif
                if UnregisterLastEvent then
                    set UnregisterLastEvent=false
                    call Unlink(Trigger$NAME$Pointer,Trigger$NAME$Mem)
                    call FreeMem(Trigger$NAME$Mem)
                endif
                set Trigger$NAME$Mem=Trigger$NAME$NextMem
            endloop
            return false
        endfunction
        
        private function Init$NAME$ takes nothing returns nothing
            local integer i=bj_MAX_PLAYER_SLOTS
            call TriggerAddCondition($NAME$Trigger,Condition(function Trigger$NAME$Event))
            loop
                set i=i-1
                call TriggerRegisterPlayerUnitEvent($NAME$Trigger,Player(i),EVENT_PLAYER_$EVENT$,null)
                exitwhen i==0
            endloop
        endfunction
    //! endtextmacro
    
    //! runtextmacro SetupSpecialAllPlayersEvent("StartsEffect",     "UNIT_SPELL_EFFECT",        "GetSpellAbilityId()")
    //! runtextmacro SetupSpecialAllPlayersEvent("BeginsChanelling", "UNIT_SPELL_CHANNEL",       "GetSpellAbilityId()")
    //! runtextmacro SetupSpecialAllPlayersEvent("BeginsCasting",    "UNIT_SPELL_CAST",          "GetSpellAbilityId()")
    //! runtextmacro SetupSpecialAllPlayersEvent("StopsCasting",     "UNIT_SPELL_ENDCAST",       "GetSpellAbilityId()")
    //! runtextmacro SetupSpecialAllPlayersEvent("FinishesCasting",  "UNIT_SPELL_FINISH",        "GetSpellAbilityId()")
    //! runtextmacro SetupSpecialAllPlayersEvent("TargetOrder",      "UNIT_ISSUED_TARGET_ORDER", "GetIssuedOrderId()")
    //! runtextmacro SetupSpecialAllPlayersEvent("PointOrder",       "UNIT_ISSUED_POINT_ORDER",  "GetIssuedOrderId()")
    //! runtextmacro SetupSpecialAllPlayersEvent("NoTargetOrder",    "UNIT_ISSUED_ORDER",        "GetIssuedOrderId()")
    //! runtextmacro SetupSpecialAllPlayersEvent("ItemUsed",         "UNIT_USE_ITEM",            "GetItemTypeId(GetManipulatedItem())")
    //! runtextmacro SetupSpecialAllPlayersEvent("ItemAcquired",     "UNIT_PICKUP_ITEM",         "GetItemTypeId(GetManipulatedItem())")
    //! runtextmacro SetupSpecialAllPlayersEvent("ItemDropped",      "UNIT_DROP_ITEM",           "GetItemTypeId(GetManipulatedItem())")
    //! runtextmacro SetupSpecialAllPlayersEvent("UnitDies",         "UNIT_DEATH",               "GetUnitTypeId(GetTriggerUnit())")
    //! runtextmacro SetupSpecialAllPlayersEvent("LearnsAbility",    "HERO_SKILL",               "GetLearnedSkill()")
    // Note to self: Remember to update the Init function.
    
    /////////////////////////////////////////
    // GTrigger All Players Implementation //
    ////////////////////////////////////////////////////////////////////////////
    // The textmacro implementation of other "All Players" events.
    //! textmacro SetupAllPlayersEvent takes NAME, EVENT
        globals
            private trigger $NAME$Trigger=CreateTrigger()
            private integer $NAME$ListPointer=0
        endglobals
        
        globals//locals
            private integer Register$NAME$Mem
        endglobals
        public function Register$NAME$Event takes trigger t returns trigger
            set Register$NAME$Mem=GetMem()
            set Trig[Register$NAME$Mem]=t
            call Link($NAME$ListPointer,Register$NAME$Mem)
            return t
        endfunction
        
        globals//locals
            private integer Unregister$NAME$Pointer
            private integer Unregister$NAME$Mem
        endglobals
        public function Unregister$NAME$Event takes trigger t returns trigger
            set Unregister$NAME$Mem=PointerTarget[$NAME$ListPointer]
            loop
                exitwhen Trig[Unregister$NAME$Mem]==t
                if Unregister$NAME$Mem==0 then
                    return t // Not found.
                endif
                set Unregister$NAME$Mem=Next[Unregister$NAME$Mem]
            endloop
            call Unlink($NAME$ListPointer,Unregister$NAME$Mem)
            call FreeMem(Unregister$NAME$Mem)
            return t
        endfunction
        
        private function Trigger$NAME$Event takes nothing returns boolean
            local integer Trigger$NAME$Mem=PointerTarget[$NAME$ListPointer]
            local integer Trigger$NAME$NextMem
            set UnregisterLastEvent=false
            loop
                exitwhen Trigger$NAME$Mem<1
                set Trigger$NAME$NextMem=Next[Trigger$NAME$Mem]
                if TriggerEvaluate(Trig[Trigger$NAME$Mem]) then
                    call TriggerExecute(Trig[Trigger$NAME$Mem])
                endif
                if UnregisterLastEvent then
                    set UnregisterLastEvent=false
                    call Unlink($NAME$ListPointer,Trigger$NAME$Mem)
                    call FreeMem(Trigger$NAME$Mem)
                endif
                set Trigger$NAME$Mem=Trigger$NAME$NextMem
            endloop
            return false
        endfunction
        
        private function Init$NAME$ takes nothing returns nothing
            local integer i=bj_MAX_PLAYER_SLOTS
            call TriggerAddCondition($NAME$Trigger,Condition(function Trigger$NAME$Event))
            loop
                set i=i-1
                call TriggerRegisterPlayerUnitEvent($NAME$Trigger,Player(i),EVENT_PLAYER_UNIT_$EVENT$,null)
                exitwhen i==0
            endloop
            // Initialise the pointer.
            set $NAME$ListPointer=GetPointer()
        endfunction
    //! endtextmacro
    
    // Old: //! runtextmacro SetupAllPlayersEvent("AnyUnitDies", "DEATH")
    
    private function Init takes nothing returns nothing
        // Ability events
        call InitStartsEffect()
        call InitBeginsChanelling()
        call InitBeginsCasting()
        call InitStopsCasting()
        call InitFinishesCasting()
        call InitLearnsAbility()
        // Order events
        call InitTargetOrder()
        call InitPointOrder()
        call InitNoTargetOrder()
        // Item events
        call InitItemUsed()
        call InitItemAcquired()
        call InitItemDropped()
        // Unit events
        call InitUnitDies()
    endfunction
    
    //////////////
    // Wrappers //
    ////////////////////////////////////////////////////////////////////////////
    // Wraps it up, for those who really want this interface.
    
    // General
    public function RemoveTriggeringAction takes nothing returns nothing
        call UnregisterTriggeringEvent()
        call DestroyTrigger(GetTriggeringTrigger())
    endfunction
    
    // Special All Player Events
    //! textmacro AddSpecialAllPlayersWrapper takes EVENT
        public function Add$EVENT$Action takes code func, integer special returns nothing
            call TriggerAddCondition(Register$EVENT$Event(CreateTrigger(),special),Condition(func))
        endfunction
    //! endtextmacro
    //! runtextmacro AddSpecialAllPlayersWrapper("StartsEffect")
    //! runtextmacro AddSpecialAllPlayersWrapper("BeginsChanelling")
    //! runtextmacro AddSpecialAllPlayersWrapper("BeginsCasting")
    //! runtextmacro AddSpecialAllPlayersWrapper("StopsCasting")
    //! runtextmacro AddSpecialAllPlayersWrapper("FinishesCasting")
    //! runtextmacro AddSpecialAllPlayersWrapper("TargetOrder")
    //! runtextmacro AddSpecialAllPlayersWrapper("PointOrder")
    //! runtextmacro AddSpecialAllPlayersWrapper("NoTargetOrder")
    //! runtextmacro AddSpecialAllPlayersWrapper("ItemUsed")
    //! runtextmacro AddSpecialAllPlayersWrapper("ItemAcquired")
    //! runtextmacro AddSpecialAllPlayersWrapper("ItemDropped")
    //! runtextmacro AddSpecialAllPlayersWrapper("UnitDies")
    //! runtextmacro AddSpecialAllPlayersWrapper("LearnsAbility")
    // Note to self: Remember to update the Init function.
    
    // All Player Events
    //! textmacro AddAllPlayersWrapper takes EVENT
        public function Add$EVENT$Action takes code func returns nothing
            call TriggerAddCondition(Register$EVENT$Event(CreateTrigger()),Condition(func))
        endfunction
    //! endtextmacro
    //// runtextmacro AddAllPlayersWrapper("UnitSell")
    // Old: //! runtextmacro AddAllPlayersWrapper("AnyUnitDies")
endlibrary//===========================================================================
// Trigger: MSGS
//===========================================================================
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library MSGS{define{c_goldbrown="daa520";c_gold="ffd700";c_palegreen="7aff7c";c_pink="db7093";c_pretty="ee82ee"
c_grassgreen="7fff00";c_brightgreen="00ff00";c_brightblue="0000ff";c_aqua="00ffff";c_white="f0ffff"
c_black="000000";c_seagreen="7fffd4";c_twilightblur="20b2aa";c_twilightgreen="009966"
c_coralgreen="00fa9a";c_coralpink="f08080";c_coralblue="33aaff";c_plum="ba55d3";c_indigo="4169e1"
c_flowerpurple="aaaaff";c_green="32cd32";c_blue="4169e1";c_yellowgreen="adff2f";c_brightpurple="ff00ff"
c_paledenim="c3dbff";c_orange="ffa500";c_purple="da70d6";c_royalpurple="aa00ff";c_flowerred="ee2222"                             
c_grey="c0c0c0";c_gray="c0c0c0";c_redorange="ff4500";c_red="ff0000";c_spanishgreen="9acd32"
c_darkspanishgreen="6b8e23";c_brown ="995500";c_yellow="ffff00";c_sand="ffffcc";private low=1;private high=5
}//if I2R(d.orb/2)==I2R(d.orb)/I2R(2) then

string gtc(string x, string y){return "|cff"+x+y+"|r"}//colors text
string msggetcolor(integer x, string y){if x==0 then;return gtc(c_red,y);elseif x==1 then
return gtc(c_brightblue,y);elseif x==2 then;return gtc(c_aqua,y);elseif x==3 then
return gtc(c_purple,y);elseif x==4 then;return gtc(c_yellow,y);elseif x==5 then
return gtc(c_orange,y);else;return gtc(c_white,y);endif;return y}//colors text based on player color
integer GetPlayerTeamMSGS(integer playerid){if playerid==0 then;return 1;elseif playerid==1 then
return 2;elseif playerid==3 then;return 1;elseif playerid>high then;return 3;endif;return 2}//player number for team number//customize as needed
nothing msgally(real x, player y, string z, boolean ally){integer a=GetPlayerId(y),b=GetPlayerTeamMSGS(a)
if ally then;a=low;whilenot(a++>high){if GetPlayerTeamMSGS(a)==b then;timedmsg(Player(a),0,0,x,z);endif}
else;a=low;whilenot(a++>high){if GetPlayerTeamMSGS(a)!=b then;timedmsg(Player(a),0,0,x,z);endif}endif}
nothing msgallyo(real x, player y, string z){integer a=GetPlayerId(y),b=GetPlayerTeamMSGS(a)
a=low;whilenot(a++>high){if GetPlayerTeamMSGS(a)==b then;timedmsg(Player(a),0,0,x,z);endif}}
nothing msgenemyno(real x, player y, string z){integer a=GetPlayerId(y),b=GetPlayerTeamMSGS(a)
a=low;whilenot(a++>high){if GetPlayerTeamMSGS(a)!=b then;timedmsg(Player(a),0,0,x,z);endif}}
nothing msgall(real dur, string s){integer i=low;whilenot (i++>high){timedmsg(Player(i),0,0,dur,s)}}//standard text
nothing msgone(real dur, player p, string s, boolean one){integer i=low,ip=GetPlayerId(p);if one then
timedmsg(p,0,0,dur,(s));else;whilenot(i++>high){if i!=ip then;timedmsg(Player(i),0,0,dur,s);endif}endif}}//===========================================================================
// Trigger: DebugS
//===========================================================================
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library DebugS uses MSGS
define{gdx=GetDestructableX;gdy=GetDestructableY;gux=GetUnitX;guy=GetUnitY;gix=GetItemX;giy=GetItemY
gtu=GetTriggerUnit()}
void gos(string order, integer orderid){msgall(5,order);msgall(5,I2S(orderid))}
string sxyi(item x){return R2S(gix(x))+","+R2S(giy(x))};string sxyu(unit x){return R2S(gux(x))+","+R2S(guy(x))}
string sxyd(destructable x){return R2S(gdx(x))+","+R2S(gdy(x))}
boolean cxyi(item x, real x1, real y1, real x2, real y2)
{if gix(x) > x1 and gix(x) < x2 and giy(x) > y1 and giy(x) < y2 then;return true;endif;return false}
boolean cxyu(unit x, real x1, real y1, real x2, real y2)
{if gux(x) > x1 and gux(x) < x2 and guy(x) > y1 and guy(x) < y2 then;return true;endif;return false}
boolean cxyd(destructable x, real x1, real y1, real x2, real y2)
{if gdx(x) > x1 and gdx(x) < x2 and gdy(x) > y1 and gdy(x) < y2 then;return true;endif;return false};endlibrary
scope GetOrderStringForUnit initializer I
define {feedgos=OrderId2String(GetIssuedOrderId()),GetIssuedOrderId()
unitgos=GetUnitTypeId(GetOrderedUnit());private UNITID='U004'}
private boolean f(){if unitgos==UNITID then;msgall(5,"target order:");gos(feedgos);endif;return false}
private boolean g(){if unitgos==UNITID then;msgall(5,"point order:");gos(feedgos);msgall(5,R2S(GetOrderPointX())+\
R2S(GetOrderPointY()));endif;return false}
private boolean h(){if unitgos==UNITID then;msgall(5,"order:");gos(feedgos);endif;return false}
private void I(){trigger t=CreateTrigger();TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER);TriggerAddCondition( t,Condition( function f));set t = CreateTrigger(  )
TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER );TriggerAddCondition( t,Condition( function g));set t = CreateTrigger(  )
TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ISSUED_ORDER );TriggerAddCondition( t,Condition( function h))}
endscope//===========================================================================
// Trigger: jBoard
//===========================================================================
//TESH.scrollpos=36
//TESH.alwaysfold=0
//==============================================================================
//  jBoard -- ADVANCED MULTIBOARD SYSTEM BY MAGENTIX -- v1.2
//==============================================================================

//==============================================================================
//  Quick manual:
//==============================================================================
//
//    Implement by adding "requires jBoardLib" behind your library/scope names
//
//    ----------------------------------------------------------------------
//      What is jBoard?
//    ----------------------------------------------------------------------
//
//      jBoard is an enhanced multiboard management system, inspired by the
//      jQuery library that is available to webdesigners. That javascript library
//      allows for a cool functionality called "chaining".
//
//      Because WC3 multiboards often require a huge amount of function calls,
//      I came up with jBoard to allow you to make your multiboard code shorter,
//      smoother and overall more easy to use.
//
//
//    ----------------------------------------------------------------------
//      What is chaining and how to use it?
//    ----------------------------------------------------------------------
//
//      An example says a thousand words, assume this is your 10x5 multiboard setup
//      and you want to set all fields to "0" and the first field to "1":
//
//      -  local multiboard MB = CreateMultiboard()
//         local multiboarditem MBI
//         call MultiboardSetTitleText(MB,"My Multiboard")
//         call MultiboardDisplay(MB,true)
//         call MultiboardSetRowCount(MB,10)
//         call MultiboardSetColumnCount(MB,5)
//         call MultiboardSetItemsValue(MB,"0")
//         call MultiboardSetItemsStyle(MB,true,false)
//         set MBI = MultiboardGetItem(MB,0,0)
//         call MultiboardSetItemValue(MBI,"1")
//
//      Now take a look at jBoard:
//      -  //! runtextmacro jBoardCreate("MyBoard","10","5")
//         local MyBoard MB = MyBoard.create("My Multiboard").field(0,0).setValue("1")
//      That's all you need to type!
//
//      Remember: the textmacro also only has to be called ONCE to create a
//      multiboard with the wanted dimensions. So actually that line wouldn't be
//      there, but at the top of your script.
//
//      Did you also notice how every method call returned an object that you
//      could then call another method on? That is the beauty of chaining.
//
//   !! EVERY FUNCTION CALL RETURNS A jBoard OBJECT UNLESS STATED OTHERWISE !!
//
//
//    ----------------------------------------------------------------------
//      I noticed a textmacro there, what gives?
//    ----------------------------------------------------------------------
//      
//      Since you need to create structs that represent your multiboard, jBoard
//      needs to know the dimensions of your multiboard to ensure the structs
//      don't take up more space than they need to.
//
//      For every multiboard variation you plan to use, simply call this once at
//      the top of your script:
//      //! runtextmacro jBoardCreate("StructName","RowAmount","ColAmount")
//
//      Example for an 8 row, 4 col board:
//      //! runtextmacro jBoardCreate("My8x4Board","8","4")
//      Which you can then instanciate in your script as
//      My8x4Board.create("BoardTitle")
//
//
//    ----------------------------------------------------------------------
//      Defaults
//    ----------------------------------------------------------------------
//      
//      Somtimes we don't want our board cells to be empty by default, but show
//      0 for example. This is easy to achieve by setting a default. Take a look
//      at the jBoard struct further down this info block and edit the defaults
//      you like to see changed. Every jBoard that gets created after a change
//      will take those defaults into account.
//
//      Note that you can hardcode defaults below and still change them on the fly!
//      set jBoard.defaultItemValue = "1" -- Valid syntax!
//
//      Edit your defaults here:
//ReplaceableTextures\CommandButtons\BTNUndeadShrine.blp
//ReplaceableTextures\CommandButtons\BTNReplay-Speedup.blp
//ReplaceableTextures\CommandButtons\BTNReplay-Speeddown.blp
//ReplaceableTextures\CommandButtons\BTNReplay-Loop.blp
//ReplaceableTextures\CommandButtons\BTNReplay-Pause.blp
//ReplaceableTextures\CommandButtons\BTNReplay-Play.blp
//! textmacro jBoardDefaults
        static string  defaultItemValue = "/"
        static string  defaultIconPath  = "war3mapImported\\sankaku.blp"
        static boolean defaultShowValue = true
        static boolean defaultShowIcon  = true
        static boolean defaultShowBoard = true
        static real    defaultItemWidth = 0.03
//! endtextmacro
//
//==============================================================================

//==============================================================================
//  Tip: Commenting out newlines
//==============================================================================
//
//  Sometimes when chaining methods, a command can get quite lengthy. jQuery
//  doesn't suffer from this visually, because javascript allows people to write
//  code over multiple lines until they end it with a semicolon (;)
//
//  JASS, however, doesn't allow that directly. Fortunately you can call jBoard
//  commands just as easily on multiple lines. Remember: Until you call .reset(),
//  your selection will be saved to the next line!
//
//  Example:
//  local MyBoard MB = MyBoard.create("funkyboard").setplayerrow(0,2).setcolour("ff0000").reset().setplayerrow(1,3).setcolour("0000ff").reset().etc...
//
//  Could become:
//      local MyBoard MB = MyBoard.create("funkyboard")
//      call MB.setplayerrow(0,2).setcolour("ff0000").reset()
//      call MB.setplayerrow(1,3)
//      call MB.setcolour("0000ff").reset() <-- Previous row selection was saved to this line
//
//  In the end it all boils down to which type of coding you prefer, of course.
//
//==============================================================================

//==============================================================================
//  Tip: -R Functions
//==============================================================================
//
//  When chaining several commands onto a set of fields, one could easily say:
//  "There, now let me reset my selection and continue chaining methods"
//
//  However, when chaining that way, a string of jBoard commands could easily
//  contain the call .reset() a dozen times.
//
//  To save coding space and safeguard readability, I introduced the -R functions:
//  Basically, any non-selector function that returns a jBoard object can be called
//  with a capital "R" behind the name and the jBoard system will automatically
//  call a .reset() for you.
//
//  The above example of commenting out newlines would then become:
//  local MyBoard MB = MyBoard.create("funkyboard").setPlayerRow(0,2).setColourR("ff0000").setPlayerRow(1,3).setColourR("0000ff").etc...
//
//  As you can see, this makes the chaining process yet again a little smoother
//  Once again: this functionality does not work on selectors/"getters"!
//
//==============================================================================

//==============================================================================
//  Function index:
//==============================================================================
//
//    ----------------------------------------------------------------------
//      Standard Functions - Creating, showing, etc...
//    ----------------------------------------------------------------------
//
//      Main functionality you'd expect from any multiboard. May be used within
//      a local player block. Can be used on any jBoard object (boad, row, col,
//      field(s)) and returns the selection you called the function on.
//
//    .create("MultiboardName")
//    .show()
//    .hide()
//    .clear() -- SHOULD NEVER BE CALLED, just here for completion
//    .fold()
//    .unfold()
//    .setName()
//    .getName() -- Returns the multiboard name as a string, not a jBoard object
//    .setNameColour("rgb value")
//      Colour syntax: rrggbb (in hexadecimal)
//    .getNameColour()
//    .destroy()
//
//
//    ----------------------------------------------------------------------
//      Selection Functions - Adds rows, cols or fields to the selection
//    ----------------------------------------------------------------------
//
//      Selectors can be used on any jBoard object (boad, row, col, field(s))
//      They always return the collection of all the objects you selected from
//      the last .reset() up to that point.
//
//    VERY IMPORTANT!
//    .reset()
//      Resets the current selection to the board
//
//    MAIN SELECTORS
//    .row(integer start, integer end)
//    .col(integer start, integer end)
//      Selects a row, a columns or multiple of any
//      -  .row(0,0) returns the row object of row 0
//      -  .row(0,1) returns the combined fields of row 0 and row 1
//      -  ONLY WHEN HAVING -ONE- ROW/COL SELECTED will you be able
//         to use row/col only functionality
//         (it won't give errors or bugs if you try, though)
//
//    SINGLE SELECTOR
//    .field(integer row, integer col)
//      Adds one field to the selection or (if selection is empty)
//      returns one field to use field-level manipulations on
//    .getPlayerRowField(integer player, integer column)
//    .getPlayerColField(integer player, integer row)
//      The above two return just ONE field of a player's row.
//      Since the player selectors return an entire row and a deep
//      selector inside that row would clear the selection first,
//      it would otherwise be impossible to select multiple fields
//      from player rows or columns...
//      You should use this over .getPlayerRow(0).getField(3) unless
//      you want only that field of course.
//
//    DEEP SELECTOR
//    .getField(integer which)
//      Returns just ONE field, selected from your previous selection
//      
//      Quick list of what it does when used on a:
//      -  Board:  Returns the field in position X of the board,
//                 reading from top left to bottom right
//      -  Row:    Returns the field in column X of that row
//      -  Column: Returns the field in row X of that column
//      -  Fields: Returns the field in position X of the selection,
//                 reading from top left to bottom right
//      -  Field:  Does nothing (returns same field)
//
//
//    ----------------------------------------------------------------------
//      Player Selectors
//    ----------------------------------------------------------------------
//
//      Simple functions that allow you to save a row/col to a player.
//
//      Both the setters and the getters add the row/col you just set
//      to the current selection. Hence, this is both valid syntax:
//      -  MB.setPlayerRow(0,1).setcolour("ff0000")
//      -  MB.setPlayerRow(0,1)
//         MB.getPlayerRow(0,1).setcolour("ff0000")
// 
//      The player "setters" have -R functionality, but the "getters" don't!
//      
//    .setPlayerRow(integer player, integer row)
//    .setPlayerCol(integer player, integer col)
//    .getPlayerRow(integer player)
//    .getPlayerCol(integer player)
//
//
//    ----------------------------------------------------------------------
//      Manipulation Functions - Also referred to as "setters"
//    ----------------------------------------------------------------------
//
//      Setters can be used on any jBoard object (boad, row, col, field(s))
//      They always return the object that was just manipulated
//
//      ABOUT PREFIXES AND SUFFIXES:
//      Imagine you want a row with user experience values, by setting a suffix
//      "XP", you could still use .add(value) to a field, because the content
//      can still be handled by S2I(). Example:
//      -  .field(1,2) has content "2" and suffix " xp", the field shows "2 xp"
//         A user calls .field(1,2).add(4), the field now show "6 xp", without
//         having to worry about the " xp" bit!
//
//    VALUE SETTERS
//    .setValue("value")
//    .setColour("rgb value")
//      Colour syntax: rrggbb (in hexadecimal)
//    .setPrefix("value")
//    .setSuffix("value")
//    .setIconPath("path")
//    .setWidth(real width)
//
//    VALUE MANIPULATORS
//    .add(integer value)
//      Only works if field contents are numerical strings, value can be negative
//
//
//    ----------------------------------------------------------------------
//      Retrieval Functions - Also referred to as "getters"
//    ----------------------------------------------------------------------
//
//      Getters can be used on any jBoard object (boad, row, col, field(s))
//                      !! EVERY GETTER RETURNS A STRING !!
//
//      HERE'S WHY:
//      When using a getter on anything but a single field, a string is returned
//      with all values in it, separated by a pipe (|).
//      Future versions may support smart retrieval of a row's/col's properties
//      should they all have the same colour for example...
//
//      Naturally, the fact that these methods return a string instead of a
//      jBoard object means that calling any of these methods is in fact
//      "The end of the line" for that chaining process...
//
//    .getValue()
//    .getColour()
//    .getPrefix()
//    .getSuffix()
//    .getIconPath() -- CAREFUL USE on many fields! (might blow up in your face)
//    .getWidth()
//
//
//    ----------------------------------------------------------------------
//      Extra Functions - Various
//    ----------------------------------------------------------------------
//
//    .showIcon()
//    .hideIcon()
//    .showValue()
//    .hideValue()
//
//==============================================================================

//==============================================================================
//  Credits:
//==============================================================================
//
//  John Resig for coming up with jQuery and its chaining
//  Vexorian for vJass and JassHelper, making jBoard possible
//
//==============================================================================

//==============================================================================
//  Open letter to Vexorian:
//==============================================================================
//
//  Take a look at the setter/getter methods and the -R functions. If that isn't
//  a reason why textmacroes should be allowed to be nested, I don't know what
//  is :x (They're all the same bar the function name...)
//
//  Protip: Yes, this is a request to you to get nested textmacroes working :)
//
//==============================================================================

//==============================================================================
//  Macro function core -- No touchy from here on out!
//==============================================================================

//! textmacro jBoardCreate takes NAME, ROWS, COLS
globals
private constant integer $NAME$SIZE = $ROWS$*$COLS$
private constant integer $NAME$ROWS = $ROWS$
private constant integer $NAME$COLS = $COLS$
endglobals

private struct $NAME$FIELD
$NAME$ parent
integer realRow
integer realCol
multiboarditem mbi

real   width= jBoard.defaultItemWidth
string iconpath = jBoard.defaultIconPath
string colour   = "ffffff"
string prefix   = ""
string content  = jBoard.defaultItemValue
string suffix   = ""

boolean showV   = jBoard.defaultShowValue
boolean showI   = jBoard.defaultShowIcon

static method create takes $NAME$ parent, integer row, integer col returns thistype
local thistype f = thistype.allocate()
set f.parent = parent
set f.realRow = row
set f.realCol = col
set f.mbi = MultiboardGetItem(f.parent.MB,f.realRow,f.realCol)

return f
endmethod

method onDestroy takes nothing returns nothing
call MultiboardReleaseItem(.mbi)
endmethod

private method updateField takes nothing returns nothing
call MultiboardSetItemValue(.mbi,"|cff"+.colour+.prefix+.content+.suffix+"|r")
endmethod

method add takes integer i returns nothing
set .content = I2S(S2I(.content) + i)
call .updateField()
endmethod

method setValue takes string s returns nothing
set .content = s
call .updateField()
endmethod

method setPrefix takes string s returns nothing
set .prefix = s
call .updateField()
endmethod

method setSuffix takes string s returns nothing
set .suffix = s
call .updateField()
endmethod

method setColour takes string rgb returns nothing
set .colour = rgb
call .updateField()
endmethod

method setWidth takes real w returns nothing
set .width = w
call MultiboardSetItemWidth(.mbi,w)
endmethod

method showIcon takes nothing returns nothing
set .showI = true
call MultiboardSetItemStyle(.mbi,.showV,.showI)
endmethod

method hideIcon takes nothing returns nothing
set .showI = false
call MultiboardSetItemStyle(.mbi,.showV,.showI)
endmethod

method showValue takes nothing returns nothing
set .showV = true
call MultiboardSetItemStyle(.mbi,.showV,.showI)
endmethod

method hideValue takes nothing returns nothing
set .showV = false
call MultiboardSetItemStyle(.mbi,.showV,.showI)
endmethod

method setIconPath takes string s returns nothing
set .iconpath = s
call MultiboardSetItemIcon(.mbi,.iconpath)
endmethod

method getValue takes nothing returns string
return .content
endmethod

method getPrefix takes nothing returns string
return .prefix
endmethod

method getSuffix takes nothing returns string
return .suffix
endmethod

method getColour takes nothing returns string
return .colour
endmethod

method getWidth takes nothing returns string
return R2S(.width)
endmethod

method getIconPath takes nothing returns string
return .iconpath
endmethod
endstruct

private interface $NAME$FIELDCOLLECTION
$NAME$ parent
method getField takes integer i returns $NAME$FIELD
endinterface

private struct $NAME$UTILITY extends $NAME$FIELDCOLLECTION
stub method getField takes integer i returns $NAME$FIELD
return 0
endmethod
endstruct

private struct $NAME$ROW extends $NAME$UTILITY
$NAME$FIELD array fields[$COLS$]
integer realPos
integer fromPlayer = -1

static method create takes $NAME$ parent, integer pos returns thistype
local thistype row = thistype.allocate()
local integer i = 0
set row.parent = parent
set row.realPos = pos

loop
exitwhen i == $NAME$COLS
set row.fields[i] = $NAME$FIELD.create(parent,pos,i)
set i = i + 1
endloop

return row
endmethod

method getField takes integer i returns $NAME$FIELD
return .fields[i]
endmethod
endstruct

private struct $NAME$COL extends $NAME$UTILITY
$NAME$FIELD array fields[$ROWS$]
integer realPos
integer fromPlayer = -1

static method create takes $NAME$ parent, integer pos returns thistype
local thistype col = thistype.allocate()
local integer i = 0
set col.parent = parent
set col.realPos = pos

loop
exitwhen i == $NAME$ROWS
set col.fields[i] = col.parent.rows[i].fields[pos]
set i = i + 1
endloop

return col
endmethod

method getField takes integer i returns $NAME$FIELD
return .fields[i]
endmethod
endstruct

private struct $NAME$FLD extends $NAME$UTILITY
$NAME$FIELD array fields[$NAME$SIZE]

static method create takes $NAME$ parent returns thistype
local thistype fld = thistype.allocate()
set fld.parent = parent
return fld
endmethod

private method hasField takes $NAME$FIELD f returns boolean
local integer i = 0

loop
exitwhen i == .parent.selectionAmount
if (.fields[i] == f) then
return true
endif
set i = i + 1
endloop

return false
endmethod

method addFields takes $NAME$FIELDCOLLECTION f, integer amount returns nothing
local integer i = 0

loop
exitwhen i == amount
if not(.hasField(f.getField(i))) then
set .fields[.parent.selectionAmount] = f.getField(i)
set .parent.selectionAmount = .parent.selectionAmount + 1
endif

set i = i + 1
endloop
endmethod

method getField takes integer i returns $NAME$FIELD
return .fields[i]
endmethod
endstruct

struct $NAME$ extends jBoard
$NAME$ROW array rows[$ROWS$]
$NAME$COL array cols[$COLS$]
$NAME$FLD selection

static method create takes string boardName returns thistype
local thistype board = thistype.allocate(boardName)
local integer i = 0

call MultiboardSetRowCount(board.MB,$NAME$ROWS)
call MultiboardSetColumnCount(board.MB,$NAME$COLS)

set board.selection = $NAME$FLD.create(board)
loop
exitwhen i == $NAME$ROWS
set board.rows[i] = $NAME$ROW.create(board,i)
set i = i + 1
endloop
set i = 0
loop
exitwhen i == $NAME$COLS
set board.cols[i] = $NAME$COL.create(board,i)
set i = i + 1
endloop

call board.initBoard()
return board
endmethod

private method transfer takes $NAME$FIELDCOLLECTION f, integer ftype, integer amount returns nothing
set .selectionLevel = IntegerTertiaryOp(.selectionLevel == jBoard_SELECTION_LVL_BOARD,ftype,jBoard_SELECTION_LVL_FIELDS)
call .selection.addFields(f,amount)
endmethod

method reset takes nothing returns thistype
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
set .selectionAmount = 0
return this
endmethod

method field takes integer row, integer col returns thistype
set .selection.fields[0] = .rows[row].fields[col]
set .selectionLevel = jBoard_SELECTION_LVL_FLD
return this
endmethod

method getField takes integer which returns thistype
if .selectionLevel == jBoard_SELECTION_LVL_ROW then
set .selection.fields[0] = .rows[.selectionSpecial].fields[which]
elseif .selectionLevel == jBoard_SELECTION_LVL_COL then
set .selection.fields[0] = .cols[.selectionSpecial].fields[which]
elseif .selectionLevel == jBoard_SELECTION_LVL_FIELDS then
set .selection.fields[0] = .selection.fields[which]
elseif .selectionLevel == jBoard_SELECTION_LVL_BOARD then
set .selection.fields[0] = .rows[which/$NAME$COLS].fields[ModuloInteger(which,$NAME$COLS)]
endif

set .selectionLevel = jBoard_SELECTION_LVL_FLD
return this
endmethod

method row takes integer start, integer end returns thistype
local integer i = IntegerTertiaryOp(start<end,start,end)
local integer j = IntegerTertiaryOp(start<end,end,start)

if start == end then
set .selectionSpecial = start
call .transfer(.rows[start],jBoard_SELECTION_LVL_ROW,$NAME$COLS)
else
loop
exitwhen i > j
call .transfer(.rows[i],jBoard_SELECTION_LVL_ROW,$NAME$COLS)
set i = i + 1
endloop
endif

return this
endmethod

method col takes integer start, integer end returns thistype
local integer i = IntegerTertiaryOp(start<end,start,end)
local integer j = IntegerTertiaryOp(start<end,end,start)

if start == end then
set .selectionSpecial = start
call .transfer(.cols[start],jBoard_SELECTION_LVL_COL,$NAME$ROWS)
else
loop
exitwhen i > j
call .transfer(.cols[i],jBoard_SELECTION_LVL_COL,$NAME$ROWS)
set i = i + 1
endloop
endif

return this
endmethod

method setPlayerRow takes integer p, integer row returns thistype
set .playerRow = row
set .rows[row].fromPlayer = p
return .row(row,row)
endmethod

method getPlayerRow takes integer p returns thistype
return .row(.playerRow,.playerRow)
endmethod

method getPlayerRowField takes integer p, integer i returns thistype
return .field(.playerRow,i)
endmethod

method setPlayerCol takes integer p, integer col returns thistype
set .playerCol = col
set .cols[col].fromPlayer = p
return .col(col,col)
endmethod

method getPlayerCol takes integer p returns thistype
return .col(.playerCol,.playerCol)
endmethod

method getPlayerColField takes integer p, integer i returns thistype
return .field(i,.playerCol)
endmethod

method setColour takes string rgb returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).setColour(rgb)
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].setColour(rgb)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].setColour(rgb)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].setColour(rgb)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].setColour(rgb)
endif

return this
endmethod

method setWidth takes real w returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).setWidth(w)
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].setWidth(w)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].setWidth(w)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].setWidth(w)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].setWidth(w)
endif

return this
endmethod

method setPrefix takes string val returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).setPrefix(val)
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].setPrefix(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].setPrefix(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].setPrefix(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].setPrefix(val)
endif

return this
endmethod

method setSuffix takes string val returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).setSuffix(val)
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].setSuffix(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].setSuffix(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].setSuffix(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].setSuffix(val)
endif

return this
endmethod

method setIconPath takes string val returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).setIconPath(val)
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].setIconPath(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].setIconPath(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].setIconPath(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].setIconPath(val)
endif

return this
endmethod

method showIcon takes nothing returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).showIcon()
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].showIcon()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].showIcon()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].showIcon()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].showIcon()
endif

return this
endmethod

method hideIcon takes nothing returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).hideIcon()
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].hideIcon()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].hideIcon()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].hideIcon()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].hideIcon()
endif

return this
endmethod

method showValue takes nothing returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).showValue()
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].showValue()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].showValue()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].showValue()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].showValue()
endif

return this
endmethod

method hideValue takes nothing returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).hideValue()
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].hideValue()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].hideValue()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].hideValue()
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].hideValue()
endif

return this
endmethod

method setValue takes string val returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).setValue(val)
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].setValue(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].setValue(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].setValue(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].setValue(val)
endif

return this
endmethod

method add takes integer val returns thistype
local integer i = 0
  
if (.selectionLevel == jBoard_SELECTION_LVL_BOARD) then
loop
exitwhen i == $NAME$ROWS
call .reset().row(i,i).add(val)
set i = i + 1
endloop
set .selectionLevel = jBoard_SELECTION_LVL_BOARD
elseif (.selectionLevel == jBoard_SELECTION_LVL_FIELDS) then
loop
exitwhen i == .selectionAmount
call .selection.fields[i].add(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_ROW) then
loop
exitwhen i == $NAME$COLS
call .rows[.selectionSpecial].fields[i].add(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_COL) then
loop
exitwhen i == $NAME$ROWS
call .cols[.selectionSpecial].fields[i].add(val)
set i = i + 1
endloop
elseif (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
call .selection.fields[0].add(val)
endif

return this
endmethod

method getValue takes nothing returns string
local integer i = 0
local string s = ""

if (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
set s = .selection.fields[0].getValue()
else
loop
exitwhen i == .selectionAmount
set s = s + .selection.fields[i].getValue()
set i = i + 1
exitwhen i == .selectionAmount
set s = s + "|"
endloop
endif

call .reset()
return s
endmethod

method getPrefix takes nothing returns string
local integer i = 0
local string s = ""

if (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
set s = .selection.fields[0].getPrefix()
else
loop
exitwhen i == .selectionAmount
set s = s + .selection.fields[i].getPrefix()
set i = i + 1
exitwhen i == .selectionAmount
set s = s + "|"
endloop
endif

call .reset()
return s
endmethod

method getSuffix takes nothing returns string
local integer i = 0
local string s = ""

if (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
set s = .selection.fields[0].getSuffix()
else
loop
exitwhen i == .selectionAmount
set s = s + .selection.fields[i].getSuffix()
set i = i + 1
exitwhen i == .selectionAmount
set s = s + "|"
endloop
endif

call .reset()
return s
endmethod

method getWidth takes nothing returns string
local integer i = 0
local string s = ""

if (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
set s = .selection.fields[0].getWidth()
else
loop
exitwhen i == .selectionAmount
set s = s + .selection.fields[i].getWidth()
set i = i + 1
exitwhen i == .selectionAmount
set s = s + "|"
endloop
endif

call .reset()
return s
endmethod

method getColour takes nothing returns string
local integer i = 0
local string s = ""

if (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
set s = .selection.fields[0].getColour()
else
loop
exitwhen i == .selectionAmount
set s = s + .selection.fields[i].getColour()
set i = i + 1
exitwhen i == .selectionAmount
set s = s + "|"
endloop
endif

call .reset()
return s
endmethod

method getIconPath takes nothing returns string
local integer i = 0
local string s = ""

if (.selectionLevel == jBoard_SELECTION_LVL_FLD) then
set s = .selection.fields[0].getIconPath()
else
loop
exitwhen i == .selectionAmount
set s = s + .selection.fields[i].getIconPath()
set i = i + 1
exitwhen i == .selectionAmount
set s = s + "|"
endloop
endif

call .reset()
return s
endmethod

method setName takes string s returns thistype
set .boardName = s
call MultiboardSetTitleText(.MB,"|cff"+.boardNameColour+.boardName+"|r")
return this
endmethod

method getName takes nothing returns string
call .reset()
return .boardName
endmethod

method setNameColour takes string s returns thistype
set .boardNameColour = s
call MultiboardSetTitleText(.MB,"|cff"+.boardNameColour+.boardName+"|r")
return this
endmethod

method getNameColour takes nothing returns string
call .reset()
return .boardNameColour
endmethod

method show takes nothing returns thistype
call MultiboardDisplay(.MB,true)
return this
endmethod

method hide takes nothing returns thistype
call MultiboardDisplay(.MB,false)
return this
endmethod

method clear takes nothing returns thistype
call MultiboardClear(.MB)
return this
endmethod

method fold takes nothing returns thistype
call MultiboardMinimize(.MB,true)
return this
endmethod

method unfold takes nothing returns thistype
call MultiboardMinimize(.MB,false)
return this
endmethod

method setValueR takes string val returns thistype
call .setValue(val)
call .reset()
return this
endmethod

method setColourR takes string rgb returns thistype
call .setColour(rgb)
call .reset()
return this
endmethod

method setPrefixR takes string val returns thistype
call .setPrefix(val)
call .reset()
return this
endmethod

method setSuffixR takes string val returns thistype
call .setSuffix(val)
call .reset()
return this
endmethod

method setIconPathR takes string val returns thistype
call .setIconPath(val)
call .reset()
return this
endmethod

method setWidthR takes real w returns thistype
call .setWidth(w)
call .reset()
return this
endmethod

method addR takes integer val returns thistype
call .add(val)
call .reset()
return this
endmethod

method setPlayerRowR takes integer p, integer col returns thistype
call .setPlayerRow(p,row)
call .reset()
return this
endmethod

method setPlayerColR takes integer p, integer col returns thistype
call .setPlayerCol(p,col)
call .reset()
return this
endmethod

method setNameR takes string s returns thistype
call .setName(s)
call .reset()
return this
endmethod

method setNameColourR takes string s returns thistype
call .setNameColour(s)
call .reset()
return this
endmethod

method showR takes nothing returns thistype
call .show()
call .reset()
return this
endmethod

method showIconR takes nothing returns thistype
call .showIcon()
call .reset()
return this
endmethod

method hideIconR takes nothing returns thistype
call .hideIcon()
call .reset()
return this
endmethod

method showValueR takes nothing returns thistype
call .showValue()
call .reset()
return this
endmethod

method hideValueR takes nothing returns thistype
call .hideValue()
call .reset()
return this
endmethod

method hideR takes nothing returns thistype
call .hide()
call .reset()
return this
endmethod

method clearR takes nothing returns thistype
call .clear()
call .reset()
return this
endmethod

method foldR takes nothing returns thistype
call .fold()
call .reset()
return this
endmethod

method unfoldR takes nothing returns thistype
call .unfold()
call .reset()
return this
endmethod

method destroy takes nothing returns nothing
local integer i = 0
local integer j = 0

loop
exitwhen i == $NAME$ROWS
loop
exitwhen j == $NAME$COLS
call rows[i].fields[j].destroy()
set j = j + 1
endloop

set i = i + 1
endloop

call DestroyMultiboard(.MB)
call .deallocate()
endmethod
endstruct
//! endtextmacro

/*method setItemIcon takes integer column, integer row, string iconFileName returns nothing
//Works similar to the MultiboardSetItem* functions.
//However, a value of 0 refers to the first column/row, -1 refers to all columns/rows
//Using a Column or Row higher than the current max will result in the function not doing anything.
local integer curCol = 0
local integer curRow = 0
if column > .columnCount or row > .rowCount then
return
endif
if column == -1 or row == -1 then
if column == -1 and row == -1 then
call MultiboardSetItemsIcon(.which,iconFileName)
return
elseif column == -1 then
loop
exitwhen curCol > .columnCount
call MultiboardSetItemIcon(.MBIZ[curCol * MAX_ROW_COUNT + row],iconFileName)
set curCol = curCol + 1
endloop
return
else
loop
exitwhen curRow > .rowCount
call MultiboardSetItemIcon(.MBIZ[column * MAX_ROW_COUNT + curRow],iconFileName)
set curRow = curRow + 1
endloop
return
endif
endif
call MultiboardSetItemIcon(.MBIZ[column * MAX_ROW_COUNT + row],iconFileName)
endmethod*/

//==============================================================================
//  ACTUAL LIBRARY
//==============================================================================
library jBoardLib
globals
constant integer jBoard_SELECTION_LVL_BOARD = 0
constant integer jBoard_SELECTION_LVL_ROW = 1
constant integer jBoard_SELECTION_LVL_COL = 2
constant integer jBoard_SELECTION_LVL_FLD = 3
constant integer jBoard_SELECTION_LVL_FIELDS = 4
endglobals
struct jBoard
//! runtextmacro jBoardDefaults()
multiboard MB
string boardName
string boardNameColour = "ffffcc"
integer selectionLevel = 0
integer selectionSpecial = 0
integer selectionAmount = 0
integer array playerRow[12]
integer array playerCol[12]
static method create takes string boardName returns jBoard
local integer i = 0
set jB = thistype.allocate()
set  jB.MB = CreateMultiboard()
set  jB.boardName = boardName
call MultiboardSetTitleText(jB.MB,boardName)
call MultiboardDisplay(jB.MB,false)
return jB
endmethod
method initBoard takes nothing returns nothing
call MultiboardSetItemsValue(.MB,.defaultItemValue)
call MultiboardSetItemsIcon(.MB,defaultIconPath)
call MultiboardSetItemsStyle(.MB,.defaultShowValue,.defaultShowIcon)
call MultiboardSetItemsWidth(.MB,.defaultItemWidth)
call MultiboardDisplay(.MB,.defaultShowBoard)
endmethod
endstruct
endlibrary
//==============================================================================
//  END OF jBoard ADVANCED MULTIBOARD SYSTEM
//==============================================================================//===========================================================================
// Trigger: STM
//===========================================================================
//TESH.scrollpos=31
//TESH.alwaysfold=0
//SLARK, THE MURLOC
//==By SanKakU
//==               
//==Don't bother looking in the quests section for credits because you won't see them there.
//==Just find what you want here in the Trigger editor.  It's all here.
library STM uses MSGS
define CREDITSFORSTM={
ICONS
kola
MODELS
republicola
SKINS
chr2
sankaku
}
define {timedmsg=DisplayTimedTextToPlayer;void=nothing
getitemGT(x, y) = {GT_AddItemAcquiredAction(function x, y)}
targetorderGT(x,y) = {GT_AddTargetOrderAction(function x, y)}
pointorderGT(x,y) = {GT_AddPointOrderAction(function x, y)}
iorderGT(x,y) = {GT_AddNoTargetOrderAction(function x, y)}
unitdiesGT(x, y) = {GT_AddUnitDiesAction(function x, y)}
effectstartGT(x, y) = {GT_AddStartsEffectAction(function x, y)}
skillGT(x, y) = {GT_AddLearnsAbilityAction(function x, y)}
STM_PUE(x,y)={TriggerRegisterPlayerUnitEvent(x,Player(6),y,null)}
}
define iconTIME="UI\\Widgets\\BattleNet\\bnet-tournament-clock.blp"


globals
endglobals
//== snippet by Jesus4Lyf
function SetDistanceToUnit takes unit y, unit x, real dist returns nothing
local real rx=GetUnitX(x)-GetUnitX(y)
local real ry=GetUnitY(x)-GetUnitY(y)
local real factor=dist/SquareRoot(rx*rx+ry*ry)
call SetUnitX(x,GetUnitX(y)+rx*factor)
call SetUnitY(x,GetUnitY(y)+ry*factor)
endfunction
function SetDistanceToXY takes real rx, real ry, unit x, real dist returns nothing
local real tx=GetUnitX(x)-rx
local real ty=GetUnitY(x)-ry
local real factor=dist/SquareRoot(tx*tx+ty*ty)
call SetUnitX(x,rx+tx*factor)
call SetUnitY(x,ry+ty*factor)
endfunction
//extension to snippet.
function getdis takes unit x, unit y returns real
local real dx = GetUnitX(x) - GetUnitX(y)
local real dy = GetUnitY(x) - GetUnitY(y)
return SquareRoot(dx * dx + dy * dy)
endfunction
function getdisr takes real x, real y, unit z returns real
local real dx = x - GetUnitX(z)
local real dy = y - GetUnitY(z)
return SquareRoot(dx * dx + dy * dy)
endfunction
//==end of extension to snippet

function GetHeroSlotMultiboard takes integer heroid, integer playerid returns integer
return heroid+((playerid - 2)*3)
endfunction
//
public function MID takes integer a, integer b, integer c, real x, real y, itempool p returns nothing
call ItemPoolAddItemType(p,a,6)//monster common itemdrop
call ItemPoolAddItemType(p,b,3)//monster uncommon itemdrop
call ItemPoolAddItemType(p,c,1)//monster rare itemdrop
call PlaceRandomItem(p,x,y)
endfunction
//not sure if i'm going to end up using this function, but i used to use it so...here it is
public function IUTNI takes unit u, unittype ut returns boolean
return IsUnitType(u, ut) and IsUnitIllusion(u)==false
endfunction
//this is an interesting function, i need to write more like this
public function IUIDNI takes unit u, integer uid returns boolean
return GetUnitTypeId(u)==uid and IsUnitIllusion(u)==false
endfunction

endlibrary
//===========================================================================
// Trigger: TimerEvents
//===========================================================================
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope TimerEvents initializer I
globals
private boolean debugmode=true
endglobals

private function mbtime  takes nothing returns boolean
call ConditionalTriggerExecute( gg_trg_mbSTM )
call SetPlayerState(Player(6), PLAYER_STATE_RESOURCE_GOLD, 1)
return false
endfunction
private function mbtimeaddsec takes nothing returns boolean
local integer x=S2I(jBoard_STM.field(0,1).getSuffix())+1
if x==60 then
call jBoard_STM.field(0,1).setSuffix("0")
set x=S2I(jBoard_STM.field(0,1).getPrefix())+1
if x==60 then
call jBoard_STM.field(0,1).setPrefix("0")
return false
endif
call jBoard_STM.field(0,1).setPrefix(I2S(x))
return false
endif
call jBoard_STM.field(0,1).setSuffix(I2S(x))
return false
endfunction

globals
group TIMERGROUP=CreateGroup()
endglobals
private function ru0 takes nothing returns boolean
if GetUnitAbilityLevel(GetFilterUnit(), 'A0C3')>1 then
call IssuePointOrder(GetFilterUnit(), "attack", 3000.0,3000.0 )
endif
return false
endfunction
private function ru1 takes nothing returns boolean
if GetUnitAbilityLevel(GetFilterUnit(), 'A0C3')>1 then
call IssuePointOrder(GetFilterUnit(), "attack", -3000.0,-3000.0 )
endif
return false
endfunction
private function removeall takes nothing returns nothing
call GroupEnumUnitsOfPlayer(TIMERGROUP, Player(0), Filter(function ru0))
call GroupEnumUnitsOfPlayer(TIMERGROUP, Player(1), Filter(function ru1))
endfunction
private function fbf takes nothing returns boolean
call removeall()
return false
endfunction//
public function I takes nothing returns nothing
local trigger t = CreateTrigger(  )
call TriggerRegisterTimerEvent( t, 1.0 ,false)
call TriggerAddCondition( t,Condition( function mbtime ))
set t= CreateTrigger()
call TriggerRegisterTimerEvent( t, 1.0 ,true)
call TriggerAddCondition( t,Condition( function mbtimeaddsec ))
endfunction
endscope//===========================================================================
// Trigger: mbSTM
//===========================================================================
//TESH.scrollpos=0
//TESH.alwaysfold=0
library mbSTM initializer Init requires jBoardLib
globals
MyBoard jBoard_STM
jBoard jB
endglobals
//! runtextmacro jBoardCreate("MyBoard","1","2")
private function Actions takes nothing returns nothing
set jBoard_STM = MyBoard.create(".")
call jBoard_STM.col(0,0).hideIconR().field(0,0).hideValue().showIcon().setIconPathR(iconTIME)
call jBoard_STM.field(0,1).hideIcon().setPrefix("0").setSuffix("0").setValueR(":")
endfunction
public function Init takes nothing returns nothing
set gg_trg_mbSTM =CreateTrigger()
call TriggerAddAction(gg_trg_mbSTM,function Actions)
endfunction
endlibrary//===========================================================================
// Trigger: TimerUtils
//===========================================================================
//TESH.scrollpos=56
//TESH.alwaysfold=0
library_once TimerUtils initializer init
//*********************************************************************
//* TimerUtils (Blue flavor for 1.23b or later) 
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Blue Flavor: Slower than the red flavor, it got a 408000 handle id
//*             limit, which means that if more than 408000 handle ids
//*             are used in your map, TimerUtils might fail, this
//*             value is quite big and it is much bigger than the 
//*             timer limit in Red flavor.
//*
//********************************************************************

    //==================================================================================================
    globals
        private hashtable hasht //I <3 blizz
    endglobals

    //It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
    function SetTimerData takes timer t, integer value returns nothing
        call SaveInteger(hasht,0, GetHandleId(t), value)
    endfunction

    function GetTimerData takes timer t returns integer
        return LoadInteger(hasht, 0, GetHandleId(t))
    endfunction

    //==========================================================================================
    globals
        private timer array tT
        private integer tN = 0
        private constant integer HELD=0x28829022
        //use a totally random number here, the more improbable someone uses it, the better.
    endglobals

    //==========================================================================================
    function NewTimer takes nothing returns timer
        if (tN==0) then
            set tT[0]=CreateTimer()
        else
            set tN=tN-1
        endif
        call SetTimerData(tT[tN],0)
     return tT[tN]
    endfunction

    //==========================================================================================
    function ReleaseTimer takes timer t returns nothing
        if(t==null) then
            debug call BJDebugMsg("Warning: attempt to release a null timer")
            return
        endif
        if (tN==8191) then
            debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")

            //stack is full, the map already has much more troubles than the chance of bug
            call DestroyTimer(t)
        else
            call PauseTimer(t)
            if(GetTimerData(t)==HELD) then
                debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
                return
            endif
            call SetTimerData(t,HELD)
            set tT[tN]=t
            set tN=tN+1
        endif    
    endfunction

    private function init takes nothing returns nothing
        set hasht = InitHashtable()
    endfunction

endlibrary
//===========================================================================
// Trigger: xebasic Copy
//===========================================================================
//TESH.scrollpos=0
//TESH.alwaysfold=0
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
//                   use the dummy.mdx model, so remember to import it as
//                   well, just use copy&paste to copy the dummy from the
//                   xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
//                    this rawcode to another spell that morphs into a flier
//                    in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
//                      raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
//                      timer that depends on it, if you put a low value
//                      the movement will look good but it may hurt your
//                      performance, if instead you use a high value it
//                      will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
//                        you got a unit bigger than 197.0 it would be
//                        a good idea to update this constant, since some
//                        enums will not find it. Likewise, if none of
//                        your units can go bellow X and X is much smaller
//                        than 197.0, it would be a good idea to update
//                        as well, since it will improve the performance
//                        those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely. 
//
//**************************************************************************

//===========================================================================
globals
   constant integer XE_DUMMY_UNITID       = 'e000'
   constant integer XE_HEIGHT_ENABLER     = 'Amrf'
   constant integer XE_TREE_RECOGNITION   = 'Aeat'
   constant real    XE_ANIMATION_PERIOD   =  0.025
   constant real    XE_MAX_COLLISION_SIZE =  197.0
endglobals

endlibrary


//===========================================================================
// Trigger: xedamage Copy
//===========================================================================
//TESH.scrollpos=0
//TESH.alwaysfold=0
library xedamage initializer init requires xebasic
//************************************************************************
// xedamage 0.8
// --------
//  For all your damage and targetting needs.
//
//************************************************************************

//===========================================================================================================
    globals
        private constant integer   MAX_SUB_OPTIONS = 3
        
        private constant real      FACTOR_TEST_DAMAGE = 0.01 
        // a low damage to do on units to test their damage factors for specific
        // attacktype/damagetype combos.
        // You'll need something as high as 20.0 to make it work well with armor resistances.
        // (Yes, you read it correctly, 20 ...
        //
        // If you use such a large value, there may be conflicts with some things relying on damage
        // (ie they are not away of the isDummyDamage tag that xedamage posseses.) which may be quite bad if you think about it...
        // then maybe it is better to change it to 0.01 ... then will work fine, just fine - but it will generally ignore armor - 
        // I am leaving it as 0.01 by default, because honestly, I'd rather make it ignore armor than have a lot of people sending me
        // rants about how they detect 20.0 damage where none is visible...
        private constant real      MAX_DAMAGE_FACTOR = 3.00
        // The maximum damage factor in the map. I think 3 is fine.
       

        //=======================================================
        private constant real      EPSILON = 0.000000001
        private unit     dmger
        private constant integer   MAX_SPACE = 8190 // MAX_SPACE/MAX_SUB_OPTIONS is the instance limit for xedamage, usually big enough...
    endglobals

    private keyword structInit

    struct xedamage[MAX_SPACE]

        //----
        // fields and methods for a xedamage object, they aid determining valid targets and special
        // damage factor conditions.
        //
        // Notice the default values.
        //
        boolean damageSelf    = false  // the damage and factor methods  usually have a source unit parameter
                                       // xedamage would consider this unit as immune unless you set damageSelf to true

        boolean damageAllies  = false  // Alliance dependent target options.
        boolean damageEnemies = true   // *
        boolean damageNeutral = true   // *
        boolean ranged        = true   // Is the attack ranged? This has some effect on the AI of the affected units
                                       // true by default, you may not really need to modify this.

        boolean visibleOnly   = false  // Should only units that are visible for source unit's owner be affected?
        boolean deadOnly      = false  // Should only corpses be affected by "the damage"? (useful when using xedamage as a target selector)
        boolean alsoDead      = false  // Should even corpses and alive units be considered?

        boolean damageTrees   = true  //Also damage destructables? Notice this is used only in certain methods.
                                       //AOE for example targets a circle, so it can affect the destructables
                                       //in that circle, a custom spell using xedamage for targetting configuration
                                       //could also have an if-then-else implemented so it can verify if it is true
                                       //then affect trees manually.

        //
        // Damage type stuff:
        //    .dtype : the "damagetype" , determines if the spell is physical, magical or ultimate.
        //    .atype : the "attacktype" , deals with armor.
        //    .wtype : the "weapontype" , determines the sound effect to be played when damage is done.
        //
        //  Please use common.j/blizzard.j/ some guide to know what damage/attack/weapon types can be used
        //
        damagetype dtype  = DAMAGE_TYPE_UNIVERSAL
        attacktype atype  = ATTACK_TYPE_MAGIC
        weapontype wtype  = WEAPON_TYPE_WHOKNOWS

        //
        // Damage type 'tag' people might use xedamage.isInUse() to detect xedamage usage, there are other static
        //  variables like xedamage.CurrentDamageType and xedamage.CurrentDamageTag. The tag allows you to specify
        //  a custom id for the damage type ** Notice the tag would aid you for some spell stuff, for example,
        //  you can use it in a way similar to Rising_Dusk's damage system.
        //
        integer    tag    = 0

        //
        // if true, forceDamage will make xedamage ignore dtype and atype and try as hard as possible to deal 100%
        // damage.
        boolean    forceDamage = false


        //
        // Ally factor! Certain spells probably have double purposes and heal allies while harming enemies. This
        // field allows you to do such thing.
        //
        real     allyfactor = 1.0

        //
        // field: .exception = SOME_UNIT_TYPE
        // This field adds an exception unittype (classification), if the unit belongs to this unittype it will
        // be ignored.
        //
        method operator exception= takes unittype ut returns nothing
            set this.use_ex=true
            set this.ex_ut=ut
        endmethod

        //
        // field: .required = SOME_UNIT_TYPE
        // This field adds a required unittype (classification), if the unit does not belong to this unittype
        //  it will be ignored.
        //
        method operator required= takes unittype ut returns nothing
            set this.use_req=true
            set this.req_ut=ut
        endmethod
        private boolean  use_ex    =  false
        private unittype ex_ut = null

        private boolean  use_req   = false
        private unittype req_ut  = null


        private unittype array fct[MAX_SUB_OPTIONS]
        private real     array fc[MAX_SUB_OPTIONS]
        private integer  fcn=0

        
        
        //
        // method .factor(SOME_UNIT_TYPE, factor)
        //  You might call factor() if you wish to specify a special damage factor for a certain classification,
        // for example call d.factor(UNIT_TYPE_STRUCTURE, 0.5) makes xedamage do half damage to structures.
        //
        
        
        method factor takes unittype ut, real fc returns nothing
            if(this.fcn==MAX_SUB_OPTIONS) then
                debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to factor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of factor() calls")
                return
            endif
            set this.fct[this.fcn] = ut
            set this.fc[this.fcn] = fc
            set this.fcn = this.fcn+1
        endmethod

        private integer  array abifct[MAX_SUB_OPTIONS]
        private real     array abifc[MAX_SUB_OPTIONS]
        private integer  abifcn=0

        //
        // method .abilityFactor('abil', factor)
        //  You might call abilityFactor() if you wish to specify a special damage factor for units that have a
        // certain ability/buff.
        // for example call d.abilityFactor('A000', 1.5 ) makes units that have the A000 ability take 50% more
        // damage than usual.
        //
        
        method abilityFactor takes integer abilityId, real fc returns nothing
            if(this.abifcn==MAX_SUB_OPTIONS) then
                debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to abilityFactor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of abilityFactor() calls")
                return
            endif
            set this.abifct[this.abifcn] = abilityId
            set this.abifc[this.abifcn] = fc
            set this.abifcn = this.abifcn+1
        endmethod

        private boolean  usefx  = false
        private string   fxpath
        private string   fxattach

        //
        // method .useSpecialEffect("effect\\path.mdl", "origin")
        // Makes it add (and destroy) an effect when damage is performed.
        //
        method useSpecialEffect takes string path, string attach returns nothing
            set this.usefx = true
            set this.fxpath=path
            set this.fxattach=attach
        endmethod


        //********************************************************************
        //* Now, the usage stuff:
        //*

        //================================================================================
        // static method xedamage.isInUse()  will return true during a unit damaged
        // event in case this damage was caused by xedamage, in this case, you can
        // read variables like CurrentDamageType, CurrentAttackType and CurrentDamageTag
        // to be able to recognize what sort of damage was done.
        //
        readonly static damagetype CurrentDamageType=null
        readonly static attacktype CurrentAttackType=null
        readonly static integer    CurrentDamageTag =0

        private static integer    inUse = 0
        static method isInUse takes nothing returns boolean 
            return (inUse>0) //inline friendly.
        endmethod
        
        readonly static boolean isDummyDamage = false

        //========================================================================================================
        // This function calculates the damage factor caused by a certain attack and damage
        // type, it is static : xedamage.getDamageTypeFactor(someunit, ATTAcK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, 100)
        //
        static method getDamageTypeFactor takes unit u, attacktype a, damagetype d returns real
         local real hp=GetWidgetLife(u)
         local real mana=GetUnitState(u,UNIT_STATE_MANA)
         local real r
         local real fc = FACTOR_TEST_DAMAGE

            //Since a unit is in that point, we don't need checks.
            call SetUnitX(dmger,GetUnitX(u))
            call SetUnitY(dmger,GetUnitY(u))

            call SetUnitOwner(dmger,GetOwningPlayer(u),false)
            set r=hp
            if (hp< FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR) then
                 call SetWidgetLife(u, hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR )
                 set r = hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR
                 set fc = GetWidgetLife(u)-hp + EPSILON
            endif
            set isDummyDamage = true
            call UnitDamageTarget(dmger,u, fc ,false,false,a,d,null)
            static if DEBUG_MODE then
                if IsUnitType(u, UNIT_TYPE_DEAD) and (hp>0.405) then
                    call BJDebugMsg("xedamage: For some reason, the unit being tested by getDamageTypeFactor has died. Verify MAX_DAMAGE_FACTOR is set to a correct value. ") 
                endif
            endif
            
            set isDummyDamage = false
            call SetUnitOwner(dmger,Player(15),false)
            if (mana>GetUnitState(u,UNIT_STATE_MANA)) then
                //Unit had mana shield, return 1 and restore mana too.
                call SetUnitState(u,UNIT_STATE_MANA,mana)
                set r=1
            else
                set r= (r-GetWidgetLife(u)) / fc
            endif
            call SetWidgetLife(u,hp)
         return r
        endmethod


        private method getTargetFactorCore takes unit source, unit target, boolean usetypes returns real
         local player p=GetOwningPlayer(source)
         local boolean allied=IsUnitAlly(target,p)
         local boolean enemy =IsUnitEnemy(target,p)
         local boolean neutral=allied
         local real   f
         local real   negf=1.0
         local integer i

            if(this.damageAllies != this.damageNeutral) then
                set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_REQUEST ))
                //I thought accuracy was not as important as speed , I think that REQUEST is false is enough to consider
                // it neutral.
                //set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_RESPONSE ))
                //set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_XP ))
                //set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_SPELLS ))
                set allied= allied and not(neutral)
            endif

            if (not this.damageAllies) and allied then
                return 0.0
            elseif (not this.damageEnemies) and enemy then
                return 0.0
            elseif( (not this.damageSelf) and (source==target) ) then
                return 0.0
            elseif (not this.damageNeutral) and neutral  then
                return 0.0
            elseif( this.use_ex and IsUnitType(target, this.ex_ut) ) then
                return 0.0
            elseif( this.visibleOnly and not IsUnitVisible(target,p) ) then
                return 0.0
            elseif ( this.deadOnly and not IsUnitType(target,UNIT_TYPE_DEAD) ) then
                return 0.0
            elseif ( not(this.alsoDead) and IsUnitType(target,UNIT_TYPE_DEAD) ) then
                return 0.0               
            endif

            set f=1.0
            
            if ( IsUnitAlly(target,p) ) then
                set f=f*this.allyfactor
                if(f<=-EPSILON) then
                    set f=-f
                    set negf=-1.0
                endif
            endif
            if (this.use_req and not IsUnitType(target,this.req_ut)) then
                return 0.0
            endif

            set i=.fcn-1
            loop
                exitwhen (i<0)
                if( IsUnitType(target, this.fct[i] ) ) then
                    set f=f*this.fc[i]
                    if(f<=-EPSILON) then
                        set f=-f
                        set negf=-1.0
                    endif
                endif
                set i=i-1
            endloop
            set i=.abifcn-1
            loop
                exitwhen (i<0)
                if( GetUnitAbilityLevel(target,this.abifct[i] )>0 ) then
                    set f=f*this.abifc[i]
                    if(f<=-EPSILON) then
                        set f=-f
                        set negf=-1.0
                    endif
                endif
                set i=i-1
            endloop
            set f=f*negf

            if ( f<EPSILON) and (f>-EPSILON) then
                return 0.0
            endif
            if( this.forceDamage or not usetypes ) then
                return f
            endif
            set f=f*xedamage.getDamageTypeFactor(target,this.atype,this.dtype)

            if ( f<EPSILON) and (f>-EPSILON) then
                return 0.0
            endif

            return f
        endmethod

        //====================================================================
        // With this you might decide if a unit is a valid target for a spell.
        //
        method getTargetFactor takes unit source, unit target returns real
            return this.getTargetFactorCore(source,target,true)
        endmethod

        //======================================================================
        // a little better, I guess
        //
        method allowedTarget takes unit source, unit target returns boolean
            return (this.getTargetFactorCore(source,target,false)!=0.0)
        endmethod


        //=======================================================================
        // performs damage to the target unit, for unit 'source'. 
        //
        method damageTarget takes unit source, unit target, real damage returns boolean
         local damagetype dt=.CurrentDamageType
         local attacktype at=.CurrentAttackType
         local integer    tg=.CurrentDamageTag
         local real       f = this.getTargetFactorCore(source,target,false)
         local real       pl

            if(f!=0.0) then
                set .CurrentDamageType = .dtype
                set .CurrentAttackType = .atype
                set .CurrentDamageTag  = .tag

                
                set .inUse = .inUse +1
                set pl=GetWidgetLife(target)
                call UnitDamageTarget(source,target,  f*damage, true, .ranged, .atype, .dtype, .wtype )
                set .inUse = .inUse -1
                set .CurrentDamageTag = tg
                set .CurrentDamageType = dt
                set .CurrentAttackType = at
                if(pl != GetWidgetLife(target) ) then
                    if(usefx) then
                         call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
                    endif
                    return true
                endif
            endif
            return false
        endmethod

        //=======================================================================================
        // The same as damageTarget, but it forces a specific damage value, good if you already
        // know the target.
        //
        method damageTargetForceValue takes unit source, unit target, real damage returns nothing
         local damagetype dt=.CurrentDamageType
         local attacktype at=.CurrentAttackType
         local integer    tg=.CurrentDamageTag

                set .CurrentDamageType = .dtype
                set .CurrentAttackType = .atype
                set .CurrentDamageTag  = .tag

                if( usefx) then
                    call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
                endif
                
                set .inUse = .inUse +1
                call UnitDamageTarget(source,target,  damage, true, .ranged, null, null, .wtype )
                set .inUse = .inUse -1
                set .CurrentDamageTag  = tg
                set .CurrentDamageType = dt
                set .CurrentAttackType = at
        endmethod

        //=====================================================================================
        // Notice: this will not Destroy the group, but it will certainly empty the group.
        //
        method damageGroup takes unit source, group targetGroup, real damage returns integer
         local damagetype dt=.CurrentDamageType
         local attacktype at=.CurrentAttackType
         local integer    tg=.CurrentDamageTag
         local unit       target
         local real       f
         local integer    count=0
         local real hp

            set .CurrentDamageType = .dtype
            set .CurrentAttackType = .atype
            set .CurrentDamageTag  = .tag
            set .inUse = .inUse +1
            loop
                set target=FirstOfGroup(targetGroup)
                exitwhen (target==null)
                call GroupRemoveUnit(targetGroup,target)
                set f= this.getTargetFactorCore(source,target,false)
                if (f!=0.0) then
                    set count=count+1
                    if(usefx) then
                        set hp = GetWidgetLife(target)
                    endif

                    call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
                    if(usefx and (hp > GetWidgetLife(target)) ) then
                        call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
                    endif                 

                endif
            endloop


            set .inUse = .inUse -1
            set .CurrentDamageTag=tg
            set .CurrentDamageType = dt
            set .CurrentAttackType = at
         return count
        endmethod

        private static xedamage instance
        private integer countAOE
        private unit    sourceAOE
        private real    AOEx
        private real    AOEy
        private real    AOEradius
        private real    AOEdamage
        private static boolexpr filterAOE
        private static boolexpr filterDestAOE
        private static group    enumgroup
        private static rect     AOERect

        private static method damageAOE_Enum takes nothing returns boolean
         local unit target=GetFilterUnit()
         local xedamage this=.instance //adopting a instance.
         local real f
         local real hp
         
             if( not IsUnitInRangeXY(target,.AOEx, .AOEy, .AOEradius) ) then
                 set target=null
                 return false
             endif
             set f=.getTargetFactorCore(.sourceAOE, target, false)
             if(f!=0.0) then
                 set .countAOE=.countAOE+1
                 if(this.usefx) then
                      set hp =GetWidgetLife(target)
                 endif
                 call UnitDamageTarget(.sourceAOE,target, f*this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
                 if(this.usefx and (hp > GetWidgetLife(target) ) ) then
                     call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
                 endif                                  
             endif

          set .instance= this //better restore, nesting IS possible!
          set target=null
          return false
        endmethod

        private static method damageAOE_DestructablesEnum takes nothing returns boolean
         local destructable target=GetFilterDestructable()
         local xedamage this=.instance //adopting a instance.
         local real     dx=.AOEx-GetDestructableX(target)
         local real     dy=.AOEy-GetDestructableY(target)

             if( dx*dx + dy*dy >= .AOEradius+EPSILON )  then
                 set target=null
                 return false
             endif
             set .countAOE=.countAOE+1
             if(.usefx) then
                 call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
             endif             
             call UnitDamageTarget(.sourceAOE,target, this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )

          set .instance= this //better restore, nesting IS possible!
          set target=null
          return false
        endmethod
        //==========================================================================================
        // will affect trees if damageTrees is true!
        // 
        method damageAOE takes unit source, real x, real y, real radius, real damage returns integer
         local damagetype dt=.CurrentDamageType
         local attacktype at=.CurrentAttackType
         local integer    tg=.CurrentDamageTag

            set .CurrentDamageType = .dtype
            set .CurrentAttackType = .atype
            set .CurrentDamageTag  = .tag
            set .inUse = .inUse +1
            set .instance=this
            set .countAOE=0
            set .sourceAOE=source
            set .AOEx=x
            set .AOEradius=radius
            set .AOEy=y
            set .AOEdamage=damage
            call GroupEnumUnitsInRange(.enumgroup,x,y,radius+XE_MAX_COLLISION_SIZE, .filterAOE)
            if(.damageTrees) then
                call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
                set .AOEradius=.AOEradius*.AOEradius
                call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
            endif
            set .inUse = .inUse -1
            set .CurrentDamageTag  = tg
            set .CurrentDamageType = dt
            set .CurrentAttackType = at
         return .countAOE
        endmethod

        method damageAOELoc takes unit source, location loc, real radius, real damage returns integer
            return .damageAOE(source, GetLocationX(loc), GetLocationY(loc), radius, damage)
        endmethod

        //==========================================================================================
        // only affects trees, ignores damageTrees
        // 
        method damageDestructablesAOE takes unit source, real x, real y, real radius, real damage returns integer
            set .instance=this
            set .countAOE=0
            set .sourceAOE=source
            set .AOEx=x
            set .AOEradius=radius*radius
            set .AOEy=y
            set .AOEdamage=damage
            //if(.damageTrees) then
                call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
                call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
            //endif
         return .countAOE
        endmethod
        method damageDestructablesAOELoc takes unit source, location loc, real radius, real damage returns integer
            return .damageDestructablesAOE(source,GetLocationX(loc), GetLocationY(loc), radius, damage)
        endmethod

        //'friend' with the library init
        static method structInit takes nothing returns nothing
            set .AOERect= Rect(0,0,0,0)
            set .filterAOE= Condition(function xedamage.damageAOE_Enum)
            set .filterDestAOE = Condition( function xedamage.damageAOE_DestructablesEnum)
            set .enumgroup = CreateGroup()
        endmethod
    endstruct

    private function init takes nothing returns nothing
        set dmger=CreateUnit(Player(15), XE_DUMMY_UNITID , 400,-400,0.)
        call UnitAddAbility(dmger,'Aloc')
        call xedamage.structInit()
    endfunction




endlibrary


//===========================================================================
// Trigger: xepreload Copy Copy
//===========================================================================
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library xepreload initializer init requires xebasic, optional TimerUtils
//******************************************************************************
// xepreload 0.8
// ---------
// Ah, the joy of preloading abilities, it is such a necessary evil...
// Notice you are not supposed to use this system in places outside map init
//
// This one does the preloading and tries to minimize the hit on loading time
// for example, it only needs one single native call per ability preloaded.
//
//******************************************************************************

//==============================================================================
    globals
        private unit dum=null
    endglobals
    private keyword DebugIdInteger2IdString

    //inline friendly (when debug mode is off..)
    function XE_PreloadAbility takes integer abilid returns nothing
        call UnitAddAbility(dum, abilid)
        /*static if DEBUG_MODE then
            if(dum==null) then
                call BJDebugMsg("XE_PreloadAbility: do not load abilities after map init or during structs' onInit")
            elseif GetUnitAbilityLevel(dum, abilid) == 0 then
                call BJDebugMsg("XE_PreloadAbility: Ability "+DebugIdInteger2IdString.evaluate(abilid)+" does not exist.")
            endif
        endif*/
    endfunction
    // ................................................................................

    //================================================================================
    // Convert a integer id value into a 4-letter id code.
    // * Taken from cheats.j so I don't have to code it again.
    // * Used only on debug so making a whole library for it seemed silly
    // * Private so people don't begin using xepreload just to call this function....
    // * It will not work correctly if you paste this code in the custom script section
    //   due to the infamous % bug. Then again, if you do that then you probably 
    // deserve it....
    //
    private function DebugIdInteger2IdString takes integer value returns string
     local string charMap = ".................................!.#$%&'()*+,-./0123456789:;<=>.@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`abcdefghijklmnopqrstuvwxyz{|}~................................................................................................................................."
     local string result = ""
     local integer remainingValue = value
     local integer charValue
     local integer byteno

     set byteno = 0
     loop
         set charValue = ModuloInteger(remainingValue, 256)
         set remainingValue = remainingValue / 256
         set result = SubString(charMap, charValue, charValue + 1) + result
 
         set byteno = byteno + 1
         exitwhen byteno == 4
     endloop
     return result
    endfunction

    //--------------------------------
    private function kill takes nothing returns nothing
        call RemoveUnit(dum)
        set dum=null
     //   static if (LIBRARY_TimerUtils ) then
            call ReleaseTimer( GetExpiredTimer() )
     //   else
        //    call DestroyTimer(GetExpiredTimer())
        //endif
    endfunction
    
    private function init takes nothing returns nothing
     local timer t
        set dum = CreateUnit( Player(15), XE_DUMMY_UNITID, 400,-400,0)
        if( dum == null) then
            debug call BJDebugMsg("xePreload : XE_DUMMY_UNITID ("+DebugIdInteger2IdString.evaluate(XE_DUMMY_UNITID)+") not added correctly to the map.")
        endif
        //static if (LIBRARY_TimerUtils) then
            set t=NewTimer()
       // else
            set t=CreateTimer()
       // endif
        call TimerStart(t,0.0,false,function kill)
        set t=null
    endfunction




endlibrary

//===========================================================================
// Trigger: xecast Copy Copy
//===========================================================================
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library xecast initializer init requires xebasic
//******************************************************************************
// xecast 0.7
// ------
//  Because dummy casters REALLY ARE this complicated!
//
//******************************************************************************

//==============================================================================
 globals
    private constant integer MAXINSTANCES         = 8190
    //this is a lot, unless you leak xecast objects (which is a bad thing)
    
    private constant integer INITIAL_DUMMY_COUNT  = 12
    
    //don't allow to keep more than DUMMY_STACK_LIMIT innactive dummy units :
    private constant integer DUMMY_STACK_LIMIT    = 50
    
    // If your map does not give visibility to all players, or
    // for other reasons, you might want xecast to work on
    // units that are not visible to the player, in that case
    // change this to true, else it is just a performance loss.
    private constant boolean FORCE_INVISIBLE_CAST = false

    //When AUTO_RESET_MANA_COOLDOWN is set to true, xecast will reset
    // the dummy unit's cooldown and mana before casting every spell.
    // it is a performance penalty, so if you are sure that all dummy spells
    // in your map got 0 mana and cooldown cost, you may set it to false.    
    private constant boolean AUTO_RESET_MANA_COOLDOWN = true 
 endglobals

//=========================================================================
// Please notice all textmacros in this library are considered private.
//  in other words: DON'T RUN THOSE TEXTMACROS!
//
private keyword structinit

globals
    private real EPSILON=0.001 //noticed in war3 this is the sort of precision we want...
endglobals

struct xecast[MAXINSTANCES]

    public integer abilityid    = 0    //ID (rawcode) of the ability to cast
    public integer level        = 1    //Level of the ability to cast

    public real    recycledelay = 0.0  //Please notice, some spells need a recycle delay
                                       // This is, a time period before they get recycle.
                                       // For example, some spells are not instant, there is
                                       // also the problem with damaging spells, this recycle
                                       // delay must be large enough to contain all the time
                                       // in which the spell can do damage.


    public player  owningplayer=Player(15)  //which player to credit for the ability cast?
                                            //notice this can also affect what units are targeteable

    //==================================================================================================
    // You need an order id for the ability so the dummy unit is able to cast it, two ways to assign it
    //   set instance.orderid     = 288883            //would assign an integer orderid
    //   set instance.orderstring = "chainlightning"  //would assign an orderstring
    //                                                 (as those in the object editor)
    //
    method operator orderid= takes integer v returns nothing 
        set .oid=v
    endmethod
    method operator orderstring= takes string s returns nothing
        set .oid=OrderId(s)
    endmethod

    //=================================================================================================
    // Finally, you can determine from which point to cast the ability: z is the height coordinate.
    //
    public boolean customsource=false //Use a custom casting source?

    public real    sourcex     // Determine the casting source for the dummy spell, require customsource =true
    public real    sourcey     // You might prefer to use the setSourcePoint method
    public real    sourcez=0.0 //

    method setSourcePoint takes real x, real y, real z returns nothing
       set .sourcex=x
       set .sourcey=y
       set .sourcez=z
       set .customsource=true
    endmethod

    method setSourceLoc takes  location loc, real z returns nothing
       set .sourcex=GetLocationX(loc)
       set .sourcey=GetLocationY(loc)
       set .sourcez=z
       set .customsource=true
    endmethod


    private boolean autodestroy  = false
    //========================================================================================================
    // you are always allowed to use .create() but you can also use createBasic which sets some things that
    // are usually necessary up.
    //
    public static method createBasic takes integer abilityID, integer orderid, player owner returns xecast
     local xecast r=xecast.allocate()
        if(r==0) then
            debug call BJDebugMsg("Warning: unbelievable but you actually used all xecast instances in your map! Please make sure you are not forgetting to destroy those what you create intensively, if that's not the case, then you'll have to increase xecast MAXINSTANCES")
        endif
        set r.oid=orderid
        set r.abilityid=abilityID
        set r.owningplayer=owner
     return r
    endmethod

    //========================================================================================================
    // Just like the above one, but the instance will self destruct after a call to any cast method
    // (recommended)
    //
    public static method createBasicA takes integer abilityID, integer orderid, player owner returns xecast
     local xecast r=xecast.allocate()
        if(r==0) then
            debug call BJDebugMsg("Warning: unbelievable but you actually used all xecast instances in your map! Please make sure you are not forgetting to destroy those what you create intensively, if that's not the case, then you'll have to increase xecast MAXINSTANCES")
        endif
        set r.oid=orderid
        set r.abilityid=abilityID
        set r.owningplayer=owner
        set r.autodestroy=true
     return r
    endmethod

    //==========================================================================================================
    // Just like create, but the struct instance self destructs after a call to any cast method
    // (Recommended)
    //
    public static method createA takes nothing returns xecast
     local xecast r=xecast.allocate()
        set r.autodestroy=true
     return r
    endmethod

    //==========================================================================================================
    // So, create the dummy, assign options and cast the skill!
    // .castOnTarget(w)       : If you want to hit a widget w with the ability
    // .castOnPoint(x,y)      : If you want to hit a point (x,y) with the ability
    // .castInPoint(x,y)      : For spells like warstomp which do not have a target.
    // .castOnAOE(x,y,radius) : Classic area of effect cast. Considers collision size
    // .castOnGroup(g)        : Cast unit the unit group g, notice it will empty the group yet not destroy it.
    //

    //**********************************************************************************************************
    // The implementation of such methods follows: 

    private static  unit array dummystack
    private static  integer    top=0
    private static  unit       instantdummy

    private integer oid=0

    private static timer       gametime
    private static timer       T
    private static unit array  recycle
    private static real array  expiretime
    private static integer     rn=0

    //==========================================================================================================
    // private dorecycle method, sorry but I need this up here.
    //
    private static method dorecycle takes nothing returns nothing
     local unit u =.recycle[0]
     local integer l
     local integer r
     local integer p
     local real    lt
        call UnitRemoveAbility(u,GetUnitUserData(u))
        call SetUnitUserData(u,0)
        call SetUnitFlyHeight(u,0,0)
        call PauseUnit(u,false)
        if(.top==DUMMY_STACK_LIMIT) then
            call RemoveUnit(u)
        else
            set .dummystack[.top]=u
            set .top=.top+1
        endif
        set .rn=.rn-1
        if(.rn==0) then
            return
        endif
        set p=0
        set lt=.expiretime[.rn]
        loop
            set l=p*2+1
            exitwhen l>=.rn
            set r=p*2+2
            if(r>=.rn)then
                if(.expiretime[l]<lt) then
                    set .expiretime=.expiretime[l]
                    set .recycle=.recycle[l]
                    set p=l
                else
                    exitwhen true
                endif
            elseif (lt<=.expiretime[l]) and (lt<=.expiretime[r]) then
                exitwhen true
            elseif (.expiretime[l]<.expiretime[r]) then
                set .expiretime=.expiretime[l]
                set .recycle=.recycle[l]
                set p=l
            else
                set .expiretime=.expiretime[r]
                set .recycle=.recycle[r]
                set p=r
            endif
        endloop
        set .recycle=.recycle[.rn]
        set .expiretime=lt
        call TimerStart(.T, .expiretime[0]-TimerGetElapsed(.gametime), false, function xecast.dorecycle)
    endmethod

    private static trigger abilityRemove


    // Repetitive process and no inline implemented for large functions, so for now it is a textmacro:
    //! textmacro xecast_allocdummy
        if(.recycledelay<EPSILON) then
            set dummy=.instantdummy
            call SetUnitOwner(dummy,.owningplayer,false)
        elseif (.top>0) then
            set .top=.top-1
            set dummy=.dummystack[.top]
            call SetUnitOwner(dummy,.owningplayer,false)
        else
            set dummy=CreateUnit(.owningplayer,XE_DUMMY_UNITID,400,-400,0)
            call TriggerRegisterUnitEvent(.abilityRemove,dummy,EVENT_UNIT_SPELL_ENDCAST)
            call UnitAddAbility(dummy,'Aloc')
            call UnitAddAbility(dummy,XE_HEIGHT_ENABLER)
            call UnitRemoveAbility(dummy,XE_HEIGHT_ENABLER)
        endif
        call UnitAddAbility(dummy, abilityid)
        static if AUTO_RESET_MANA_COOLDOWN then
            call UnitResetCooldown(dummy)
            call SetUnitState(dummy, UNIT_STATE_MANA, 10000.0)
        endif
        if(level>1) then
            call SetUnitAbilityLevel(dummy, abilityid, level)
        endif
    //! endtextmacro
    private static integer cparent
    private static integer current
    private static real    cexpire
    //! textmacro xecast_deallocdummy
        if(.recycledelay>=EPSILON) then
            set .cexpire=TimerGetElapsed(.gametime)+.recycledelay
            set .current=.rn
            set .rn=.rn+1
            loop
                exitwhen (.current==0)
                set .cparent=(.current-1)/2
                exitwhen (.expiretime[.cparent]<=.cexpire)
                set .recycle[.current]=.recycle[.cparent]
                set .expiretime[.current]=.expiretime[.cparent]
                set .current=.cparent
            endloop
            set .expiretime[.current]=.cexpire
            set .recycle[.current]=dummy
            call SetUnitUserData(dummy,.abilityid)
            call TimerStart(.T, .expiretime[0]-TimerGetElapsed(.gametime), false, function xecast.dorecycle)
        else
            call SetUnitUserData(dummy,0)
            call SetUnitFlyHeight(dummy,0,0)
            call UnitRemoveAbility(dummy,.abilityid)
        endif
    //! endtextmacro

    method castOnTarget takes unit target returns nothing
     local unit dummy
     local unit tar
        //! runtextmacro xecast_allocdummy()
        if (.customsource) then
            call SetUnitX(dummy,.sourcex)
            call SetUnitY(dummy,.sourcey)
            call SetUnitFlyHeight(dummy,.sourcez,0.0)
        else
            call SetUnitX(dummy,GetWidgetX(target))
            call SetUnitY(dummy,GetWidgetY(target))
        endif
        if (FORCE_INVISIBLE_CAST) then
            call UnitShareVision(target, .owningplayer, true)
            call IssueTargetOrderById(dummy,this.oid,target)
            call UnitShareVision(target, .owningplayer, false)
        else
            call IssueTargetOrderById(dummy,this.oid,target)
        endif

        //! runtextmacro xecast_deallocdummy()
        if(.autodestroy ) then
            call this.destroy()
        endif
    endmethod

    //accepts units, items and destructables, if you know it is
    // a unit it is better to use castOnTarget since that would
    // be able to use FORCE_INVISIBLE_CAST if necessary.
    //
    method castOnWidgetTarget takes widget target returns nothing
     local unit dummy
     local unit tar
        //! runtextmacro xecast_allocdummy()
        if (.customsource) then
            call SetUnitX(dummy,.sourcex)
            call SetUnitY(dummy,.sourcey)
            call SetUnitFlyHeight(dummy,.sourcez,0.0)
        else
            call SetUnitX(dummy,GetWidgetX(target))
            call SetUnitY(dummy,GetWidgetY(target))
        endif
        call IssueTargetOrderById(dummy,this.oid,target)

        //! runtextmacro xecast_deallocdummy()
        if(.autodestroy ) then
            call this.destroy()
        endif
    endmethod



    method castOnPoint takes real x, real y returns nothing
     local unit dummy
        //! runtextmacro xecast_allocdummy()
        if (.customsource) then
            call SetUnitX(dummy,.sourcex)
            call SetUnitY(dummy,.sourcey)
            call SetUnitFlyHeight(dummy,.sourcez,0.0)
        else
            call SetUnitX(dummy,x)
            call SetUnitY(dummy,y)
        endif
        call IssuePointOrderById(dummy,this.oid,x,y)
        //! runtextmacro xecast_deallocdummy()
        if(.autodestroy ) then
            call this.destroy()
        endif
    endmethod
    method castOnLoc takes location loc returns nothing
        //debug call BJDebugMsg("Warning: Locations are in use")
        //nah but I should 
        call .castOnPoint(GetLocationX(loc),GetLocationY(loc))
    endmethod

    //ignores custom source x and y (for obvious reasons)
    method castInPoint takes real x, real y returns nothing
     local unit dummy
        //! runtextmacro xecast_allocdummy()
        if (.customsource) then
            call SetUnitFlyHeight(dummy,.sourcez,0.0)
        endif
        call SetUnitX(dummy, x)
        call SetUnitY(dummy, y)
        call IssueImmediateOrderById(dummy,this.oid)
        //! runtextmacro xecast_deallocdummy()
        if(.autodestroy ) then
            call this.destroy()
        endif
    endmethod
    method castInLoc takes location loc returns nothing
        //debug call BJDebugMsg("Warning: Locations are in use")
        //nah but I should 
        call .castInPoint(GetLocationX(loc),GetLocationY(loc))
    endmethod


    //===================================================================================================
    // For method castOnAOE:
    //
    private static group    enumgroup
    private static real     aoex
    private static real     aoey
    private static real     aoeradius
    private static xecast   cinstance
    private static boolexpr aoefunc

    // Might look wrong, but this is the way to make it consider collision size, a spell that
    // got a target circle and uses this method will let the user know which units it will
    // hit with the mass cast.
    static method filterAOE takes nothing returns boolean
     local unit u=GetFilterUnit()
        if IsUnitInRangeXY(u, .aoex, .aoey, .aoeradius) then
            call .cinstance.castOnTarget(u)
        endif
     set u=null
     return false
    endmethod

    //
    method castOnAOE takes real x, real y, real radius returns nothing
     local boolean ad=this.autodestroy

        if(ad) then
            set this.autodestroy=false
        endif
        set .aoex=x
        set .aoey=y
        set .aoeradius=radius
        set .cinstance=this
        call GroupEnumUnitsInRange(.enumgroup,x,y,radius + XE_MAX_COLLISION_SIZE , .aoefunc)
        if(ad) then
            call this.destroy()
        endif
    endmethod

    method castOnAOELoc takes location loc,real radius returns nothing
        call .castOnAOE(GetLocationX(loc),GetLocationY(loc),radius)
    endmethod

    //==================================================================================================
    // A quick and dirt castOnGroup method, perhaps it'll later have castOntarget inlined, but not now
    //
    method castOnGroup takes group g returns nothing
     local boolean ad=this.autodestroy    
     local unit t
        if(ad) then
            set this.autodestroy=false
        endif

        loop
            set t=FirstOfGroup(g)
            exitwhen(t==null)
            call GroupRemoveUnit(g,t)
            call .castOnTarget(t)
        endloop
        if(ad) then
            call this.destroy()
        endif
    endmethod

    private static method removeAbility takes nothing returns boolean
     local unit u=GetTriggerUnit()
         if(GetUnitUserData(u)!=0) then
             call PauseUnit(u,true)
         endif
        //This is necessary, picture a value for recycle delay that's higher than the casting time,
        //for example if the spell does dps, if you leave the dummy caster with the ability and it 
        //is owned by an AI player it will start casting the ability on player units, so it is
        // a good idea to pause it...

     set u=null
     return true
    endmethod

    //===================================================================================================
    // structinit is a scope private keyword.
    //
    static method structinit takes nothing returns nothing
     local integer i=INITIAL_DUMMY_COUNT+1
     local unit u
        set .aoefunc=Condition(function xecast.filterAOE)
        set .enumgroup=CreateGroup()
        set .abilityRemove = CreateTrigger()
        loop
            exitwhen (i==0)
            set u=CreateUnit(Player(15),XE_DUMMY_UNITID,400,-400,0)
            call TriggerRegisterUnitEvent(.abilityRemove,u,EVENT_UNIT_SPELL_ENDCAST)
            call UnitAddAbility(u,'Aloc')
            call UnitAddAbility(u,XE_HEIGHT_ENABLER)
            call UnitRemoveAbility(u,XE_HEIGHT_ENABLER)
            set .dummystack[.top]=u
            set .top=.top+1
            set i=i-1
        endloop
        call TriggerAddCondition(.abilityRemove, Condition(function xecast.removeAbility ) )
        set .top=.top-1
        set .instantdummy=.dummystack[.top]
        set .T=CreateTimer()
        set .gametime=CreateTimer()
        call TimerStart(.gametime,12*60*60,false,null)
    endmethod


endstruct


private function init takes nothing returns nothing
    call xecast.structinit()
endfunction

endlibrary

//===========================================================================
// Trigger: KT
//===========================================================================
//TESH.scrollpos=66
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ KT ~~ Key Timers 2 ~~ By Jesus4Lyf ~~ Version 1.6.1 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is Key Timers?
//         - Key Timers attaches structs to timers, or more to the point timed
//           effects.
//         - You can specify different periods.
//         - Key Timers only uses one timer with one trigger per low period
//           to keep things efficient, especially within the looping.
//         - Key Timers alternatively uses one single timer for all higher periods
//           to allow accurate expirations in a stable and reasonably efficient fashion.
//
//    =Pros=
//         - Easy to use.
//         - Fastest attachment loading system (storing in parallel arrays).
//         - Fastest execution system for low periods (attaching all functions to one trigger).
//         - Allows multiple periods to be used.
//
//    =Cons=
//         - The code passed into KT2 must call KT_GetData exactly once.
//         - Periods must be a multiple of 0.00125 seconds. Not 0.007, for example.
//
//    Functions:
//         - KT_Add(userFunc, struct, period)
//         - KT_GetData returns the struct
//
//         - userFunc is to be a user function that takes nothing and returns boolean.
//           It will be executed by the system every period until it returns true.
//
//         - KT_GetData is to be used inside func, it will return the struct passed to
//           to the Add function. It must be called exactly once within the func.
//
//  Details:
//         - KT2 treats low periods and high periods differently, optimizing each
//           with appropriate speed and accuracy, although this effect is invisible
//           to you, the mapper.
//
//         - While func returns false the timer will continue to call it each period.
//           Once func returns true the instance will be detached from system.
//
//  Thanks:
//         - Daxtreme: For encouraging me to return to Key Timers 2, rather than
//           leave it to rot. His interest in the system restored it, and helped
//           it to become what it is now. :)
//
//         - Captain Griffen: For his work on Rapid Timers, demonstrating that it
//           is possible to attach all functions to one trigger, and that it is
//           indeed faster.
//
//         - Cohadar: Told me to make Key Timers without a textmacro.
//           Thanks to him for helping me with the original Key Timers system too.
//           Also, I'd like to thank him for his work on Timer Ticker (TT) which
//           demonstrated how to use triggers/conditions in this sort of system,
//           which has been used in Key Timers 2.
//
//  How to import:
//         - Create a trigger named KT.
//         - Convert it to custom text and replace the whole trigger text with this.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library KT initializer Init
    ///////////////
    // Constants //
    ////////////////////////////////////////////////////////////////////////////
    // That bit that users may play with if they know what they're doing.
    // Not touching these at all is recommended.
    globals
        private constant real PERIODTHRESHOLD=0.3 // MUST be below 10.24 seconds.
        private constant real HT_MARGINOFERROR=0.01
    endglobals
    
    //////////////////////////
    // Previous KT2 Globals //
    ////////////////////////////////////////////////////////////////////////////
    // These needed to be moved here for HT to hook GetData.
    globals
        private timer array KeyTimer
        private trigger array TimerTrigger
        private integer array KeyTimerListPointer
        private integer array KeyTimerListEndPointer
        private triggercondition array TriggerCond
        private boolexpr array Boolexpr
        private integer array Data
        private integer array Next
        private integer array Prev
        private integer TrigMax=0
        private integer array NextMem
        private integer NextMemMaxPlusOne=1
        private integer array ToAddMem
        private triggercondition array ToRemove
        private boolexpr array ToDestroy
        private boolean array IsAdd
        private integer AddRemoveMax=0
        
        // Locals
        private integer t_id=-1
        private integer t_mem
        private integer t_lastmem
        private integer a_id
        private integer a_mem
        
        // Code Chunks
        private conditionfunc RemoveInstanceCond
    endglobals
    
    /////////////////////
    // Hibernate Timer //
    ////////////////////////////////////////////////////////////////////////////
    // KT2 implementation for higher periods (low frequency).
    private keyword HTnode
    globals
        private timer HT_Moderator=CreateTimer()
        private real HT_Time=0.0
        private HTnode HT_Top
        private constant integer HT_DATAMEM=8190 // Added for KT2 hook. Don't change.
    endglobals
    
    globals//locals
        private HTnode newHTnode
    endglobals
    private struct HTnode
        HTnode prev // Make sure to link this before use
        HTnode next // Make sure to link this before use
        real period
        real firewhen // = HT_Time at creation
        trigger trig
        integer data
        static method new takes code func, integer data, real period returns HTnode
            set newHTnode=HTnode.create()
            if newHTnode.trig==null then
                set newHTnode.trig=CreateTrigger()
            endif
            call TriggerAddCondition(newHTnode.trig,Condition(func))
            set newHTnode.data=data
            set newHTnode.period=period
            set newHTnode.firewhen=HT_Time
            return newHTnode
        endmethod
        method link takes HTnode prev, HTnode next returns nothing
            set prev.next=this
            set next.prev=this
            set this.next=next
            set this.prev=prev
        endmethod
        method unlink takes nothing returns nothing
            set this.prev.next=this.next
            set this.next.prev=this.prev
        endmethod
        method autolink takes HTnode start returns nothing
            loop
                if start.next==0 then
                    call this.link(start,0)
                    return
                endif
                if start.next.firewhen > this.firewhen then
                    call this.link(start,start.next)
                    return
                endif
                set start=start.next
            endloop
        endmethod
    endstruct
    
    globals//locals
        private HTnode HT_handlenode
        private HTnode HT_handlenext
    endglobals
    private function HT_Handler takes nothing returns nothing
        // KT2 Data Hook
        set t_mem=HT_DATAMEM
        // End KT2 Data Hook
        set HT_handlenode=HT_Top
        set HT_handlenext=HT_handlenode.next
        loop
            set HT_handlenode=HT_handlenext
            exitwhen HT_handlenode==0 // Would pause timer here under old method.
            set HT_handlenext=HT_handlenode.next
            if HT_handlenode.firewhen<HT_Time+HT_MARGINOFERROR then
                // Load data
                set Data[HT_DATAMEM]=HT_handlenode.data
                // End load data
                if TriggerEvaluate(HT_handlenode.trig) then
                    call HT_handlenode.unlink()
                    call TriggerClearConditions(HT_handlenode.trig)
                    call HT_handlenode.destroy()
                else
                    set HT_handlenode.firewhen=HT_handlenode.firewhen+HT_handlenode.period
                    call HT_handlenode.unlink()
                    call HT_handlenode.autolink(HT_handlenode.prev)
                    if HT_handlenext==0 then
                        set HT_handlenext=HT_handlenode
                    endif
                endif
            else
                // More to fire, but not yet.
                return
            endif
        endloop
    endfunction
    
    globals//locals
        private HTnode HT_addnode
    endglobals
    private function HTadd takes code func, integer data, real period returns nothing
        set HT_addnode=HTnode.new(func, data, period)
        set HT_addnode.firewhen=HT_Time+period
        call HT_addnode.autolink(HT_Top)
        //if HT_Top.next==HT_addnode then
        //  //Old start timer stuff
        //endif
    endfunction
    private function HT_ModeratorLoop takes nothing returns nothing
        set HT_Time=HT_Time+HT_MARGINOFERROR
        if HT_Top.next.firewhen<HT_Time then
            call HT_Handler()
        endif
    endfunction
    private function HTinit takes nothing returns nothing
        call TimerStart(HT_Moderator,HT_MARGINOFERROR,true,function HT_ModeratorLoop)
        set HT_Top=HTnode.create()
        set HT_Top.prev=0
        set HT_Top.next=0
        set HT_Top.firewhen=0.0
        // Allow for GetData
        set Next[HT_DATAMEM]=HT_DATAMEM
        set Prev[HT_DATAMEM]=HT_DATAMEM
        // End allow for GetData
    endfunction
    
    //////////////////
    // Previous KT2 //
    ////////////////////////////////////////////////////////////////////////////
    // The rest of the KT2 implementation
    // Globals have been moved to top.
    private function KeyTimerLoop takes nothing returns nothing
        set t_id=R2I(TimerGetTimeout(GetExpiredTimer())*800)
        set t_mem=KeyTimerListEndPointer[t_id]
        call TriggerEvaluate(TimerTrigger[t_id])
        set t_mem=0
        loop
            exitwhen t_mem==AddRemoveMax
            set t_mem=t_mem+1
            if IsAdd[t_mem] then
                set TriggerCond[ToAddMem[t_mem]]=TriggerAddCondition(TimerTrigger[t_id],Boolexpr[ToAddMem[t_mem]])
            else
                call TriggerRemoveCondition(TimerTrigger[t_id],ToRemove[t_mem])
                call DestroyBoolExpr(ToDestroy[t_mem])
            endif
        endloop
        set AddRemoveMax=0
        set t_id=-1
    endfunction
    
    private function RemoveInstance takes nothing returns boolean
        // Will only fire if code returns true.
        set AddRemoveMax=AddRemoveMax+1
        set IsAdd[AddRemoveMax]=false
        set ToRemove[AddRemoveMax]=TriggerCond[t_lastmem]
        set ToDestroy[AddRemoveMax]=Boolexpr[t_lastmem]
        if Next[t_lastmem]==0 then
            set KeyTimerListEndPointer[t_id]=Prev[t_lastmem]
        endif
        set Prev[Next[t_lastmem]]=Prev[t_lastmem]
        if Prev[t_lastmem]==0 then
            set KeyTimerListPointer[t_id]=Next[t_lastmem]
            if KeyTimerListPointer[t_id]<1 then
                call PauseTimer(KeyTimer[t_id])
            endif
        else
            set Next[Prev[t_lastmem]]=Next[t_lastmem]
        endif
        set NextMem[NextMemMaxPlusOne]=t_lastmem
        set NextMemMaxPlusOne=NextMemMaxPlusOne+1
        return false
    endfunction
    
    private function KTadd takes code func, integer data, real period returns nothing
        set a_id=R2I(period*800)
        
        if KeyTimer[a_id]==null then
            set KeyTimer[a_id]=CreateTimer()
            set TimerTrigger[a_id]=CreateTrigger()
        endif
        
        if NextMemMaxPlusOne==1 then
            set TrigMax=TrigMax+1
            set a_mem=TrigMax
        else
            set NextMemMaxPlusOne=NextMemMaxPlusOne-1
            set a_mem=NextMem[NextMemMaxPlusOne]
        endif
        
        set Boolexpr[a_mem]=And(Condition(func),RemoveInstanceCond)
        if t_id==a_id then
            set AddRemoveMax=AddRemoveMax+1
            set IsAdd[AddRemoveMax]=true
            set ToAddMem[AddRemoveMax]=a_mem
        else
            if KeyTimerListPointer[a_id]<1 then
                call TimerStart(KeyTimer[a_id],a_id/800.0,true,function KeyTimerLoop)
                set KeyTimerListEndPointer[a_id]=a_mem
            endif
            
            set TriggerCond[a_mem]=TriggerAddCondition(TimerTrigger[a_id],Boolexpr[a_mem])
        endif
        set Data[a_mem]=data
        
        set Prev[a_mem]=0
        set Next[a_mem]=KeyTimerListPointer[a_id]
        set Prev[KeyTimerListPointer[a_id]]=a_mem
        set KeyTimerListPointer[a_id]=a_mem
    endfunction
    
    public function GetData takes nothing returns integer // Gets hooked by HT.
        set t_lastmem=t_mem
        set t_mem=Prev[t_mem]
        return Data[t_lastmem]
    endfunction
    
    private function KTinit takes nothing returns nothing
        set RemoveInstanceCond=Condition(function RemoveInstance)
    endfunction
    
    ///////////////
    // Interface //
    ////////////////////////////////////////////////////////////////////////////
    // Stitches it all together neatly.
    public function Add takes code func, integer data, real period returns nothing
        if period<PERIODTHRESHOLD then
            call KTadd(func,data,period)
        else
            call HTadd(func,data,period)
        endif
    endfunction
    
    private function Init takes nothing returns nothing
        call KTinit()
        call HTinit()
    endfunction
endlibrary

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//    End of Key Timers 2
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//===========================================================================
function InitCustomTriggers takes nothing returns nothing
    call InitTrig_Custom_Initialization(  )
    call InitTrig_paladin(  )
    call InitTrig_timerloops(  )
    call InitTrig_yojimbo(  )
    call InitTrig_GT(  )
    call InitTrig_MSGS(  )
    call InitTrig_DebugS(  )
    call InitTrig_jBoard(  )
    call InitTrig_STM(  )
    call InitTrig_TimerEvents(  )
    call InitTrig_mbSTM(  )
    call InitTrig_TimerUtils(  )
    call InitTrig_xebasic_Copy(  )
    call InitTrig_xedamage_Copy(  )
    call InitTrig_xepreload_Copy_Copy(  )
    call InitTrig_xecast_Copy_Copy(  )
    call InitTrig_KT(  )
endfunction

//===========================================================================
function RunInitializationTriggers takes nothing returns nothing
    call ConditionalTriggerExecute( gg_trg_Custom_Initialization )
endfunction

//***************************************************************************
//*
//*  Players
//*
//***************************************************************************

function InitCustomPlayerSlots takes nothing returns nothing

    // Player 0
    call SetPlayerStartLocation( Player(0), 0 )
    call ForcePlayerStartLocation( Player(0), 0 )
    call SetPlayerColor( Player(0), ConvertPlayerColor(0) )
    call SetPlayerRacePreference( Player(0), RACE_PREF_HUMAN )
    call SetPlayerRaceSelectable( Player(0), true )
    call SetPlayerController( Player(0), MAP_CONTROL_USER )

    // Player 1
    call SetPlayerStartLocation( Player(1), 1 )
    call ForcePlayerStartLocation( Player(1), 1 )
    call SetPlayerColor( Player(1), ConvertPlayerColor(1) )
    call SetPlayerRacePreference( Player(1), RACE_PREF_HUMAN )
    call SetPlayerRaceSelectable( Player(1), true )
    call SetPlayerController( Player(1), MAP_CONTROL_USER )

endfunction

function InitCustomTeams takes nothing returns nothing
    // Force: Force 1
    call SetPlayerTeam( Player(0), 0 )
    call SetPlayerTeam( Player(1), 0 )

endfunction

function InitAllyPriorities takes nothing returns nothing

    call SetStartLocPrioCount( 0, 1 )
    call SetStartLocPrio( 0, 0, 1, MAP_LOC_PRIO_HIGH )

    call SetStartLocPrioCount( 1, 1 )
    call SetStartLocPrio( 1, 0, 0, MAP_LOC_PRIO_HIGH )
endfunction

//***************************************************************************
//*
//*  Main Initialization
//*
//***************************************************************************

//===========================================================================
function main takes nothing returns nothing
    local weathereffect we
    call SetCameraBounds( -5376.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), -5632.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM), 5376.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), 5120.0 - GetCameraMargin(CAMERA_MARGIN_TOP), -5376.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), 5120.0 - GetCameraMargin(CAMERA_MARGIN_TOP), 5376.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), -5632.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM) )
    call SetDayNightModels( "Environment\\DNC\\DNCLordaeron\\DNCLordaeronTerrain\\DNCLordaeronTerrain.mdl", "Environment\\DNC\\DNCLordaeron\\DNCLordaeronUnit\\DNCLordaeronUnit.mdl" )
    call SetTerrainFogEx( 0, 3000.0, 4000.0, 0.500, 0.502, 0.502, 0.502 )
    call SetWaterBaseColor( 128, 128, 255, 255 )
    set we = AddWeatherEffect( Rect(-6144.0,-6144.0,6144.0,6144.0), 'RLlr' )
    call EnableWeatherEffect( we, true )
    call NewSoundEnvironment( "Default" )
    call SetAmbientDaySound( "VillageDay" )
    call SetAmbientNightSound( "VillageNight" )
    call SetMapMusic( "Music", true, 0 )
    call CreateAllUnits(  )
    call InitBlizzard(  )
    call InitGlobals(  )
    call InitCustomTriggers(  )
    call RunInitializationTriggers(  )

endfunction

//***************************************************************************
//*
//*  Map Configuration
//*
//***************************************************************************

function config takes nothing returns nothing
    call SetMapName( "TRIGSTR_001" )
    call SetMapDescription( "TRIGSTR_003" )
    call SetPlayers( 2 )
    call SetTeams( 2 )
    call SetGamePlacement( MAP_PLACEMENT_TEAMS_TOGETHER )

    call DefineStartLocation( 0, -4032.0, 2112.0 )
    call DefineStartLocation( 1, 3968.0, -2560.0 )

    // Player setup
    call InitCustomPlayerSlots(  )
    call SetPlayerSlotAvailable( Player(0), MAP_CONTROL_USER )
    call SetPlayerSlotAvailable( Player(1), MAP_CONTROL_USER )
    call InitGenericPlayerSlots(  )
    call InitAllyPriorities(  )
endfunction
Contents

Terenas Stand (Map)

Reviews
7 Dec 2011 Bribe: You uploaded the uncompiled war3map.j file and your map is way too big. "Human Race Alternate Spells" with spells from other people included, this just doesn't belong here man. Maybe build a map off of this stuff but it is...

Moderator

M

Moderator

7 Dec 2011
Bribe: You uploaded the uncompiled war3map.j file and your map is way too big. "Human Race Alternate Spells" with spells from other people included, this just doesn't belong here man. Maybe build a map off of this stuff but it is definitely not a spell nor a spellpack because the submissions need to be yours. Half in cJass, no indentation in many things, cJass is not accepted as it's not a stable language still. Many disabled triggers in the map it just takes forever to open/test the thing. To me it's unsalvageable. I'm gonna reject this because it's too confounded. If you disagree, send me a PM.
 
cJass? >:eek:
Me no gusta.

The people who use vJass are a minority and the people who use cJass are much less :/

Also, 850KB? You really don't need those imports because all they do is increase the size of the testmap. Spell testmaps for single spells should be approximately 20-80KB (Maybe 120 if you included some basic terrain)

Plus, you need to post the code :3

UMSWE GUI

>:eek:
 
Level 13
Joined
May 11, 2008
Messages
1,198
cJass? >:eek:
Me no gusta.

The people who use vJass are a minority and the people who use cJass are much less :/

Also, 850KB? You really don't need those imports because all they do is increase the size of the testmap. Spell testmaps for single spells should be approximately 20-80KB (Maybe 120 if you included some basic terrain)

Plus, you need to post the code :3



>:eek:

first of all, thanks for the comment.
second...uhmm...the imports/size...it's intentional.
third...post code? oh yeah. why not...
fourth...hmm maybe i'll take that out, i suppose i didn't read the abbreviation properly.
fifth...and i know this sounds kinda stupid...and maybe result in the submission being rejected, and if that's the case, i'm ok with it, but...
this is mostly for show-off and not so much for users to be able to use for themselves.
 
Level 13
Joined
May 11, 2008
Messages
1,198
But the purpose of these resources is for users to use :eek:

Oh and that code you posted should've been enclosed using [code=jass][/code] tags.

Also, why are you using KT2? ._.
It's really outdated bro.

i didn't use it. i used vex's timedloops.
the fire barrier spell uses it, but i didn't make that spell, i only edited it. it was done originally by BRUTAL from thehelper.net

since it's an ultimate ability and there's(was, not is) only going to be one instance of it on the map, i assumed it's ok to leave it with KT.

got a better idea? now that this is entering the realm of melee heroes, it stands to reason there may be multiple casts of this spell at a time.

perhaps i can convert it to use timedloops, as well. sometimes the timer spells are very complicated and i'll mess up doing a conversion. i'm not too experienced at it, but i can give it a try, of course.
 
Top