• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[Solved] Deep Wound Spell Problems!

Status
Not open for further replies.
Level 30
Joined
Nov 29, 2012
Messages
6,637
I have a spell here namely Deep Wounds made by Daffa to me (but I dont want to disturb him that much and I need an answer ASAP.), the spell works like gives an x% chance to deal 2x bonus damage and reduce armor of enemies by 2. The armor reduction stacks for 5 times which means 10 armor reduction in total but a stack will deduct if 4 seconds passes by. It should work as intended but for some weird reason it does not stack. It only reduces up to 2 then nothing happens after that. I set the chance to 100% for testing purpose but still it won't get any higher than the first stack.

Here are the triggers:

  • DW Configuration
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- CONFIGURABLE --------
      • -------- Set this to the Death Wound Ability that has been copy-psted --------
      • Set DW_Ability = Deep Wound
      • -------- Chance for the spell (Min : 1, Max : 100) --------
      • Set DW_Chance = 100
      • -------- Damage Amplification --------
      • Set DW_Multiplier = 2.00
      • -------- Armor Reduction duration (real second) --------
      • Set DW_ReductionDuration = 4.00
      • -------- Armor Reduction (positive values, else it will add armor) --------
      • Set ArmorReduction = 2
      • -------- SFX Path - Path of effect created on target --------
      • Set DW_SFX_Path = Objects\Spawnmodels\Human\HumanBlood\BloodElfSpellThiefBlood.mdl
      • -------- SFX Instant Remove - if true will remove SFX after display, if false it will remove SFX after spell effect ends. --------
      • Set DW_SFX_Removal = True
      • -------- UNCONFIGURABLE --------
      • -------- Loop Timer, touch at risk --------
      • Set DW_Timer = 0.03
      • Trigger - Add to DW Debuff <gen> the event (Time - Every DW_Timer seconds of game time)
      • -------- Spell Min chance, don't touch! --------
      • Set DW_MinChance = 1
      • -------- Spell Max chance, don't touch! --------
      • Set DW_MaxChance = 100
  • DW Cast
    • Events
      • Game - damageEventTrigger becomes Equal to 1.00
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Level of DW_Ability for source) Equal to 1
          • damageType Equal to PHYSICAL
          • (Random integer number between DW_MinChance and DW_MaxChance) Less than or equal to 100
        • Then - Actions
          • -------- Activate Data --------
          • Set amount = (DW_Multiplier x amount)
          • Set DW_Index_Unit = (Custom value of target)
          • -------- Attack Special effect, automatically applied in every attack --------
          • -------- ignores wether unit is in effect before or not --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • DW_SFX_Removal Equal to True
            • Then - Actions
              • Special Effect - Create a special effect attached to the origin of target using DW_SFX_Path
              • Special Effect - Destroy (Last created special effect)
            • Else - Actions
          • -------- Float Text --------
          • Floating Text - Create floating text that reads (String(amount)) above target with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
          • Set DW_FT = (Last created floating text)
          • Floating Text - Set the velocity of DW_FT to 64.00 towards 90.00 degrees
          • Floating Text - Change DW_FT: Disable permanence
          • Floating Text - Change the fading age of DW_FT to 4.00 seconds
          • Floating Text - Change the lifespan of DW_FT to 6.00 seconds
          • -------- Registration check --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (target is in DW_Group) Equal to False
            • Then - Actions
              • Unit Group - Add target to DW_Group
              • Custom script: call CSS_AddBonus(udg_target, -udg_ArmorReduction, 0)
              • Special Effect - Create a special effect attached to the origin of target using DW_SFX_Path
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • DW_SFX_Removal Equal to False
                • Then - Actions
                  • Set DW_EffectRegistered[DW_Index_Unit] = (Last created special effect)
                • Else - Actions
                  • Special Effect - Destroy (Last created special effect)
            • Else - Actions
              • Skip remaining actions
          • Set DW_DebuffTimer[DW_Index_Unit] = DW_ReductionDuration
          • -------- Run Loop Status Check --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of units in DW_Group) Equal to 1
            • Then - Actions
              • Trigger - Turn on DW Debuff <gen>
            • Else - Actions
        • Else - Actions
  • DW Debuff
    • Events
    • Conditions
    • Actions
      • Unit Group - Pick every unit in DW_Group and do (Actions)
        • Loop - Actions
          • Set DW_PickedUnit = (Picked unit)
          • Set DW_Index_Unit = (Custom value of DW_PickedUnit)
          • Set DW_DebuffTimer[DW_Index_Unit] = (DW_DebuffTimer[DW_Index_Unit] - DW_Timer)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • DW_DebuffTimer[DW_Index_Unit] Less than or equal to 0.00
            • Then - Actions
              • Custom script: call CSS_AddBonus(udg_DW_PickedUnit, udg_ArmorReduction, 0)
              • Unit Group - Remove DW_PickedUnit from DW_Group
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • DW_SFX_Removal Equal to False
                • Then - Actions
                  • Special Effect - Destroy DW_EffectRegistered[DW_Index_Unit]
                • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Number of units in DW_Group) Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
            • Else - Actions



Anyway, it requires some abilities from the CCS of Doomlord but it's unknown to me why it's still not working and please do provide me the revised trigger because I can understand that more.
 
Last edited:
Level 5
Joined
Jan 27, 2014
Messages
164
> (Number of units in DW_Group) Equal to 1
In the 'DW Cast' trigger, the final ITE, shouldn't it be conditioned as 'Greater than or equal to 1'.

This will only turn on the periodic trigger only if there is 1 unit in the unit group.
Btw, the number check is pretty much redundant, isn't it? Just turn on the trigger whenever a unit is added will do imo.

Then again, I'm unfamiliar with the damage detection system used.
Is 'target' defined?
 
Level 30
Joined
Nov 29, 2012
Messages
6,637
Forgot to add the systems associated with it such as these:

