- Joined
- Oct 12, 2011
- Messages
- 3,449
[System] Dalv's DamageDetection (DDD)
Greetings
Code
Demo
Credits
Greetings
Why use this?
- Lite & fast
- GUI friendly
- Low requirement
- Supports damage type detection
- Efficient memory usage
- GUI friendly
- Low requirement
- Supports damage type detection
- Efficient memory usage
Code
JASS:
//x=============================================================== //
//x
// Dalv's Damage Detection
// v1.7.1
//
//x=============================================================== //
//x
// Advantages:
// - Lite & fast
// - GUI friendly
// - Low requirement
// - Supports damage type detection
// - Efficient memory usage
//
//
// Requirement(s):
// - Bribe's UnitIndexer
//
//
// How to install:
// - Copy DDD_ABILITY_1 ability to your map
// - Copy DDD_ABILITY_2 ability to your map
// - Copy the DDD trigger folder to your map
// - Delete VarCreator trigger
// - Install required systems correctly
// - Configure the system correctly
//
//
// User API:
// 1. Register a unit into the system, will ignore unit filtering.
// | function DDD__RegisterUnit takes unit whichUnit returns boolean
//
//
// 2. Remove a unit from the system.
// | function DDD__UnregisterUnit takes unit whichUnit returns boolean
//
//
// 3. Catch the damage event.
// | DDD__Event__Trigger EQUAL 1.00
//
//
// 4. Event responses (customizable).
// | DDD__Event__Source => source of damage (attacker)
//
// | DDD__Event__Target => target of damage (attacked)
//
// | DDD__Event__Amount => amount of damage
//
// | DDD__Event__Type => type of damage
// - DDD__DamageTypeSpell
// - DDD__DamageTypePhysic
// - DDD__DamageTypeCode
//
//
// 5. All damages by this function will be classified as "code" damage.
// | function DDD__DealCodeDamage takes unit source, widget target, reeal amount, boolean attack, boolean ranged,
// attacktype attackType, damagetype damageType, weapontype weaponType returns nothing
//
//
// 6. Turn on/off the damage detection.
// | function DDD__EnableDetection takes boolean enable returns boolean
// - true => on
// - false => off
//
// To check whether the detection is currently on/off (do not modify!)
// | DDD_IsDetectionEnabled
//
//
// 7. Turn on/off damage detection for a specific unit.
// | function DDD__EnableDetectionForUnit takes unit whichUnit, boolean enable returns boolean
// - true => on
// - false => off
//
//
// 8. Ignore (avoid) damage, damage won't be dealt completely.
// | set DDD__IgnoreThisEvent = true
//
//
// (You are not recommended to use any function or
// variable that is not mentioned in user API.)
//
//
// Credits:
// - Bribe for his GUI friendly UnitIndexer and UnitEvent.
//
// - Nestharus for his get spell resistance method
// and for his guidances.
//
// - Special thanks to looking_for_help for his
// damage type detection method.
//
//x=============================================================== //
//x
// CONFIGURATION //
//
// DDD_ABILITY_1's raw code at Object Editor
constant function DDD__Ability_1 takes nothing returns integer
return 'A000'
endfunction
// DDD_ABILITY_2's raw code at Object Editor
constant function DDD__Ability_2 takes nothing returns integer
return 'A001'
endfunction
// Number of units for each group.
// Higher value will increase the memory usage efficiency
// but will slow down the trigger clean up process
constant function DDD__GroupMaxMember takes nothing returns integer
return 25
endfunction
// If true, all classified unit will be registered automatically to
// the system
constant function DDD__EnableAutoRegister takes nothing returns boolean
return true
endfunction
// Classification for units that can be automatically registered to
// the system
function DDD__FilterUnit takes unit whichUnit returns boolean
return true // Currently it allows any unit to be registered
endfunction
//
//x=============================================================== //
// Enable/disable detection for specific unit
function DDD__EnableDetectionForUnit takes unit whichUnit, boolean enable returns boolean
local integer data = GetUnitUserData(whichUnit)
// If unit is registered
if udg_DDD__UnitIndex[data] != 0 and enable != udg_DDD__UnitDetectionState[data] then
set udg_DDD__UnitDetectionState[data] = enable
// Add or remove damage type detector
if enable and UnitAddAbility(whichUnit, DDD__Ability_1()) and UnitMakeAbilityPermanent(whichUnit, true, DDD__Ability_1()) then
elseif GetUnitAbilityLevel(whichUnit, DDD__Ability_1()) > 0 and UnitRemoveAbility(whichUnit, DDD__Ability_1()) then
endif
endif
return udg_DDD__UnitDetectionState[data]
endfunction
// Enable/disable detection for all registered units
function DDD__EnableDetection takes boolean enable returns boolean
local integer i = 1
local group tempGroup
local unit first
if enable != udg_DDD__IsDetectionEnabled then
loop
exitwhen i > udg_DDD__Group__Index
// Enable/disable detection triggers
if enable then
call EnableTrigger(udg_DDD__Group__Trigger[i])
else
call DisableTrigger(udg_DDD__Group__Trigger[i])
endif
// Disable detection for all registered units
set tempGroup = CreateGroup()
loop
set first = FirstOfGroup(udg_DDD__Group__Group[i])
exitwhen first == null
call GroupRemoveUnit(udg_DDD__Group__Group[i], first)
call GroupAddUnit(tempGroup, first)
call DDD__EnableDetectionForUnit(first, enable)
endloop
// Recycle group
call DestroyGroup(udg_DDD__Group__Group[i])
set udg_DDD__Group__Group[i] = tempGroup
set tempGroup = null
set i = i + 1
endloop
set udg_DDD__IsDetectionEnabled = enable
endif
return udg_DDD__IsDetectionEnabled
endfunction
// Function to obtain unit's spell resistance
function DDD__GetSpellResistance takes unit whichUnit returns real
local real life = GetWidgetLife(whichUnit)
local real max = GetUnitState(whichUnit, UNIT_STATE_MAX_LIFE)
local real result
call SetWidgetLife(whichUnit, max)
// Deal test damage
set udg_DDD__Enabled = false
call UnitDamageTarget(whichUnit, whichUnit, -max/2, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
set udg_DDD__Enabled = true
// Calculate resistance based on collected data
set result = 2*(max-GetWidgetLife(whichUnit))/max
call SetWidgetLife(whichUnit, life)
return result
endfunction
// Detect damage type
function DDD__GetDamageType takes nothing returns integer
if udg_DDD__CodeDetector then
set udg_DDD__CodeDetector = false
return udg_DDD__DamageTypeCode
elseif udg_DDD__Event__Amount < 0 then
set udg_DDD__Event__Amount = -udg_DDD__Event__Amount
return udg_DDD__DamageTypeSpell
else
return udg_DDD__DamageTypePhysic
endif
return 0
endfunction
// Remove protection
function DDD__Deprotect takes nothing returns boolean
local unit u = GetTriggerUnit()
// Remove health bonus
if GetUnitAbilityLevel(u, DDD__Ability_2()) > 0 and UnitRemoveAbility(u, DDD__Ability_2()) then
endif
// Refresh life
call SetWidgetLife(u, udg_DDD__Protect__Health[GetUnitUserData(u)])
call DestroyTrigger(GetTriggeringTrigger())
set u = null
return false
endfunction
// Protect unit from a native damage
function DDD__Protect takes unit whichUnit, real damage returns nothing
local trigger t = CreateTrigger()
local real life = GetWidgetLife(whichUnit)
local real max = GetUnitState(whichUnit, UNIT_STATE_MAX_LIFE)
set udg_DDD__Protect__Health[GetUnitUserData(whichUnit)] = life
// If the unit needs additional hp
if life + RAbsBJ(damage) > max then
call UnitAddAbility(whichUnit, DDD__Ability_2())
endif
// If physical damage
if damage > 0 then
call SetWidgetLife(whichUnit, life+damage)
call TriggerRegisterUnitStateEvent(t, whichUnit, UNIT_STATE_LIFE, LESS_THAN, life+damage/2)
else
call SetWidgetLife(whichUnit, life)
call TriggerRegisterUnitStateEvent(t, whichUnit, UNIT_STATE_LIFE, GREATER_THAN, life-damage/2)
endif
call TriggerAddCondition(t, Condition(function DDD__Deprotect))
set t = null
endfunction
function DDD__killTarget takes nothing returns nothing
call DDD__EnableDetectionForUnit(udg_DDD__Event__Target, false)
call UnitDamageTarget(udg_DDD__Event__Source, udg_DDD__Event__Target, 10000000, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
call DDD__EnableDetectionForUnit(udg_DDD__Event__Target, true)
endfunction
// Executed on damage event
function DDD__onDamage takes nothing returns boolean
local real resistance
local real life
local real damage
local unit target
local unit ptarget
local unit psource
local real pamount
local integer ptype
local integer data
if udg_DDD__Enabled then
// Original target
set target = GetTriggerUnit()
set data = GetUnitUserData(target)
// If target is registered in the system
if udg_DDD__UnitIndex[data] != 0 and udg_DDD__UnitDetectionState[data] then
// Original damage
set damage = GetEventDamage()
// Previous data
set ptarget = udg_DDD__Event__Target
set psource = udg_DDD__Event__Source
set pamount = udg_DDD__Event__Amount
set ptype = udg_DDD__Event__Type
// If spell damage is detected
if damage < 0 then
set resistance = DDD__GetSpellResistance(target)
if resistance > 1 then
set damage = damage*resistance
endif
endif
// Modifiable data
set udg_DDD__Event__Target = target
set udg_DDD__Event__Amount = damage
set udg_DDD__Event__Source = GetEventDamageSource()
set udg_DDD__Event__Type = DDD__GetDamageType()
// Fire the damage event
set udg_DDD__Event__Trigger = 1
set udg_DDD__Event__Trigger = 0
// Substract life by damage amount
set life = GetWidgetLife(udg_DDD__Event__Target) - udg_DDD__Event__Amount
if life > 0.405 then
call SetWidgetLife(udg_DDD__Event__Target, life)
endif
// If event target isn't modified
if target == udg_DDD__Event__Target then
// If need to be protected
if life > 0.405 then
if RAbsBJ(damage) > 0.01 then
call DDD__Protect(target, damage)
endif
// If need damage to kill
elseif damage < 0 then
call DDD__killTarget()
else
call SetWidgetLife(target, damage)
endif
else
// If need to be protected
if RAbsBJ(damage) > 0.01 then
call DDD__Protect(target, damage)
endif
// If need damage to kill
if life <= 0.405 then
call DDD__killTarget()
endif
endif
// Reset the data
set udg_DDD__Event__Source = psource
set udg_DDD__Event__Target = ptarget
set udg_DDD__Event__Amount = pamount
set udg_DDD__Event__Type = ptype
// Remove leak
set psource = null
set ptarget = null
endif
set target = null
endif
return false
endfunction
// Register a unit into the system
function DDD__RegisterUnit takes unit whichUnit returns boolean
local integer data = GetUnitUserData(whichUnit)
// If unit hasn't been registered yet
if udg_DDD__UnitIndex[data] == 0 then
// If new node is required then create it
if udg_DDD__Group__Counter[udg_DDD__Group__Index] == DDD__GroupMaxMember() then
set udg_DDD__Group__Index = udg_DDD__Group__Index + 1
set udg_DDD__Group__Group[udg_DDD__Group__Index] = CreateGroup()
set udg_DDD__Group__Trigger[udg_DDD__Group__Index] = CreateTrigger()
call TriggerAddCondition(udg_DDD__Group__Trigger[udg_DDD__Group__Index], Condition(function DDD__onDamage))
endif
// Register unit into the current node
set udg_DDD__UnitDetectionState[data] = true
set udg_DDD__UnitIndex[data] = udg_DDD__Group__Index
set udg_DDD__Group__Counter[udg_DDD__Group__Index] = udg_DDD__Group__Counter[udg_DDD__Group__Index] + 1
// Add damage type detector ability
if UnitAddAbility(whichUnit, DDD__Ability_1()) and UnitMakeAbilityPermanent(whichUnit, true, DDD__Ability_1()) then
endif
call GroupAddUnit(udg_DDD__Group__Group[udg_DDD__Group__Index], whichUnit)
call TriggerRegisterUnitEvent(udg_DDD__Group__Trigger[udg_DDD__Group__Index], whichUnit, EVENT_UNIT_DAMAGED)
return true
endif
return false
endfunction
// Remove a unit from the system
function DDD__UnregisterUnit takes unit whichUnit returns boolean
local integer data = GetUnitUserData(whichUnit)
local integer index = udg_DDD__UnitIndex[data]
local unit first
// If unit is registered
if index > 0 then
// Remove from current node
call GroupRemoveUnit(udg_DDD__Group__Group[index], whichUnit)
set udg_DDD__Group__Counter[index] = udg_DDD__Group__Counter[index] - 1
set udg_DDD__UnitDetectionState[data] = false
set udg_DDD__UnitIndex[data] = 0
// Check whether unit is in the latest node or not
if index == udg_DDD__Group__Index then
// If node is empty then destroy it
if udg_DDD__Group__Counter[index] == 0 then
// Remove leaks
call DestroyTrigger(udg_DDD__Group__Trigger[index])
call DestroyGroup(udg_DDD__Group__Group[index])
set udg_DDD__Group__Trigger[index] = null
set udg_DDD__Group__Group[index] = null
set udg_DDD__Group__Index = udg_DDD__Group__Index - 1
endif
// If unit isn't located in the last node and
// that node is empty already, then destroy
elseif udg_DDD__Group__Counter[index] == 0 then
call DestroyTrigger(udg_DDD__Group__Trigger[index])
// Transfer data from last node to the destroyed node
loop
set first = FirstOfGroup(udg_DDD__Group__Group[udg_DDD__Group__Index])
exitwhen first == null
call GroupRemoveUnit(udg_DDD__Group__Group[udg_DDD__Group__Index], first)
call GroupAddUnit(udg_DDD__Group__Group[index], first)
set udg_DDD__UnitIndex[GetUnitUserData(first)] = index
endloop
set udg_DDD__Group__Trigger[index] = udg_DDD__Group__Trigger[udg_DDD__Group__Index]
set udg_DDD__Group__Counter[index] = udg_DDD__Group__Counter[udg_DDD__Group__Index]
// Remove leaks
call DestroyGroup(udg_DDD__Group__Group[udg_DDD__Group__Index])
set udg_DDD__Group__Trigger[udg_DDD__Group__Index] = null
set udg_DDD__Group__Group[udg_DDD__Group__Index] = null
set udg_DDD__Group__Index = udg_DDD__Group__Index - 1
endif
return true
endif
return false
endfunction
// All damages caused by this function will be classified as "code" damage
function DDD__DealCodeDamage takes unit source, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns nothing
set udg_DDD__CodeDetector = true
call UnitDamageTarget(source, target, amount, attack, ranged, attackType, damageType, weaponType)
endfunction
// Executed on index event
function DDD__onIndex takes nothing returns boolean
if DDD__FilterUnit(udg_UDexUnits[udg_UDex]) then
call DDD__RegisterUnit(udg_UDexUnits[udg_UDex])
endif
return false
endfunction
// Executed on deindex event
function DDD__onDeindex takes nothing returns boolean
call DDD__UnregisterUnit(udg_UDexUnits[udg_UDex])
return false
endfunction
function InitTrig_DDD takes nothing returns nothing
local trigger t
// Init damage types
set udg_DDD__DamageTypePhysic = 1
set udg_DDD__DamageTypeSpell = 2
set udg_DDD__DamageTypeCode = 3
set udg_DDD__Enabled = true
set udg_DDD__Group__Counter[0] = DDD__GroupMaxMember()
if DDD__EnableAutoRegister() then
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 1.00)
call TriggerAddCondition(t, Condition(function DDD__onIndex))
endif
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_DeathEvent", EQUAL, 3.00)
call TriggerAddCondition(t, Condition(function DDD__onDeindex))
set t = null
endfunction
Demo
-
on damage
-
Events
- Game - DDD__Event__Trigger becomes Equal to 1.00
-
Conditions
- DDD__Event__Amount Not equal to (!=) 0.00
-
Actions
- -------- --------------------------------------------------- --------
- -------- ----------Manipulating Event---------- --------
-
-------- --------------------------------------------------- --------
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- (Unit-type of DDD__Event__Source) Equal to (==) Sorceress
-
Then - Actions
- -------- Switch to code damage type --------
- Set DDD__Event__Type = DDD__DamageTypeCode
- Else - Actions
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- (Unit-type of DDD__Event__Source) Equal to (==) Priest
-
Then - Actions
- -------- Switch to spell damage type --------
- Set DDD__Event__Type = DDD__DamageTypeSpell
- Else - Actions
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- (Unit-type of DDD__Event__Source) Equal to (==) Knight
-
Then - Actions
- -------- Reduce Knight's damage to 10% --------
- Set DDD__Event__Amount = (DDD__Event__Amount x 0.10)
- Else - Actions
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- (Unit-type of DDD__Event__Target) Equal to (==) Peasant
-
Then - Actions
- -------- Peasant heals the damage source --------
- Set DDD__Event__Target = DDD__Event__Source
- Set DDD__Event__Amount = (DDD__Event__Amount x -1.00)
- Else - Actions
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- (Unit-type of DDD__Event__Source) Equal to (==) Footman
-
Then - Actions
- -------- Footman hurts himself --------
- Set DDD__Event__Target = DDD__Event__Source
- Else - Actions
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- (Unit-type of DDD__Event__Source) Equal to (==) Mountain King
-
Then - Actions
- -------- MK deals 4x damage --------
- Set DDD__Event__Amount = (DDD__Event__Amount x 4.00)
- Else - Actions
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- (Unit-type of DDD__Event__Target) Equal to (==) Priest
-
Then - Actions
- Custom script: if GetWidgetLife(udg_DDD__Event__Target) < 100 then
- -------- Priest explodes on certain condition --------
- Custom script: call SetUnitExploded(udg_DDD__Event__Target, true)
- Unit - Cause DDD__Event__Source to damage DDD__Event__Target, dealing 99999.00 damage of attack type Chaos and damage type Normal
- Custom script: endif
- Else - Actions
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
- -------- #################### --------
- -------- --------------------------------------------------- --------
- -------- to deal un-detected damage, you can do this trick --------
- Custom script: call DDD__EnableDetectionForUnit(udg_DDD__Event__Target, false)
- Unit - Cause DDD__Event__Source to damage DDD__Event__Target, dealing 100.00 damage of attack type Spells and damage type Normal
- Custom script: call DDD__EnableDetectionForUnit(udg_DDD__Event__Target, true)
- -------- the damage will be dealt without being recognized by the detector, and you can do it anywhere --------
- -------- --------------------------------------------------- --------
- -------- #################### --------
- -------- --------------------------------------------------- --------
- -------- ----------Displaying Damage---------- --------
- -------- --------------------------------------------------- --------
-
-------- If damage type is physic --------
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- DDD__Event__Type Equal to (==) DDD__DamageTypePhysic
-
Then - Actions
- -------- give red color --------
- Set demo_color = |cffff0000
-
Else - Actions
-
-------- If damage type is spell --------
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- DDD__Event__Type Equal to (==) DDD__DamageTypeSpell
-
Then - Actions
- -------- give blue color --------
- Set demo_color = |cff0000ff
-
Else - Actions
-
-------- If damage type is code --------
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
- DDD__Event__Type Equal to (==) DDD__DamageTypeCode
-
Then - Actions
- -------- give green color --------
- Set demo_color = |cff00ff00
- Else - Actions
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
-------- If damage type is code --------
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
-------- If damage type is spell --------
-
If - Conditions
-
Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
- -------- display damage as floating text --------
- Floating Text - Create floating text that reads (demo_color + ((String(DDD__Event__Amount)) + |r)) above DDD__Event__Target with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
- Floating Text - Set the velocity of (Last created floating text) to 64.00 towards 90.00 degrees
- Floating Text - Change (Last created floating text): Disable permanence
- Floating Text - Change the lifespan of (Last created floating text) to 2.50 seconds
- Floating Text - Change the fading age of (Last created floating text) to 2.00 seconds
-
Events
Credits
- looking_for_help for his damage type detection method
and for being my main inspiration for this system.
- Bribe for his GUI unit indexer.
- Nestharus
and for being my main inspiration for this system.
- Bribe for his GUI unit indexer.
- Nestharus
Attachments
Last edited: