• 🏆 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!
  • ✅ Time to vote for the top 3 models! The POLL for Hive's 6th HD Modeling Contest: Mechanical is now open! 📅 Poll close on July 16, 2024! 🔗 Cast your vote now!
  • ✅ The POLL for Hive's Texturing Contest #33 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!

[Feedback] Compiled List of 1.30 / 1.29 Bugs & Issues

Not open for further replies.
Level 20
Apr 12, 2018
Well in RoC there just plain wasn't an Inventory ability; that was introduced in TFT. It's probably another thing that somehow bled into the RoC data because of compatibility reasons.
Warcraft III's CPU usage is much higher in my map in the current patch than it is in an older patch.

CPU Usage in patch => 0.2% ~ 0.7%
CPU Usage in patch => 2.9% ~ 5% (up to 7% in small bursts)

This is me just moving the mouse around, doing nothing. Not using any commands or creating any units.


  • development.w3x
    1.4 MB · Views: 174
Unit filters don't work with player unit death events. Or has this always been the case and it's intended? Because it works fine with other events.

function UnitFilter takes nothing returns boolean
    return GetFilterUnit() == someUnit


call TriggerRegisterPlayerUnitEvent(trg, plr, EVENT_PLAYER_UNIT_DEATH, function UnitFilter)

Confirmed to work:
Last edited:
Actually, I see now you use the filter only at event registration, but not when the event itself is fired. I would not exactly know what response to expect there, but GetFilterUnit() should only work when the event itself was fired, so only when the trigger action/condition runs. But not at registration.
I tested with the death event, and it seems the filter function at registration isn't fired at all for me. So I couldn't do anything there. Are you sure it works for you somewhere - might you attach a demo?
Sure. The attached map has two triggers:
EVENT_PLAYER_UNIT_DEATH with filter GetUnitTypeId(GetFilterUnit()) == 'hpea'
EVENT_PLAYER_UNIT_SPELL_CAST with filter GetUnitTypeId(GetFilterUnit()) == 'hmpr'

Both have actions that will show the triggering unit's name -- BJDebugMsg(GetUnitName(GetDyingUnit())) and BJDebugMsg(GetUnitName(GetSpellAbilityUnit()))
If you type "kill" all selected units will be killed.

On my end, I only get shown the Priest's name when it casts an ability, not any other unit.
On the other hand, when any unit is killed, their name will be shown.

Edit: I added debugmsgs to the filter functions, and the death event filter indeed does not even fire at all.

function PeasantFilter takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == 'hpea'

function PeasantDeath takes nothing returns nothing
    call BJDebugMsg(GetUnitName(GetDyingUnit()))

function InitTrig_Test_Death takes nothing returns nothing
    set gg_trg_Test_Death = CreateTrigger(  )
    call TriggerRegisterPlayerUnitEvent(gg_trg_Test_Death, Player(0), EVENT_PLAYER_UNIT_DEATH, function PeasantFilter)
    call TriggerAddAction( gg_trg_Test_Death, function PeasantDeath )

function PriestFilter takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == 'hmpr'

function PriestSpell takes nothing returns nothing
    call BJDebugMsg(GetUnitName(GetSpellAbilityUnit()))

function InitTrig_Test_Spell takes nothing returns nothing
    set gg_trg_Test_Spell = CreateTrigger(  )
    call TriggerRegisterPlayerUnitEvent(gg_trg_Test_Spell, Player(0), EVENT_PLAYER_UNIT_SPELL_CAST, function PriestFilter)
    call TriggerAddAction( gg_trg_Test_Spell, function PriestSpell )


  • FilterUnitTest.w3x
    18.1 KB · Views: 165
Last edited:
Yes, the death filter doesn't fire at all, while the spell filter fires each cast.. Good find.^^ It's at least not consistent behaviour at all.

So for cast event you can write something like
function Actions takes nothing returns nothing
    if GetUnitTypeId(GetFilterUnit()) == 'Hpal' then
        call BJDebugMsg(GetUnitName(GetFilterUnit()))

function InitTrig_Test_Spell takes nothing returns nothing
    set gg_trg_Test_Spell = CreateTrigger()
    call TriggerRegisterPlayerUnitEvent(gg_trg_Test_Spell, Player(0), EVENT_PLAYER_UNIT_SPELL_CAST, function Actions)
.. which seems kind of abusive. I'd probably just always filter on action/condition level..
How do you mean, abusive? I was actually thinking it's a good way to not even use actions/conditions at all (if you don't need GetTriggerUnit() or other event functions), but just go through the filter function whenever possible. No idea if this is the case, but it seems logical that it's faster and/or uses less memory?

I've added the events that I know to be working to my original bug report post. I'll add more if I confirm any (and remember to).

Though actually ^, not 100% sure atm, but I think it needs to return a boolean because the final argument for event register functions is a boolexpr, otherwise it will give a syntax error.
Idk, it makes more sense to me, to have event registration seperated from execution logics.

