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

Switch Attack

Switch Attack v2.2

Simple system for GUI users that allows to choose what attack (from 2 available in ObjectEditor) will be enabled on given unit.
Recommended for units / structures. Uses War Club ability to switch between two attacks.

Instalation:
Copy from OE: destructable tree: "TreeForAttackChange", 2 abilities: "SwitchAttack1" and "SwitchAttack2",
copy in TriggerEditor whole "SwitchAttack" category, Set dummy tree and 2 abilities in "SwitchAttackConfig" trigger. Keep "SwitchAttackConfig" trigger above "SwitchAttack" trigger.

How to use:
Prepare your units in Object Editor you wish to use with changeable attacks.
Set "Combat Attack 1" and "Combat Attack 2" parameters. Enable "Attack 1 Only" or "Attack 2 Only".
To set on unit "Combat Attack 1" as active attack and other one disabled:
  1. set SwitchAttackTo1_Unit = <Your Unit>
  2. Trigger - Run SwitchAttack (ignoring conditions)
And vice versa: to enable "Combat Attack 2" and disable "Combat Attack 1":
  1. set SwitchAttackTo2_Unit = <Your Unit>
  2. Trigger - Run SwitchAttack (ignoring conditions)
Why not recommened for heroes:
It works on heroes. However there are issues:
After switching to "Attack 2" attack icon on User Interface will disapear (see picture). Hero can normally attack but no icon is annoying.

When mixed with Orbs (which enables "Attack 2" like Orb of Frost, Orb of Slow) may result in losing both attacks.
Scenario: Orb is picked up, System enables "Attack 2", Orb is dropped. It can be fixed by re-pick an Orb or <Trigger - Run SwitchAttack >


Triggers:

  • SwitchAttackConfig
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set SwitchAttack_Tree = TreeForAttackChange
      • Set SwitchAttack_Ability1 = SwitchAttack1
      • Set SwitchAttack_Ability2 = SwitchAttack2
      • -------- ---------------------- --------
      • Set SwitchAttackTo1_Unit = No unit
      • Set SwitchAttackTo2_Unit = No unit
      • -------- ---------------------- --------
  • SwitchAttack
    • Events
    • Conditions
    • Actions
      • Custom script: local real x
      • Custom script: local real y
      • Custom script: local real r
      • Custom script: local unit u
      • -------- ---------------------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SwitchAttackTo1_Unit Not equal to No unit
        • Then - Actions
          • Unit - Add SwitchAttack_Ability1 to SwitchAttackTo1_Unit
          • Custom script: set u=udg_SwitchAttackTo1_Unit
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • SwitchAttackTo2_Unit Not equal to No unit
            • Then - Actions
              • Unit - Add SwitchAttack_Ability2 to SwitchAttackTo2_Unit
              • Custom script: set u=udg_SwitchAttackTo2_Unit
            • Else - Actions
              • Game - Display to (All players) the text: |cffff4500 Switch A...
              • Skip remaining actions
      • -------- ---------------------- --------
      • Custom script: call SetUnitPosition(u, GetUnitX(u), GetUnitY(u))
      • Custom script: call SetUnitFacing(u, GetUnitFacing(u))
      • -------- ---------------------- --------
      • Custom script: set r = GetUnitFacing(u)*bj_DEGTORAD
      • Custom script: set x = GetUnitX(u)+10.00*Cos(r)
      • Custom script: set y = GetUnitY(u)+10.00*Sin(r)
      • Custom script: set bj_lastCreatedDestructable = CreateDestructable(udg_SwitchAttack_Tree, x, y, 0.00, 1.00, 0)
      • Custom script: call IssueTargetOrder(u, "grabtree", bj_lastCreatedDestructable)
      • Custom script: call UnitRemoveAbility(u, udg_SwitchAttack_Ability1)
      • Custom script: call UnitRemoveAbility(u, udg_SwitchAttack_Ability2)
      • Custom script: call RemoveDestructable(bj_lastCreatedDestructable)
      • Custom script: set bj_lastCreatedDestructable = null
      • -------- ---------------------- --------
      • Custom script: set u=null
      • Set SwitchAttackTo1_Unit = No unit
      • Set SwitchAttackTo2_Unit = No unit
