//TESH.scrollpos=168
//TESH.alwaysfold=0
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ARMOR DETECTION SYSTEM>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//<< >> by DAELIN << >>
//<< >> (v 1.0) << >>
//<< ^^^^^^^^^^^^^^^^^^^^^^^ >>
//<< Description: This system is composed of four important functions, and two auxiliary . >>
//<< Using them you can not only detect the current armor of an unit, but you can >>
//<< also detect the type of armor the unit has (Small, Medium, Large, Fortified, >>
//<< Normal, Hero, Divine or Unarmored). You can also get the actual damage the >>
//<< unit could have received if it had no armor. >>
//<< >>
//<< Note: The system will work only if you do not play with the gameplay constants which affect >>
//<< the amount of damage each damage type can do to the armor type, along with the damage >>
//<< reduction an armor point does. >>
//<< >>
//<< Requirements: - Copy the code of this system entirely into the header of the map. >>
//<< - Copy the "Armor System Auxiliary" ability into your map. >>
//<< - Leave the constants of damage infliction and reduction as they are. >>
//<< - Leave 'Allz' (Item life bonus (least)) ability unchanged. >>
//<< >>
//<< Known bugs: - If an unit with Large armor is magic immune, the function will wrongly return >>
//<< "Normal". That is because the difference between the two types of armors is >>
//<< given by the 200% damage done by Magic attacks to Large armor. I have not >>
//<< succeeded yet to damage a spell immune unit with magical attack no matter >>
//<< the damage type. >>
//<< >>
//<< Armor Codes: Instead of messing up with map's files or common.j, I have made a separate >>
//<< function which converts the code of the armor types returned by the >>
//<< GetUnitArmorType function into a string with the name of the armor type. Here >>
//<< is the numeric equivalence of each armor type: >>
//<< >>
//<< Small (1) Medium (2) Large(3) >>
//<< >>
//<< Fortified(4) Normal(5) >>
//<< >>
//<< Hero (6) Unarmored (7) Divine(8) >>
//<< >>
//<< Contact: [email][email protected][/email] - Send an email if you have questions or suggestions >>
//<< >>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
constant function Armor_ID takes nothing returns integer
return 'A000' //rawcode of the auxiliary ability
endfunction
function IsUnitInvulnerable takes unit whichUnit returns boolean
local real life
local boolean b
call UnitAddAbility(whichUnit, 'allz')
set life = GetWidgetLife(whichUnit)
call UnitDamageTarget(whichUnit, whichUnit, 0.01, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
if GetWidgetLife(whichUnit)<life then
set b = false
else
set b = true
endif
call SetWidgetLife(whichUnit, life)
call UnitRemoveAbility(whichUnit, 'allz')
return b
endfunction
//DETECT UNIT"S ARMOR
function GetUnitArmor takes unit whichUnit returns real
local real life = GetWidgetLife(whichUnit)
local real reduction
local integer ID = Armor_ID() //rawcode of the auxiliary ability
local boolean b = IsUnitInvulnerable(whichUnit)
call UnitAddAbility(whichUnit, 'allz')
call UnitAddAbility(whichUnit, ID)
if b==true then
call SetUnitInvulnerable(whichUnit, false)
endif
call UnitDamageTarget( whichUnit, whichUnit, 16.00, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
if b==true then
call SetUnitInvulnerable(whichUnit, true)
endif
set reduction = (16.00-(life-GetWidgetLife(whichUnit)))/16.00
call UnitRemoveAbility(whichUnit, 'allz')
call UnitRemoveAbility(whichUnit, ID)
call SetWidgetLife(whichUnit, life)
return (50*reduction/(3.00-(3.00*reduction)))-30.00
endfunction
//GET DAMAGE WITHOUT ARMOR
function GetFullDamage takes real damage, real armor returns real
if armor>=0.00 then
return damage/(1-(((armor)*0.06)/(1.00+0.06*(armor))))
else
return damage/(2.00-Pow(0.94,(-armor)))
endif
endfunction
function EvalDamage takes unit whichUnit, real damage, attacktype t, real armor returns real
local real life = GetWidgetLife(whichUnit)
local real cdam
local boolean b = IsUnitInvulnerable(whichUnit)
if b==true then
call SetUnitInvulnerable(whichUnit, false)
endif
call UnitDamageTarget(whichUnit, whichUnit, damage, true, false, t, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
if b==true then
call SetUnitInvulnerable(whichUnit, true)
endif
set cdam = life-GetWidgetLife(whichUnit)
call SetWidgetLife(whichUnit, life)
return GetFullDamage(cdam, armor)
endfunction
//DETECT THE ARMOR OF AN UNIT
function GetUnitArmorType takes unit whichUnit returns integer
local real armor = GetUnitArmor(whichUnit)
local real damage
call UnitAddAbility(whichUnit, 'allz')
set damage = EvalDamage(whichUnit, 16.00,ATTACK_TYPE_MELEE, armor)
if (damage<=2.00 and EvalDamage(whichUnit, 16.00, ATTACK_TYPE_CHAOS, armor)>=15.98) then
call UnitRemoveAbility(whichUnit, 'allz')
return 8 //divine
elseif (damage>16.02) then
call UnitRemoveAbility(whichUnit, 'allz')
return 2 //medium
elseif (damage<15.98) then
call UnitRemoveAbility(whichUnit, 'allz')
return 4 //fortified
endif
set damage = EvalDamage(whichUnit, 16.00, ATTACK_TYPE_SIEGE, armor)
if (damage<15.98) then
call UnitRemoveAbility(whichUnit, 'allz')
return 6 //hero
elseif (damage>16.02) then
call UnitRemoveAbility(whichUnit, 'allz')
return 7 //unarmored
endif
if (EvalDamage(whichUnit,16.00,ATTACK_TYPE_PIERCE,armor)>16.02) then
call UnitRemoveAbility(whichUnit, 'allz')
return 1 //small
endif
if (EvalDamage(whichUnit,16.00,ATTACK_TYPE_MAGIC,armor)>16.02) then
call UnitRemoveAbility(whichUnit, 'allz')
return 3 //large
else
call UnitRemoveAbility(whichUnit, 'allz')
return 5 //normal
endif
endfunction
//CONVERT ARMOR TYPE TO STRING
function A2S takes integer armortype returns string
if (armortype==1) then
return "Small"
elseif (armortype==2) then
return "Medium"
elseif (armortype==3) then
return "Large"
elseif (armortype==4) then
return "Fortified"
elseif (armortype==5) then
return "Normal"
elseif (armortype==6) then
return "Hero"
elseif (armortype==7) then
return "Unarmored"
else
return "Divine"
endif
endfunction
function KnockBackUnit_Timer takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit knockbacked = LoadUnitHandle(udg_Hashtable,GetHandleId(t),0)
local integer amount = LoadInteger(udg_Hashtable,GetHandleId(t),1)
local real portion = LoadReal(udg_Hashtable,GetHandleId(t),2)
local integer current = LoadInteger(udg_Hashtable,GetHandleId(t),3)
local real angle = LoadReal(udg_Hashtable,GetHandleId(t),4)
local real x = GetUnitX(knockbacked) + portion * Cos(angle * 0.0174532)
local real y = GetUnitY(knockbacked) + portion * Sin(angle * 0.0174532)
call SaveInteger(udg_Hashtable,GetHandleId(t),3,current + 1)
if current == amount then
call FlushChildHashtable(udg_Hashtable,GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
elseif current < amount then
if IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) == false then
call SetUnitX(knockbacked,x)
call SetUnitY(knockbacked,y)
else
call SetUnitX(knockbacked,GetUnitX(knockbacked))
call SetUnitY(knockbacked,GetUnitY(knockbacked))
endif
endif
set knockbacked = null
set t = null
endfunction
function KnockBackUnit takes unit knockbacked, real distance, real time, real degrees, real period returns nothing
local integer amount = R2I(time / period)
local real portion = distance / amount
local timer t = CreateTimer()
call SaveUnitHandle(udg_Hashtable,GetHandleId(t),0,knockbacked)
call SaveInteger(udg_Hashtable,GetHandleId(t),1,amount)
call SaveReal(udg_Hashtable,GetHandleId(t),2,portion)
call SaveInteger(udg_Hashtable,GetHandleId(t),3,0)
call SaveReal(udg_Hashtable,GetHandleId(t),4,degrees)
call TimerStart(t,period,true,function KnockBackUnit_Timer)
set t = null
endfunction