• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Mana steal and some other questions

Status
Not open for further replies.
Level 1
Joined
Aug 28, 2012
Messages
5
I would like to make a passive ability that similar to vampiric ability but make the hero gain some mp when hits the enemy

In the CandyWar map, Blizzard gives the warriors such an ability. However, it has a small bug that you can still gain mp when stop the action before hits, though there's a 0.9 second cooldown

I use a unit damage event to eliminate this bug, but I thought it is wasteful to register every unit a damage event. And then I write a new method (maybe just new for me)
JASS:
//condition for attack event
function Trig_Battlesoul_Conditions takes nothing returns boolean
    return (GetUnitAbilityLevel(GetAttacker(), 'A60A')>0) and (not IsUnitType(GetTriggerUnit(), UNIT_TYPE_MECHANICAL)) and (not IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE)) and (IsUnitEnemy(GetTriggerUnit(), GetOwningPlayer(GetAttacker())))
endfunction

//condition for damage event
function Trig_Battlesoul_Hit_Conditions takes nothing returns boolean
    return (GetUnitAbilityLevel(GetEventDamageSource(), 'A60A') > 0)
endfunction

//action for damage event that grants the attacker some mp
function Trig_Battlesoul_Hit_Actions takes nothing returns nothing
    call SetUnitManaBJ(GetEventDamageSource(), ( GetUnitState( GetEventDamageSource(), UNIT_STATE_MANA) + ( 45.00 + ( 10.00 * I2R(GetUnitAbilityLevelSwapped('A60A', GetEventDamageSource())) ) ) ) )
    call DisableTrigger(GetTriggeringTrigger())
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

//action for attack event, which dynamically creates a temporate damage event trigger
function Trig_Battlesoul_Actions takes nothing returns nothing
    local trigger udg_trg = CreateTrigger()
    local unit udg_target = GetTriggerUnit()
    call TriggerRegisterUnitEvent(udg_trg, udg_target, EVENT_UNIT_DAMAGED)
    call TriggerAddCondition(udg_trg, Condition(function Trig_Battlesoul_Hit_Conditions))
    call TriggerAddAction(udg_trg, function Trig_Battlesoul_Hit_Actions)
    call EnableTrigger(udg_trg)
    call TriggerSleepAction(5)
    call DisableTrigger(udg_trg)
    call DestroyTrigger(udg_trg)
    set udg_trg = null
endfunction

//===========================================================================
function InitTrig_Battlesoul takes nothing returns nothing
    set gg_trg_Battlesoul = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Battlesoul, EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddCondition(gg_trg_Battlesoul, Condition(function Trig_Battlesoul_Conditions))
    call TriggerAddAction(gg_trg_Battlesoul, function Trig_Battlesoul_Actions)
endfunction

So I just dynamically create trigger for the target unit. But I don't know the cost of creating new triggers and destroying them after. Does my method really save computational resource or just do the reverse
 
Level 1
Joined
Aug 28, 2012
Messages
5
The problem with damage detection is that ANY damage will trigger this.
thx for the reply
yeah, I know this small defect. I think I can modify my condition function latter.
but I'm realy interested in the efficiency of allocation and releasing the objects like triggers in jass


Not if you use booleans or different damage-types.
thx for point this out
luckily, my hero doesn't have other damage ability except attack, and I can add an user data for the unit when he spells an ability
but for those item ability like clock of flames I don't have any idea
 
Level 19
Joined
Feb 25, 2009
Messages
2,004
You can give them hidden passive Poison ability and check whether the target has the buff.
Since it can have it only when an attack is finished, it means it is a basic attack, not a spell or anything else.

Same thing is used into DotA, for the Nightcrawler passive ability which allows him to steal agility for each hit against a hero.
The Poison Arrows ability, on the other hand is used for the missle abilities of:
Silencer (deals % bonus damage based on intelligence)
Enchantress (deals % bonus damage based on distance)
Obsidian Destroyer (deals % damage based on mana pool)
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
The "best" method I found was triggering all magic by creating a dummy that casts the ability dealing 0 damage, detect that damage and the damage source, and index the main hero with the same player number the dummy does (obviously, as owner) then cause the real hero to do the damage via triggers. That way, any other damage would be taken as default damage.
 
