HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Defend ability - Reduce damage of frontal attacks?

02-08-2008, 10:58 AM#1
Bsycho
hi people, im trying to implement a modified defend version in my map.
im expecting difficulties, so im asking you guys if it can be done without being an advanced jasser.


so here it goes -
idea: defend ability that does not work in its original way, but reduces the damage of incoming attacks in a certain angle (say: 90°) in front of the defending unit (ie: footman).

my approach:
1) modify defend - so it doesnt reduce or deflect any damage
2) if defend is used - add disabled spellbook containing hardened skin ability (ie: reduce damage by 8 points)
3) if defend is switched off - remove spellbook
4) use modified backstab system to detect angle of incoming attacks
5) if attacker is NOT in front of the defending unit - damage defending unit equal to attacker damage (to a maximum of ie: 8 damage)


ok, problems start with 5):

i cant just trigger 8 damage, because if the attack would deal 5 damage before reduction, the trigger will cause too much damage.
so this means if have to use a attack damage system, right?
i thought of this one: http://www.wc3campaigns.net/showthread.php?t=98231
but as im using only basic jass functions to remove leaks and such, im not sure if ill be able to implement it well.


so basicly i want to know:
- if there's an easier way to get the effect i want
- some advice how to best approach the detection of attacker damage

thx,
bsycho
02-08-2008, 12:28 PM#2
Gorman
Cant you just remake the whole system so it works differently?

1) modify defend - so it doesnt reduce or deflect any damage
2) if defend is used - Add unit to a special group called "yay defend!"
3) defend is switched off - remove the unit from the group
4) when ever a unit from that group is DAMAGED check the modified back stab to see angles
5) if attacker IS in front of defender prevent that damage, then damage the defender for the modified damage (damage - 8 or whatever you wanted).

Wouldnt that work much better?
02-08-2008, 12:49 PM#3
Bsycho
if you could explain me how to do that exactly - yes

but how do u prevent the damage of a specified source? how do u get the damage value in the first place?
so, i still would need the damage detection.
02-08-2008, 01:05 PM#4
Gorman
sry man i cant show you how now, im sure Pyro or someone will, i gtg go sleep
02-08-2008, 01:49 PM#5
Anitarf
Heh, I have a defend ability coded that works like that, but it requires an altered version of my aBuff system to work. I was going to add damage prevention functionality to my regular release of the system, but it will take me some time to do so. In the meantime, I can supply you with some functions that I use, but not a whole system:

Collapse JASS:
    globals
        private constant integer SURVIVAL_ABILITY = 'A022' //bonus hp ability to allow for prevention of lethal damage
    endglobals

    private function DefendAngle takes unit att, unit def returns boolean
        local real r1 = GetUnitX( att )
        local real r2 = GetUnitY( att )
        local real r3 = GetUnitX( def )
        local real r4 = GetUnitY( def )
        local real r5 = Atan2BJ( ( r4 - r2 ), ( r3 - r1 ) )
        local real r6 = GetUnitFacing( def )
        local real r7

        if r5 < 0.0 then
            set r5 = r5 + 360.0
        endif
        set r7 = r6 - r5
        if r7 > 180 then
            set r7 = r7 - 360
        elseif r7 < -180 then
            set r7 = r7 + 360
        endif
        return (r7>135 or r7<-135)
    endfunction    

    private function GetUnitArmour takes unit u, unit damager returns real
        local real armour = 0

                if IsUnitInGroup(u, udg_defendingUnits) and DefendAngle(damager, u) then
                    set armour = armour + 8
                endif
                //you can insert other damage reduction effects here

        return armour
    endfunction
    
    private struct delayedHP
        unit u
        real hp
    endstruct
    
    private function DelayedHP takes nothing returns nothing
        local timerStr t = GetTimerStruct(GetExpiredTimer()) //I use my aBuff system's timers here
        local delayedHP dhp = delayedHP(t.data)
        call UnitRemoveAbility(dhp.u, SURVIVAL_ABILITY)
        call SetWidgetLife(dhp.u, dhp.hp)
        call dhp.destroy()
        call t.destroy()
    endfunction
    
// The following function must be called from a damage detection system
    private function ArmourSystem takes unit damaged, unit damager, real damage returns real
        local real armour = GetUnitArmour(damaged, damager)
        local real life = GetWidgetLife(damaged)
        local real maxlife = GetUnitState(damaged,UNIT_STATE_MAX_LIFE)
        local delayedHP dhp
        local timerStr t //I use my aBuff system's timers here

        //call BJDebugMsg(GetUnitName(damager)+" deals "+R2S(damage)+" damage. "+GetUnitName(damaged)+"'s armour: "+R2S(armour))

        //damage prevention
        if armour > damage then
            set armour = damage
        endif
        if life-damage+armour>0.405 then
        //unit should survive, bother about it
            if maxlife < life+armour then
            //need a delayed hp restoration
                call SetWidgetLife(damaged, maxlife)
                set armour = life-maxlife+armour
                set dhp = delayedHP.create()
                set dhp.u=damaged
                set dhp.hp=maxlife-damage+armour
                if maxlife-damage <=0.405 then
                //need a survival ability
                    call UnitAddAbility(damaged, SURVIVAL_ABILITY)
                endif
                set t = timerStr.create()
                set t.data = integer(dhp)
                call TimerStart(t.t, 0.0, false, function DelayedHP)
            else
            //hp may be restored immediately
                call SetWidgetLife(damaged, life+armour)
            endif

        endif
        
        return damage
    endfunction