use examples:
  • Attack1
    • Events
      • Player - Player 1 (Red) types a chat message containing 1 as An exact match
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • Set SwitchAttackTo1_Unit = (Picked unit)
          • Trigger - Run SwitchAttack <gen> (ignoring conditions)
  • Attack2
    • Events
      • Player - Player 1 (Red) types a chat message containing 2 as An exact match
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • Set SwitchAttackTo2_Unit = (Picked unit)
          • Trigger - Run SwitchAttack <gen> (ignoring conditions)
special thanks: IcomanBo, Reventhous
Previews
Contents

Switch Attack v2.2 (Map)

Reviews
IcemanBo
I've just read it now. It would probably work, too, when the unit gets paused, ordered stop, and unpaused. But it doesn't really matter I guess. You may. Simple, and useful -- approved.
Level 18
Joined
Nov 21, 2012
Messages
835
@KILLCIDE you mean change Tags in description to GUI/JASS ? or convert triggers SetAttack1, SetAttack2 to Jass, I'll change name to "system" :)
@IcemanBo it's 0.80sec because original WarClub uses 0.80sec delay, it will not always work with 0.00sec, won't work without "wait" (tested). Grabtree is not instant and with 0sec gap unit sometimes has no time to get the tree (ability is removed)
and I forgot to say: war club abilities uses button positions x=0, y=-11 to hide an icon on UI during this 0.80sec
Im not sure about global tree: cannotfind something like SetDestructableX ?
setting a unit, and runnng a trigger is simplest way for user to use this I belive
 
It seems to work for me well, can you test?

  • SetAttack
    • Events
    • Conditions
      • AttackChangeUnit Not equal to (!=) No unit
        • Multiple ConditionsOr - Any (Conditions) are true
          • Conditions
            • AttackType Equal to (==) 1
            • AttackType Equal to (==) 2
    • Actions
      • Destructible - Create a AttackChangeTree at ((Position of AttackChangeUnit) offset by 10.00 towards (Facing of AttackChangeUnit) degrees) facing (Random angle) with scale 1.00 and variation 0
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • AttackType Equal to (==) 1
          • Then - Actions
            • Unit - Add AttackChangeAbility1 to AttackChangeUnit
            • Unit - Order AttackChangeUnit to Night Elf Mountain Giant - War Club (Last created destructible)
            • Unit - Remove AttackChangeAbility1 from AttackChangeUnit
          • Else - Actions
            • Unit - Add AttackChangeAbility2 to AttackChangeUnit
            • Unit - Order AttackChangeUnit to Night Elf Mountain Giant - War Club (Last created destructible)
            • Unit - Remove AttackChangeAbility2 from AttackChangeUnit
Im not sure about global tree: cannotfind something like SetDestructableX ?
Yes, I didn't consider it doesn't exist. ^^

edit:

and maybe nulling the unit variable in the end is good, and also removing the tree.
 

Attachments

  • SetAttack.w3x
    23.9 KB · Views: 247
Level 18
Joined
Nov 21, 2012
Messages
835
it will not work, sometimes works, sometimes not,
run game, select all knights, type "2", try to attack Barracks (just to see attack is ranged on knights), type "1", attack Barracks, repeat 2-3 times in few seconds intervals and you will see it will start to mess. There must be delay between issued order "grabtree" and removing ability from unit, I tested it now and also yesterday before submitted here.

one trigger "SetAttack" instead of 2 will work, ok but user has to put 3 lines to run this, intead of 2 lines :) I want to keep it as simple for user as possible ;)
 