JASS:
////////////////////////////////////////////////////////////////////////////////////
//
//  Physical Damage Detection Engine GUI v 1.0.0.2
//   ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
//  By looking_for_help aka eey
//
//  This system is able to detect, modify and deal damage. It can differentiate 
//  between physical and spell damage, as well as block, reduce or increase the
//  applied damage to a desired value. You can also allocate damage events from
//  running damage events.
//
//  This is the GUI version of the system, meaning that you can use this with the
//  standard editor and basically without any knowledge of JASS.
//
////////////////////////////////////////////////////////////////////////////////////
//
//  Implementation
//   ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
//  1.  Create all variables that this system uses (compare the variable editor).
//      You don't have to set them to specific values, they get initialized
//      automatically by the system so just create them.
//  2.  Copy this trigger to your map. You can then add damage handlers by using
//      the event "value of real variable becomes equal to 1" with the variable 
//      damageEventTrigger. Compare the OnDamage trigger for an example usage.
//  3.  Copy the two custom abilities to your map and make sure they have the
//      correct ID. You can specify the ID in the function InitGlobalVariables
//      above.
//  4.  Go to the locust swarm ability and invert its damage return portion
//      from (default) 0.75 to -0.75.
//  5.  Remove the spell damage reduction ability from the spell damage reduction
//      items you use (runed bracers). You can configure the resistance of this
//      item in the InitGlobalVariables function, modifying the golbal variable
//      BRACERS_SPELL_DAMAGE_REDUCTION.
//
////////////////////////////////////////////////////////////////////////////////////
//
//  Important Notes
//   ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
//  1.  Life Drain does not work with this system, so you should use a triggered 
//      version of this spell if you want to use it.
//  2.  Same for Finger of Death, if you want to use this spell bug free with this
//      system, you should use a triggered version of it.
//  3.  If you use damage modifiers by setting the damage amount variable, you have
//      to use GetUnitLife, GetUnitMaxLife and SetUnitLife instead of GetWidgetLife,
//      GetUnitState for UNIT_STATE_MAX_LIFE and SetWidgetLife in your whole map to
//      ensure there occure no bugs.
//  4.  The boolean USE_SPELL_RESISTANCE_AUTO_DETECT is only neccessary set to true
//      if you want to use a customized damage table with spell damage resistance
//      above 100%. If this is not the case, it should be set to false, as the 
//      system is faster then and still works correct.
//  5.  As already mentioned you can't use the spell reduction ability when using this
//      system (runed bracers and elunes grace). If you want to use them, you can 
//      trigger them by using the damage modifiers. Runed bracers is already considered
//      in this system, so you don't have to code it.
//
////////////////////////////////////////////////////////////////////////////////////
//  
//  System API
//   ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
//  real damageEventTrigger
//      - Use the event "value of real variable becomes equal to 1" to detect a damage
//        event. In this event you can use the following API. Compare the OnDamage
//        trigger for an example usage.
//
//  unit target
//      - In this global unit variable, the damaged unit is saved. Don't write any-
//        thing into this variable, use it as readonly.
//
//  unit source
//      - In this global unit variable, the damage source is saved. Don't write any-
//        thing into this variable, use it as readonly.
//
//  real amount
//      - In this global real variable, the amount of damage is saved. This amount
//        can be modified by simply setting it to the desired amount that should be
//        applied to the target. Set the amount to 0.0 to block the damage completly.
//        Negative values will result in heal.
//
//  integer damageType
//      - In this global integer variable, the damage type of the current damage is
//        saved. Use it to differentiate between physical, spell and code damage. The
//        variable can takes the values PHYSICAL == 0, SPELL == 1 and CODE == 2. Don't 
//        write anything into this variable, use it as readonly.        
//
//  function GetUnitLife takes unit u returns real
//      - Use this function instead of the GetWidgetLife native. It ensures that you
//        get the correct health value, even when damage modifiers are applied. If
//        you don't use damage modifiers at all, you don't need this function.
//
//  function GetUnitMaxLife takes unit u returns real
//      - Use this function instead of the GetUnitState(u, UNIT_STATE_MAX_LIFE) native.
//        It will return the correct value, even when damage modifiers are applied. If
//        you don't use damage modifiers at all, you don't need this function.
//
//  function SetUnitLife takes unit u, real newLife returns nothing
//      - Use this function instead of the SetWidgetLife(u, newLife) native if you use
//        damage modifiers in your map. Same rules as for the GetUnitMaxLife and the
//        GetUnitMaxLife functions.
//
//  function AddDamageHandler takes code damageHandler returns nothing
//      - Allows you to add a damage handler function to the system. This is not
//        required for GUI users, only for vanilla JASS users. GUI users should
//        use the real variable damageEventTrigger to add damage handlers to this
//        system as explained above.
//
//  function RemoveDamageHandler takes code damageHandler returns nothing
//      - Allows you to remove a damage handler function from the system dynamic-
//        ally. If you added the same handler function multiple times to the sys-
//        tem, this function will remove all of these equal functions. This is not
//        required for GUI users, only for vanilla JASS users.
//
//////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////
//  Configurable globals
//////////////////////////////////////////////////////////////////////////////////

function InitGlobalVariables takes nothing returns nothing
    // Put here the correct ability IDs
    // Ctrl + D at Object Editor in Abilities Tab to see their IDs
    set udg_DAMAGE_TYPE_DETECTOR = 'A011'
    set udg_SET_MAX_LIFE = 'A012'
    
    // Here you can configure some stuff, read the documentation for further info
    set udg_SPELL_DAMAGE_REDUCTION_ITEM = 'brac'
    set udg_SPELL_RESISTANCE_AUTO_DETECT = false
    set udg_ETHEREAL_DAMAGE_FACTOR = 1.66
    set udg_BRACERS_SPELL_DAMAGE_REDUCTION = 0.33
    set udg_TRIGGER_CLEANUP_PERIOD = 60.0
endfunction

//////////////////////////////////////////////////////////////////////////////////
//  End of configurable globals
//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////
//  User functions
//////////////////////////////////////////////////////////////////////////////////

function AddDamageHandler takes code func returns nothing
    local integer id = GetHandleId(Condition(func))
    local integer index = 0
    
    // Loop to manage equal damage handlers
    loop
        exitwhen ( LoadTriggerConditionHandle(udg_h, id, index) == null )
        set index = index + 1
    endloop
    
    // Store the desired damage handler function
    call SaveTriggerConditionHandle(udg_h, id, index, TriggerAddCondition(udg_damageHandler, Filter(func)))
endfunction

function RemoveDamageHandler takes code func returns nothing
    local integer id = GetHandleId(Condition(func))
    local integer index = 0
    
    // Loop through all equal damage handlers
    loop
        exitwhen ( LoadTriggerConditionHandle(udg_h, id, index) == null )
        call TriggerRemoveCondition(udg_damageHandler, LoadTriggerConditionHandle(udg_h, id, index))
        set index = index + 1
    endloop
    
    // Clean things up
    call FlushChildHashtable(udg_h, id)
endfunction

function GetUnitLife takes unit u returns real
    local boolean duringModification
    local integer uId = GetHandleId(u)
    local real health
    local real storedHealth = LoadReal(udg_h, uId, 2)
    local real storedDamage = LoadReal(udg_h, uId, 1)
    
    // Check if the unit is being rescued from damage
    set duringModification = GetUnitAbilityLevel(u, udg_SET_MAX_LIFE) > 0
    if duringModification then
        call UnitRemoveAbility(u, udg_SET_MAX_LIFE)
    endif

    // Get the correct health value of the unit 
    if storedHealth != 0.0 then
        set health = storedHealth - storedDamage
    else
        set health = GetWidgetLife(u) - storedDamage
    endif

    // Restore the rescue ability and return
    if duringModification then
        call UnitAddAbility(u, udg_SET_MAX_LIFE)
    endif
    return health
endfunction

function GetUnitMaxLife takes unit u returns real
    local real maxHealth
    
    // Check if the unit is being rescued from damage
    if GetUnitAbilityLevel(u, udg_SET_MAX_LIFE) > 0 then
        call UnitRemoveAbility(u, udg_SET_MAX_LIFE)
        set maxHealth = GetUnitState(u, UNIT_STATE_MAX_LIFE)
        call UnitAddAbility(u, udg_SET_MAX_LIFE)
        return maxHealth
    endif
    
    // If the unit isn't being rescued, use the standard native
    return GetUnitState(u, UNIT_STATE_MAX_LIFE)
endfunction

function SetUnitLife takes unit u, real newLife returns nothing
    local integer targetId
    local integer oldTimerId
    local real oldHealth

    // Check if the unit is being rescued from damage
    if GetUnitAbilityLevel(u, udg_SET_MAX_LIFE) > 0 then
        call UnitRemoveAbility(u, udg_SET_MAX_LIFE)
        call SetWidgetLife(u, newLife)
        call UnitAddAbility(u, udg_SET_MAX_LIFE)
        
        // Get the unit specific timer information
        set targetId = GetHandleId(u)
        set oldHealth = LoadReal(udg_h, targetId, 0)
        
        // Update the unit specific timer information
        if oldHealth != 0.0 then
            set oldTimerId = LoadInteger(udg_h, targetId, 3)
            call SaveReal(udg_h, targetId, 2, newLife)
            call SaveReal(udg_h, targetId, 0, newLife)
            call SaveReal(udg_h, oldTimerId, 4, newLife)
        endif
        return
    endif
    
    // If the unit isn't being rescued, use the standard native
    call SetWidgetLife(u, newLife)
