HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Intuitive Damage Detection System

05-25-2008, 07:22 AM#1
Rising_Dusk
Zoom (requires log in)
Intuitive Damage Detection System
v1.14

Background:
So, I would first and foremost like to thank the Tides of Blood team for inspiring me to make a (releasable) damage detection system in the first place. Past that, the background of the system is simple: I wanted to create a damage detection system that allows easy detection of attacks and spells and infinitely many damage types without changing the way people think about triggers. I wanted to create a world where damage detection is your friend and where you can easily check damage types in triggers, use waits, whatever you want, just like if Blizzard itself had made it for us. Well, I achieved that and am damned proud to present to you all the IDDS, intuitive and simple, for your use.

Requirements:Notes:
  • This system is only applicable if all of the damage from spells in your map is triggered. The only way this system is useful is if the only damage units deal themselves is from attacks.
  • The system requires that all damage dealt via triggers be done using a function from the system rather than UnitDamageTarget().
System Code:
Expand Library:

Attached is a demo map that shows many of the facets of the system being used. There are also sufficiently many examples inside the test map to show anyone how to use it. Enjoy!
Attached Files
File type: w3xIDDSTestMap_114.w3x (43.0 KB)
05-25-2008, 07:29 AM#2
darkwulfv
Jesus Christ Dusk, you're my new hero. I can go batshit with this thing for my AoS, since all spell damage is done via triggers.

Quote:
Totally configurable system allows for detecting infinitely many damage types of your own creation.
So, I could literally invent a new damage type?? Or am I mis-interpreting it?

EDIT: Looked at the code, and I can make a constant integer that does that. Like, DAMAGE_TYPE_AWESOME or whatever.

EDITEDIT: I'm assuming this works generally the same way as the others; units get registered when they enter the map, and then they can be picked up by the event which catches units being damaged.
05-25-2008, 07:43 AM#3
Rising_Dusk
Quote:
Originally Posted by darkwulfv
EDITEDIT: I'm assuming this works generally the same way as the others; units get registered when they enter the map, and then they can be picked up by the event which catches units being damaged.
It does it all internally, but yes. It only loads the units to a single, system-used trigger which then divvies things up to all of the respective triggers you actually registered to the system. In this sense, you're not registering hundreds of events for each trigger you register to the system, just one for the system in general that then shares with all of the others.
05-25-2008, 08:30 AM#4
Fulla
EDIT: Woops, tested wrong one, will edit with feedback.
05-25-2008, 08:38 AM#5
Rising_Dusk
Quote:
Originally Posted by Fulla
- Detecting the blizzard attack event, then creating a trigger to detect/wait for the damage to happen, with a 3 seconds timeout.
What? Where do you get this 3 second timeout stuff from? That isn't how it works at all. And no, it doesn't have any attack event stuff in it at all, it actually uses damage events. You obviously have not looked at the map or the code at all; it doesn't work in any way, shape, or form similar to what you're suggesting.
Quote:
Originally Posted by Fulla
I tested the map a bit, how comes you didn't add any spells?
I started casting blizzard/flamestrike, I thought you'd have set them up
Quote:
Originally Posted by First Post
This system is only applicable if all of the damage from spells in your map is triggered. The only way this system is useful is if the only damage units deal themselves is from attacks.
Blizzard and Flame strike the standard spells will not work unless the damage is triggered.
05-25-2008, 08:47 AM#6
Fulla
Bah you replied to fast above ^

==

This system looks very interesting.
So basically if the damage wasn't done by the system it has to be an attack, haha neat.

For the testmap, I'd recommend also adding in 1-2 ability examples that trigger on attack, such as a
- Critical Strike, Evasion, Backstab etc.

On that note, say I want a critical strike, to add on 200% damage or whatever.
What damage type should I have it dealt as, since its attack damage, but I don't want it to register another attack?

==

This should allow a few interesting possiblities such as my favourite d2 abilities:
- Double Swing
- Strafe
Where you can make secondary attacks/shots actually still count as physical attacks.
05-25-2008, 02:52 PM#7
darkwulfv
Ah yes Dusk, if this system can allow for custom evasions/critical strikes/cleaving strikes, then that would be awesome.

A question: Can it find the amount of damage that was dealt when a unit is damaged? I'm assuming it can, but I wanted to be sure.
05-25-2008, 03:08 PM#8
TEC_Ghost
Quote:
Originally Posted by darkwulfv
Ah yes Dusk, if this system can allow for custom evasions/critical strikes/cleaving strikes, then that would be awesome.

A question: Can it find the amount of damage that was dealt when a unit is damaged? I'm assuming it can, but I wanted to be sure.

Collapse JASS:
set Damage = GetEventDamage()
05-25-2008, 03:39 PM#9
Rising_Dusk
Quote:
Originally Posted by Fulla
On that note, say I want a critical strike, to add on 200% damage or whatever.
What damage type should I have it dealt as, since its attack damage, but I don't want it to register another attack?
You can trigger using the damage type DAMAGE_TYPE_ATTACK and it will function identically to if the unit actually attacked. Yes, custom critical strike is super possible and is actually ridiculously easy using this system.
Collapse Critical Strike:
scope ExampleCriticalStrike
private function Conditions takes nothing returns boolean
    return GetTriggerDamageType() == DAMAGE_TYPE_ATTACK and GetRandomInt(1,100) <= 15
endfunction

