• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

[Spell] These 2 spells are a little bugged.

Level 17
Joined
Jul 19, 2007
Messages
970
Ok here is 2 spells I have imported from a spell pack and they seems to be working fine actually but the silence-effect doesn't appear on attacked enemies when "Dark Blade" is active and even more wierd, the "Charging Strikes" spell sometimes seems to silence enemies that are damage by the spell, even if it doesn't have "Dark Blade" spell active. Why is this bugs happening? Here is describtion how the spells works like.

db.webp

cs.webp


Here is the triggers for these spells and they seems to be using a "Dummy Caster" system for it.
JASS:
//TESH.scrollpos=3
//TESH.alwaysfold=0
library DarkBlades initializer InitTrig uses Damage

//=====================================================================//
//                           Dark Blades                               //
//                      by iAyanami aka Glenphir                       //
//=====================================================================//
//                                                                     //
//=====================================================================//
//                     Implementation Instructions                     //
//---------------------------------------------------------------------//
// Copy these objects into your map                                    //
// [Abilities]                                                         //
// 1) Dark Blades                                                      //
// 2) Dark Blades (Spell Book)                                         //
// 3) Dark Blades (Damage - Level 1)                                   //
// 4) Dark Blades (Damage - Level 2)                                   //
// 5) Dark Blades (Damage - Level 3)                                   //
// 6) Dark Blades (Damage - Level 4)                                   //
// 7) Dark Blades (Silence)                                            //
// Ensure that 3), 4), 5), and 6) are inside the Spell Book, 2)        //
//                                                                     //
// [Buffs]                                                             //
// 1) Dark Blades (Caster)                                             //
// 2) Dark Blades (Target)                                             //
//                                                                     //
//=====================================================================//

//=====================================================================//
//                       CONFIGURATION                                 //
//=====================================================================//

globals
    private constant integer ABIL_ID1 = 'A0TE' // raw code of Ability "Dark Blades"
    private constant integer ABIL_ID2 = 'A0TF' // raw code of Ability "Dark Blades (Spell Book)"
    private constant integer ABIL_ID3 = 'A0TD' // raw code of Ability "Dark Blades (Silence)"
    private constant integer BUFF_ID = 'B08S' // raw code of Buff "Dark Blades (Caster)"
    private constant boolean PLAYSOUND = false // true if sound is played upon casting
endglobals

private function GetDuration takes unit caster returns real
    return 2.00 + (GetUnitAbilityLevel(caster, ABIL_ID1)) // duration of the spell
endfunction

//=====================================================================//
//                       END CONFIGURATION                             //
//=====================================================================//

private struct db
    unit u
    real r
endstruct
   
public function GetDarkBlades takes unit u returns integer
    return GetUnitAbilityLevel(u, ABIL_ID1)
endfunction

public function GetSilenceAbil takes nothing returns integer
    return ABIL_ID3
endfunction

public function GetSilence takes unit u returns integer
    return GetUnitAbilityLevel(u, ABIL_ID1)
endfunction

private function Expire takes nothing returns boolean
    local db d = KT_GetData()
    set d.r = d.r - 0.10
    if d.r <= 0.00 then
        call UnitRemoveAbility(d.u, ABIL_ID2)
        call UnitRemoveAbility(d.u, BUFF_ID)
        call d.destroy()
        return true
    elseif GetUnitAbilityLevel(d.u, ABIL_ID2) == 0 then
        call UnitAddAbility(d.u, ABIL_ID2)
        call SetUnitAbilityLevel(d.u, ABIL_ID2, GetUnitAbilityLevel(d.u, ABIL_ID1))
    endif
    return false
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == ABIL_ID1
endfunction

private function Actions takes nothing returns nothing
    local db d = db.create()
    set d.u = GetTriggerUnit()
    set d.r = GetDuration(d.u)
    if PLAYSOUND then
    endif
    call UnitAddAbility(d.u, ABIL_ID2)
    call SetUnitAbilityLevel(d.u, ABIL_ID2, GetUnitAbilityLevel(d.u, ABIL_ID1))
    call KT_Add(function Expire, d, 0.10)
endfunction

private function Silence takes nothing returns boolean
    local unit c = GetEventDamageSource()
    local unit t = GetTriggerUnit()
    if Damage_IsAttack() and GetUnitAbilityLevel(c, BUFF_ID) > 0 then
        call CasterDummy_TargetPoint(c, GetUnitX(t), GetUnitY(t), ABIL_ID3, GetUnitAbilityLevel(c, ABIL_ID1), "silence")
    endif
    set c = null
    set t = null
    return false
endfunction

private function InitTrig takes nothing returns nothing
    local trigger t = CreateTrigger()
    local trigger t2 = CreateTrigger()
    local integer i = 0
    loop
        exitwhen i == 12
        call SetPlayerAbilityAvailable(Player(i), ABIL_ID2, false)
        set i = i + 1
    endloop
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Actions)
    call TriggerAddCondition(t2, Condition(function Silence))
    call Damage_RegisterEvent(t2)
endfunction

endlibrary

JASS:
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ChargingStrikes initializer InitTrig

//=====================================================================//
//                         Charging Strikes                            //
//                      by iAyanami aka Glenphir                       //
//=====================================================================//
//                                                                     //
//=====================================================================//
//                     Implementation Instructions                     //
//---------------------------------------------------------------------//
// Copy these objects into your map                                    //
// [Abilities]                                                         //
// 1) Charging Strikes                                                 //
// 2) Charging Strikes (Attack Speed)                                  //
//                                                                     //
//=====================================================================//

//=====================================================================//
//                       CONFIGURATION                                 //
//=====================================================================//

globals
    private constant integer ABIL_ID1 = 'A0TG' // raw code of Ability "Charging Strikes"
    private constant integer ABIL_ID2 = 'A0TH' // raw code of Ability "Charging Strikes (Attack Speed)"
    
    private constant real MINDMG = 23.00 // minimum damage dealt
    private constant real MAXDMG = 25.00 // maximum damage dealt
    private constant real TIME = 0.25 // time taken for charge
    private constant real AOE = 150.00 // area of effect of the damage
    
    private constant string SLIDE_EFFECT = "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl" // special effect of the charge. set to "none.mdl" if no effects are desired
    private constant string HIT_EFFECT = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl" // special effect on the targets when they are hit. set to "none.mdl" if no effects are desired.
    private constant string HIT_ATTACH = "chest" // attachment point of HIT_EFFECT
    
    private constant boolean STR = false // true if the hero's primary attribute is strength
    private constant boolean AGI = true // true if the hero's primary attribute is agility
    private constant boolean INT = false // true if the hero's primary attribute is intelligence
    // if all is set to false, damage dealt will be random number between MINDMG and MAXDMG
endglobals

private function GetDuration takes unit caster returns real
    return 6.00 // duration of attack speed bonus 
endfunction

globals
    private constant boolean EXTRADMG = true // set to true to deal extra damage and silence enemies if dark blades are activated
endglobals

private function GetExtraDamage takes unit caster, real damage returns real
    local integer i = DarkBlades_GetDarkBlades(caster)
    if i == 0 then
        return damage
    endif
    return damage * (1.30 + (0.20 * DarkBlades_GetDarkBlades(caster))) // new damage dealt
endfunction

//=====================================================================//
//                       END CONFIGURATION                             //
//=====================================================================//

private struct cs
    real offsetx
    real offsety
    real dist
    real speed
    real damage
    real r
    group g
    unit u
endstruct

private function GetDamage takes unit caster returns real
    if STR then
        return GetRandomReal(MINDMG, MAXDMG) + I2R(GetHeroStr(caster, true)) 
    elseif AGI then
        return GetRandomReal(MINDMG, MAXDMG) + I2R(GetHeroAgi(caster, true)) 
    elseif INT then
        return GetRandomReal(MINDMG, MAXDMG) + I2R(GetHeroInt(caster, true)) 
    endif
    return GetRandomReal(MINDMG, MAXDMG)
endfunction

private function AttackSpeed takes nothing returns boolean
    local cs d = KT_GetData()
    set d.r = d.r - 0.10
    if d.r <= 0 then
        call UnitRemoveAbility(d.u, ABIL_ID2)
        call d.destroy()
        return true
    elseif GetUnitAbilityLevel(d.u, ABIL_ID2) == 0 then
        call UnitAddAbility(d.u, ABIL_ID2)
        call SetUnitAbilityLevel(d.u, ABIL_ID2, GetUnitAbilityLevel(d.u, ABIL_ID1))
    endif
    return false
endfunction

private function Slide takes nothing returns boolean
    local cs d = KT_GetData()
    local group g = Group.get()
    local real x = GetUnitX(d.u) + d.offsetx
    local real y = GetUnitY(d.u) + d.offsety
    local real damage
    local unit u
    if d.dist <= 0 then
        call SetUnitPathing(d.u, true)
        call UnitAddAbility(d.u, ABIL_ID2)
        call SetUnitAbilityLevel(d.u, ABIL_ID2, GetUnitAbilityLevel(d.u, ABIL_ID1))
        call KT_Add(function AttackSpeed, d, 0.10)
        call Group.release(d.g)
        return true
    elseif not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) then
        call SetUnitPathing(d.u, false)
        call SetUnitX(d.u, x)
        call SetUnitY(d.u, y)
    endif
    call AddSpecialEffect(SLIDE_EFFECT, x, y)
    call DestroyEffect(bj_lastCreatedEffect)
    set d.dist = d.dist - d.speed
    call GroupEnumUnitsInRange(g, x, y, AOE, null)
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitEnemy(u, GetOwningPlayer(d.u)) and not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitInGroup(u, d.g) then
            if EXTRADMG == true then
                call CasterDummy_TargetPoint(d.u, GetUnitX(u), GetUnitY(u), DarkBlades_GetSilenceAbil(), DarkBlades_GetDarkBlades(d.u), "silence")
            endif
            call UnitDamageTargetEx2(d.u, u, d.damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
            call AddSpecialEffectTarget(HIT_EFFECT, u, HIT_ATTACH)
            call GroupAddUnit(d.g, u)
            set d.damage = d.damage * 0.85
        endif
        call GroupRemoveUnit(g, u)
    endloop
    call Group.release(g)
    set g = null
    set u = null
    return false
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == ABIL_ID1
endfunction

private function Actions takes nothing returns nothing
    local cs d = cs.create()
    local real dx = GetSpellTargetX()
    local real dy = GetSpellTargetY()
    local real angle
    local real x
    local real y
    set d.damage = GetDamage(d.u)
    if EXTRADMG == true then
        set d.damage = GetExtraDamage(d.u, d.damage)
    endif
    set d.g = Group.get()
    set d.u = GetTriggerUnit()
    set x = GetUnitX(d.u)
    set y = GetUnitY(d.u)
    set angle = Atan2(dy - y, dx - x)
    set d.dist = SquareRoot(((x - dx) * (x - dx)) + ((y - dy) * (y - dy)))
    set d.speed = d.dist / TIME * 0.03
    set d.offsetx = d.speed * Cos(angle)
    set d.offsety = d.speed * Sin(angle)
    set d.r = GetDuration(d.u)
    call KT_Add(function Slide, d, 0.03)
endfunction

private function InitTrig takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Actions)
endfunction

endscope
[CODE=JASS]
//TESH.scrollpos=0
//TESH.alwaysfold=0
library CasterDummy initializer InitTrig

//=====================================================================//
//                       CONFIGURATION                                 //
//=====================================================================//

globals
    private constant integer DUMMY_ID = 'n023' // raw code of Caster Dummy
endglobals

//=====================================================================//
//                       END CONFIGURATION                             //
//=====================================================================//

globals
    private unit dummy
endglobals

public function TargetUnit takes unit owner, unit target, integer abil, integer level, string order returns nothing
    call UnitAddAbility(dummy, abil)
    call SetUnitAbilityLevel(dummy, abil, level)
    call SetUnitOwner(dummy, GetOwningPlayer(owner), false)
    call IssueTargetOrder(dummy, order, target)
    call UnitRemoveAbility(dummy, abil)
endfunction

public function TargetPoint takes unit owner, real x, real y, integer abil, integer level, string order returns nothing
    call UnitAddAbility(dummy, abil)
    call SetUnitAbilityLevel(dummy, abil, level)
    call SetUnitOwner(dummy, GetOwningPlayer(owner), false)
    call IssuePointOrder(dummy, order, x, y)
    call UnitRemoveAbility(dummy, abil)
endfunction

private function InitTrig takes nothing returns nothing
    local trigger t = CreateTrigger()
    set dummy = CreateUnit(Player(0), DUMMY_ID, 0.00, 0.00, 0.00)
endfunction

endlibrary

So why isn't the attacked unit silenced if "Dark Blade" is active and why does "Charging Strikes" sometimes silence damaged enemies by the spell, even if "Dark Blade" isn't active? And yes I have checked everything and rawcodes is correct. These bugs is even happening on the original spell pack map...
 
