• 🏆 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!

[Trigger] Checking target classification and cancelling issued order

Status
Not open for further replies.
Level 5
Joined
Feb 5, 2008
Messages
109
Hi again!

I got a somewhat weird thing this time. I have an ability which can be used on hostile units of any type, but just on friendly ones being organic and no building. The ability also needs special points to be casted.

The thing I don't get is that sometimes this check works and sometimes not. Help appreciated.

If I do the same check when the unit begins to cast the ability, it always gets cancelled if one of the conditions returns false, but I'd like to check those things when the order is issued so the unit does not have to get near to the target's location.

  • Check target
    • Events
      • Unit - A unit Is issued an order targeting an object
    • Conditions
      • (Issued order) Equal to (Order(shadowstrike))
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • EnergyPoints[(Player number of (Owner of (Triggering unit)))] Less than or equal to 0.00
        • Then - Actions
          • Unit - Order (Triggering unit) to Stop
          • Spiel - Display to (Player group((Owner of (Triggering unit)))) the text: |cffffcc00You have ...
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Target unit of ability being cast) belongs to an ally of (Owner of (Triggering unit))) Equal to True
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Target unit of ability being cast) is Mechanical) Equal to True
                • Then - Actions
                  • Unit - Order (Triggering unit) to Stop
                  • Spiel - Display to (Player group((Owner of (Triggering unit)))) the text: |cffffcc00Allied ta...
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • ((Target unit of ability being cast) is A treant) Equal to True
                    • Then - Actions
                      • Unit - Order (Triggering unit) to Stop
                      • Spiel - Display to (Player group((Owner of (Triggering unit)))) the text: |cffffcc00Allied ta...
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Life of (Target unit of ability being cast)) Greater or equal to (Max. life of (Target unit of ability being cast))
                        • Then - Actions
                          • Unit - Order (Triggering unit) to Stop
                          • Spiel - Display to (Player group((Owner of (Triggering unit)))) the text: |cffffcc00That unit...
                        • Else - Actions
            • Else - Actions
Thanks in advance
Triax
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
Well, I would bet it is because you are using "target unit of ability being cast", since your event is an issued order eventtype while ability being cast is another. It should work properly if you change it to "target unit of issued order" I hope.

~Eccho~
 
Level 5
Joined
Feb 5, 2008
Messages
109
Damn, I thought "Yeah, that's it!" Well, actually, it is not. It's even worse, now it never checks the classifications.

I had a compile error when I wanted to test the map. The order check was somehow broken after compiling, so I converted it to JASS, that didn't give me an error anymore. So the trigger looks like this right now:

JASS:
function Trig_Unseal_Energy_check_Kopieren_Kopieren_Conditions takes nothing returns boolean
    if ( not ( GetIssuedOrderIdBJ() == OrderId("thunderbolt") ) ) then
        return false
    endif
    return true
endfunction

function Trig_Unseal_Energy_check_Kopieren_Kopieren_Actions takes nothing returns nothing
    if ( udg_EnergyPoints[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))] <= 0.00 ) then
        call IssueImmediateOrder( GetTriggerUnit(), "stop" )
        call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetTriggerUnit())), "TRIGSTR_212" )
    else
        if ( IsUnitAlly(GetOrderTargetUnit(), GetOwningPlayer(GetTriggerUnit())) == true ) then
            if ( IsUnitType(GetOrderTargetUnit(), UNIT_TYPE_MECHANICAL) == true ) then
                call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetTriggerUnit())), "TRIGSTR_211" )
            else
                if ( IsUnitType(GetOrderTargetUnit(), UNIT_TYPE_ANCIENT) == true ) then
                    call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                    call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetTriggerUnit())), "TRIGSTR_209" )
                else
                    if ( GetUnitStateSwap(UNIT_STATE_LIFE, GetOrderTargetUnit()) >= GetUnitStateSwap(UNIT_STATE_MAX_LIFE, GetSpellTargetUnit()) ) then
                        call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                        call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetTriggerUnit())), "TRIGSTR_210" )
                    else
                    endif
                endif
            endif
        else
        endif
    endif
endfunction

//===========================================================================
function InitTrig_Unseal_Energy_check_Kopieren_Kopieren takes nothing returns nothing
    set gg_trg_Unseal_Energy_check_Kopieren_Kopieren = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Unseal_Energy_check_Kopieren_Kopieren, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
    call TriggerAddCondition( gg_trg_Unseal_Energy_check_Kopieren_Kopieren, Condition( function Trig_Unseal_Energy_check_Kopieren_Kopieren_Conditions ) )
    call TriggerAddAction( gg_trg_Unseal_Energy_check_Kopieren_Kopieren, function Trig_Unseal_Energy_check_Kopieren_Kopieren_Actions )