endfunction

function UnitDamageTargetEx takes unit localSource, unit localTarget, real localAmount, boolean attack, boolean ranged, attacktype localAttackType, damagetype localDamageType, weapontype localWeaponType returns boolean
    // Avoid infinite loop due to recursion
    if udg_damageType == udg_CODE then
        return false
    endif
    
    // Avoid allocating attacks on units that are about to be killed
    if ( localTarget == udg_target and GetUnitLife(localTarget) - udg_amount < udg_UNIT_MIN_LIFE ) then
        return false
    endif
    
    // Store all damage parameters determined by the user
    set udg_allocatedAttacks = udg_allocatedAttacks + 1
    call SaveUnitHandle(udg_h, udg_allocatedAttacks, 0, localSource)
    call SaveUnitHandle(udg_h, udg_allocatedAttacks, 1, localTarget)
    call SaveReal(udg_h, udg_allocatedAttacks, 2, localAmount)
    call SaveBoolean(udg_h, udg_allocatedAttacks, 3, attack)
    call SaveBoolean(udg_h, udg_allocatedAttacks, 4, ranged)
    call SaveInteger(udg_h, udg_allocatedAttacks, 5, GetHandleId(localAttackType))
    call SaveInteger(udg_h, udg_allocatedAttacks, 6, GetHandleId(localDamageType))
    call SaveInteger(udg_h, udg_allocatedAttacks, 7, GetHandleId(localWeaponType))

    // Return true if the damage was allocated
    return true
endfunction

////////////////////////////////////////////////////////////////////////////////////
//  Sub functions
////////////////////////////////////////////////////////////////////////////////////

function DealFixDamage takes unit source, unit target, real pureAmount returns nothing
    local real MAX_DAMAGE = 1000000.0
    local real beforeHitpoints
    local real newHitpoints

    // Ensure the amount is positive
    if pureAmount < 0 then
        set pureAmount = -pureAmount
    endif

    // Save the targets hitpoints
    set beforeHitpoints = GetWidgetLife(target)
    set newHitpoints = beforeHitpoints - pureAmount

    // Apply the desired, fixed amount
    if newHitpoints >= udg_UNIT_MIN_LIFE then
        call SetUnitState(target, UNIT_STATE_LIFE, newHitpoints)
    else
        if ( IsUnitType(target, UNIT_TYPE_ETHEREAL) == false ) then
            call SetWidgetLife(target, 1.0)
            call UnitDamageTarget(source, target, MAX_DAMAGE, true, false, udg_ATTACK_TYPE_UNIVERSAL, DAMAGE_TYPE_UNIVERSAL, null)
        else
            call UnitRemoveAbility(target, udg_DAMAGE_TYPE_DETECTOR)
            call SetWidgetLife(target, 1.0)
            call UnitDamageTarget(source, target, MAX_DAMAGE, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, null)
        endif
    endif
endfunction

function GetUnitSpellResistance takes unit u returns real
    local real originalHP
    local real beforeHP
    local real afterHP
    local real resistance
    local real DUMMY_DAMAGE = 100
    local real DUMMY_FACTOR = 0.01
    
    // Deal spell damage in order to get the units resistance
    call UnitRemoveAbility(udg_target, udg_DAMAGE_TYPE_DETECTOR)
    set originalHP = GetWidgetLife(udg_target)
    call UnitAddAbility(udg_target, udg_SET_MAX_LIFE)
    call SetWidgetLife(udg_target, 20000.0)
    set beforeHP = GetWidgetLife(udg_target)
    call DisableTrigger(udg_damageEvent)
    call UnitDamageTarget(udg_source, udg_target, DUMMY_DAMAGE, true, false, null, DAMAGE_TYPE_UNIVERSAL, null)
    call EnableTrigger(udg_damageEvent)
    set afterHP = GetWidgetLife(udg_target)
    call UnitRemoveAbility(udg_target, udg_SET_MAX_LIFE)
    call SetWidgetLife(udg_target, originalHP)
    call UnitAddAbility(udg_target, udg_DAMAGE_TYPE_DETECTOR)
    call UnitMakeAbilityPermanent(udg_target, true, udg_DAMAGE_TYPE_DETECTOR)

    // Calculate this resistance
    set resistance = DUMMY_FACTOR*(beforeHP - afterHP)

    // If the resistance was greater than 100%, return it
    if resistance > 1.0 then
        return resistance
    else
        return 1.0
    endif
endfunction

function UnitHasItemOfType takes unit u, integer itemId returns integer
    local integer index = 0
    local item indexItem

    // Check if the target has a spell damage reducing item
    loop
        set indexItem = UnitItemInSlot(u, index)
        if ( indexItem != null ) and ( GetItemTypeId(indexItem) == itemId ) then
            return index + 1
        endif

        set index = index + 1
        exitwhen index >= bj_MAX_INVENTORY
    endloop
    return 0
endfunction


////////////////////////////////////////////////////////////////////////////////////
//  Damage Engine
////////////////////////////////////////////////////////////////////////////////////

function AfterDamage takes nothing returns nothing
    local timer time = GetExpiredTimer()
    local integer id = GetHandleId(time)
    local unit localSource = LoadUnitHandle(udg_h, id, 0)
    local unit localTarget = LoadUnitHandle(udg_h, id, 1)
    local real pureAmount = LoadReal(udg_h, id, 2)
    local real amount = LoadReal(udg_h, id, 3)
    local real originalHealth = LoadReal(udg_h, id, 4)

    // If the damage was modified, restore units health
    if originalHealth != 0.0 then
        call UnitRemoveAbility(localTarget, udg_SET_MAX_LIFE)
        call SetWidgetLife(localTarget, originalHealth)
    endif

    // Apply the desired amount of damage
    if amount > 0.0 then
        call DisableTrigger(udg_damageEvent)
        call DealFixDamage(localSource, localTarget, amount)
        call EnableTrigger(udg_damageEvent)
    else
        call SetWidgetLife(localTarget, originalHealth - amount)
    endif
    
    // Clean things up
    call FlushChildHashtable(udg_h, id)
    call FlushChildHashtable(udg_h, GetHandleId(localTarget))
    call DestroyTimer(time)
    set time = null
    set localSource = null
    set localTarget = null
endfunction

