ibrary GetDamage requires Table
globals
private HandleTable tab
private HandleTable damage
//Set this to true if you want this system to get the attack damage of every unit of your map.
//But be aware that this may lag.
//If you let this to false then you will have to use the function Add(unit) to add a unit to this system.
private constant boolean ALL_UNITS = false
private constant integer DUMMY_ID = 'd000'
private constant real ARMOR_CONSTANT = 0.06
endglobals
static if not ALL_UNITS then
globals
private group UNITS = CreateGroup()
endglobals
public function Add takes unit u returns nothing
call GroupAddUnit( UNITS, u )
endfunction
endif
public function GetDamage takes unit u returns integer
return damage[u]
endfunction
public function GetArmor takes unit u returns real
local real life = GetWidgetLife( u )
local real life2
local real x = GetUnitX( u )
local real y = GetUnitY( u )
local unit v = CreateUnit( Player(15), DUMMY_ID, x, y, 0 )
local real test = 10
if GetWidgetLife(u) > 200 then
set test = 100
endif
call UnitDamageTarget( v, u, test, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null )
set life2 = life - GetWidgetLife( u )
call RemoveUnit( v )
set v = null
call SetWidgetLife( u, GetWidgetLife( u ) + life2 )
if ( life2 > test ) then
return (-1*(test - life2 ) ) / ( life2 * ARMOR_CONSTANT )
else
return ( test - life2 ) / ( life2 * ARMOR_CONSTANT )
endif
endfunction
private struct Damage extends array
unit attacker
unit attacked
trigger t
thistype recycle
static integer instanceCount
static thistype recycleNext
static method cond2 takes nothing returns boolean
local thistype this
if tab[GetEventDamageSource()] != 0 then
set this = tab[GetEventDamageSource()]
set damage[this.attacker] = R2I(GetEventDamage())
call tab.flush(this.attacker)
call DestroyTrigger(this.t)
set this.attacker = null
set this.attacked = null
set this.t = null
call this.destroy()
endif
return false
endmethod
static method cond takes nothing returns boolean
local thistype this
local boolean b = true
static if not ALL_UNITS then
if not IsUnitInGroup(GetAttacker(), UNITS) then
set b = false
endif
endif
if b then
if recycle == 0 then
set instanceCount = instanceCount + 1
set this = instanceCount
else
set this = recycle
set recycle = recycle.recycleNext
endif
set this.attacker = GetAttacker()
set this.attacked = GetTriggerUnit()
set this.t = CreateTrigger()
set tab[this.attacked] = this
call TriggerRegisterUnitEvent( this.t, this.attacked, EVENT_UNIT_DAMAGED )
call TriggerAddCondition( this.t, Condition( function thistype.cond2 ) )
endif
return false
endmethod
method destroy takes nothing returns nothing
set recycleNext = recycle
set recycle = this
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( t, Condition(function thistype.cond) )
set tab = HandleTable.create()
set damage = HandleTable.create()
set instanceCount = 0
set recycleNext = 0
set t = null
endmethod
endstruct
endlibrary
And putting them in a command bar is impossible. Unless.. you create a dummy counterpart for all heroes everytime one is selected, then force select. The dummy hero should use the Vexorian dummy model, and should look like the original hero through special effect creation. Also should be owned by an empty and shared control player slot to make it visible to everyone.
How to make it un-orderable without creating dummy abilities for all abilities? Set its cast point/backswing to 2+, then create a trigger that makes it stop everytime it's ordered. Remember to remove it from the minimap, and its ability to move and attack. Set the stats to be completely the same as the Hero. Preferably also move it to the Hero's pos. Deindex and kill it once deselected.
How to imitate original hero damage? Use +1 and -1 permanent damage tomes in conjunction with the GetDamage/armor library by Malhorne.
JASS:ibrary GetDamage requires Table globals private HandleTable tab private HandleTable damage //Set this to true if you want this system to get the attack damage of every unit of your map. //But be aware that this may lag. //If you let this to false then you will have to use the function Add(unit) to add a unit to this system. private constant boolean ALL_UNITS = false private constant integer DUMMY_ID = 'd000' private constant real ARMOR_CONSTANT = 0.06 endglobals static if not ALL_UNITS then globals private group UNITS = CreateGroup() endglobals public function Add takes unit u returns nothing call GroupAddUnit( UNITS, u ) endfunction endif public function GetDamage takes unit u returns integer return damage[u] endfunction public function GetArmor takes unit u returns real local real life = GetWidgetLife( u ) local real life2 local real x = GetUnitX( u ) local real y = GetUnitY( u ) local unit v = CreateUnit( Player(15), DUMMY_ID, x, y, 0 ) local real test = 10 if GetWidgetLife(u) > 200 then set test = 100 endif call UnitDamageTarget( v, u, test, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null ) set life2 = life - GetWidgetLife( u ) call RemoveUnit( v ) set v = null call SetWidgetLife( u, GetWidgetLife( u ) + life2 ) if ( life2 > test ) then return (-1*(test - life2 ) ) / ( life2 * ARMOR_CONSTANT ) else return ( test - life2 ) / ( life2 * ARMOR_CONSTANT ) endif endfunction private struct Damage extends array unit attacker unit attacked trigger t thistype recycle static integer instanceCount static thistype recycleNext static method cond2 takes nothing returns boolean local thistype this if tab[GetEventDamageSource()] != 0 then set this = tab[GetEventDamageSource()] set damage[this.attacker] = R2I(GetEventDamage()) call tab.flush(this.attacker) call DestroyTrigger(this.t) set this.attacker = null set this.attacked = null set this.t = null call this.destroy() endif return false endmethod static method cond takes nothing returns boolean local thistype this local boolean b = true static if not ALL_UNITS then if not IsUnitInGroup(GetAttacker(), UNITS) then set b = false endif endif if b then if recycle == 0 then set instanceCount = instanceCount + 1 set this = instanceCount else set this = recycle set recycle = recycle.recycleNext endif set this.attacker = GetAttacker() set this.attacked = GetTriggerUnit() set this.t = CreateTrigger() set tab[this.attacked] = this call TriggerRegisterUnitEvent( this.t, this.attacked, EVENT_UNIT_DAMAGED ) call TriggerAddCondition( this.t, Condition( function thistype.cond2 ) ) endif return false endmethod method destroy takes nothing returns nothing set recycleNext = recycle set recycle = this endmethod private static method onInit takes nothing returns nothing local trigger t = CreateTrigger() call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ATTACKED ) call TriggerAddCondition( t, Condition(function thistype.cond) ) set tab = HandleTable.create() set damage = HandleTable.create() set instanceCount = 0 set recycleNext = 0 set t = null endmethod endstruct endlibrary
The only problem here is the armor, though you can use any BonusMod to add armor.
Otherwise it is near perfect visually. If you want more cake, have a selection model created at its origin with the color of red.