Last edited:
Are the descriptions of Dark Blade and Charging Strike also from the spell pack (i.e. written by spell's author) or are those descriptions your own, i.e. how you image the spells should work?

Dark Blade uses library "Damage", as well as other as it seems (i.e. there are calls like "KT_GetData", which I assume is some "KT" library, also calls like Group.get(), but nowhere do I see declaration of a struct called Group).
It would be helpful to:
  • post all related code
  • write the base abilities your custom abilities are based off (e.g. I can assume from usage that
    Code:
    private constant integer ABIL_ID3 = 'A0TD' // raw code of Ability "Dark Blades (Silence)"
    is based off Banshee's Silence ability, but I don't understand the other spells.

Why Dark Blade does not sometimes apply Silence:
It most likely uses the "Damage" library, I can only see following:
JASS:
private function Silence takes nothing returns boolean
    ...
endfunction

private function InitTrig takes nothing returns nothing
    ...
    call TriggerAddCondition(t2, Condition(function Silence))
    call Damage_RegisterEvent(t2)
endfunction
The Silence function seems to be the one applying Silence on units, but the "Damage_RegisterEvent" function most likely comes from the "Damage" library. Since you did not post script for it, nobody can determine why it's not being applied.

Why Charging Strikes applies silence:
There is actually no code that would check if Dark Blade is active. What is checked is if Dark Blade is learned (i.e. level is greater than 0) and if so, bonus damage and Silence is applied.
 
Are the descriptions of Dark Blade and Charging Strike also from the spell pack (i.e. written by spell's author) or are those descriptions your own, i.e. how you image the spells should work?

Dark Blade uses library "Damage", as well as other as it seems (i.e. there are calls like "KT_GetData", which I assume is some "KT" library, also calls like Group.get(), but nowhere do I see declaration of a struct called Group).
It would be helpful to:
  • post all related code
  • write the base abilities your custom abilities are based off (e.g. I can assume from usage that
    Code:
    private constant integer ABIL_ID3 = 'A0TD' // raw code of Ability "Dark Blades (Silence)"
    is based off Banshee's Silence ability, but I don't understand the other spells.

Why Dark Blade does not sometimes apply Silence:
It most likely uses the "Damage" library, I can only see following:
JASS:
private function Silence takes nothing returns boolean
    ...
endfunction

private function InitTrig takes nothing returns nothing
    ...
    call TriggerAddCondition(t2, Condition(function Silence))
    call Damage_RegisterEvent(t2)
endfunction
The Silence function seems to be the one applying Silence on units, but the "Damage_RegisterEvent" function most likely comes from the "Damage" library. Since you did not post script for it, nobody can determine why it's not being applied.

Why Charging Strikes applies silence:
There is actually no code that would check if Dark Blade is active. What is checked is if Dark Blade is learned (i.e. level is greater than 0) and if so, bonus damage and Silence is applied.
Dark Blades is based on the "Berserk" ability and the dummy ability (Dark Blades (Damage - Level 1) is Command Aura.
Charging Strikes is based on the "Channel" ability with "channel" as based order ID.

Here is the "Damage" system.
JASS:
//TESH.scrollpos=75
//TESH.alwaysfold=0
//  
//      ___   _     __  __   _   ___  ____    _______________________________
//     |   \ /_\   /  |/  | /_\ /  _\|  __|   ||      D E A L   I T ,      ||
//     | |) / _ \ / / | / |/ _ \| |/||  __|   ||    D E T E C T   I T ,    ||
//     |___/_/ \_/_/|__/|_|_/ \_\___/|____|   ||     B L O C K   I T .     ||
//                            By Jesus4Lyf    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//                                                                    v 1.0.5
//      What is Damage?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          Damage is a damage dealing, detection and blocking system. It implements
//          all such functionality. It also provides a means to detect what type
//          of damage was dealt, so long as all damage in your map is dealt using
//          this system's deal damage functions (except for basic attacks).
//
//          It is completely recursively defined, meaning if you deal damage on
//          taking damage, the type detection and other features like blocking
//          will not malfunction.
//          
//      How to implement?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          Create a new trigger object called Damage, go to 'Edit -> Convert to
//          Custom Text', and replace everything that's there with this script.
//
//          At the top of the script, there is a '//! external ObjectMerger' line.
//          Save your map, close your map, reopen your map, and then comment out this
//          line. Damage is now implemented. This line creates a dummy ability used
//          in the system in some circumstances with damage blocking.
//
//      Functions:
//     ¯¯¯¯¯¯¯¯¯¯¯¯
//          function Damage_RegisterEvent takes trigger whichTrigger returns nothing
//              - This registers a special "any unit takes damage" event.
//              - This event supports dynamic trigger use.
//              - Only triggers registered on this event may block damage.
//              - Only fires when the damage dealt is not 0.
//
//          function Damage_RegisterZeroEvent takes trigger whichTrigger returns nothing
//              - The same as Damage_RegisterEvent, but for only zero damage events
//                (which are excluded from Damage_RegisterEvent).
//              - Note that getting the damage type may be unreliable, since spells
//                like faerie fire trigger 0 damage, but it will count as an attack.
//
//          function Damage_GetType takes nothing returns damagetype
//              - This will get the type of damage dealt, like an event response,
//                for when using a unit takes damage event (or the special event above).
//
//          function Damage_IsPhysical takes nothing returns boolean
//          function Damage_IsSpell takes nothing returns boolean
//          function Damage_IsPure takes nothing returns boolean
//              - Wrappers to simply check if Damage_GetType is certain types.
//
//          function Damage_IsAttack takes nothing returns boolean
//              - Checks if the damage is from a physical attack (so you can deal
//                physical damage without it being registered as an actual attack).
//
//          function Damage_Block takes real amount returns nothing
//          function Damage_BlockAll takes nothing returns nothing
//              - For use only with Damage_RegisterEvent.
//              - Blocks 'amount' of the damage dealt.
//              - Multiple blocks at once work correctly.
//              - Blocking more than 100% of the damage will block 100% instead.
//              - Damage_BlockAll blocks 100% of the damage being dealt.
//
//          function Damage_EnableEvent takes boolean enable returns nothing
//              - For disabling and re-enabling the special event.
//              - Use it to deal damage which you do not want to be detected by
//                the special event.
//
//          function UnitDamageTargetEx takes lots of things returns boolean
//              - Replaces UnitDamageTarget in your map, with the same arguments.
//
//          function Damage_Physical takes unit source, unit target, real amount,
//            attacktype whichType, boolean attack, boolean ranged returns boolean
//              - A clean wrapper for physical damage.
//              - 'attack' determines if this is to be treated as a real physical
//                attack or just physical type damage.
//              - 'ranged' determines if this is to be treated as a ranged or melee
//                attack.
//
//          function Damage_Spell takes unit source, unit target, real amount returns boolean
//              - A clean wrapper for spell damage.
//
//          function Damage_Pure takes unit source, unit target, real amount returns boolean
//              - A clean wrapper for pure type damage (universal type, 100% damage).
//          
//      Thanks:
//     ¯¯¯¯¯¯¯¯¯
//          - Romek, for helping me find a better way to think about damage blocking.
//
library Damage uses AIDS, Event
    //============================================================
    // external ObjectMerger w3a AIlz dprv anam "Life Bonus" ansf "(Damage System)" Ilif 1 500000 aite 0
    globals
        private constant integer LIFE_BONUS_ABIL='dprv'
    endglobals
    
    //============================================================
    globals
        private Event OnDamageEvent
        private Event OnZeroDamageEvent
        private boolean EventEnabled=true
    endglobals
    
    public function RegisterEvent takes trigger whichTrigger returns nothing
        call OnDamageEvent.register(whichTrigger)
    endfunction
    
    public function RegisterZeroEvent takes trigger whichTrigger returns nothing
        call OnZeroDamageEvent.register(whichTrigger)
    endfunction
    
    public function EnableEvent takes boolean enable returns nothing
        set EventEnabled=enable
    endfunction
    
    //============================================================
    globals
        private integer TypeStackLevel=0
        private damagetype array TypeStackValue
        private boolean array TypeStackAttack
        private real array ToBlock
    endglobals
    
    public function GetType takes nothing returns damagetype
        return TypeStackValue[TypeStackLevel]
    endfunction
    
    public function IsAttack takes nothing returns boolean
        return TypeStackAttack[TypeStackLevel]
    endfunction
    
    public function Block takes real amount returns nothing
        set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+amount
    endfunction
    
    public function BlockAll takes nothing returns nothing
        set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+GetEventDamage()
    endfunction
    
    //============================================================
    globals
        private integer BlockNum=0
        private unit array BlockUnit
        private real array BlockUnitLife
        private real array BlockRedamage
        private unit array BlockDamageSource
        
        private timer BlockTimer=CreateTimer()
    endglobals
    
    //============================================================
    globals
        private unit array RemoveBoosted
        private integer RemoveBoostedMax=0
        
        private timer RemoveBoostedTimer=CreateTimer()
    endglobals
    
    globals//locals
        private real BoostedLifeTemp
        private unit BoostedLifeUnit
    endglobals
    private function RemoveBoostedTimerFunc takes nothing returns nothing
        loop
            exitwhen RemoveBoostedMax==0
            set BoostedLifeUnit=RemoveBoosted[RemoveBoostedMax]
            set BoostedLifeTemp=GetWidgetLife(BoostedLifeUnit)
            call UnitRemoveAbility(BoostedLifeUnit,LIFE_BONUS_ABIL)
            if BoostedLifeTemp>0.405 then
                call SetWidgetLife(BoostedLifeUnit,BoostedLifeTemp)
            endif
            set RemoveBoostedMax=RemoveBoostedMax-1
        endloop
    endfunction
    
    //============================================================
    private keyword Detector // Darn, I actually had to do this. XD
    globals//locals
        private unit ForUnit
        private real NextHealth
    endglobals
    private function OnDamageActions takes nothing returns boolean
        if EventEnabled then
            if GetEventDamage()==0. then
                call OnZeroDamageEvent.fire()
            else
                call OnDamageEvent.fire()
            endif
            
            if ToBlock[TypeStackLevel]!=0. then
                //====================================================
                // Blocking
                set ForUnit=GetTriggerUnit()
                
                set NextHealth=GetEventDamage()
                if ToBlock[TypeStackLevel]>=NextHealth then
                    set NextHealth=GetWidgetLife(ForUnit)+NextHealth
                else
                    set NextHealth=GetWidgetLife(ForUnit)+ToBlock[TypeStackLevel]
                endif
                
                call SetWidgetLife(ForUnit,NextHealth)
                if GetWidgetLife(ForUnit)<NextHealth then
                    // NextHealth is over max health.
                    call UnitAddAbility(ForUnit,LIFE_BONUS_ABIL)
                    call SetWidgetLife(ForUnit,NextHealth)
                    
                    set RemoveBoostedMax=RemoveBoostedMax+1
                    set RemoveBoosted[RemoveBoostedMax]=ForUnit
                    call ResumeTimer(RemoveBoostedTimer)
                endif
                //====================================================
                set ToBlock[TypeStackLevel]=0.
            endif
        endif
        return false
    endfunction
    
    //============================================================
    function UnitDamageTargetEx2 takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
        local boolean result
        set TypeStackLevel=TypeStackLevel+1
        set TypeStackValue[TypeStackLevel]=damageType
        set TypeStackAttack[TypeStackLevel]=attack
        set result=UnitDamageTarget(whichUnit,target,amount,attack,ranged,attackType,damageType,weaponType)
        set TypeStackLevel=TypeStackLevel-1
        return result
    endfunction
    //! textmacro Damage__DealTypeFunc takes NAME, TYPE
        public function $NAME$ takes unit source, unit target, real amount returns boolean
            return UnitDamageTargetEx2(source,target,amount,false,false,ATTACK_TYPE_NORMAL,$TYPE$,WEAPON_TYPE_WHOKNOWS)
        endfunction
        public function Is$NAME$ takes nothing returns boolean
            return GetType()==$TYPE$
        endfunction
    //! endtextmacro
    
    //! runtextmacro Damage__DealTypeFunc("Pure","DAMAGE_TYPE_UNIVERSAL")
    //! runtextmacro Damage__DealTypeFunc("Spell","DAMAGE_TYPE_MAGIC")
    
    // Uses different stuff, but works much the same way.
    public function Physical takes unit source, unit target, real amount, attacktype whichType, boolean attack, boolean ranged returns boolean
        return UnitDamageTargetEx2(source,target,amount,attack,ranged,whichType,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
    endfunction
    public function IsPhysical takes nothing returns boolean
        return GetType()==DAMAGE_TYPE_NORMAL
    endfunction
    
    //============================================================
    private struct Detector extends array // Uses AIDS.
        //! runtextmacro AIDS()
        
        private static conditionfunc ACTIONS_COND
        
        private trigger t
        
        private method AIDS_onCreate takes nothing returns nothing
            set this.t=CreateTrigger()
            call TriggerAddCondition(this.t,thistype.ACTIONS_COND)
            call TriggerRegisterUnitEvent(this.t,this.unit,EVENT_UNIT_DAMAGED)
        endmethod
        
        private method AIDS_onDestroy takes nothing returns nothing
            call DestroyTrigger(this.t)
        endmethod
        
        private static method AIDS_onInit takes nothing returns nothing
            set thistype.ACTIONS_COND=Condition(function OnDamageActions)
        endmethod
    endstruct
    
    //============================================================
    private module InitModule
        private static method onInit takes nothing returns nothing
            local unit abilpreload=CreateUnit(Player(15),'uloc',0,0,0)
            call UnitAddAbility(abilpreload,LIFE_BONUS_ABIL)
            call RemoveUnit(abilpreload)
            set abilpreload=null
            
            set OnDamageEvent=Event.create()
            set OnZeroDamageEvent=Event.create()
            set TypeStackValue[TypeStackLevel]=DAMAGE_TYPE_NORMAL
            set TypeStackAttack[TypeStackLevel]=true
            call TimerStart(RemoveBoostedTimer,0.0,false,function RemoveBoostedTimerFunc)
        endmethod
    endmodule
    private struct InitStruct extends array
        implement InitModule
    endstruct
endlibrary
 
The "Damage" library is dependent on other libraries, as can be seen right after the initial comment block:
JASS:
library Damage uses AIDS, Event
So this library uses AIDS and Event libraries. Post them if you can.

So far from what I was able to piece together:
  • the "Damage" library runs whenever any unit takes damage
  • once unit takes damage, it will run its 'OnDamageActions' function
  • that function checks if damage taken is greater than 0, if so, it will do call OnDamageEvent.fire()
  • The "OnDamageEvent" (which is from "Event" library) references and runs the "Silence" function from Dark Blade
  • Your "Silence" function is checking if Damage_IsAttack() call returns true
  • the "Damage_IsAttack" will return true only if "Damage_Physical" was called
  • I do not see "Damage_Physical" called anywhere

I don't know if "Damage_Physical" is called anywhere from the AIDS or Event libraries, but if not, it would explain why Dark Blade never silences anyone.
 
The "Damage" library is dependent on other libraries, as can be seen right after the initial comment block:
JASS:
library Damage uses AIDS, Event
So this library uses AIDS and Event libraries. Post them if you can.

So far from what I was able to piece together:
  • the "Damage" library runs whenever any unit takes damage
  • once unit takes damage, it will run its 'OnDamageActions' function
  • that function checks if damage taken is greater than 0, if so, it will do call OnDamageEvent.fire()
  • The "OnDamageEvent" (which is from "Event" library) references and runs the "Silence" function from Dark Blade
  • Your "Silence" function is checking if Damage_IsAttack() call returns true
  • the "Damage_IsAttack" will return true only if "Damage_Physical" was called
  • I do not see "Damage_Physical" called anywhere

I don't know if "Damage_Physical" is called anywhere from the AIDS or Event libraries, but if not, it would explain why Dark Blade never silences anyone.
Ok here they are.
JASS:
//TESH.scrollpos=0
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  ~~    Event     ~~    By Jesus4Lyf    ~~    Version 1.04    ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is Event?
//         - Event simulates Warcraft III events. They can be created,
//           registered for, fired and also destroyed.
//         - Event, therefore, can also be used like a trigger "group".
//         - This was created when there was an influx of event style systems 
//           emerging that could really benefit from a standardised custom
//           events snippet. Many users were trying to achieve the same thing
//           and making the same kind of errors. This snippet aims to solve that.
//
//  Functions:
//         - Event.create()       --> Creates a new Event.
//         - .destroy()           --> Destroys an Event.
//         - .fire()              --> Fires all triggers which have been
//                                    registered on this Event.
//         - .register(trigger)   --> Registers another trigger on this Event.
//         - .unregister(trigger) --> Unregisters a trigger from this Event.
//
//  Details:
//         - Event is extremely efficient and lightweight.
//         - It is safe to use with dynamic triggers.
//         - Internally, it is just a linked list. Very simple.
//
//  How to import:
//         - Create a trigger named Event.
//         - Convert it to custom text and replace the whole trigger text with this.
//
//  Thanks:
//         - Builder Bob for the trigger destroy detection method.
//         - Azlier for inspiring this by ripping off my dodgier code.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library Event
    ///////////////
    // EventRegs //
    ////////////////////////////////////////////////////////////////////////////
    // For reading this far, you can learn one thing more.
    // Unlike normal Warcraft III events, you can attach to Event registries.
    // 
    // Event Registries are registrations of one trigger on one event.
    // These cannot be created or destroyed, just attached to.
    //
    // It is VERY efficient for loading and saving data.
    // 
    //  Functions:
    //         - set eventReg.data = someStruct --> Store data.
    //         - eventReg.data                  --> Retreive data.
    //         - Event.getTriggeringEventReg()  --> Get the triggering EventReg.
    //         - eventReg.destroy()             --> Undo this registration.
    // 
    private keyword destroyNode
    struct EventReg extends array
        integer data
        method clear takes nothing returns nothing
            set this.data=0
        endmethod
        method destroy takes nothing returns nothing
            call Event(this).destroyNode()
        endmethod
    endstruct
    
    private module Stack
        static thistype top=0
        static method increment takes nothing returns nothing
            set thistype.top=thistype(thistype.top+1)
        endmethod
        static method decrement takes nothing returns nothing
            set thistype.top=thistype(thistype.top-1)
        endmethod
    endmodule
    
    private struct EventStack extends array
        implement Stack
        Event current
    endstruct
    
    struct Event
        private trigger trig
        private thistype next
        private thistype prev
        
        static method getTriggeringEventReg takes nothing returns EventReg
            return EventStack.top.current
        endmethod
        
        static method create takes nothing returns Event
            local Event this=Event.allocate()
            set this.next=this
            set this.prev=this
            return this
        endmethod
        
        private static trigger currentTrigger
        method fire takes nothing returns nothing
            local thistype curr=this.next
            call EventStack.increment()
            loop
                exitwhen curr==this
                set thistype.currentTrigger=curr.trig
                if IsTriggerEnabled(thistype.currentTrigger) then
                    set EventStack.top.current=curr
                    if TriggerEvaluate(thistype.currentTrigger) then
                        call TriggerExecute(thistype.currentTrigger)
                    endif
                else
                    call EnableTrigger(thistype.currentTrigger) // Was trigger destroyed?
                    if IsTriggerEnabled(thistype.currentTrigger) then
                        call DisableTrigger(thistype.currentTrigger)
                    else // If trigger destroyed...
                        set curr.next.prev=curr.prev
                        set curr.prev.next=curr.next
                        call curr.deallocate()
                    endif
                endif
                set curr=curr.next
            endloop
            call EventStack.decrement()
        endmethod
        method register takes trigger t returns EventReg
            local Event new=Event.allocate()
            set new.prev=this.prev
            set this.prev.next=new
            set this.prev=new
            set new.next=this
            
            set new.trig=t
            
            call EventReg(new).clear()
            return new
        endmethod
        method destroyNode takes nothing returns nothing // called on EventReg
            set this.prev.next=this.next
            set this.next.prev=this.prev
            call this.deallocate()
        endmethod
        method unregister takes trigger t returns nothing
            local thistype curr=this.next
            loop
                exitwhen curr==this
                if curr.trig==t then
                    set curr.next.prev=curr.prev
                    set curr.prev.next=curr.next
                    call curr.deallocate()
                    return
                endif
                set curr=curr.next
            endloop
        endmethod
        
        method destroy takes nothing returns nothing
            local thistype curr=this.next
            loop
                call curr.deallocate()
                exitwhen curr==this
                set curr=curr.next
            endloop
        endmethod
        method chainDestroy takes nothing returns nothing
            call this.destroy() // backwards compatability.
        endmethod
    endstruct
    
    /////////////////////////////////////////////////////
    // Demonstration Functions & Alternative Interface //
    ////////////////////////////////////////////////////////////////////////////
    // What this would look like in normal WC3 style JASS (should all inline).
    // 
    function CreateEvent takes nothing returns Event
        return Event.create()
    endfunction
    function DestroyEvent takes Event whichEvent returns nothing
        call whichEvent.chainDestroy()
    endfunction
    function FireEvent takes Event whichEvent returns nothing
        call whichEvent.fire()
    endfunction
    function TriggerRegisterEvent takes trigger whichTrigger, Event whichEvent returns EventReg
        return whichEvent.register(whichTrigger)
    endfunction
    
    // And for EventRegs...
    function SetEventRegData takes EventReg whichEventReg, integer data returns nothing
        set whichEventReg.data=data
    endfunction
    function GetEventRegData takes EventReg whichEventReg returns integer
        return whichEventReg.data
    endfunction
    function GetTriggeringEventReg takes nothing returns integer
        return Event.getTriggeringEventReg()
    endfunction
endlibrary
JASS:
//TESH.scrollpos=7
//TESH.alwaysfold=0
//  
//        _   ___ ___  ___    _______________________________________________
//       /_\ |_ _|   \/ __|   ||     A D V A N C E D   I N D E X I N G     ||
//      / _ \ | || |) \__ \   ||                  A N D                    ||
//     /_/ \_\___|___/|___/   ||         D A T A   S T O R A G E           ||
//            By Jesus4Lyf    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//                                                                    v 1.0.5
//      What is AIDS?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          AIDS assigns unique integers between 1 and 8191 to units which enter
//          the map. These can be used for arrays and data attaching.
//          
//          AIDS also allows you to define structs which are created automatically
//          when units enter the map, and filtering which units should be indexed
//          as well as for which units these structs should be created.
//          
//      How to implement?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          Simply create a new trigger object called AIDS, go to 'Edit -> Convert
//          to Custom Text', and replace everything that's there with this script.
//
//          Save the map, close it, reopen it, and then delete the "!" from the
//          FAR left side of the next lines (so "external" will line up with this line):
//          external ObjectMerger w3a Adef AIDS anam "State Detection" ansf "(AIDS)" aart "" arac 0
//
//          At the top of the script, there is a 'UnitIndexingFilter' constant
//          function. If the function returns true for the unit, then that unit
//          will be automatically indexed. Setting this to true will automatically
//          index all units. Setting it to false will disable automatic indexing.
//
//      Functions:
//     ¯¯¯¯¯¯¯¯¯¯¯¯
//          function GetUnitId takes unit u returns integer
//              - This returns the index of an indexed unit. This will return 0
//                if the unit has not been indexed.
//              - This function inlines. It does not check if the unit needs an
//                index. This function is for the speed freaks.
//              - Always use this if 'UnitIndexingFilter' simply returns true.
//
//          function GetUnitIndex takes unit u returns integer
//              - This will return the index of a unit if it has one, or assign
//                an index if the unit doesn't have one (and return the new index).
//              - Use this if 'UnitIndexingFilter' doesn't return true.
//
//          function GetIndexUnit takes integer index returns unit
//              - This returns the unit which has been assigned the 'index'.
//
//      AIDS Structs:
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          - Insert: //! runtextmacro AIDS() at the top of a struct to make it
//            an AIDS struct.
//          - AIDS structs cannot be created or destroyed manually. Instead, they
//            are automatically created when an appropriate unit enters the map.
//          - You cannot give members default values in their declaration.
//            (eg: private integer i=5 is not allowed)
//          - You cannot use array members.
//          - AIDS structs must "extend array". This will remove some unused
//            functions and enforce the above so there will be no mistakes.
//          - There are four optional methods you can use in AIDS structs:
//              - AIDS_onCreate takes nothing returns nothing
//                  - This is called when the struct is 'created' for the unit.
//                  - In here you can assign members their default values, which
//                    you would usually assign in their declarations.
//                    (eg: set this.i=5)
//              - AIDS_onDestroy takes nothing returns nothing
//                  - This is called when the struct is 'destroyed' for the unit.
//                  - This is your substitute to the normal onDestroy method.
//              - AIDS_filter takes unit u returns boolean
//                  - This is similar to the constant filter in the main system.
//                  - Each unit that enters the map will be tested by each AIDS
//                    struct filter. If it returns true for that unit, that unit
//                    will be indexed if it was not already, the AIDS struct will
//                    have its AIDS_onCreate method called, and later have its
//                    AIDS_onDestroy method called when the index is recycled.
//                  - Not declaring this will use the default AIDS filter instead.
//              - AIDS_onInit takes nothing returns nothing
//                  - This is because I stole your onInit function with my textmacro.
//          - You can use '.unit' from any AIDS struct to get the unit for which
//            the struct is for.
//          - The structs id will be the units index, so getting the struct for
//            a unit inlines to a single native call, and you can typecast between
//            different AIDS structs. This is the premise of AIDS.
//          - Never create or destroy AIDS structs directly.
//          - You can call .AIDS_addLock() and AIDS_removeLock() to increase or
//            decrease the lock level on the struct. If a struct's lock level is
//            not 0, it will not be destroyed until it is reduced to 0. Locks just
//            put off AIDS struct destruction in case you wish to attach to a timer
//            or something which must expire before the struct data disappears.
//            Hence, not freeing all locks will leak the struct (and index).
//
//      PUI and AutoIndex:
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          - AIDS includes the PUI textmacros and the AutoIndex module, because
//            these systems are not compatible with AIDS but have valid and distinct
//            uses.
//          - The PUI textmacros are better to use for spells than AIDS structs,
//            because they are not created for all units, just those targetted by
//            the spell (or whatever else is necessary).
//          - The AutoData module is good for very simple array syntax for data
//            attachment (although I don't recommend that people actually use it,
//            it's here mostly for compatability). Note that unlike the PUI textmacros,
//            units must pass the AIDS filter in order for this module to work with
//            them. This is exactly as the same as in AutoIndex itself (AutoIndex
//            has a filter too).
//          
//      Thanks:
//     ¯¯¯¯¯¯¯¯¯
//          - Romek, for writing 90% of this user documentation, challenging my
//            interface, doing some testing, suggesting improvements and inspiring
//            me to re-do my code to include GetUnitIndex as non-inlining.
//          - grim001, for writing the AutoData module, and AutoIndex. I used the
//            on-enter-map method that he used. Full credits for the AutoData module.
//          - Cohadar, for writing his PUI textmacros. Full credits to him for these,
//            except for my slight optimisations for this system.
//            Also, I have used an optimised version of his PeriodicRecycler from
//            PUI in this system to avoid needing a RemoveUnitEx function.
//          - Vexorian, for helping Cohadar on the PUI textmacro.
//          - Larcenist, for suggesting the AIDS acronym. Originally he suggested
//            'Alternative Index Detection System', but obviously I came up with
//            something better. In fact, I'd say it looks like the acronym was
//            an accident. Kinda neat, don't you think? :P
//
//      Final Notes:
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          - With most systems, I wouldn't usually add substitutes for alternative
//            systems. However, UnitData systems are an exception, because they
//            are incompatible with eachother. Since using this system forbids
//            people from using the real PUI or AutoIndex, and a lot of resources
//            use either of these, it made sense not to break them all.
//
//          - If this documentation confused you as to how to use the system, just
//            leave everything as default and use GetUnitId everywhere.
//
//          - To use this like PUI (if you don't like spamming indices) simply
//            make the AIDS filter return false, and use GetUnitIndex.
//
library AIDS initializer InitAIDS
    //==============================================================================
    // Configurables
    //
    globals
        private constant boolean USE_PERIODIC_RECYCLER = false
        private constant real PERIOD = 0.03125 // Recycles 32 units/second max.
                                               // Lower to be able to recycle faster.
                                               // Only used if USE_PERIODIC_RECYCLER
                                               // is set to true.
        
        private constant integer LEAVE_DETECTION_ABILITY = 'AIDS'
    endglobals
    
    private function UnitIndexingFilter takes unit u returns boolean
        return true
    endfunction
    
    //==============================================================================
    // System code
    //
    globals
        // The unit stored at an index.
        private unit array IndexUnit
        private integer array LockLevel
    endglobals
    
    //==============================================================================
    globals
        // Recycle stack
        private integer array RecycledIndex
        private integer MaxRecycledIndex = 0
        
        // Previous highest index
        private integer MaxIndex = 0
    endglobals
    
    //==============================================================================
    globals
        private integer array DecayingIndex
        private integer MaxDecayingIndex=0
        private integer DecayChecker=0
    endglobals
    
    globals
        private timer UndefendTimer=CreateTimer()
        private integer array UndefendIndex
        private integer UndefendStackIndex=0
    endglobals
    globals
        private integer array UndefendExpiringIndex
        private integer UndefendExpiringIndexLevel=0
    endglobals
    
    //==============================================================================
    globals
        // The Add/Remove stack (or assign/recycle stack).
        // 
        // Indexing can become recusive since units can be created on index
        // assignment or deallocation.
        // To support this, a stack is used to store the event response results.
        private integer ARStackLevel=0
        private integer array ARStackIndex
        private unit    array ARStackUnit
        
        // A later discovery revealed that the Add/Remove stack did not need to be
        // used for deallocation. The alternative used works fine...
    endglobals
    
    public constant function GetEnteringIndexUnit takes nothing returns unit
        return ARStackUnit[ARStackLevel]
    endfunction
    
    public function GetIndexOfEnteringUnit takes nothing returns integer
        // Called in AIDS structs when units do not pass the initial AIDS filter.
        
        if ARStackIndex[ARStackLevel]==0 then
            // Get new index, from recycler first, else new.
            // Store the current index on the (new) top level of the AR stack.
            if MaxRecycledIndex==0 then // Get new.
                set MaxIndex=MaxIndex+1
                set ARStackIndex[ARStackLevel]=MaxIndex
            else // Get from recycle stack.
                set ARStackIndex[ARStackLevel]=RecycledIndex[MaxRecycledIndex]
                set MaxRecycledIndex=MaxRecycledIndex-1
            endif
            
            // Store index on unit.
            call SetUnitUserData(ARStackUnit[ARStackLevel],ARStackIndex[ARStackLevel])
            set IndexUnit[ARStackIndex[ARStackLevel]]=ARStackUnit[ARStackLevel]
            
            // Add index to recycle list.
            set MaxDecayingIndex=MaxDecayingIndex+1
            set DecayingIndex[MaxDecayingIndex]=ARStackIndex[ARStackLevel]
        endif
        
        return ARStackIndex[ARStackLevel]
    endfunction
    
    public constant function GetIndexOfEnteringUnitAllocated takes nothing returns integer
        // Called in AIDS structs when units have passed the initial AIDS filter.
        return ARStackIndex[ARStackLevel]
    endfunction
    public constant function GetDecayingIndex takes nothing returns integer
        static if USE_PERIODIC_RECYCLER then
            return DecayingIndex[DecayChecker]
        else
            return UndefendExpiringIndex[UndefendExpiringIndexLevel]
        endif
    endfunction
    
    //==============================================================================
    globals
        // For structs and such which need to do things on unit index assignment.
        private trigger OnEnter=CreateTrigger()
        // The same, but for when units pass the initial filter anyway.
        private trigger OnEnterAllocated=CreateTrigger()
        // For structs and such which need to do things on unit index deallocation.
        private trigger OnDeallocate=CreateTrigger()
    endglobals
    
    public function RegisterOnEnter takes boolexpr b returns triggercondition
        return TriggerAddCondition(OnEnter,b)
    endfunction
    public function RegisterOnEnterAllocated takes boolexpr b returns triggercondition
        return TriggerAddCondition(OnEnterAllocated,b)
    endfunction
    public function RegisterOnDeallocate takes boolexpr b returns triggercondition
        return TriggerAddCondition(OnDeallocate,b)
    endfunction
    
    //==============================================================================
    function GetIndexUnit2 takes integer index returns unit
        debug if index==0 then
        debug   call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the unit of index 0.")
        debug elseif IndexUnit[index]==null then
        debug   call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the unit of unassigned index.")
        debug endif
        
        return IndexUnit[index]
    endfunction
    
    function GetUnitId2 takes unit u returns integer
        debug if u==null then
        debug   call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the id (inlines) of null unit.")
        debug elseif GetUnitUserData(u)==0 then
        debug   call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to use GetUnitId (inlines) when you should be using GetUnitIndex (unit didn't pass filter).")
        debug endif
        
        return GetUnitUserData(u)
    endfunction
    
    globals//locals
        private integer getindex
    endglobals
    function GetUnitIndex takes unit u returns integer // Cannot be recursive.
        debug if u==null then
        debug   call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the index of null unit.")
        debug endif
        
        set getindex=GetUnitUserData(u)
        
        if getindex==0 then
            // Get new index, from recycler first, else new.
            // Store the current index in getindex.
            if MaxRecycledIndex==0 then // Get new.
                set MaxIndex=MaxIndex+1
                set getindex=MaxIndex
            else // Get from recycle stack.
                set getindex=RecycledIndex[MaxRecycledIndex]
                set MaxRecycledIndex=MaxRecycledIndex-1
            endif
            
            // Store index on unit.
            call SetUnitUserData(u,getindex)
            set IndexUnit[getindex]=u
            
            static if USE_PERIODIC_RECYCLER then
                
                // Add index to recycle list.
                set MaxDecayingIndex=MaxDecayingIndex+1
                set DecayingIndex[MaxDecayingIndex]=getindex
                
            else
            
                // Add leave detection ability.
                call UnitAddAbility(ARStackUnit[ARStackLevel],LEAVE_DETECTION_ABILITY)
                call UnitMakeAbilityPermanent(ARStackUnit[ARStackLevel],true,LEAVE_DETECTION_ABILITY)
                
            endif
            
            // Do not fire things here. No AIDS structs will be made at this point.
        endif
        
        return getindex
    endfunction
    
    //==============================================================================
    public function AddLock takes integer index returns nothing
        set LockLevel[index]=LockLevel[index]+1
    endfunction
    public function RemoveLock takes integer index returns nothing
        set LockLevel[index]=LockLevel[index]-1
        
        static if not USE_PERIODIC_RECYCLER then
            if GetUnitUserData(IndexUnit[index])==0 and LockLevel[index]==0 then
                
                // Increment stack for recursion.
                set UndefendExpiringIndexLevel=UndefendExpiringIndexLevel+1
                set UndefendExpiringIndex[UndefendExpiringIndexLevel]=index
                
                // Fire things.
                call TriggerEvaluate(OnDeallocate)
                
                // Decrement stack for recursion.
                set UndefendExpiringIndexLevel=UndefendExpiringIndexLevel-1
                
                // Add the index to the recycler stack.
                set MaxRecycledIndex=MaxRecycledIndex+1
                set RecycledIndex[MaxRecycledIndex]=index
                
                // Null the unit.
                set IndexUnit[index]=null
                
            endif
        endif
    endfunction
    
    //==============================================================================
    static if USE_PERIODIC_RECYCLER then
        
        private function PeriodicRecycler takes nothing returns nothing
            if MaxDecayingIndex>0 then
                set DecayChecker=DecayChecker+1
                if DecayChecker>MaxDecayingIndex then
                    set DecayChecker=1
                endif
                if GetUnitUserData(IndexUnit[DecayingIndex[DecayChecker]])==0 then
                if LockLevel[DecayingIndex[DecayChecker]]==0 then
                    
                    // Fire things.
                    call TriggerEvaluate(OnDeallocate)
                    
                    // Add the index to the recycler stack.
                    set MaxRecycledIndex=MaxRecycledIndex+1
                    set RecycledIndex[MaxRecycledIndex]=DecayingIndex[DecayChecker]
                    
                    // Null the unit.
                    set IndexUnit[DecayingIndex[DecayChecker]]=null
                    
                    // Remove index from decay list.
                    set DecayingIndex[DecayChecker]=DecayingIndex[MaxDecayingIndex]
                    set MaxDecayingIndex=MaxDecayingIndex-1
                    
                endif
                endif
            endif
        endfunction
        
    else
        
        private function UndefendFilter takes nothing returns boolean
            return IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD)
        endfunction
        
        private function OnUndefendTimer takes nothing returns nothing
            loop
                exitwhen UndefendStackIndex==0
                
                set UndefendStackIndex=UndefendStackIndex-1
                set UndefendExpiringIndex[0]=UndefendIndex[UndefendStackIndex]
                
                if IndexUnit[UndefendExpiringIndex[0]]!=null then
                if GetUnitUserData(IndexUnit[UndefendExpiringIndex[0]])==0 then
                if LockLevel[UndefendExpiringIndex[0]]==0 then
                    
                    // Fire things.
                    call TriggerEvaluate(OnDeallocate)
                    
                    // Add the index to the recycler stack.
                    set MaxRecycledIndex=MaxRecycledIndex+1
                    set RecycledIndex[MaxRecycledIndex]=UndefendExpiringIndex[0]
                    
                    // Null the unit.
                    set IndexUnit[UndefendExpiringIndex[0]]=null
                    
                endif
                endif
                endif
                
            endloop
        endfunction
        
        globals//locals
            private integer UndefendFilterIndex
        endglobals
        private function OnUndefend takes nothing returns boolean
            if GetIssuedOrderId()==852056 then // If undefend then...
                set UndefendFilterIndex=GetUnitUserData(GetOrderedUnit())
                
                if UndefendIndex[UndefendStackIndex-1]!=UndefendFilterIndex then // Efficiency perk.
                    set UndefendIndex[UndefendStackIndex]=UndefendFilterIndex
                    set UndefendStackIndex=UndefendStackIndex+1
                    
                    call TimerStart(UndefendTimer,0,false,function OnUndefendTimer)
                endif
            endif
            
            return false
        endfunction
        
    endif
    
    //==============================================================================
    public function IndexEnum takes nothing returns boolean // Can be recursive...
        // Start by adding another level on the AR stack (for recursion's sake).
        set ARStackLevel=ARStackLevel+1
        
        // Store the current unit on the (new) top level of the AR stack.
        set ARStackUnit[ARStackLevel]=GetFilterUnit()
        
        if GetUnitUserData(ARStackUnit[ARStackLevel])==0 then // Has not been indexed.
            
            if UnitIndexingFilter(ARStackUnit[ARStackLevel]) then
                
                // Get new index, from recycler first, else new.
                // Store the current index on the (new) top level of the AR stack.
                if MaxRecycledIndex==0 then // Get new.
                    set MaxIndex=MaxIndex+1
                    set ARStackIndex[ARStackLevel]=MaxIndex
                else // Get from recycle stack.
                    set ARStackIndex[ARStackLevel]=RecycledIndex[MaxRecycledIndex]
                    set MaxRecycledIndex=MaxRecycledIndex-1
                endif
                
                // Store index on unit.
                call SetUnitUserData(ARStackUnit[ARStackLevel],ARStackIndex[ARStackLevel])
                set IndexUnit[ARStackIndex[ARStackLevel]]=ARStackUnit[ARStackLevel]
                
                static if USE_PERIODIC_RECYCLER then
                    
                    // Add index to recycle list.
                    set MaxDecayingIndex=MaxDecayingIndex+1
                    set DecayingIndex[MaxDecayingIndex]=ARStackIndex[ARStackLevel]
                    
                else
                    
                    // Add leave detection ability.
                    call UnitAddAbility(ARStackUnit[ARStackLevel],LEAVE_DETECTION_ABILITY)
                    call UnitMakeAbilityPermanent(ARStackUnit[ARStackLevel],true,LEAVE_DETECTION_ABILITY)
                    
                endif
                
                // Fire things.
                call TriggerEvaluate(OnEnter)
                
            else
                
                // The unit did not pass the filters, so does not need to be auto indexed.
                // However, for certain AIDS structs, it may still require indexing.
                // These structs may index the unit on their creation.
                // We flag that an index must be assigned by setting the current index to 0.
                set ARStackIndex[ARStackLevel]=0
                
                // Fire things.
                call TriggerEvaluate(OnEnter)
                
            endif
            
        endif
        
        // Decrement the stack.
        set ARStackLevel=ARStackLevel-1
        
        return false
    endfunction
    
    //==============================================================================
    private function InitAIDS takes nothing returns nothing
        local region r=CreateRegion()
        
        local group g=CreateGroup()
        local integer n=15
        
        static if USE_PERIODIC_RECYCLER then
            
            call TimerStart(UndefendTimer,PERIOD,true,function PeriodicRecycler)
            
        else
            
            local trigger t=CreateTrigger()
            
            loop
                call TriggerRegisterPlayerUnitEvent(t,Player(n),EVENT_PLAYER_UNIT_ISSUED_ORDER,Filter(function UndefendFilter))
                call SetPlayerAbilityAvailable(Player(n),LEAVE_DETECTION_ABILITY,false)
                // Capture "undefend" orders.
                exitwhen n==0
                set n=n-1
            endloop
            set n=15
            
            call TriggerAddCondition(t,Filter(function OnUndefend))
            set t=null
            
        endif
        
        // This must be done first, due to recursion. :)
        call RegionAddRect(r,GetWorldBounds())
        call TriggerRegisterEnterRegion(CreateTrigger(),r,Filter(function IndexEnum))
        set r=null
        
        loop
            call GroupEnumUnitsOfPlayer(g,Player(n),Filter(function IndexEnum))
            //Enum every non-filtered unit on the map during initialization and assign it a unique
            //index. By using GroupEnumUnitsOfPlayer, even units with Locust can be detected.
            exitwhen n==0
            set n=n-1
        endloop
        call DestroyGroup(g)
        set g=null
    endfunction
    
    //==============================================================================
    public struct DEFAULT extends array
        method AIDS_onCreate takes nothing returns nothing
        endmethod
        method AIDS_onDestroy takes nothing returns nothing
        endmethod
        
        static method AIDS_filter takes unit u returns boolean
            return UnitIndexingFilter(u)
        endmethod
        
        static method AIDS_onInit takes nothing returns nothing
        endmethod
    endstruct
    
    //===========================================================================
    //  Never create or destroy AIDS structs directly.
    //  Also, do not initialise members except by using the AIDS_onCreate method.
    //===========================================================================
    //! textmacro AIDS
        // This magic line makes default methods get called which do nothing
        // if the methods are otherwise undefined.
        private static delegate AIDS_DEFAULT AIDS_DELEGATE=0
        
        //-----------------------------------------------------------------------
        // Gotta know whether or not to destroy on deallocation...
        private boolean AIDS_instanciated
        
        //-----------------------------------------------------------------------
        static method operator[] takes unit whichUnit returns thistype
            return GetUnitId(whichUnit)
        endmethod
        
        method operator unit takes nothing returns unit
            // Allows structVar.unit to return the unit.
            return GetIndexUnit2(this)
        endmethod
        
        //-----------------------------------------------------------------------
        method AIDS_addLock takes nothing returns nothing
            call AIDS_AddLock(this)
        endmethod
        method AIDS_removeLock takes nothing returns nothing
            call AIDS_RemoveLock(this)
        endmethod
        
        //-----------------------------------------------------------------------
        private static method AIDS_onEnter takes nothing returns boolean
            // At this point, the unit might not have been assigned an index.
            if thistype.AIDS_filter(AIDS_GetEnteringIndexUnit()) then
                // Flag it for destruction on deallocation.
                set thistype(AIDS_GetIndexOfEnteringUnit()).AIDS_instanciated=true
                // Can use inlining "Assigned" function now, as it must be assigned.
                call thistype(AIDS_GetIndexOfEnteringUnitAllocated()).AIDS_onCreate()
            endif
            
            return false
        endmethod
        
        private static method AIDS_onEnterAllocated takes nothing returns boolean
            // At this point, the unit must have been assigned an index.
            if thistype.AIDS_filter(AIDS_GetEnteringIndexUnit()) then
                // Flag it for destruction on deallocation. Slightly faster!
                set thistype(AIDS_GetIndexOfEnteringUnitAllocated()).AIDS_instanciated=true
                // Can use inlining "Assigned" function now, as it must be assigned.
                call thistype(AIDS_GetIndexOfEnteringUnitAllocated()).AIDS_onCreate()
            endif
            
            return false
        endmethod
        
        private static method AIDS_onDeallocate takes nothing returns boolean
            if thistype(AIDS_GetDecayingIndex()).AIDS_instanciated then
                call thistype(AIDS_GetDecayingIndex()).AIDS_onDestroy()
                // Unflag destruction on deallocation.
                set thistype(AIDS_GetDecayingIndex()).AIDS_instanciated=false
            endif
            
            return false
        endmethod
        
        //-----------------------------------------------------------------------
        private static method onInit takes nothing returns nothing
            call AIDS_RegisterOnEnter(Filter(function thistype.AIDS_onEnter))
            call AIDS_RegisterOnEnterAllocated(Filter(function thistype.AIDS_onEnterAllocated))
            call AIDS_RegisterOnDeallocate(Filter(function thistype.AIDS_onDeallocate))
            
            // Because I robbed you of your struct's onInit method.
            call thistype.AIDS_onInit()
        endmethod
    //! endtextmacro
endlibrary

library PUI uses AIDS
    //===========================================================================
    //  Allowed PUI_PROPERTY TYPES are: unit, integer, real, boolean, string
    //  Do NOT put handles that need to be destroyed here (timer, trigger, ...)
    //  Instead put them in a struct and use PUI textmacro
    //===========================================================================
    //! textmacro PUI_PROPERTY takes VISIBILITY, TYPE, NAME, DEFAULT
    $VISIBILITY$ struct $NAME$
        private static unit   array pui_unit
        private static $TYPE$ array pui_data
        
        //-----------------------------------------------------------------------
        //  Returns default value when first time used
        //-----------------------------------------------------------------------
        static method operator[] takes unit whichUnit returns $TYPE$
            local integer pui = GetUnitId(whichUnit) // Changed from GetUnitIndex.
            if .pui_unit[pui] != whichUnit then
                set .pui_unit[pui] = whichUnit
                set .pui_data[pui] = $DEFAULT$
            endif
            return .pui_data[pui]
        endmethod
        
        //-----------------------------------------------------------------------
        static method operator[]= takes unit whichUnit, $TYPE$ whichData returns nothing
            local integer pui = GetUnitIndex(whichUnit)
            set .pui_unit[pui] = whichUnit
            set .pui_data[pui] = whichData
        endmethod
    endstruct
    //! endtextmacro

    //===========================================================================
    //  Never destroy PUI structs directly.
    //  Use .release() instead, will call .destroy()
    //===========================================================================
    //! textmacro PUI
        private static unit    array pui_unit
        private static integer array pui_data
        private static integer array pui_id
        
        //-----------------------------------------------------------------------
        //  Returns zero if no struct is attached to unit
        //-----------------------------------------------------------------------
        static method operator[] takes unit whichUnit returns integer
            local integer pui = GetUnitId(whichUnit) // Changed from GetUnitIndex.
            // Switched the next two lines for optimisation.
            if .pui_unit[pui] != whichUnit then
                if .pui_data[pui] != 0 then
                    // recycled index detected
                    call .destroy(.pui_data[pui])
                    set .pui_unit[pui] = null
                    set .pui_data[pui] = 0            
                endif
            endif
            return .pui_data[pui]
        endmethod
        
        //-----------------------------------------------------------------------
        //  This will overwrite already attached struct if any
        //-----------------------------------------------------------------------
        static method operator[]= takes unit whichUnit, integer whichData returns nothing
            local integer pui = GetUnitIndex(whichUnit)
            if .pui_data[pui] != 0 then
                call .destroy(.pui_data[pui])
            endif
            set .pui_unit[pui] = whichUnit
            set .pui_data[pui] = whichData
            set .pui_id[whichData] = pui
        endmethod

        //-----------------------------------------------------------------------
        //  If you do not call release struct will be destroyed when unit handle gets recycled
        //-----------------------------------------------------------------------
        method release takes nothing returns nothing
            local integer pui= .pui_id[integer(this)]
            call .destroy()
            set .pui_unit[pui] = null
            set .pui_data[pui] = 0
        endmethod
    //! endtextmacro
endlibrary

library AutoIndex uses AIDS
    module AutoData
        private static thistype array data
        
        // Fixed up the below to use thsitype instead of integer.
        static method operator []= takes unit u, thistype i returns nothing
            set .data[GetUnitId(u)] = i //Just attaching a struct to the unit
        endmethod                       //using the module's thistype array.
        
        static method operator [] takes unit u returns thistype
            return .data[GetUnitId(u)] //Just returning the attached struct.
        endmethod
    endmodule
endlibrary

  • the "Damage_IsAttack" will return true only if "Damage_Physical" was called
  • I do not see "Damage_Physical" called anywhere
But an attack is always physical isn't it? So "Damage_IsAttack" should be enough, right?
 
But an attack is always physical isn't it? So "Damage_IsAttack" should be enough, right?
Well, not always. Damage done by spells/triggers may not be physical. In case of the "Damage" library, the "IsAttack" function looks like this:
JASS:
public function IsAttack takes nothing returns boolean
    return TypeStackAttack[TypeStackLevel]
endfunction
where TypeStackAttack is a boolean array and TypeStackLevel is an integer. So it checks if last configured boolean value in the array is set to 'true'. The "Damage_Physical" sets that boolean value into the array as 'true', hence my comment.

But I see now that in module init they set a default/first value in the array to always be 'true', as can be seen here:
JASS:
private module InitModule
        private static method onInit takes nothing returns nothing
            ...
            set TypeStackValue[TypeStackLevel]=DAMAGE_TYPE_NORMAL
            set TypeStackAttack[TypeStackLevel]=true //<-- this
            ...
        endmethod
    endmodule
So in your "Silence" function the call Damage_IsAttack() should return 'true', in which case there is only one other candidate where it could fail:
GetUnitAbilityLevel(c, BUFF_ID) > 0

The above checks if damage source has the Dark Blade buff on them. You wrote that the Dark Blade ability used by hero/caster is based off Berserk. Check that spell's buff in object editor: Is that buff's ID the one you have configured in globals? I.e.
JASS:
globals
    ...
    private constant integer BUFF_ID = 'B08S' // raw code of Buff "Dark Blades (Caster)"
    ...
endglobals
If the buff you use has different ID, then that's the most likely cause of the issue you have and to fix it you need to change the ID in the script so that it matches the buff's ID in object editor.

If buff's ID in object editor already matches the ID in script, maybe try to replace the entire "Silence" function in Dark Blades with this version:
JASS:
private function Silence takes nothing returns boolean
    local unit c = GetEventDamageSource()
    local unit t = GetTriggerUnit()
    call BJDebugMsg("DarkBlades Silence: function called")
    if Damage_IsAttack() and GetUnitAbilityLevel(c, BUFF_ID) > 0 then
        call BJDebugMsg("DarkBlades Silence: dummy should cast silence")
        call CasterDummy_TargetPoint(c, GetUnitX(t), GetUnitY(t), ABIL_ID3, GetUnitAbilityLevel(c, ABIL_ID1), "silence")
    endif
    set c = null
    set t = null
    return false
endfunction
All I added are the two "BJDebugMsg" calls. They should print message "DarkBlades Silence: function called" when any (and I really mean ANY) unit takes damage, and message "DarkBlades Silence: dummy should cast silence" if the system determined that unit was damaged by physical attack and the damage source has the Dark Blades buff.

This should tells us a few things:
  • If no "DarkBlades Silence: function called" message is printed, then the "Silence" method is not called at all
  • If the above message is printed, but no "DarkBlades Silence: dummy should cast silence" is printed even when unit with Dark Blades deals damage, then we know that the condition fails (either damage is not physical, or unit does not have correct buff)
  • If both messages are printed, but no unit is silenced, then the issue may be in dummy unit (or whatever logic the call "CasterDummy_TargetPoint" executes)
 
Well, not always. Damage done by spells/triggers may not be physical. In case of the "Damage" library, the "IsAttack" function looks like this:
JASS:
public function IsAttack takes nothing returns boolean
    return TypeStackAttack[TypeStackLevel]
endfunction
where TypeStackAttack is a boolean array and TypeStackLevel is an integer. So it checks if last configured boolean value in the array is set to 'true'. The "Damage_Physical" sets that boolean value into the array as 'true', hence my comment.

But I see now that in module init they set a default/first value in the array to always be 'true', as can be seen here:
JASS:
private module InitModule
        private static method onInit takes nothing returns nothing
            ...
            set TypeStackValue[TypeStackLevel]=DAMAGE_TYPE_NORMAL
            set TypeStackAttack[TypeStackLevel]=true //<-- this
            ...
        endmethod
    endmodule
So in your "Silence" function the call Damage_IsAttack() should return 'true', in which case there is only one other candidate where it could fail:
GetUnitAbilityLevel(c, BUFF_ID) > 0

The above checks if damage source has the Dark Blade buff on them. You wrote that the Dark Blade ability used by hero/caster is based off Berserk. Check that spell's buff in object editor: Is that buff's ID the one you have configured in globals? I.e.
JASS:
globals
    ...
    private constant integer BUFF_ID = 'B08S' // raw code of Buff "Dark Blades (Caster)"
    ...
endglobals
If the buff you use has different ID, then that's the most likely cause of the issue you have and to fix it you need to change the ID in the script so that it matches the buff's ID in object editor.

If buff's ID in object editor already matches the ID in script, maybe try to replace the entire "Silence" function in Dark Blades with this version:
JASS:
private function Silence takes nothing returns boolean
    local unit c = GetEventDamageSource()
    local unit t = GetTriggerUnit()
    call BJDebugMsg("DarkBlades Silence: function called")
    if Damage_IsAttack() and GetUnitAbilityLevel(c, BUFF_ID) > 0 then
        call BJDebugMsg("DarkBlades Silence: dummy should cast silence")
        call CasterDummy_TargetPoint(c, GetUnitX(t), GetUnitY(t), ABIL_ID3, GetUnitAbilityLevel(c, ABIL_ID1), "silence")
    endif
    set c = null
    set t = null
    return false
endfunction
All I added are the two "BJDebugMsg" calls. They should print message "DarkBlades Silence: function called" when any (and I really mean ANY) unit takes damage, and message "DarkBlades Silence: dummy should cast silence" if the system determined that unit was damaged by physical attack and the damage source has the Dark Blades buff.

This should tells us a few things:
  • If no "DarkBlades Silence: function called" message is printed, then the "Silence" method is not called at all
  • If the above message is printed, but no "DarkBlades Silence: dummy should cast silence" is printed even when unit with Dark Blades deals damage, then we know that the condition fails (either damage is not physical, or unit does not have correct buff)
  • If both messages are printed, but no unit is silenced, then the issue may be in dummy unit (or whatever logic the call "CasterDummy_TargetPoint" executes)
Hmm no message was printed and enemies didn't get silenced... And yes the Buff ID is correct in the globals.
I was trying to make the 2 variables and I did them just like you told but I get error that variable is undeclared :-/
error.webp
 
The "IsAttack" function I posted in my previous post, i.e.
JASS:
public function IsAttack takes nothing returns boolean
    return TypeStackAttack[TypeStackLevel]
endfunction

already exists in "Damage" library, you don't need to create it in DarkBlades script.

Edit: the only two things you should check and modify in DarkBlades script were
  • private constant integer BUFF_ID = 'B08S' // raw code of Buff "Dark Blades (Caster)" so that it matches the buff's ID in object editor
  • replace Silence function with the modified version:
JASS:
private function Silence takes nothing returns boolean
    local unit c = GetEventDamageSource()
    local unit t = GetTriggerUnit()
    call BJDebugMsg("DarkBlades Silence: function called")
    if Damage_IsAttack() and GetUnitAbilityLevel(c, BUFF_ID) > 0 then
        call BJDebugMsg("DarkBlades Silence: dummy should cast silence")
        call CasterDummy_TargetPoint(c, GetUnitX(t), GetUnitY(t), ABIL_ID3, GetUnitAbilityLevel(c, ABIL_ID1), "silence")
    endif
    set c = null
    set t = null
    return false
endfunction
 
The "IsAttack" function I posted in my previous post, i.e.
JASS:
public function IsAttack takes nothing returns boolean
    return TypeStackAttack[TypeStackLevel]
endfunction

already exists in "Damage" library, you don't need to create it in DarkBlades script.

Edit: the only two things you should check and modify in DarkBlades script were
  • private constant integer BUFF_ID = 'B08S' // raw code of Buff "Dark Blades (Caster)" so that it matches the buff's ID in object editor
  • replace Silence function with the modified version:
JASS:
private function Silence takes nothing returns boolean
    local unit c = GetEventDamageSource()
    local unit t = GetTriggerUnit()
    call BJDebugMsg("DarkBlades Silence: function called")
    if Damage_IsAttack() and GetUnitAbilityLevel(c, BUFF_ID) > 0 then
        call BJDebugMsg("DarkBlades Silence: dummy should cast silence")
        call CasterDummy_TargetPoint(c, GetUnitX(t), GetUnitY(t), ABIL_ID3, GetUnitAbilityLevel(c, ABIL_ID1), "silence")
    endif
    set c = null
    set t = null
    return false
endfunction
Ok but what type of variable is "TypeStackValue" meant to be?

Nwm I found it but it still doesn't work, no silence appears on the attacked unit when the buff is up :-/ It can't be anything wrong with the dummy because it works with the "Charging Strikes" ability but then it ignores the Dark Blades buff-requirement...
 
I checked the map, but it does not seem like they use any special configuration (i.e. scripts in map header, etc.), so my guess is you must have imported something wrong or forgot to change something.
Can you also upload your map where the spell does not work?
But try use the spells in the spellpack, they do not work there either :-/ Believe me I have checked everything over and over again and everything is correct in my map.

I checked the map, but it does not seem like they use any special configuration (i.e. scripts in map header, etc.), so my guess is you must have imported something wrong or forgot to change something.
Can you also upload your map where the spell does not work?
Sry I was wrong. The spells works in the spellpack but not in my map... I'll send you my map in private message.
 
For anyone having similar issues, the problem with Dark Blades was in the AIDS system. This system acts as a unit indexer: On map start it will check if unit was not yet indexed (by checking if unit's custom value is 0) and if so, it will assign it an index and basically set up its "Unit takes damage" trigger.

However Dinodin already had a different unit indexer, which was executed before AIDS system. It already assigned custom values to all units. By the time AIDS system ran, it incorrectly assume that AIDS indexed units and so it skipped them all, hence the "Unit takes damage" triggers were never fully initialized.

We fixed it by using a DDS that Dinodin already had in map instead of AIDS.

As for Silence failing - it was failing on units that had no silenceable spells. This seems to be a hard-coded behavior of the spel.
 
Back
Top