function DamageEngine takes nothing returns nothing
    local timer time
    local integer id
    local real health
    local real rawAmount
    local real originalHealth
    local integer targetId
    local integer oldTimerId
    local real oldHealth
    local real oldOriginalHealth
    local real oldAmount

    // Set damage variables  
    set udg_source = GetEventDamageSource()
    set udg_target = GetTriggerUnit()
    set rawAmount = GetEventDamage()
    
    // Determine the damage type
    if udg_damageType == udg_CODE and rawAmount != 0.0 then
        set udg_damageType = udg_CODE
    elseif rawAmount > 0.0 then
        set udg_damageType = udg_PHYSICAL
    elseif rawAmount < 0.0 then
        set udg_damageType = udg_SPELL
    else
        return
    endif
    
    // Correct the damage amount
    if rawAmount < 0.0 then
        set udg_amount = -rawAmount
    else
        set udg_amount = rawAmount
    endif
    
    // Register spell reduction above 100%
    if udg_SPELL_RESISTANCE_AUTO_DETECT then
        set udg_amount = GetUnitSpellResistance(udg_target)*udg_amount
    else
        if ( IsUnitType(udg_target, UNIT_TYPE_ETHEREAL) and IsUnitEnemy(udg_target, GetOwningPlayer(udg_source)) and rawAmount < 0.0 ) then
            set udg_amount = udg_ETHEREAL_DAMAGE_FACTOR*udg_amount
        endif
    endif
    
    // Register spell damage reducing items like runed bracers
    if ( IsUnitType(udg_target, UNIT_TYPE_HERO) and UnitHasItemOfType(udg_target, udg_SPELL_DAMAGE_REDUCTION_ITEM) > 0 ) and rawAmount < 0.0 then
        set udg_amount = (1 - udg_BRACERS_SPELL_DAMAGE_REDUCTION)*udg_amount
    endif
    
    // Save health and damage variables
    if udg_damageType != udg_CODE then
        call UnitRemoveAbility(udg_target, udg_SET_MAX_LIFE)
    endif
    set udg_pureAmount = udg_amount
    set originalHealth = GetWidgetLife(udg_target)
    set oldTimerId = 0
    
    // Call damage handlers
    set udg_damageEventTrigger = 1.0
    set udg_damageEventTrigger = 0.0

    // If the damage was modified, apply the rescue ability
    if udg_amount != udg_pureAmount then
        call UnitAddAbility(udg_target, udg_SET_MAX_LIFE)
        call SetWidgetLife(udg_target, GetWidgetLife(udg_target) + udg_pureAmount)
    endif
    
    // Check if a previous timer didn't yet expire
    set targetId = GetHandleId(udg_target)
    set oldHealth = LoadReal(udg_h, targetId, 0)
    
    // If this is the case, update the timer information
    if oldHealth != 0.0 then
        set oldTimerId = LoadInteger(udg_h, targetId, 3)
        set oldOriginalHealth = LoadReal(udg_h, targetId, 2)
        set oldAmount = LoadReal(udg_h, targetId, 1)
        set originalHealth = oldOriginalHealth - oldAmount
        call SaveReal(udg_h, oldTimerId, 4, oldOriginalHealth)
    endif

    // Call after damage event if damage was spell, modified, code or parallel 
    if ( rawAmount < 0.0 or udg_pureAmount != udg_amount or oldTimerId != 0 or udg_allocatedAttacks > 0 ) then
        set time = CreateTimer()
        set id = GetHandleId(time)
        
        // Save handles for after damage event
        call SaveUnitHandle(udg_h, id, 0, udg_source)
        call SaveUnitHandle(udg_h, id, 1, udg_target)
        call SaveReal(udg_h, id, 2, udg_pureAmount)
        call SaveReal(udg_h, id, 3, udg_amount)
        call SaveReal(udg_h, id, 4, originalHealth)

        // Save this extra to manage parallel damage instances
        call SaveReal(udg_h, targetId, 0, GetWidgetLife(udg_target))
        call SaveReal(udg_h, targetId, 1, udg_amount)
        call SaveReal(udg_h, targetId, 2, originalHealth)
        call SaveInteger(udg_h, targetId, 3, id)

        // Avoid healing of negative spell damage
        if rawAmount < 0.0 then
            call DisableTrigger(udg_damageEvent)
            call DealFixDamage(udg_source, udg_target, -rawAmount)
            if ( originalHealth - udg_amount < udg_UNIT_MIN_LIFE ) then
                call UnitRemoveAbility(udg_target, udg_SET_MAX_LIFE)
                call DealFixDamage(udg_source, udg_target, udg_amount)
            endif
            call EnableTrigger(udg_damageEvent)
        endif
        
        // Guarantee unit exploding
        if originalHealth - udg_amount < udg_UNIT_MIN_LIFE then
            if rawAmount > 0.0 then
                call UnitRemoveAbility(udg_target, udg_SET_MAX_LIFE)
                call SetWidgetLife(udg_target, udg_UNIT_MIN_LIFE)
            endif
        endif
        
        // Start the after damage event
        call TimerStart(time, 0.0, false, function AfterDamage)
    endif

    // Handle allocated attacks from UnitDamageTargetEx
    if udg_totalAllocs == 0 then
        set udg_totalAllocs = udg_allocatedAttacks
    endif
    if udg_allocatedAttacks > 0 then
        set udg_allocatedAttacks = udg_allocatedAttacks - 1
        set udg_allocCounter = udg_allocCounter + 1
        call TriggerEvaluate(udg_runAllocatedAttacks)
    endif

    // Reset all required variables
    set udg_damageType = -1
    set udg_totalAllocs = 0
    set udg_allocCounter = -1
endfunction


////////////////////////////////////////////////////////////////////////////////////
//  Initialization
////////////////////////////////////////////////////////////////////////////////////

function RestoreTriggers takes nothing returns nothing
    local unit enumUnit = GetEnumUnit()

    // Re-register units that are alive
    if GetWidgetLife(enumUnit) >= udg_UNIT_MIN_LIFE then
        call TriggerRegisterUnitEvent(udg_damageEvent, enumUnit, EVENT_UNIT_DAMAGED)
    endif
    set enumUnit = null
endfunction

function ClearMemory_Actions takes nothing returns nothing
    local group g = CreateGroup()
    local code c = function DamageEngine
    
    // Reset the damage event
    call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, null)
    call ResetTrigger(udg_damageEvent)
    call DestroyTrigger(udg_damageEvent)
    set udg_damageEvent = null
   
    // Rebuild it then
    set udg_damageEvent = CreateTrigger()
    call TriggerAddCondition(udg_damageEvent, Filter(c))
    call ForGroup(g, function RestoreTriggers)
    
    // Clean things up
    call DestroyGroup(g)
    set g = null
    set c = null
endfunction

function MapInit takes nothing returns nothing
    local unit enumUnit = GetEnumUnit()

    // Register units on map initialization
    call UnitAddAbility(enumUnit, udg_DAMAGE_TYPE_DETECTOR)
    call UnitMakeAbilityPermanent(enumUnit, true, udg_DAMAGE_TYPE_DETECTOR)
    call TriggerRegisterUnitEvent(udg_damageEvent, enumUnit, EVENT_UNIT_DAMAGED)
    set enumUnit = null
endfunction

function UnitEntersMap takes nothing returns nothing
    local unit triggerUnit = GetTriggerUnit()

    // Register units that enter the map
    if ( GetUnitAbilityLevel(triggerUnit, udg_DAMAGE_TYPE_DETECTOR) < 1 ) then
        call UnitAddAbility(triggerUnit, udg_DAMAGE_TYPE_DETECTOR)
        call UnitMakeAbilityPermanent(triggerUnit, true, udg_DAMAGE_TYPE_DETECTOR)
        call TriggerRegisterUnitEvent(udg_damageEvent, triggerUnit, EVENT_UNIT_DAMAGED)
    endif
    set triggerUnit = null
endfunction

function RunAllocatedAttacks takes nothing returns nothing
    local integer localAllocAttacks = udg_allocatedAttacks + 1

    // Calculate the correct sequence of allocated attacks
    set localAllocAttacks = localAllocAttacks - udg_totalAllocs + 1 + 2*udg_allocCounter
    
    // Deal code damage if the unit isn't exploding
    set udg_damageType = udg_CODE
    if GetUnitLife(LoadUnitHandle(udg_h, localAllocAttacks, 1)) >= udg_UNIT_MIN_LIFE then
        call UnitDamageTarget(LoadUnitHandle(udg_h, localAllocAttacks, 0), LoadUnitHandle(udg_h, localAllocAttacks, 1), LoadReal(udg_h, localAllocAttacks, 2), LoadBoolean(udg_h, localAllocAttacks, 3), LoadBoolean(udg_h, localAllocAttacks, 4), ConvertAttackType(LoadInteger(udg_h, localAllocAttacks, 5)), ConvertDamageType(LoadInteger(udg_h, localAllocAttacks, 6)), ConvertWeaponType(LoadInteger(udg_h, localAllocAttacks, 7)))
    else
        call FlushChildHashtable(udg_h, localAllocAttacks - 1)
    endif
    
    // Clean things up
    call FlushChildHashtable(udg_h, localAllocAttacks)
