HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Crtical Strike + ADamage = code opinion!

06-22-2009, 08:29 AM#1
Flame_Phoenix
Hi guys, this is a simple critical spell that heals nearby units. I made it using ADamage and I pan submiting it with other spells I made using ADamage in a small spellpack.
Basically, I would like some opinions about the code, rep++ will be awarded.

Collapse JASS:
//===========================================================================
//A JESP spell that causes the attacker to deal extra damage to an enemy unit
//on an attack. Nearby allied units are then healed by the damaged caused.
//
//@author Flame_Phoenix 
//
//Requires:
// - Adamage
// - xebasic and xedamage
//
//@credits:
// - Anitarf, for ADamage
// - Vexorian, for xebasic and xedamage
// - Moyack, for helping on improving this script
// - 0zyx0, for telling me how to make this script more efficient
//
//@version 1.3.2
//===========================================================================
scope WolfStrike initializer Init
//===========================================================================
//=============================SETUP START===================================
//===========================================================================
    globals
        private constant integer AID = 'A023'   //rw of the hero ability
        private constant string ALLY_EFFECT = "Abilities\\Spells\\Undead\\DeathPact\\DeathPactTarget.mdl"  //heal effect that will appear on healed units
        private constant string ENEMY_EFFECT = "Objects\\Spawnmodels\\Other\\BeastmasterBlood\\BeastmasterBlood.mdl"    //Damage effect that will appear on damage units
        private constant string FIRE_EFF = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl"  //an extra effect on the victim to make it look cooler =P
    endglobals
    
    private function Radius takes integer level returns real
    //the radius of the heal
        return level * 200.
    endfunction
    
    private function HealTargets takes unit attacker, unit friend returns boolean
    //the targets(friends) that will be healed with the damage caused
        return IsUnitAlly(friend, GetOwningPlayer(attacker)) and (IsUnitType(friend, UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(friend, UNIT_TYPE_MECHANICAL) == false) and (GetWidgetLife(friend) > 0.405) 
    endfunction
    
    private function Chances takes integer level returns real
    //the chances the caster has of causing extra damage
        return 1.//level * 0.1
    endfunction
    
    private function Damage takes real dam, integer level returns real
    //the extra damage caused
        return dam * (level + 0.5)
    endfunction
    
    private function setupDamageOptions takes xedamage d returns nothing
       set d.dtype = DAMAGE_TYPE_NORMAL   
       set d.atype = ATTACK_TYPE_NORMAL 
    endfunction

//===========================================================================
//=============================SETUP END=====================================
//===========================================================================
    globals
        private group g
        private boolexpr b
        private unit tmpAtt
        private xedamage damageOptions
        private timer damageTime    //timer that will be started at 0.0 to deal the extra damage
    endglobals
    
    private struct aVictim 
        unit attacker
        unit victim
        real extraDam
        integer level
        
        static method create takes unit att, unit vic, real bonusDam returns aVictim
            local aVictim this = aVictim.allocate()
            
            set .attacker = att
            set .victim = vic
            set .extraDam = bonusDam
            set .level = GetUnitAbilityLevel(att, AID)
            
            return this
        endmethod
    endstruct
//===========================================================================
    private function Targets takes nothing returns boolean
        return HealTargets(tmpAtt, GetFilterUnit())
    endfunction
//===========================================================================
    private function Conditions takes unit attacker, unit victim returns boolean 
        return (GetRandomReal(0, 1) <= Chances(GetUnitAbilityLevel(attacker, AID))) and (GetUnitAbilityLevel(attacker, AID) > 0) and (damageOptions.isInUse()==false) and IsUnitEnemy(victim, GetOwningPlayer(attacker)) and (IsUnitType(victim, UNIT_TYPE_STRUCTURE)==false) and (IsUnitType(victim, UNIT_TYPE_MECHANICAL)==false)
    endfunction
//===========================================================================
    private function DoDamage takes nothing returns nothing
        local aVictim thisVic = aVictim(GetTimerData(GetExpiredTimer()))
        
        //deal damage and release the timer !
        call damageOptions.damageTarget(thisVic.attacker, thisVic.victim, thisVic.extraDam)
        call ReleaseTimer(GetExpiredTimer())
    endfunction
//===========================================================================
    private function Actions takes unit damagedUnit, unit damageSource, real damage, real prevented returns nothing
        local integer lv  //level of the ability
        local real bonus    //bonus damage
        local texttag text //the nice textag
        local unit f
        local aVictim thisVic   //this will keep information about the damage we will cause
        
        if Conditions(damageSource, damagedUnit) then  
            set lv = GetUnitAbilityLevel(damageSource, AID) 
            set text = CreateTextTag()  
            set bonus = damage + Damage(damage, lv)
            set damageTime = NewTimer()
            set thisVic = aVictim.create(damageSource, damagedUnit, bonus)
            
            //Let's make the unit look as if it is taking fire, how? Let's make a fireball effect explode on them:
            call DestroyEffect( AddSpecialEffectTarget(FIRE_EFF, damagedUnit, "origin") ) 

            // We know it is a valid target, let's damage it?
            // we are retrieving the level from the struct's members, and it is used in
            // a simple damage formula, for every level the damage increases by 25.
            call SetTimerData(damageTime, integer(thisVic))
            call TimerStart(damageTime, 0.0, false, function DoDamage)
            
            call DestroyEffect(AddSpecialEffect(ENEMY_EFFECT, GetUnitX(damagedUnit), GetUnitY(damagedUnit)))
            
            set tmpAtt = damageSource
            call GroupEnumUnitsInRange(g, GetUnitX(damageSource), GetUnitY(damageSource), Radius(lv), b)
            loop
                set f = FirstOfGroup(g)
                exitwhen(f == null)
                call GroupRemoveUnit(g, f)
                    
                call SetWidgetLife(f, GetWidgetLife(f) + bonus)
                call DestroyEffect(AddSpecialEffect(ALLY_EFFECT, GetUnitX(f), GetUnitY(f)))
            endloop
                
            call SetTextTagText(text, I2S(R2I(bonus)) + "!", 0.024)
            call SetTextTagPos(text, GetUnitX(damageSource), GetUnitY(damageSource), 0.00)
            call SetTextTagColor(text, 255, 0, 0, 255)
            call SetTextTagVelocity(text, 0, 0.04)
            call SetTextTagVisibility(text, true)
            call SetTextTagFadepoint(text, 2)
            call SetTextTagLifespan(text, 5)
            call SetTextTagPermanent(text, false)
        endif
        
        set text = null
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        call ADamage_AddResponse( ADamage_Response.Actions )
        
        // Initializing the damage options:
        set damageOptions=xedamage.create()    // first instanciate a xeobject.
        call setupDamageOptions(damageOptions) // now call the function we saw before.
        
        //setting globals
        set g = CreateGroup()
        set b = Condition(function Targets)
        
        //Preloading effects
        call Preload(ALLY_EFFECT)
        call Preload(ENEMY_EFFECT)
        call Preload(FIRE_EFF)
    endfunction
endscope
06-22-2009, 08:51 AM#2
Anitarf
I never thought ADamage was this lame.
06-22-2009, 10:31 AM#3
moyack
Collapse JASS:
local trigger WolfStrikeTrg = CreateTrigger(  )
You never use this trigger....
06-22-2009, 10:46 AM#4
0zyx0
You could use HealTargets() as a boolexpr directly, it will reduce the number of function call by one every time the filter is called. HealTargets() isn't inline friendly anyway, so there is no noticable drawback in making it a multiline function.

setupDamageOptions can be replaced by two global constants.

aVictim doesn't need a creation method, the members can be set directly, this reduces the number of function calls.

ForGroup() is faster for iterating through groups than the FirstOfGroup() + remove method, but that would require you to pass additional data to a function that doesn't take anything.

And don't set damageTime to null. Use a global variable instead.
06-22-2009, 01:41 PM#5
Flame_Phoenix
Quote:
I never thought ADamage was this lame.
You never thought I would use it in the first place. This explains it all xD
Quote:
You never use this trigger....
Wermmm, in fact, you make a good point !

Quote:
You could use HealTargets() as a boolexpr directly, it will reduce the number of function call by one every time the filter is called. HealTargets() isn't inline friendly anyway, so there is no noticable drawback in making it a multiline function.
I could do it that way, but the user SETUP would be harder for the newb user to use. Besides, I believe the user shouldn't use GetFilterUnit(), he may not even know what that is!

Quote:
setupDamageOptions can be replaced by two global constants.
True, but I would have to use a keyword if I am not mistaken. I usually try to avoid them because I don't like them personally =P
Quote:
aVictim doesn't need a creation method, the members can be set directly, this reduces the number of function calls.
True again, but it makes the code harder to read for me. I simply think that if God created a "create" method, then we should use it=P
Quote:
ForGroup() is faster for iterating through groups than the FirstOfGroup() + remove method, but that would require you to pass additional data to a function that doesn't take anything.
True, but I believe the difference here is quite small ... I mean, no one will die for not using it =D
Quote:
And don't set damageTime to null. Use a global variable instead.
This is where you scare me ... so you say my Timer should be a global variable, Won't that make my spell not-MUI ? I am not sure about the speed of 0. timers, and I am (as you can see) totally afraid of using globals =S

It pisses me off that I can't rep++ you guys, when you deserve it .. I guess I will have to give you a special place in my credits section for you all =P
Anyway, you are now on credits, this is the least I can do.
06-22-2009, 02:02 PM#6
Anitarf
Quote:
Originally Posted by 0zyx0
setupDamageOptions can be replaced by two global constants.
Not entirely. You can do more things with setupDamageOptions than with just two constants.

Quote:
Originally Posted by Flame_Phoenix
You never thought I would use it in the first place. This explains it all xD
It doesn't matter who uses it, having to deal damage with a timer, not to mention having to deal damage to get bonus damage in the first place seems super lame now that I figured out a way to avoid all that.
06-22-2009, 02:11 PM#7
Flame_Phoenix
Quote:
It doesn't matter who uses it
Ah damn ... here I was, thinking I was the cause of your unhappiness.... well there will be other days and other opportunities =P
Quote:
having to deal damage with a timer, not to mention having to deal damage to get bonus damage in the first place seems super lame now that I figured out a way to avoid all that.
Now you say!? ... well, so should we (users of ADamage) expect some sort of upgrade soon?
Because if not, I was thinking and I intend to make a mini-script library, a function that does the damage, using xedamage and timer utils and it does all timer things inside it, so the user only need to do "UnitADamageTarget(args)" ...
=P

Anyway, code updated !! =D
06-22-2009, 02:33 PM#8
Anitarf
Quote:
Originally Posted by Flame_Phoenix
Now you say!? ... well, so should we (users of ADamage) expect some sort of upgrade soon?
Yes.
06-22-2009, 02:47 PM#9
0zyx0
Quote:
Originally Posted by Flame_Phoenix
True, but I would have to use a keyword if I am not mistaken.
Collapse JASS:
private constant damagetype DTYPE = DAMAGE_TYPE_NORMAL
private constant weapontype ATYPE = WEAPON_TYPE_NORMAL
//...
set damageOptions.dtype = DTYPE
set damageOptions.atype = ATYPE

Quote:
I simply think that if God created a "create" method, then we should use it=P
If that's true, there are six or seven gods.
06-22-2009, 04:45 PM#10
Flame_Phoenix
Collapse JASS:
private constant damagetype DTYPE = DAMAGE_TYPE_NORMAL
private constant weapontype ATYPE = WEAPON_TYPE_NORMAL
//...
set damageOptions.dtype = DTYPE
set damageOptions.atype = ATYPE
Somehow I always end up complicating things more than necessary .... yet I will follow Ani's suggestion, having in mind he is a mod and that I want my spell approved here xD
1+1 = fish !
Quote:
If that's true, there are six or seven gods.
Most likely xD
Btw, Chinese Gods don't count =P