private function Actions takes nothing returns nothing
    local unit u = GetTriggerDamageSource()
    local unit t = GetTriggerDamageTarget()
    local integer lvl = GetUnitAbilityLevel(u, 'A000') //Whatever ability
    local real d = GetTriggerDamage()
    
    //Deals +100%/200%/300%/etc damage
    call UnitDamageTargetEx(u, t, d*(lvl), ATTACK_TYPE_HERO, DAMAGE_TYPE_EXTRA, true)
    //Use a different damage type that considers armor identically to an attack, but so the 
    //trigger doesn't fire itself
    
    //Do a call for fading text
    
    set u = null
    set t = null
endfunction

public function InitTrig takes nothing returns nothing
    local trigger trg = CreateTrigger()
    call TriggerRegisterDamageEvent(trg, function Actions, Condition(function Conditions))
    set trg = null
endfunction
endscope
That's it. If you want to make the unit do the slam animation, just tack a SetUnitAnimation() call in there too. You can also extend that to Evasion if you want and use one of the many methods of blocking attack damage and getting the damage type as DAMAGE_TYPE_ATTACK.

Backstab is equally easy, heck, everything is; seriously, one example explains all! Dude, if you wanted the system to allow you to trigger all attacks for all units on the map, all you'd have to do is add a Hardened Skin ability to every unit on the map in a disabled spellbook and make its minimum damage 0.1, that way it'd still register an attack with the system but not hurt the enemy. Voillah, now you can make your own custom attack system with virtually no effort using this Damage Detection system as a base.
Quote:
Originally Posted by darkwulfv
A question: Can it find the amount of damage that was dealt when a unit is damaged? I'm assuming it can, but I wanted to be sure.
Of course, in the callback you'd use the event response GetTriggerDamage().
05-25-2008, 04:06 PM#10
darkwulfv
Dusk, I think you deserve some cookies. *cookies*

I think we need to gather the best systems from Wc3c and make a huge map. It'd be the epitome of vJASS and JASS systems coming together in one huge map.
05-25-2008, 07:51 PM#11
grim001
A fine system for those who prefer to work with triggers and avoid structs.
05-25-2008, 08:18 PM#12
Pyrogasm
Quote:
Originally Posted by Rising_Dusk
Doesn't work for pre-placed units because in vJass the initializer function is run after the game creates the pre-placed units.
Couldn't you just...
Collapse JASS:
private function LoadEnumConditions takes unit EnumUnit returns boolean
    //* The conditions for registering a unit with the damage system upon map initialization
    return true
endfunction

private function InitLoadEnum takes nothing returns boolean
    local unit u = GetFilter()

    if LoadEnumConditions(u) then
        call TriggerRegisterUnitEvent(RunTrigger, u, EVENT_UNIT_DAMAGED)
    endif

    set u = null
    return false
endfunction

private function DamageSystemInit takes nothing returns nothing
    local rect r = GetWorldBounds()
    local region re = CreateRegion()
    local integer i = 0
    local group g = CreateGroup()
    
    loop
        exitwhen i > 11
        set AlternateSource[i] = CreateUnit(Player(i), DummyUnitID, 0, 0, 0)
        call UnitAddAbility(AlternateSource[i], 'Aloc')
        call PauseUnit(AlternateSource[i], true)
        set i = i + 1
    endloop
    
    set RunTrigger = CreateTrigger()
    call TriggerAddAction(RunTrigger, function Run)
    call TriggerAddCondition(RunTrigger, Condition(function RunConditions))
    
    set AddTrigger = CreateTrigger()
    call RegionAddRect(re, r)
    call TriggerRegisterEnterRegion(AddTrigger, re, null)
    call TriggerAddAction(AddTrigger, function Load)
    call TriggerAddCondition(AddTrigger, Condition(function AddConditions))

    call GroupEnumUnitsInRect(g, r, Condition(function InitLoadEnum))

    set i = 0
    loop
        exitwhen i > TrgCount
        set Trg[i] = null
        set Cond[i] = null
        set Action[i] = null
        set i = i + 1
    endloop
    
    call RemoveRect(r)
    call DestroyGroup(g)
    set re = null
    set r = null
    set g = null
endfunction
05-25-2008, 08:23 PM#13
Rising_Dusk
Yeah, but that would be a lame solution. The more logical solution is to harass Vex to make me able to move those initializations before the pre-placed unit creation. If you couldn't tell, I wanted to avoid such brute force crap; most mapmakers that want to trigger all damage will create their units at runtime anyways.

Your method wouldn't compile anyways; it's GetFilterUnit(). :P

EDIT: I suppose I could do that if you think it's necessary, though I hate the method you approached it with.
05-25-2008, 08:30 PM#14
Pyrogasm
Shaddup, so I forgot a word >_<

And what says it's a lame solution? That's the only way there is to do it, and wouldn't it be better to have that functionality than not to have it because you want Vexorian to add something to vJASS so you don't have to write it yourself?

For Pete's sake, I even wrote it for you already; all you have to do is copy/paste :P
05-25-2008, 08:34 PM#15
Rising_Dusk
Quote:
Originally Posted by Pyrogasm
For Pete's sake, I even wrote it for you already; all you have to do is copy/paste :P
I wouldn't do that. Ever.

Actually, I want Vex to add it to vJass because it's a logical thing to do. Having this system as collateral to help in persuading him increases my chances of getting him to do it. I'll go ahead and write in my own way for getting the pre-placed units anyways, though.