• 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.

Ability Issues

Status
Not open for further replies.
Level 7
Joined
Aug 11, 2010
Messages
270
First things first; here's the script.

  • HIJ Repel Strikes Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Repel Strikes (Iron Juggernaut)
    • Actions
      • Set TempUnit = (Triggering unit)
      • Set TempInteger = (Custom value of TempUnit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (TempUnit is in HIJRepelStrikes_Group) Equal to True
        • Then - Actions
          • Set HIJRepelStrikes_Counter[TempInteger] = 0
          • Floating Text - Create floating text that reads Repel Strikes Refre... above TempUnit with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
          • Set TempFloatingText = (Last created floating text)
          • Floating Text - Set the velocity of TempFloatingText to 64.00 towards 90.00 degrees
          • Floating Text - Change TempFloatingText: Disable permanence
          • Floating Text - Change the lifespan of TempFloatingText to 1.50 seconds
          • Floating Text - Change the fading age of TempFloatingText to 0.75 seconds
        • Else - Actions
          • -------- ----- --------
          • Unit Group - Add TempUnit to HIJRepelStrikes_Group
          • Floating Text - Create floating text that reads Repel Strikes Activ... above TempUnit with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
          • Set TempFloatingText = (Last created floating text)
          • Floating Text - Set the velocity of TempFloatingText to 64.00 towards 90.00 degrees
          • Floating Text - Change TempFloatingText: Disable permanence
          • Floating Text - Change the lifespan of TempFloatingText to 1.50 seconds
          • Floating Text - Change the fading age of TempFloatingText to 0.75 seconds
          • -------- ----- --------
      • Set HIJRepelStrikes_MaxIndex = (HIJRepelStrikes_MaxIndex + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • HIJRepelStrikes_MaxIndex Equal to 1
        • Then - Actions
          • Trigger - Turn on HIJ Repel Strikes Loop <gen>
        • Else - Actions
  • HIJ Repel Strikes Effect
    • Events
    • Conditions
      • ((Owner of source) is an enemy of (Owner of target)) Equal to True
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (target is in HIJRepelStrikes_Group) Equal to True
        • Then - Actions
          • Set TempUnit = target
          • Set TempInteger = (Custom value of TempUnit)
          • -------- ----- --------
          • -------- Level 1 --------
          • -------- ----- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Level of Repel Strikes (Iron Juggernaut) for TempUnit) Equal to 1
            • Then - Actions
              • Set HIJRepelStrikes_Damage[TempInteger] = (HIJRepelStrikes_Damage[(Custom value of TempUnit)] + (amount x 0.50))
              • Set amount = (amount - 0.10)
            • Else - Actions
          • -------- ----- --------
          • -------- Level 2 --------
          • -------- ----- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Level of Repel Strikes (Iron Juggernaut) for TempUnit) Equal to 2
            • Then - Actions
              • Set HIJRepelStrikes_Damage[TempInteger] = (HIJRepelStrikes_Damage[(Custom value of TempUnit)] + (amount x 0.50))
              • Set amount = (amount - 0.15)
            • Else - Actions
          • -------- ----- --------
          • -------- Level 3 --------
          • -------- ----- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Level of Repel Strikes (Iron Juggernaut) for TempUnit) Equal to 3
            • Then - Actions
              • Set HIJRepelStrikes_Damage[TempInteger] = (HIJRepelStrikes_Damage[(Custom value of TempUnit)] + (amount x 0.75))
              • Set amount = (amount - 0.20)
            • Else - Actions
          • -------- ----- --------
          • -------- Level 4 --------
          • -------- ----- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Level of Repel Strikes (Iron Juggernaut) for TempUnit) Equal to 4
            • Then - Actions
              • Set HIJRepelStrikes_Damage[TempInteger] = (HIJRepelStrikes_Damage[(Custom value of TempUnit)] + (amount x 0.75))
              • Set amount = (amount - 0.25)
            • Else - Actions
          • -------- ----- --------
          • -------- Level 5 --------
          • -------- ----- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Level of Repel Strikes (Iron Juggernaut) for TempUnit) Equal to 3
            • Then - Actions
              • Set HIJRepelStrikes_Damage[TempInteger] = (HIJRepelStrikes_Damage[(Custom value of TempUnit)] + (amount x 1.00))
              • Set amount = (amount - 0.30)
            • Else - Actions
        • Else - Actions
  • HIJ Repel Strikes Loop
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in HIJRepelStrikes_Group and do (Actions)
        • Loop - Actions
          • Set TempUnit = (Picked unit)
          • Set TempInteger = (Custom value of TempUnit)
          • Set HIJRepelStrikes_Counter[TempInteger] = (HIJRepelStrikes_Counter[TempInteger] + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • HIJRepelStrikes_Counter[TempInteger] Equal to 10
            • Then - Actions
              • -------- ----- --------
              • Unit Group - Remove TempUnit from HIJRepelStrikes_Group
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (TempUnit is alive) Equal to True
                • Then - Actions
                  • Set TempPoint = (Position of TempUnit)
                  • Set TempGroup = (Units within 500.00 of TempPoint matching ((((Owner of TempUnit) is an enemy of (Owner of (Matching unit))) Equal to True) and (((Matching unit) is alive) Equal to True)))
                  • Floating Text - Create floating text that reads Repel Strikes Expir... above TempUnit with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
                  • Set TempFloatingText = (Last created floating text)
                  • Floating Text - Set the velocity of TempFloatingText to 64.00 towards 90.00 degrees
                  • Floating Text - Change TempFloatingText: Disable permanence
                  • Floating Text - Change the lifespan of TempFloatingText to 1.50 seconds
                  • Floating Text - Change the fading age of TempFloatingText to 0.75 seconds
                  • Trigger - Turn off M Damage Display <gen>
                  • Unit Group - Pick every unit in TempGroup and do (Actions)
                    • Loop - Actions
                      • Unit - Cause TempUnit to damage (Picked unit), dealing HIJRepelStrikes_Damage[TempInteger] damage of attack type Chaos and damage type Universal
                      • Floating Text - Create floating text that reads (String((Integer(HIJRepelStrikes_Damage[TempInteger])))) above (Picked unit) with Z offset 0.00, using font size 10.00, color (15.00%, 100.00%, 15.00%), and 0.00% transparency
                      • Set TempFloatingText = (Last created floating text)
                      • Floating Text - Set the velocity of TempFloatingText to 64.00 towards 90.00 degrees
                      • Floating Text - Change TempFloatingText: Disable permanence
                      • Floating Text - Change the lifespan of TempFloatingText to 1.50 seconds
                      • Floating Text - Change the fading age of TempFloatingText to 0.75 seconds
                  • Trigger - Turn on M Damage Display <gen>
                  • Custom script: call DestroyGroup (udg_TempGroup)
                  • Custom script: call RemoveLocation (udg_TempPoint)
                • Else - Actions
              • -------- ----- --------
              • Set HIJRepelStrikes_Counter[TempInteger] = 0
              • Set HIJRepelStrikes_Damage[TempInteger] = 0.00
              • Set HIJRepelStrikes_MaxIndex = (HIJRepelStrikes_MaxIndex - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • HIJRepelStrikes_MaxIndex Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
            • Else - Actions

Cooldown: 10 sec
Damage Type: Universal
When activated, reduces the physical damage Garth takes from enemy attacks by 10% for 10 seconds. After the damage reduction effect expires, Garth deals damage equal to 50% of the damage he's taken over the duration to those who surround him.


[jass=DamgeEvent]
////////////////////////////////////////////////////////////////////////////////////
//
// Physical Damage Detection Engine GUI v 1.1.0.0
// ----------------------------------------------
// 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
set udg_DAMAGE_TYPE_DETECTOR = 'A03G'
set udg_SET_MAX_LIFE = 'A03H'

// 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)
call SetWidgetLife(target, 0.0)
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)
call SetWidgetLife(target, 0.0)
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
[/code]

  • 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
The problem:
Well; the trigger works perfectly fine -- except for one thing; damage reduction is applied before the damage can be stored into a variable for the damage dealt. This means; the damage is reduced -- which isn't something I wanted...
I'm not quite sure how to fix this irritating problem since
  • Set amount = (amount - 0.15)
seems to happen before the damage can be stored inside of a variable; REGARDLESS of it's order on the script. Does anyone know how to fix this?
Also, I apologize in advance for the terrible layout; there's alot of information I needed to relay so I figured hidden boxes were the way to go.
 
Level 12
Joined
Nov 3, 2013
Messages
989
I'm pretty sure that the 1 second perodic event won't be accurate (from 0.01 to 1.00 seconds) for all arrays where index is bigger 1, because it will already be running.

Too tired to get the rest ._.

Edit: I don't think you reduce the damage taken at all?

AFAIK you don't change the actual damage taken, only the value that's being stored for the blast or w/e when the duration ends

Edit 2: or maybe the real variable "amount" is just that? Shouldn't it be multiplied though? I mean now you remove less than a single point of damage taken

I think it should be
  • Set amount = (amount * (0.95 - 5 * level of ability for unit))
I might be completely off and not know what I'm talking about though, have happened before :3

Edit 3: Whelp im off to sleep then before I make a fool out of myself even further, gl
 
Level 7
Joined
Aug 11, 2010
Messages
270
I'm pretty sure that the 1 second perodic event won't be accurate (from 0.01 to 1.00 seconds) for all arrays where index is bigger 1, because it will already be running.

Too tired to get the rest ._.

Edit: I don't think you reduce the damage taken at all?

AFAIK you don't change the actual damage taken, only the value that's being stored for the blast or w/e when the duration ends

Edit 2: or maybe the real variable "amount" is just that? Shouldn't it be multiplied though? I mean now you remove less than a single point of damage taken

I'm sorry? I don't quite understand what you mean. Well; I get the comment you made about the counter; but I don't quite understand what you mean.
I used the method of modifying the damage that was suggested by the author.

Edit: Oh, I get what you're saying. No -- the Set amount = (amount - 0.15) is there to catch any further damage reductions that the map has. (So it subtracts 15, rather than setting the damage reduction.)
 
Status
Not open for further replies.
Top