You can add multiple actions/conditions to a trigger, not depending on one filter func from registration, at any time. But here for specific cases it might work same, sure.

Natives GetTriggerExecCount or GetTriggerExecCount are probably rarely used, but they would probably return not expected result.

You're probably right that avoiding actions and conditions could be a bit faster, but if a difference exists I believe it would be not enough to adapt coding to, for me, a bit more weird style. But probably also for some others, it's totally ok.
Last edited:
Well I guess it would be limited to a small set of usecases, only when you need no info about the trigger at all (except maybe filter info). After you can always add more actions/conditions as long as the filter function returns true.

But apart from that hacky way of using it, I think it's worth using it for just simple filters like the examples above, because I believe it not only avoids actions and conditions, but even the event itself from firing and thus the trigger is not executed at all (well I don't know, but it seems logical that that's what it's there for).
Except of course when you don't want to limit the trigger event to specific unit or unit properties (or players, destructables or items).

Anyway, I guess we're getting too far off topic :p
The most useful application of trigger event filters for me (considering that any speed diference is untested, to my knowledge) is reusing filters from GroupEnums without making the code look ugly by checking if a filter unit exists and setting the local variable to triggerunit if it does not. But I have always assumed they were faster.



Level 3
May 6, 2017
The recent patches have introduced stability issues. For the last several months, maybe more, I have been disconnecting from ladder games on a regular basis despite having strong Internet connection and no history of disconnects for X years.

There are more people who have been suffering from it.
FilterUnit in Death/Attack Events refere to the killer/attacker, probably a takeover from the specific unit events. That is why one thinks it does not work; in your example: do a kill with a peasant then your trigger should execute.

Hmm, there must be some advantage or reason to the filter functions, otherwise why are they there? Seems like they should stop execution at some earlier point than conditions or actions.
Filtered events won't increase GetTriggerEvalCount.
The same with triggerconditions: if triggerconditions filter an successful event evalutation GetTriggerExecCount won't increase.
Ah, that explains it. Just tested it and you're right. Sorry for clogging the thread.
Filtered events won't increase GetTriggerEvalCount.
The same with triggerconditions: if triggerconditions filter an successful event evalutation GetTriggerExecCount won't increase.
Cool, good to know. So I assume that means it's preferable to use conditions instead of actions where possible?
I meant using TriggerAddCondition over TriggerAddAction so that GetTriggerExecCount doesn't increase. I've never used GetTriggerEval/ExecCount either, but I assume it has an impact on memory usage (though probably marginal) if they increase?
Ah, I see what you mean. No, there probably isn't an impact, since the value is probably stored in a 32-bit integer for all triggers. I doubt the value is only stored for triggers that have already exececuted and is dynamically allocated at first execution.

Conditions might use more memory, since you need to create a boolexpr to use them, but maybe actions have extra hoops that cause more memory usage?

For performance, conditions are always preferable, since they are considerably faster.
Last edited:
I have never had the need to actually use those natives. If you really needed something like that, just make an integer and increase it every time the filter runs.
this trigger counters allow easy built in counters attached to triggers with that also to events, therefore without any further effort.
Yeah, kinda trivial nowadays with hashtables.
@PurgeandFire do you maybe know something why filter might not work at registration, with what @loktar experienced with death event?

scope s initializer init
    private function onDeathFilter nothing returns boolean
        call BJDebugMsg(GetUnitName(GetFilterUnit()))
        return true

    private function init takes nothing returns nothing
        call TriggerRegisterPlayerUnitEvent(CreateTrigger(), Player(0), EVENT_PLAYER_UNIT_DEATH, Filter(function onDeathFilter))
I saw, Bribe, in his UnitEvent, used GetFilterUnit() only in 2 events:
call TriggerRegisterEnterRegion(CreateTrigger(), re, enterB)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
in other events: EVENT_PLAYER_UNIT_SUMMON, EVENT_PLAYER_UNIT_LOADED, EVENT_PLAYER_UNIT_DEATH he used trigger conditions, so I assume GetFiletrUnit doesn't work with these.
I think what he means with "takeover from specific unit event" is that in a unit event, you can't filter the triggering unit because it's one specific unit, thus the filterunit is the one killing/attacking/being boarded/etc., and player unit events continue this logic.
So while it's definitely counter-intuitive IMO, these events/filters do seem to work as intended.
I'm just not sure I get what is meant with intended.

The thing is, it does not just not provide GetTriggerUnit() for the wanted unit etc, but the filter does not fire at all when attecker is null. So you don't even have a chance to filter at this "triggering-level" in here, like it is possible at the spell event. It acts like firing before it's decided to deploy public event responses, and like it was already internally decided already if to run such filter or not. -- which seems for me not as intended, because death event trigger actions and normal conditions should for sure also run with trigger kill action.
Last edited:
Not open for further replies.