Level 18
Joined
Nov 21, 2012
Messages
835
I think it is related with ability War Club itself, unit needs a non-zero time to grab the tree,
as I tested yesterday with TriggerSleepAction(0.00) (and also with timer 0.00sec) I turned back dummy tree to be visible (has used summer tree standard model) and it appears that order to unit has been given, tree created, and sometimes some trees remains: which means unit had no time to grab it,
then I created tree at point at unit face in 10.00 distance, (before - it was created at unit's location) it helps much, also with unit's turning, but still 0.00sec gap sometimes bugs,
only when set up to 0.80sec (like original WarClub delay is) it always works fine
edit:
just realized: maybe game version? Im still on 1.28.0.7205
 
Level 5
Joined
May 2, 2015
Messages
109
-I think the name "Set Attack" doesn't really suit with what this system do.
"Switch Attack" or "Toggle Attack" might be suitable.

-I agree with what @KILLCIDE say. This system would be better in JASS.
one trigger "SetAttack" instead of 2 will work, ok but user has to put 3 lines to run this, intead of 2 lines :) I want to keep it as simple for user as possible ;)
If you want to keep the 2 lines with one trigger, then create two unit variable "SwitchAttack1Unit" and "SwitchAttack2Unit". In SwitchAttack trigger, check which from those 2 variable that have unit. SwitchAttack1Unit = 1 , SwitchAttack2Unit = 2. Finaly, set both variable to no unit. DONE! :)

Btw, nice system :thumbs_up:

EDIT: I show you how (this is just my opinion :) ) Tell me if you want to see how it looks in JASS
  • SwitchAttack
    • Events
    • Conditions
      • Or - Any (Conditions) are true
        • Conditions
          • SwitchAttack_Attack1Unit Not equal to No unit
          • SwitchAttack_Attack2Unit Not equal to No unit
    • Actions
      • Custom script: local unit u
      • Custom script: local real x
      • Custom script: local real y
      • Custom script: local real a
      • Custom script: local integer warClub
      • Custom script: local destructable t
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SwitchAttack_Attack1Unit Not equal to No unit
        • Then - Actions
          • Custom script: set u = udg_SwitchAttack_Attack1Unit
          • Custom script: set warClub = udg_SwitchAttack_AttackAbility1
        • Else - Actions
          • Custom script: set u = udg_SwitchAttack_Attack2Unit
          • Custom script: set warClub = udg_SwitchAttack_AttackAbility2
      • -------- --------
      • Custom script: set a = GetUnitFacing(u)*bj_DEGTORAD
      • Custom script: set x = GetUnitX(u)+10.00*Cos(a)
      • Custom script: set y = GetUnitY(u)+10.00*Sin(a)
      • -------- --------
      • Custom script: set t = CreateDestructable(udg_SwitchAttack_ChangeTree, x, y, 0.00, 1.00, 0)
      • -------- --------
      • Custom script: call UnitAddAbility(u, warClub)
      • Custom script: call IssueTargetOrder(u, "grabtree", t)
      • Custom script: call TriggerSleepAction(0.80)
      • Custom script: call UnitRemoveAbility(u, warClub)
      • -------- --------
      • Set SwitchAttack_Attack1Unit = No unit
      • Set SwitchAttack_Attack2Unit = No unit
      • -------- --------
      • Custom script: call RemoveDestructable(t)
      • Custom script: set u=null
      • Custom script: set t=null
the test
  • test
    • Events
      • Player - Player 1 (Red) types a chat message containing <Empty String> as An exact match
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Entered chat string) Equal to 1
        • Then - Actions
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
            • Loop - Actions
              • Set SwitchAttack_Attack1Unit = (Picked unit)
              • Trigger - Run SwitchAttack <gen> (ignoring conditions)
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Entered chat string) Equal to 2
        • Then - Actions
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
            • Loop - Actions
              • Set SwitchAttack_Attack2Unit = (Picked unit)
              • Trigger - Run SwitchAttack <gen> (ignoring conditions)
        • Else - Actions
 
Last edited:
Level 18
Joined
Nov 21, 2012
Messages
835
I would prefer we understand why, or when exactly it doesn't work, and potentially can fix it.
Thanks for encouraging me to make more tests.. It was worth it :)

Once again I took your proposal (version without 'wait') and start tests, and when bug appears game also prints debug message (in game):
"unit issued point order 852512 , grabtree".
Strange because it is a target order. I think order becomes 'point order' after dummy-tree was removed and unit had no time to grab it. Why?