Level 17
Joined
Jul 17, 2011
Messages
1,864
So I just dynamically create trigger for the target unit. But I don't know the cost of creating new triggers and destroying them after. Does my method really save computational resource or just do the reverse
it is computationally costly because you reuse some native functions those should be put into locals at the start of your functions. you dont need to destroy the trigger and then create it again if you plan to run the trigger more than once.

since your hero only has an attack and no spells then it takes only 2 lines to make it "steal" mana.
first check if he has a buff or if he has the ability then set a variable for his mana to
the damage he dealt * .15 for 15% mana steal
then set the damaged unit's mana - that variable.
 
the poison buffs has a field for stacking you know... and yeah you can make them as non-orb effect type (Venomancer's poison skill is the best example)

btw,

Silencer (deals % bonus damage based on intelligence)
Enchantress (deals % bonus damage based on distance)
Obsidian Destroyer (deals % damage based on mana pool)

--> all of those abilities don't stack with orb effects...
 
Level 1
Joined
Aug 28, 2012
Messages
5
it is computationally costly because you reuse some native functions those should be put into locals at the start of your functions. you dont need to destroy the trigger and then create it again if you plan to run the trigger more than once.

since your hero only has an attack and no spells then it takes only 2 lines to make it "steal" mana.
first check if he has a buff or if he has the ability then set a variable for his mana to
the damage he dealt * .15 for 15% mana steal
then set the damaged unit's mana - that variable.

You mean it's computationally costly that I used too many native functions in my condition function, right?
For the latter comment, I think if I did't destroy them, there would be duplicated triggers. I know my code is defective. For example, if my hero attacks a target and I stop it, and then he attacks again, there would be two duplicated triggers and my hero gains double amount of mana for one hit. But this bug is interesting and I think I can use this bug to make some strange abilities like charged attack, which the damage is how many times you stop the attack action before hit @_,@
However I will change my code to use more accurate method like Spartipilo said, although the task seems quite large
 
Level 17
Joined
Jul 17, 2011
Messages
1,864
For example, if my hero attacks a target and I stop it, and then he attacks again, there would be two duplicated triggers and my hero gains double amount of mana for one hit. But this bug is interesting and I think I can use this bug to make some strange abilities like charged attack, which the damage is how many times you stop the attack action before hit @_,@
no this is wrong you dont need to create new triggers at all thats not the right way, your hero will never gain double the amount of mana if you stop him before his damage delay because he will not deal any damage thus your system will have nothing to work with.
 
Level 1
Joined
Aug 28, 2012
Messages
5
no this is wrong you dont need to create new triggers at all thats not the right way, your hero will never gain double the amount of mana if you stop him before his damage delay because he will not deal any damage thus your system will have nothing to work with.

I have tested it on my map.
Every time my hero attacks, the game create a trigger to wait for the hit damage. When I stop the attack, the trigger isn't released. The hero attacks again, another trigger is created. So if the hero hits the target, two triggers are both triggered. Though they are just the same trigger in code, they are executed independently, so the hero gains the mana twice after one hit eventually. It is PROVED
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
If you use indexer:

A unit is Attacked
Save +1 on Charge[Custom value of unit]

Damage is dealt
Cause DamageSource Charge[Custom value of unit] damage to DamagedUnit
Set Charge[Custom value of unit] to 0.

Actually.. quite a nice skill.
 
Level 1
Joined
Aug 28, 2012
Messages
5
They are destroyed immediately after hits

Yeah, I know there are easier ways to make this charged attack.

I'm new to JASS, so I'd like to know more about it. Maybe I will refer to those good systems like DDS and UnitIndexer, but I won't use them in my map until I know more about the cost of function calls and native hashtable. Sounds like a freak
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
Hashtables is like going shopping and getting all you want in your hands. Requires 1 Hash, and 3 integers.

Unit Indexer requires 1 integer and 1 unit, so, it's faster (tough requires the system) but has it's limitations, like, only handles Units; Hashtables handles anything, and you're still going to need one.

You don't need to understand DDS just because it's JASS. It just picks every unit every 15 seconds or so, and creates a trigger with "Event - Picked Unit Takes Damage" and therefore detects the DamageSource and DamagedUnit.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
one of UnitIndexers is made by Nestharus and he is the most spead freak on here probably :D so it is very fast, even if it was not function calls are that fast that when you have a trigger with 100 actions in it(other then triggerevalute or triggersleepaction) until you blink the trigger will be over already
 
Status
Not open for further replies.
Top