endfunction

function InitTrig_DamageEvent takes nothing returns nothing
    local group g = CreateGroup()
    local region r = CreateRegion()
    local trigger UnitEnters = CreateTrigger()
    local trigger ClearMemory = CreateTrigger()
    local code cDamageEngine = function DamageEngine
    local code cUnitEnters = function UnitEntersMap
    local code cClearMemory = function ClearMemory_Actions
    local code cRunAllocatedAttacks = function RunAllocatedAttacks
    
    // Initialize global variables
    set udg_h = InitHashtable()
    set udg_damageEvent = CreateTrigger()
    set udg_damageHandler = CreateTrigger()
    set udg_damageType = -1
    set udg_allocatedAttacks = 0
    set udg_runAllocatedAttacks = CreateTrigger()
    
    // Initialize global configurable constants
    call InitGlobalVariables()
    
    // Initialize global fixed constants
    set udg_PHYSICAL = 0
    set udg_SPELL = 1
    set udg_CODE = 2
    set udg_UNIT_MIN_LIFE = 0.406
    set udg_ATTACK_TYPE_UNIVERSAL = ConvertAttackType(7)
    set udg_totalAllocs = 0
    set udg_allocCounter = -1
    set udg_damageEventTrigger = 0.0
    
    // Register units on map initialization
    call TriggerRegisterVariableEvent(udg_damageHandler, "damageEventTrigger", EQUAL, 1.0)
    call TriggerAddCondition(udg_damageEvent, Filter(cDamageEngine))   
    call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, null)
    call ForGroup(g, function MapInit)
    
    // Register units that enter the map
    call RegionAddRect(r, bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(UnitEnters, r, null)
    call TriggerAddCondition(UnitEnters, Filter(cUnitEnters))
    
    // Register trigger for allocated attacks
    call TriggerAddCondition(udg_runAllocatedAttacks, Filter(cRunAllocatedAttacks))
    
    // Clear memory leaks
    call TriggerRegisterTimerEvent(ClearMemory, udg_TRIGGER_CLEANUP_PERIOD, true)
    call TriggerAddCondition(ClearMemory, Filter(cClearMemory))

    // Clean things up
    call DestroyGroup(g)
    set UnitEnters = null
    set ClearMemory = null
    set cDamageEngine = null
    set cUnitEnters = null
    set cClearMemory = null
    set cRunAllocatedAttacks = null
    set g = null
    set r = null
endfunction

JASS:
//************************************************************************************************************
//*                                                                                                          *
//*                              CUSTOM STAT SYSTEM (CSS)                                                    *
//*                                                                                                          *
//*   Author:   Doomlord                                                                                     *
//*   Version:  1.5g                                                                                         *
//*                                                                                                          *
//*   Credits:                                                                                               *
//*   + Earth-Fury:    BonusMod binary algoritm; implementation macro.                                       *
//*   + Crigges:       A great amount of help and support.                                                   *
//*   + Geries:        Help me with the item hashtable values cleanup.                                       *
//*   + rulerofiron99: Item Socketing method referenced from [GUI]Right Click Item Recipe v1.05.             *
//*   + Vexorian:      CSS_SimError [url]http://www.wc3c.net/showthread.php?t=101260[/url]                   *
//*   + Magtheridon96: [Snippet]BoundInt [url]http://www.hiveworkshop.com/forums/2294066-post804.html[/url]  *
//*   + WaterKnight:   Help with the stack for custom Event Response.                                        *
//*   + PurgeandFire:  Pinpoint a possible desync bug with the system.                                       *
//*   + Nestharus:     Mentioning the possible negative life bug in his Bonus lib.                           *
//*                                                                                                          *
//************************************************************************************************************


//**************************************************************************************
//* INTRODUCTION:                                                                      *
//*                                                                                    *
//* An alternative to BonusMod for those who prefer a vanilla JASS approach.           *
//*                                                                                    *
//* Just follow the API and you are pretty much done.                                  *
//**************************************************************************************


//********************************************************************************************************
//* REQUIREMENTS:                                                                                        *
//*                                                                                                      *
//* JNGP [url]http://www.hiveworkshop.com/forums/tools-560/jassnewgenpack-5d-227445[/url] (Recommended)  *
//* OR:                                                                                                  *
//* Your superhuman capability to transfer 198 abilities to your map. (Not Recommended)                  *
//********************************************************************************************************


//************************************************************************************************************************************************
//* INSTALLATION INSTRUCTION:                                                                                                                    *
//*                                                                                                                                              *
//* Step 1: Copy the custom code for bonus handling to your map header.                                                                          *
//* Step 2: Use JNGP to implement the system's abilities through macro. Instruction is included in the Implementation Macro trigger.             *
//* Step 3: Copy the whole CSS folder to your map. Don't forget to turn on "Automatically create unknown variables while pasting trigger data".  *
//* Step 4: Except for this trigger, delete every other useless elements.                                                                        *
//* Step 5: Use this BonusMod alternative however you want.                                                                                      *
//*                                                                                                                                              *
//************************************************************************************************************************************************


//**************************************************************************************
//* Bonus Types Identifier:                                                            *
//*                                                                                    *
//* Armor Bonus:        0                                                              *
//* Attack Speed Bonus: 1                                                              *
//* Damage Bonus:       2                                                              *
//* Agility Bonus:      3                                                              *
//* Intelligence Bonus: 4                                                              *
//* Strength Bonus:     5                                                              *
//* Life Regen Bonus:   6                                                              *
//* Mana Regen Bonus:   7                                                              *
//* Life Bonus:         8                                                              *
//* Mana Bonus:         9                                                              *
//* Sight Range Bonus:  10                                                             *
//**************************************************************************************


//********************************************************************************
//* Generic Bonus APIs                                                           *
//*                                                                              *
//* CSS_GetBonus takes unit u, integer bonusType returns integer                 *
//* CSS_AddBonus takes unit u, integer amount, integer bonusType returns nothing *
//* CSS_ClearBonus takes unit u, integer bonusType                               *
//********************************************************************************

library CSSHeaderCode
// SimError by Vexorian at wc3c.net

// Sim Error (modified)

function CSS_SimError takes string s returns nothing
    local string msg = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00" + s + "|r"
    local player ForPlayer = GetTriggerPlayer()
    local sound error = CreateSoundFromLabel("InterfaceError", false, false, false, 10, 10)

    if GetLocalPlayer() == ForPlayer then
        call ClearTextMessages()
        call DisplayTimedTextToPlayer(ForPlayer, 0.52, 0.96, 2.00, msg)
        call StartSound(error)
    endif

    set ForPlayer = null
endfunction

function CSS_SimNotification takes string s returns nothing
    local string msg = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cff32cd32" + s + "|r"
    local player ForPlayer = GetTriggerPlayer()
    local sound notify = CreateSoundFromLabel("ItemReward", false, false, false, 10, 10)

    if GetLocalPlayer() == ForPlayer then
        call ClearTextMessages()
        call DisplayTimedTextToPlayer(ForPlayer, 0.52, 0.96, 2.00, msg)
        call StartSound (notify)
    endif

    set ForPlayer = null
endfunction

// Bound Int by Magtheridon96 at hiveworkshop.com

// BoundInt

function BoundInt takes integer i, integer min, integer max returns integer
    return IMaxBJ(IMinBJ(i, max), min)
endfunction

// Bonus Handling Code

function CSS_AddBonus takes unit u, integer amount, integer bonusType returns nothing
    local integer max = udg_CSS_Power[17]
    local integer min = -udg_CSS_Power[17]
    local integer i = 16
    local integer j = LoadInteger (udg_CSS_Hashtable, GetHandleId(u), bonusType)

    if amount > max - 1 or amount < min then
        call CSS_SimError ("Value too high or too low")
        return
    endif

    if amount + j >= max or amount + j <= min then
        call CSS_SimError ("Current value at maximum or minimum")
        return
    endif

    set amount = amount + j
    call BoundInt (amount, min, max - 1)

    if bonusType < 0 or bonusType > 10 then
        call CSS_SimError ("CSS Error: Invalid bonus type (" + I2S(bonusType) + ")")
        return
    elseif bonusType == 8 or bonusType == 9 then

        if bonusType == 8 and amount*1. + GetUnitState(u, UNIT_STATE_MAX_LIFE) <= 0 then
            call CSS_SimError ("Unit's current max life is lower than the negative bonus amount. Unable to subtract.")
            return
        elseif bonusType == 9 and amount*1. + GetUnitState(u, UNIT_STATE_MAX_MANA) <= 0 then
            call CSS_SimError ("Unit's current max mana is lower than the negative bonus amount. Unable to subtract.")
            return
        endif

        call SaveInteger(udg_CSS_Hashtable, GetHandleId(u), bonusType, amount)

        if amount < 0 then
            set amount = max + amount
        else
            call UnitRemoveAbility(u, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
        endif

        loop
            if amount >= udg_CSS_Power[i] then
                call UnitAddAbility(u, udg_CSS_Abilities[bonusType*18 + i])
                call UnitMakeAbilityPermanent(u, true, udg_CSS_Abilities[bonusType*18 + i])
                set amount = amount - udg_CSS_Power[i]
            else
                call UnitRemoveAbility(u, udg_CSS_Abilities[bonusType*18 + i])
            endif
        
            set i = i - 1
            exitwhen i < 0
        endloop

        if LoadInteger(udg_CSS_Hashtable, GetHandleId(u), bonusType) < 0 then
            call UnitAddAbility(u, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
            call UnitMakeAbilityPermanent(u, true, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
        endif

    else

        call SaveInteger(udg_CSS_Hashtable, GetHandleId(u), bonusType, amount)

        if amount < 0 then
            set amount = max + amount
            call UnitAddAbility(u, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
            call UnitMakeAbilityPermanent(u, true, udg_CSS_Abilities[(bonusType + 1)*18 - 1])
        else
            call UnitRemoveAbility(u, udg_CSS_Abilities[(bonusType+1)*18 - 1])
        endif

        loop
            if amount >= udg_CSS_Power[i] then
                call UnitAddAbility(u, udg_CSS_Abilities[bonusType*18 + i])
                call UnitMakeAbilityPermanent(u, true, udg_CSS_Abilities[bonusType*18 + i])
                set amount = amount - udg_CSS_Power[i]
            else
                call UnitRemoveAbility(u, udg_CSS_Abilities[bonusType*18 + i])
            endif
        
            set i = i - 1
            exitwhen i < 0
        endloop

    endif
endfunction
endlibrary


library CSSMain initializer InitTrig_CSS_Standalone_Bonus uses CSSHeaderCode
// Clear bonus

function CSS_ClearBonus takes unit u, integer bonusType returns nothing

    if bonusType > 10 or bonusType < 0 or GetUnitTypeId (u) == 0 or IsUnitType (u, UNIT_TYPE_DEAD) then
        return
    endif

    call CSS_AddBonus (u, -LoadInteger (udg_CSS_Hashtable, GetHandleId (u), bonusType), bonusType)
endfunction

// Get current bonus

function CSS_GetBonus takes unit u, integer bonusType returns integer

    if bonusType > 10 or bonusType < 0 or GetUnitTypeId (u) == 0 or IsUnitType (u, UNIT_TYPE_DEAD) then
        return 0
    endif

    return LoadInteger (udg_CSS_Hashtable, GetHandleId (u), bonusType)
endfunction

// For preloading abilities

function CSS_Preload takes nothing returns nothing
    local integer i = 0
    local unit u = CreateUnit(Player(15), 'hfoo', 0, 0, 0.00)

    loop
        exitwhen i > 197
        call UnitAddAbility(u, udg_CSS_Abilities[i])
        set i = i + 1
    endloop

    call RemoveUnit(u)
    set u = null
endfunction

//===========================================================================
function InitTrig_CSS_Standalone_Bonus takes nothing returns nothing
    local integer i = 0
    local integer a = 1

    set udg_CSS_Abilities[0] = 'ZxA0'
    set udg_CSS_Abilities[1] = 'ZxA1'
    set udg_CSS_Abilities[2] = 'ZxA2'
    set udg_CSS_Abilities[3] = 'ZxA3'
    set udg_CSS_Abilities[4] = 'ZxA4'
    set udg_CSS_Abilities[5] = 'ZxA5'
    set udg_CSS_Abilities[6] = 'ZxA6'
    set udg_CSS_Abilities[7] = 'ZxA7'
    set udg_CSS_Abilities[8] = 'ZxA8'
    set udg_CSS_Abilities[9] = 'ZxA9'
    set udg_CSS_Abilities[10] = 'ZxAa'
    set udg_CSS_Abilities[11] = 'ZxAb'
    set udg_CSS_Abilities[12] = 'ZxAc'
    set udg_CSS_Abilities[13] = 'ZxAd'
    set udg_CSS_Abilities[14] = 'ZxAe'
    set udg_CSS_Abilities[15] = 'ZxAf'
    set udg_CSS_Abilities[16] = 'ZxAg'
    set udg_CSS_Abilities[17] = 'ZxAh'
    set udg_CSS_Abilities[18] = 'ZxI0'
    set udg_CSS_Abilities[19] = 'ZxI1'
    set udg_CSS_Abilities[20] = 'ZxI2'
    set udg_CSS_Abilities[21] = 'ZxI3'
    set udg_CSS_Abilities[22] = 'ZxI4'
    set udg_CSS_Abilities[23] = 'ZxI5'
    set udg_CSS_Abilities[24] = 'ZxI6'
    set udg_CSS_Abilities[25] = 'ZxI7'
    set udg_CSS_Abilities[26] = 'ZxI8'
    set udg_CSS_Abilities[27] = 'ZxI9'
    set udg_CSS_Abilities[28] = 'ZxIa'
    set udg_CSS_Abilities[29] = 'ZxIb'
    set udg_CSS_Abilities[30] = 'ZxIc'
    set udg_CSS_Abilities[31] = 'ZxId'
    set udg_CSS_Abilities[32] = 'ZxIe'
    set udg_CSS_Abilities[33] = 'ZxIf'
    set udg_CSS_Abilities[34] = 'ZxIg'
    set udg_CSS_Abilities[35] = 'ZxIh'
    set udg_CSS_Abilities[36] = 'ZxB0'
    set udg_CSS_Abilities[37] = 'ZxB1'
    set udg_CSS_Abilities[38] = 'ZxB2'
    set udg_CSS_Abilities[39] = 'ZxB3'
    set udg_CSS_Abilities[40] = 'ZxB4'
    set udg_CSS_Abilities[41] = 'ZxB5'
    set udg_CSS_Abilities[42] = 'ZxB6'
    set udg_CSS_Abilities[43] = 'ZxB7'
    set udg_CSS_Abilities[44] = 'ZxB8'
    set udg_CSS_Abilities[45] = 'ZxB9'
    set udg_CSS_Abilities[46] = 'ZxBa'
    set udg_CSS_Abilities[47] = 'ZxBb'
    set udg_CSS_Abilities[48] = 'ZxBc'
    set udg_CSS_Abilities[49] = 'ZxBd'
    set udg_CSS_Abilities[50] = 'ZxBe'
    set udg_CSS_Abilities[51] = 'ZxBf'
    set udg_CSS_Abilities[52] = 'ZxBg'
    set udg_CSS_Abilities[53] = 'ZxBh'
    set udg_CSS_Abilities[54] = 'ZxG0'
    set udg_CSS_Abilities[55] = 'ZxG1'
    set udg_CSS_Abilities[56] = 'ZxG2'
    set udg_CSS_Abilities[57] = 'ZxG3'
    set udg_CSS_Abilities[58] = 'ZxG4'
    set udg_CSS_Abilities[59] = 'ZxG5'
    set udg_CSS_Abilities[60] = 'ZxG6'
    set udg_CSS_Abilities[61] = 'ZxG7'
    set udg_CSS_Abilities[62] = 'ZxG8'
    set udg_CSS_Abilities[63] = 'ZxG9'
    set udg_CSS_Abilities[64] = 'ZxGa'
    set udg_CSS_Abilities[65] = 'ZxGb'
    set udg_CSS_Abilities[66] = 'ZxGc'
    set udg_CSS_Abilities[67] = 'ZxGd'
    set udg_CSS_Abilities[68] = 'ZxGe'
    set udg_CSS_Abilities[69] = 'ZxGf'
    set udg_CSS_Abilities[70] = 'ZxGg'
    set udg_CSS_Abilities[71] = 'ZxGh'
    set udg_CSS_Abilities[72] = 'ZxH0'
    set udg_CSS_Abilities[73] = 'ZxH1'
    set udg_CSS_Abilities[74] = 'ZxH2'
    set udg_CSS_Abilities[75] = 'ZxH3'
    set udg_CSS_Abilities[76] = 'ZxH4'
    set udg_CSS_Abilities[77] = 'ZxH5'
    set udg_CSS_Abilities[78] = 'ZxH6'
    set udg_CSS_Abilities[79] = 'ZxH7'
    set udg_CSS_Abilities[80] = 'ZxH8'
    set udg_CSS_Abilities[81] = 'ZxH9'
    set udg_CSS_Abilities[82] = 'ZxHa'
    set udg_CSS_Abilities[83] = 'ZxHb'
    set udg_CSS_Abilities[84] = 'ZxHc'
    set udg_CSS_Abilities[85] = 'ZxHd'
    set udg_CSS_Abilities[86] = 'ZxHe'
    set udg_CSS_Abilities[87] = 'ZxHf'
    set udg_CSS_Abilities[88] = 'ZxHg'
    set udg_CSS_Abilities[89] = 'ZxHh'
    set udg_CSS_Abilities[90] = 'ZxF0'
    set udg_CSS_Abilities[91] = 'ZxF1'
    set udg_CSS_Abilities[92] = 'ZxF2'
    set udg_CSS_Abilities[93] = 'ZxF3'
    set udg_CSS_Abilities[94] = 'ZxF4'
    set udg_CSS_Abilities[95] = 'ZxF5'
    set udg_CSS_Abilities[96] = 'ZxF6'
    set udg_CSS_Abilities[97] = 'ZxF7'
    set udg_CSS_Abilities[98] = 'ZxF8'
    set udg_CSS_Abilities[99] = 'ZxF9'
    set udg_CSS_Abilities[100] = 'ZxFa'
    set udg_CSS_Abilities[101] = 'ZxFb'
    set udg_CSS_Abilities[102] = 'ZxFc'
    set udg_CSS_Abilities[103] = 'ZxFd'
    set udg_CSS_Abilities[104] = 'ZxFe'
    set udg_CSS_Abilities[105] = 'ZxFf'
    set udg_CSS_Abilities[106] = 'ZxFg'
    set udg_CSS_Abilities[107] = 'ZxFh'
    set udg_CSS_Abilities[108] = 'ZxJ0'
    set udg_CSS_Abilities[109] = 'ZxJ1'
    set udg_CSS_Abilities[110] = 'ZxJ2'
    set udg_CSS_Abilities[111] = 'ZxJ3'
    set udg_CSS_Abilities[112] = 'ZxJ4'
    set udg_CSS_Abilities[113] = 'ZxJ5'
    set udg_CSS_Abilities[114] = 'ZxJ6'
    set udg_CSS_Abilities[115] = 'ZxJ7'
    set udg_CSS_Abilities[116] = 'ZxJ8'
    set udg_CSS_Abilities[117] = 'ZxJ9'
    set udg_CSS_Abilities[118] = 'ZxJa'
    set udg_CSS_Abilities[119] = 'ZxJb'
    set udg_CSS_Abilities[120] = 'ZxJc'
    set udg_CSS_Abilities[121] = 'ZxJd'
    set udg_CSS_Abilities[122] = 'ZxJe'
    set udg_CSS_Abilities[123] = 'ZxJf'
    set udg_CSS_Abilities[124] = 'ZxJg'
    set udg_CSS_Abilities[125] = 'ZxJh'
    set udg_CSS_Abilities[126] = 'ZxK0'
    set udg_CSS_Abilities[127] = 'ZxK1'
    set udg_CSS_Abilities[128] = 'ZxK2'
    set udg_CSS_Abilities[129] = 'ZxK3'
    set udg_CSS_Abilities[130] = 'ZxK4'
    set udg_CSS_Abilities[131] = 'ZxK5'
    set udg_CSS_Abilities[132] = 'ZxK6'
    set udg_CSS_Abilities[133] = 'ZxK7'
    set udg_CSS_Abilities[134] = 'ZxK8'
    set udg_CSS_Abilities[135] = 'ZxK9'
    set udg_CSS_Abilities[136] = 'ZxKa'
    set udg_CSS_Abilities[137] = 'ZxKb'
    set udg_CSS_Abilities[138] = 'ZxKc'
    set udg_CSS_Abilities[139] = 'ZxKd'
    set udg_CSS_Abilities[140] = 'ZxKe'
    set udg_CSS_Abilities[141] = 'ZxKf'
    set udg_CSS_Abilities[142] = 'ZxKg'
    set udg_CSS_Abilities[143] = 'ZxKh'
    set udg_CSS_Abilities[144] = 'ZxE0'
    set udg_CSS_Abilities[145] = 'ZxE1'
    set udg_CSS_Abilities[146] = 'ZxE2'
    set udg_CSS_Abilities[147] = 'ZxE3'
    set udg_CSS_Abilities[148] = 'ZxE4'
    set udg_CSS_Abilities[149] = 'ZxE5'
    set udg_CSS_Abilities[150] = 'ZxE6'
    set udg_CSS_Abilities[151] = 'ZxE7'
    set udg_CSS_Abilities[152] = 'ZxE8'
    set udg_CSS_Abilities[153] = 'ZxE9'
    set udg_CSS_Abilities[154] = 'ZxEa'
    set udg_CSS_Abilities[155] = 'ZxEb'
    set udg_CSS_Abilities[156] = 'ZxEc'
    set udg_CSS_Abilities[157] = 'ZxEd'
    set udg_CSS_Abilities[158] = 'ZxEe'
    set udg_CSS_Abilities[159] = 'ZxEf'
    set udg_CSS_Abilities[160] = 'ZxEg'
    set udg_CSS_Abilities[161] = 'ZxEh'
    set udg_CSS_Abilities[162] = 'ZxD0'
    set udg_CSS_Abilities[163] = 'ZxD1'
    set udg_CSS_Abilities[164] = 'ZxD2'
    set udg_CSS_Abilities[165] = 'ZxD3'
    set udg_CSS_Abilities[166] = 'ZxD4'
    set udg_CSS_Abilities[167] = 'ZxD5'
    set udg_CSS_Abilities[168] = 'ZxD6'
    set udg_CSS_Abilities[169] = 'ZxD7'
    set udg_CSS_Abilities[170] = 'ZxD8'
    set udg_CSS_Abilities[171] = 'ZxD9'
    set udg_CSS_Abilities[172] = 'ZxDa'
    set udg_CSS_Abilities[173] = 'ZxDb'
    set udg_CSS_Abilities[174] = 'ZxDc'
    set udg_CSS_Abilities[175] = 'ZxDd'
    set udg_CSS_Abilities[176] = 'ZxDe'
    set udg_CSS_Abilities[177] = 'ZxDf'
    set udg_CSS_Abilities[178] = 'ZxDg'
    set udg_CSS_Abilities[179] = 'ZxDh'
    set udg_CSS_Abilities[180] = 'ZxC0'
    set udg_CSS_Abilities[181] = 'ZxC1'
    set udg_CSS_Abilities[182] = 'ZxC2'
    set udg_CSS_Abilities[183] = 'ZxC3'
    set udg_CSS_Abilities[184] = 'ZxC4'
    set udg_CSS_Abilities[185] = 'ZxC5'
    set udg_CSS_Abilities[186] = 'ZxC6'
    set udg_CSS_Abilities[187] = 'ZxC7'
    set udg_CSS_Abilities[188] = 'ZxC8'
    set udg_CSS_Abilities[189] = 'ZxC9'
    set udg_CSS_Abilities[190] = 'ZxCa'
    set udg_CSS_Abilities[191] = 'ZxCb'
    set udg_CSS_Abilities[192] = 'ZxCc'
    set udg_CSS_Abilities[193] = 'ZxCd'
    set udg_CSS_Abilities[194] = 'ZxCe'
    set udg_CSS_Abilities[195] = 'ZxCf'
    set udg_CSS_Abilities[196] = 'ZxCg'
    set udg_CSS_Abilities[197] = 'ZxCh'

    loop
        exitwhen i > 30
        set udg_CSS_Power[i] = a
        set a = a*2
        set i = i + 1
    endloop

    set udg_CSS_Hashtable = InitHashtable()

    if udg_CSS_PreloadBoolean then
        call CSS_Preload()
    endif
endfunction
endlibrary

  • Unit Indexer
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: call ExecuteFunc("InitializeUnitIndexer")
      • Custom script: endfunction
      • -------- --------
      • -------- This is the most important function - it provides an index for units as they enter the map --------
      • -------- --------
      • Custom script: function IndexUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • -------- --------
      • -------- You can use the boolean UnitIndexerEnabled to protect some of your undesirable units from being indexed --------
      • -------- - Example: --------
      • -------- -- Set UnitIndexerEnabled = False --------
      • -------- -- Unit - Create 1 Dummy for (Triggering player) at TempLoc facing 0.00 degrees --------
      • -------- -- Set UnitIndexerEnabled = True --------
      • -------- --------
      • -------- You can also customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • UnitIndexerEnabled Equal to True
        • Then - Actions
          • -------- --------
          • -------- Generate a unique integer index for this unit --------
          • -------- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UDexRecycle Equal to 0
            • Then - Actions
              • Set UDex = (UDexGen + 1)
              • Set UDexGen = UDex
            • Else - Actions
              • Set UDex = UDexRecycle
              • Set UDexRecycle = UDexNext[UDex]
          • -------- --------
          • -------- Link index to unit, unit to index --------
          • -------- --------
          • Set UDexUnits[UDex] = (Matching unit)
          • Unit - Set the custom value of UDexUnits[UDex] to UDex
          • -------- --------
          • -------- Use a doubly-linked list to store all active indexes --------
          • -------- --------
          • Set UDexPrev[UDexNext[0]] = UDex
          • Set UDexNext[UDex] = UDexNext[0]
          • Set UDexNext[0] = UDex
          • -------- --------
          • -------- Fire index event for UDex --------
          • -------- --------
          • Set UnitIndexEvent = 0.00
          • Set UnitIndexEvent = 1.00
          • Set UnitIndexEvent = 0.00
          • Custom script: set udg_UDex = pdex
        • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • -------- --------
      • -------- The next function is called each time a unit enters the map --------
      • -------- --------
      • Custom script: function IndexNewUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • Custom script: local integer ndex
      • -------- --------
      • -------- Recycle indices of units no longer in-play every (15) units created --------
      • -------- --------
      • Set UDexWasted = (UDexWasted + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • UDexWasted Equal to 15
        • Then - Actions
          • Set UDexWasted = 0
          • Set UDex = UDexNext[0]
          • Custom script: loop
          • Custom script: exitwhen udg_UDex == 0
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Custom value of UDexUnits[UDex]) Equal to 0
            • Then - Actions
              • -------- --------
              • -------- Remove index from linked list --------
              • -------- --------
              • Custom script: set ndex = udg_UDexNext[udg_UDex]
              • Custom script: set udg_UDexNext[udg_UDexPrev[udg_UDex]] = ndex
              • Custom script: set udg_UDexPrev[ndex] = udg_UDexPrev[udg_UDex]
              • Set UDexPrev[UDex] = 0
              • -------- --------
              • -------- Fire deindex event for UDex --------
              • -------- --------
              • Set UnitIndexEvent = 2.00
              • Set UnitIndexEvent = 0.00
              • -------- --------
              • -------- Recycle the index for later use --------
              • -------- --------
              • Set UDexUnits[UDex] = No unit
              • Set UDexNext[UDex] = UDexRecycle
              • Set UDexRecycle = UDex
              • Custom script: set udg_UDex = ndex
            • Else - Actions
              • Set UDex = UDexNext[UDex]
          • Custom script: endloop
          • Custom script: set udg_UDex = pdex
        • Else - Actions
      • -------- --------
      • -------- Handle the entering unit (Matching unit) --------
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Custom value of (Matching unit)) Equal to 0
        • Then - Actions
          • Custom script: call IndexUnit()
        • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • -------- --------
      • -------- The next function initializes the core of the system --------
      • -------- --------
      • Custom script: function InitializeUnitIndexer takes nothing returns nothing
      • Custom script: local integer i = 0
      • Custom script: local region re = CreateRegion()
      • Custom script: local rect r = GetWorldBounds()
      • Set UnitIndexerEnabled = True
      • Custom script: call RegionAddRect(re, r)
      • Custom script: call TriggerRegisterEnterRegion(CreateTrigger(), re, Filter(function IndexNewUnit))
      • Custom script: call RemoveRect(r)
      • Custom script: set re = null
      • Custom script: set r = null
      • Custom script: loop
      • Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), Filter(function IndexUnit))
      • Custom script: set i = i + 1
      • Custom script: exitwhen i == 16
      • Custom script: endloop
      • -------- --------
      • -------- This is the "Unit Indexer Initialized" event, use it instead of "Map Initialization" for best results --------
      • -------- --------
      • Set UnitIndexEvent = 3.00
      • Set UnitIndexEvent = 0.00
 
Status
Not open for further replies.
Top