endfunction
I also tested EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER and EVENT_PLAYER_UNIT_ISSUED_ORDER instead of EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, doesn't work either.
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
Alright, I copied your code, and looked at it. Ill post it back with suggestions. I hope this helps.

JASS:
function Trig_Unseal_Energy_check_Kopieren_Kopieren_Conditions takes nothing returns boolean
    //Make sure that the orderstring is "thunderbolt" from the beginning. Even though you change it to something else, it will still use the basic orderstring for that specific spell.
    //Everything in Jass can be much more simplyfied. I'll change a little... But not much.
    return (GetIssuedOrderId() == OrderId("thunderbolt"))
endfunction

function Trig_Unseal_Energy_check_Kopieren_Kopieren_Actions takes nothing returns nothing
    //Make sure that udg_EnergyPoints[<index>] is greater than 0.00 at initialization or before the trigger is ran.
    if (udg_EnergyPoints[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))] <= 0.00) then
        call IssueImmediateOrder( GetTriggerUnit(), "stop" )
        //GetForceOfPlayer leaks and returns a NEW force (player group) everytime it is called.
        //Replace it with bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))]
        //Note that GetPlayerId is used here, not GetConvertedPlayerId
        //If the display message is for debugging only, don't bother changing if it's removed later on anyway.
        call DisplayTextToForce( bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))], "TRIGSTR_212" )
    else
        //It does only go through the first if-condition if the ordered unit is an ally of the target unit, and that's what you want right?
        if ( IsUnitAlly(GetOrderTargetUnit(), GetOwningPlayer(GetTriggerUnit())) == true ) then
            if ( IsUnitType(GetOrderTargetUnit(), UNIT_TYPE_MECHANICAL) == true ) then
                call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                call DisplayTextToForce( bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))], "TRIGSTR_211" )
            else
                if ( IsUnitType(GetOrderTargetUnit(), UNIT_TYPE_ANCIENT) == true ) then
                    call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                    call DisplayTextToForce( bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))], "TRIGSTR_209" )
                else
                    //You forgot to change to "target of issued order" at the right side of the >=. I'll change that for you here.
                    if ( GetUnitStateSwap(UNIT_STATE_LIFE, GetOrderTargetUnit()) >= GetUnitStateSwap(UNIT_STATE_MAX_LIFE, GetOrderTargetUnit()) ) then
                        call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                        call DisplayTextToForce( bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))], "TRIGSTR_210" )
                    else
                    endif
                endif
            endif
        else
        endif
    endif
endfunction

//===========================================================================
function InitTrig_Unseal_Energy_check_Kopieren_Kopieren takes nothing returns nothing
    set gg_trg_Unseal_Energy_check_Kopieren_Kopieren = CreateTrigger( )
    //Seems to be the right event.
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Unseal_Energy_check_Kopieren_Kopieren, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
    call TriggerAddCondition( gg_trg_Unseal_Energy_check_Kopieren_Kopieren, Condition( function Trig_Unseal_Energy_check_Kopieren_Kopieren_Conditions ) )
    call TriggerAddAction( gg_trg_Unseal_Energy_check_Kopieren_Kopieren, function Trig_Unseal_Energy_check_Kopieren_Kopieren_Actions )
endfunction
 
Level 5
Joined
Feb 5, 2008
Messages
109
[edit]
It's working now. It wasn't working because of the "stop"-order. I just order the triggering unit to move to its own position, works fine. (Attached map removed.) Still, the best way would be that the unit isn't ordered anything at all, because that way it becomes visible (for example) when being not.
Is there anything I can optimize about the conditions? (Look at "old post".)

So that's the way the trigger looks right now. I attached the map with the spell so you can have a look at it ingame.

JASS:
function Trig_Unseal_Energy_check_Kopieren_Kopieren_Conditions takes nothing returns boolean
    // I guess I can't simplify these conditions because I actually need two if I have to use the spell's native orderid, right?
    if ( not ( GetIssuedOrderIdBJ() == OrderId("shadowstrike") ) ) then
        return false
    endif
    if ( not ( GetUnitTypeId(GetTriggerUnit()) != 'u000' ) ) then // prevents showing messages for spells cast by dummies
        return false
    endif
    return true
endfunction