'Grab tree' ability requires from unit to be directly in front of a tree.
If unit is moving, patroling, turning around patroling point - then if we order to stop, he stops. But his facing angle may change (esspecialy when patroling and just turning back).
If this happends unit has no time to turn directly to the tree to grab it = bug.

Ordering stop will not help, but I found that SetUnitPosition + SetUnitFacing is the solution.
After SetUnitPosition + SetUnitFacing we create the tree in front of the unit and then there is no risk that unit will not grab the tree instantly.
Once agains thanks IcemanBo you were right from the beginning with no-wait version :)

Reventhous thanks for your smart hints, I'll change system as you suggested. Let's keep it GUI, advanced mappers may write a function based on this idea in 3min. It supposed to be for GUI users.

Made test on this new version: 15min game with randomly switichng weapons for random units for few seconds = hundreds changes, while units still re-ordered to partol random points / fight with hostile. No bugs at all.
 
Level 5
Joined
May 2, 2015
Messages
109
Thanks for the compliment, Zibi ;)
Overall the code looks pretty clean. But I have some more suggestion :D :-

-unnecessary multiple function call
  • Custom script: local real x = GetUnitX(u)+10.00*Cos(GetUnitFacing(u)*bj_DEGTORAD)
  • Custom script: local real y = GetUnitY(u)+10.00*Sin(GetUnitFacing(u)*bj_DEGTORAD)
There's no need use GetUnitFacing multiple times. Store the unit facing into a local variable, like this

  • Custom script: local real r = GetUnitFacing(u)*bj_DEGTORAD
  • Custom script: local real x = GetUnitX(u)+10.00*Cos(r)
  • Custom script: local real y = GetUnitY(u)+10.00*Sin(r)
-
  • Custom script: local unit u=null
No need to initialize a local variable unless you want to use it before assigning value into it.
Leave it local unit u

-
  • Game - Display to (All players) the text: |cffff4500 Switch A...
Create a boolean variable and name it "SwitchAttack_DEBUG_MODE". Then,
  • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • SwitchAttack_DEBUG_MODE (==) true
    • Then - Actions
      • Game - Display to (All players) the text: |cffff4500 Switch A...
    • Else - Actions
Add SwitchAttack_DEBUG_MODE to the configuration trigger so user can decide if they want to see the message or not.

That's it. :thumbs_up: (actually, there's some more, just lets have a talk about my suggestion first)
 
Last edited:
Could you out the "Grab Tree" function out of the init function? When working with function calls we need ensure the function to call is always generated above the caller funciton, and it might mix up with adding/removing triggers. So a way that always works would be good.
Adding the SetUnitPos and facing there, would be good, too, as the logics are directly related.

Nice trick with 2 different unit variables.

I would personaly recommend to use a local destructable variable instead of the global, but as you prefer.
 
Ordering stop will not help, but I found that SetUnitPosition + SetUnitFacing is the solution.
I've just read it now. It would probably work, too, when the unit gets paused, ordered stop, and unpaused. But it doesn't really matter I guess.

I'll stay with bj_lastCreatedDestructable and warning message always ON, if I may :)
You may. Simple, and useful -- approved.
 
Level 11
Joined
Mar 31, 2016
Messages
657
It worked however its conflicting with the Harvest system. Switch Attack abilities were replaced by the harvest gold ability after Switch Attack 2 ability successfully changed attack from attack 1 to attack 2.
EDIT - Tried leaving the system as default (enabled via text message) and the same thing happened - also after the conflict occurs, you can't switch attacks anymore.

How to solve the conflict of triggers?
 
Level 11
Joined
Mar 31, 2016
Messages
657
Zibi - idk what happened. It was working before. Now it's not working in my map, even though your map still work.
My map is glitching out and the unit loses both abilities without the switch even occuring.
I also did some troubleshooting by removing other abilities that might have been an orb effect but it still glitches.
Could you check out my map sometime this holiday season?
Cheers.
 
Top