HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Unallowing friendly splash damage

06-30-2011, 04:05 PM#1
Linaze
Hello guys, this is me asking another one of my questions.

Basically, I have in my map a unit that I don't want to be killed or even attacked by friendly units. To prevent this I've simply made friendly attackers be ordered to stop if they try to attack, and this works just fine. But splash damage from for example catapults still deal damage (obviously), so what I need is a method of prevent my unit from taking splash damage from friendly sources.

Thanks in advance.
06-30-2011, 04:29 PM#2
moyack
Damage detection is the way. You add a condition that detects if the attacking player is an ally and do the magic.
06-30-2011, 04:30 PM#3
Linaze
Well what I'm asking is how to "do the magic", really.
06-30-2011, 04:56 PM#4
Anitarf
You could give your unit a classification such as "suicidal" (provided you don't already use it for anything else) and then only allow non-suicidal units to be damaged by splash damage of units the player can use. The problem with this solution is that if the enemies can use the same units as you, their splash damage will also ignore this unit. The alternative is to make all splash damage ignore friendly units, but then none of your units will take damage from your catapults.

If you don't mind using triggers for this, you could use a Damage Modifier.
06-30-2011, 07:45 PM#5
Linaze
I don't mind using triggers. Can you help a fellow newbie on how to use the Damage Modifier to achieve my desired result?
06-30-2011, 08:35 PM#6
Anitarf
Sure. First of all, you need to import the DamageEvent and DamageModifiers libraries into your map. I suggest the Table version of DamageModifiers since Table is slightly easier to import than AutoIndex. Once you have Table, DamageEvent and DamageModifiers in your map (all three are simple copy&paste jobs, just create a trigger, convert it to custom text and overwrite it's contents with the library code), try saving the map. If you have the NewGen editor with the latest JassHelper, this should give you no problems, else you should update your JassHelper.

If the map saves successfully then DamageModifiers will automatically generate the bonus life ability it requires to be able to block damage that is higher than a unit's max life. At this point, you should close and reopen the map, then scroll through the DamageModifiers documentation until you find the objectmerger call that generated the aforementioned ability (you can't miss it, it's the only grey-coloured line in the library) and disable it. This will speed up map saves in the future since the editor won't have to generate that ability every time.

With that, DamageModifiers should be ready to use. If you want, you can also import one of the preload libraries linked to from the Damage Event thread, but those are completely optional. They're just used to prevent a lag spike that otherwise occurs the first time DamageModifiers needs to use its bonus life ability.

Collapse JASS:
library AlliedDamageBlocker requires DamageModifiers

private struct blocker extends DamageModifier
    private player owner
    method onDamageTaken takes unit damageSource, real damage returns real
        if IsUnitAlly(damageSource, .owner) then
            return -damage // Block all damage.
        endif
        return 0.0
    endmethod
    static method create takes unit u returns blocker
        local blocker this = blocker.allocate(u, 0)
        set .owner=GetOwningPlayer(u)
        return this
    endmethod
endstruct

function UnitBlockDamageFromAllies takes unit u returns nothing
    call blocker.create(u)
endfunction
/* To use this function in a GUI trigger, copy the following line to a custom script action:

    call UnitBlockDamageFromAllies( udg_YourUnitVariable )

I didn't include any code that would clean up the damage modifier when the unit dies,
but if this is only used on a few units during the course of the game then that's not a problem. */

endlibrary
06-30-2011, 08:48 PM#7
BBQ
This should help you.
Collapse Zinc:
//! zinc
library PreventAlliedDamage requires DamageEvent, DamageModifiers, AutoIndex {

    constant integer UNIT_TYPE_ID = 'unit';
    /* Change this to the type ID of the unit that you don't want to receive damage. */

    constant integer DAMAGE_MODIFIER_PRIORITY = 0x7FFFFFFF;
    /* Highest possible priority for the damage modifier. */
    
    struct preventIncomingDamage extends DamageModifier {
        /* This is the filter for the automatic allocation provided by the AutoCreate module. 
           You are free to insert whatever conditions you need here. */
        static method createFilter(unit enteringUnit) -> boolean {
            return (GetUnitTypeId(enteringUnit) == UNIT_TYPE_ID);
        }
        /* This method is called whenever the unit for which we created
           the damage modifier is damaged. */
        method onDamageTaken(unit damageSource, real damageAmount) -> real {
            if (IsUnitAlly(damageSource, GetOwningPlayer(this.me))) {
                return -damageAmount;
                /* If the damage source was an ally, then block
                   the whole damage that was dealt. */
            }
            return 0.0; /* Otherwise, return zero in order not to block any damage at all. */
        }
        /* This method will be called by AutoCreate when it tries to automatically
           create the struct for a certain unit. */
        static method create(unit enteringUnit) -> thistype {
            thistype this = thistype.allocate(enteringUnit, DAMAGE_MODIFIER_PRIORITY);
            /* Since we are extending the DamageModifier struct, our .allocate() method needs
               to match the parameters of extended struct's .create() method. */
            return this;
        }
        /* Implement the AutoCreate and the AutoDestroy modules. */
        module AutoCreate; module AutoDestroy;
    }
}
//! endzinc

EDIT: Okay, Anitarf got to it first. I spent five minutes for nothing.
06-30-2011, 09:49 PM#8
Anitarf
Quote:
Originally Posted by BBQ
EDIT: Okay, Anitarf got to it first. I spent five minutes for nothing.
Nah, your version is a lot better, I would recommend it over mine. It does everything automatically, both damage modifier creation and cleanup. Sure, it requires AutoIndex, but AutoIndex actually isn't that difficult to import, just like DamageModifiers it uses an objectmerger call to create the one custom ability it needs so you need to take those few extra steps to disable the objectmerger call once it does its job, but aside from that it's a simple copy&paste job.
06-30-2011, 09:50 PM#9
moyack
Quote:
Originally Posted by Linaze
Well what I'm asking is how to "do the magic", really.
Sure, why haven't you said before :P

You can use a triggered evasion, with the ally condition.

Link to my DD system: http://www.wc3c.net/showpost.php?p=1024305&postcount=2

1. Create a trigger, call it "damage detection", set it to custom text, erase the text done by default and replace it with this code:

Expand JASS:

2. Create other trigger, put it "AntisplashDamage", and like the first step, erase the ugly code and replace it with this:
Expand Block Damage from Allies - requires TimerUtils:

3. And that's all :)

Edit: Map attached
Attached Files
File type: w3xTesting fire.w3x (18.7 KB)