function Trig_Unseal_Energy_check_Kopieren_Kopieren_Actions takes nothing returns nothing
    if ( udg_EnergyPoints[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))] <= 0.00 ) then
        call IssueImmediateOrder( GetTriggerUnit(), "stop" )
        // I'll deleak this when the trigger works, thanks for the hint.
        call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetTriggerUnit())), "TRIGSTR_212" )
    else
        // Yes, that's right. It can be used on all enemy units but just on allies of the following classifications.
        if ( IsUnitAlly(GetOrderTargetUnit(), GetOwningPlayer(GetTriggerUnit())) == true ) then
            if ( IsUnitType(GetOrderTargetUnit(), UNIT_TYPE_MECHANICAL) == true ) then
                call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetTriggerUnit())), "TRIGSTR_211" )
            else
                if ( IsUnitType(GetOrderTargetUnit(), UNIT_TYPE_ANCIENT) == true ) then
                    call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                    call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetTriggerUnit())), "TRIGSTR_209" )
                else
                    // Oops, fixed.
                    if ( GetUnitStateSwap(UNIT_STATE_LIFE, GetOrderTargetUnit()) >= GetUnitStateSwap(UNIT_STATE_MAX_LIFE, GetOrderTargetUnit()) ) then
                        call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                        call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetTriggerUnit())), "TRIGSTR_210" )
                    else
                    endif
                endif
            endif
        else
        endif
    endif
endfunction

//===========================================================================
function InitTrig_Unseal_Energy_check_Kopieren_Kopieren takes nothing returns nothing
    set gg_trg_Unseal_Energy_check_Kopieren_Kopieren = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Unseal_Energy_check_Kopieren_Kopieren, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
    call TriggerAddCondition( gg_trg_Unseal_Energy_check_Kopieren_Kopieren, Condition( function Trig_Unseal_Energy_check_Kopieren_Kopieren_Conditions ) )
    call TriggerAddAction( gg_trg_Unseal_Energy_check_Kopieren_Kopieren, function Trig_Unseal_Energy_check_Kopieren_Kopieren_Actions )
endfunction
Eccho said:
Make sure that udg_EnergyPoints[<index>] is greater than 0.00 at initialization or before the trigger is ran.
All variables are automatically set to null or 0 at initialization, aren't they?
And if I check this before the trigger actions are ran (I think that's what you mean?) I can't show the owner of the triggering unit that there are no points he could use. (The messages are not for debugging.)

And could you send me your signature? I don't really know how to make tables here. =)
Thanks for help. =)
 
Last edited:
Level 23
Joined
Nov 29, 2006
Messages
2,482
Im glad it works for you now.

Quote:
Originally Posted by Eccho
Make sure that udg_EnergyPoints[<index>] is greater than 0.00 at initialization or before the trigger is ran.
All variables are automatically set to null or 0 at initialization, aren't they?
And if I check this before the trigger actions are ran (I think that's what you mean?) I can't show the owner of the triggering unit that there are no points he could use. (The messages are not for debugging.)

I meant that if it is not over 0 at any time, the if-conditions coming after would never be ran, since it will just give the first message and stop.

JASS:
function Trig_Unseal_Energy_check_Kopieren_Kopieren_Conditions takes nothing returns boolean
    // I guess I can't simplify these conditions because I actually need two if I have to use the spell's native orderid, right?
    if ( not ( GetIssuedOrderIdBJ() == OrderId("shadowstrike") ) ) then
        return false
    endif
    if ( not ( GetUnitTypeId(GetTriggerUnit()) != 'u000' ) ) then // prevents showing messages for spells cast by dummies
        return false
    endif
    return true
endfunction

You sure can:p

JASS:
function Trig_Unseal_Energy_check_Kopieren_Kopieren_Conditions takes nothing returns boolean
     //BJ functions are usually unnecessary. GetIssuedOrderIdBJ() can be replaced by GetIssuedOrderId()
     return GetIssuedOrderId() == OrderId("shadowstrike") and GetUnitTypeId(GetTriggerUnit()) != 'u000'
endfunction

Ill send you a PM about my table:p

~Eccho~
 
Level 5
Joined
Feb 5, 2008
Messages
109
I meant that if it is not over 0 at any time, the if-conditions coming after would never be ran, since it will just give the first message and stop.
Ah, ok, I wanted that. =)

I noticed that BJ thing as I had a look into the functions list. What are they for?

Ill send you a PM about my table:p
Impatiently waiting. ;D


Though that way works, do you know any with which the unit wouldn't do anything at all? As I said, let's say the unit is invisible and it tries to cast the ability but it is countered by the trigger, the unit becomes visible. It's not that I really really need another way, but it'd feel way better. ;)
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
BJ's are functions which Blizzard themselves have written customly in Jass (non-native ones, like those you and I are making us selves). They exist in the blizzard.j script and some of them are used to "safely" set up a map properly. However, the script also contains alot of unuseful codes (but some are good) which is used alot when you create your code as GUI.

An example of a BJ function which is useless is
JASS:
function DoNothing takes nothing returns nothing
endfunction