02-09-2008, 07:52 AM#6
Bsycho
thanks for the help, but as i mentioned, im not the expert jasser so i have my little troubles setting up functions. also i dont want to implement multiple systems only for one spell.

currently im using daelin's armor detection system for various reasons. think this will help me to detect the damage as well? it looks quite similar if i check it:

Collapse JASS:
constant function Armor_ID takes nothing returns integer
    return 'A00C' //rawcode of the auxiliary ability
endfunction

constant function ADS_Unit takes nothing returns integer
    return 'h001' //rawcode of ADS unit
endfunction


//*************************************
//Compatibility functions


function ADS_AuxiliaryCondition takes nothing returns boolean
    return GetUnitTypeId(GetEventDamageSource())!=ADS_Unit()
endfunction

//protected EVENT_UNIT_DAMAGE 
function TriggerRegisterUnitEventDamaged takes trigger t, unit u returns event
    call TriggerAddCondition(t, Condition(function ADS_AuxiliaryCondition))
    return TriggerRegisterUnitEvent (t, u, EVENT_UNIT_DAMAGED)
endfunction

//protected damage function
function ADS_UnitDamageTarget takes unit whichUnit, unit target, real amount, attacktype attackType, damagetype damageType returns boolean
    local unit aux = CreateUnit(GetOwningPlayer(whichUnit), ADS_Unit(), GetUnitX(whichUnit), GetUnitY(whichUnit), 0.00)
    local boolean b = UnitDamageTarget(aux, target, amount, true, false, attackType, damageType, null)
    call RemoveUnit(aux)
    set aux = null
    return b
endfunction

//*************************************
//Auxiliary functions

function IsUnitInvulnerable takes unit whichUnit returns boolean
    local real life
    local boolean b
    call UnitAddAbility(whichUnit, 'allz')
    set life = GetWidgetLife(whichUnit)
    call ADS_UnitDamageTarget (whichUnit, whichUnit, 0.01, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL)
//    call UnitDamageTarget(whichUnit, whichUnit, 0.01, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
    if GetWidgetLife(whichUnit)<life then
       set b = false
    else
       set b = true
    endif
    call SetWidgetLife(whichUnit, life)
    call UnitRemoveAbility(whichUnit, 'allz')
    return b
endfunction


//*************************************
//Armor functions

//DETECT UNIT'S ARMOR
function GetUnitArmor takes unit whichUnit returns real
    local real life = GetWidgetLife(whichUnit)
    local real reduction
    local integer ID
    local boolean b
    if (whichUnit!=null and life>=0.405) then
    set ID = Armor_ID()
    set b = IsUnitInvulnerable(whichUnit)
    call UnitAddAbility(whichUnit, 'allz')
    call UnitAddAbility(whichUnit, ID)
    if b==true then
      call SetUnitInvulnerable(whichUnit, false)
    endif
    call ADS_UnitDamageTarget (whichUnit, whichUnit, 16.00, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL)
    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
    else
    return 0.00
    endif
endfunction


//GIVEN INITIAL DAMAGE, DETERMINES HOW MUCH IT WOULD BE REDUCED BY AN AMOUNT OF ARMOR
function GetArmorDamage takes real damage, real armor returns real
    if (armor>=0.00) then
        return damage*(1-(((armor)*0.06)/(1+0.06*(armor))))
    else
        return damage*(2-Pow(0.94,(-armor)))
    endif
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 ADS_UnitDamageTarget (whichUnit, whichUnit, damage, t, DAMAGE_TYPE_NORMAL)
    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
constant 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"
    elseif (armortype==8) then
        return "divine"
    else
        return "unknown"
    endif
endfunction

//CONVERT STRING TO ARMOR TYPE
function S2A takes string s returns integer
    set s = StringCase(s,false)
    if (s=="small") then
        return 1
    elseif (s=="medium") then
        return 2
    elseif (s=="large") then
        return 3
    elseif (s=="fortified") then
        return 4
    elseif (s=="normal") then
        return 5
    elseif (s=="hero") then
        return 6
    elseif (s=="unarmored") then
        return 7
    elseif (s=="divine") then
        return 8
    else    
        return 0
    endif
endfunction
02-09-2008, 10:40 PM#7
Pyrogasm
I don't see how is Armor Detection System is going to help you. Why don't you show what code you do have so we can better help you. Additionally, you may find this useful: Detecting a Backstab