And some more less serious but takes longer time for the program to read since it has to call unnecessary functions (uncertain if it follows the right syntax, but it doesnt matter), which is basically just swapping the parameters of this function:
JASS:
function UnitAddAbilitySwapped takes unit whichUnit integer abil returns nothing
     call UnitAddAbility(abil, whichUnit)
endfunction

If you are saying that you are afraid that the unit would be prevented by a unit going invinsible, I dont think it will happend. Maybe rarely in some cases, I don't know right now (as I am in a hurry). If you get that problem just tell be about it and Ill help again.

You'll get the table tomorrow:p sorry for the delay.
 
Level 5
Joined
Feb 5, 2008
Messages
109
If you are saying that you are afraid that the unit would be prevented by a unit going invinsible, I dont think it will happend. Maybe rarely in some cases, I don't know right now (as I am in a hurry). If you get that problem just tell be about it and Ill help again.
An invisible unit gets visible when trying to cast the ability but being countered due to the trigger, because it moves to its own position, but still moves somehow. (I tried it.)
The only thing that comes to my mind would be a workaround for each buff making invisible, then adding the ability which led to this, changing its level, then make the unit cast it. But that's very very inelegant. ;)

Is there a way to have a look at the Death Coil trigger?
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
In that case, you would have to have wind walk on the hero with a very low cooldown, ordering the hero to cast windwalk but give him back mana when cast. Tho this is a comlex and inaccurate solution.

A suggestion would be to make a dummy unit which casts the sorceress Invinsibility ability on the hero. That's the farest you can get I think. The Death Coil trigger is hardcoded in the wc3 language (c++ I think). But basically if you would want it in Jass, make a spell based on an ability which can target both allies and enemies, and once it is cast check if it is ally or enemy and damage it/heal it manually.
 
Level 5
Joined
Feb 5, 2008
Messages
109
In that case, you would have to have wind walk on the hero with a very low cooldown, ordering the hero to cast windwalk but give him back mana when cast. Tho this is a comlex and inaccurate solution.
And the hero could take damage caused by Faerie Dragons, couldn't he? The mana thing could be solved by setting the mana cost to 0.

A suggestion would be to make a dummy unit which casts the sorceress Invinsibility ability on the hero.
Let's say the hero is invincible at that moment, then it wouldn't work.

But basically if you would want it in Jass, make a spell based on an ability which can target both allies and enemies, and once it is cast check if it is ally or enemy and damage it/heal it manually.
That's what I'm actually doing. ;)
Still, as I said in the first post, I want it to be castable on all hostile and neutral units (then it causes damage), but just on organic and non-treant allied units (then it heals).


The best way would be to make it like it's done with Death Coil, that means not even allowing the player to order the unit to cast the ability on a unit which does not match the classifications (and playing a sound =D). Also it should be shown that there are no points left when the player clicks the ability button. (But I could deactivate the ability when there's no energy, gonna try this.)
So there's no way to make it someway like the Death Coil ability but in JASS with these options? I already did it the way you suggested me to do.


Oh, dear table ... ;D
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
The best way would be to make it like it's done with Death Coil, that means not even allowing the player to order the unit to cast the ability on a unit which does not match the classifications (and playing a sound =D). Also it should be shown that there are no points left when the player clicks the ability button.

It would be most likely impossible, as the blizzard abilities and data sheet is too limited and doesn't allow you to insert all those conditions so that they work together properly.
Your code is maybe not the best one, but it should work except the thing you mentioned about invinsibility. And you are wrong on the matter that Invinsibility cant be cast on already invinsible units. As long as the dummy unit who is casting it is an ally of the affected unit, it will work.

I don't think I have any brilliant ideas at the moment :/

*Offtopic* since sou wanted to know it anyway, my signature is actually two tables nestled together

my table is made in the way like this (broken apart on a structured way to make it easier to understand)

[table]
[table]
Spells: [c](c=new column) Version: [c] Update:
[r](r=new row) Projectile System...[c] 1.12 [c] date [c] [img]tosomething[/img]
[r] blabla [c] 1.0 [c] date [c] [img]rarw[/img]
...
[/table]
[c] Current Activity...
[/table]
 
Level 5
Joined
Feb 5, 2008
Messages
109
I don't mean inviSible, but inviNCible. ;) Invincible units can't be targeted by any spell.


Ah, with [c] and [r], that's the point. -.-
The next few minutes will be spent on my signature. ;D

... There it goes, I love it, thanks. =)


Obviously there's nobody else interested in this order thing, so if we ran out of ideas, I guess that's it. =( Thanks for your effort. =)
 
Last edited:
Status
Not open for further replies.
Top