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

Unit-type Queue detection

Status
Not open for further replies.
Level 2
Joined
Apr 19, 2018
Messages
13
I just would like to know if it is possible to detect every single unit in a building queue. So, if somebody trained a footman, a rifleman, a knight, 2 more footmen, another knight, and a second rifleman in that order, could I use triggers to detect all of them? I need help because a building type that trains units in one special map of mine gets replaced .1 seconds after training a unit.
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
You cannot natively just get the full training queue at any given time, but you can detect when a unit is added to a build queue, when a unit is cancelled, and when a unit is successfully trained. This method to keep track of the queue has been compiled into a system by IcemanBo: TrainingDetection

However, I wouldn't suggest using that system at all. A much better solution is to passively morph the training structure via Bear Form. This will allow it to keep training, keep its train queue, and keep control group hotkeys! Cool, right? It has one problem: there's no direct way to get the unit that is doing the training in the Unit - A unit finishes training a unit event. There, Triggering Unit gets you the trained unit, not the training one. This is annoying, but there are workarounds... and you would run into this exact problem anyway if you tried to use the system I linked in a finishes training event. The best solution for this is to search a small radius around the trained unit and pick the closest unit that satisfies the following conditions. which in most cases will get the right training unit.
  • Is a building
  • Is owned by the same player that owns the trained unit
  • Is alive
  • Optional: is the specific unit-type of the building you want to morph (less computationally complex but only works if you tell the trigger which types of units you're looking for in the first place)
Now about the morph itself. Normally you might think to use Chaos or Metamorphosis, but those are not viable options. Chaos can be wonky with units' stats so it's generally better to avoid it if you can; Metamorphosis has a finite duration and it interrupts current orders when used. You can trick the game into morphing passively, though, with an ability based on the Druid of the Claw's Bear Form. Instead of putting Barracks2 as the "alternate form" unit and Barracks as the "normal form unit", we will switch them so that when we give the ability to the building the game thinks it's already morphed into its alt form! Then when we remove the Bear Form ability from the building immediately after adding it to it the building will morph "back" into the the "normal form unit", which is really your new building type! Trigger looks like:

  • Events
    • Unit - A unit trains a unit
  • Conditions
    • (Unit-type of (Triggering Unit)) equal to YOUR_TYPE
  • Actions
    • Set Shortest = RADIUS
    • Set Trainer = (No unit)
    • Set TP1 = (Position of (Triggering Unit)) //TP1 is a point variable used to clean a point leak here
    • Custom script: set bj_wantDestroyGroup = true //this auto-cleans a group leak in the line below this one
    • Unit Group - Pick every unit in (Units within RADIUS of TP Matching (Unit-type of (Matching unit) equal to YOUR_TRAINING_TYPE) and (Owner of (Matching Unit) equal to Owner of (Triggering Unit)) and (Life of (Matching Unit) Greater than 0.405)) and do (Actions)
      • Loop - Actions
        • Set TP2 = (Position of (Picked Unit))
        • Set Dist = Distance between TP1 and TP2
        • Custom script: call RemoveLocation(udg_TP2) //change the variable name here to udg_ plus whatever you call it
        • If (All conditions are true) then do (then actions) else do (Else actions)
          • If - Conditions
            • Dist less than or equal to Shortest
          • Then - Actions
            • Set Trainer = (Picked Unit)
            • Set Shortest = Dist
          • Else - Actions
    • Custom script: call RemoveLocation(udg_TP1) //change the variable name here too to udg_ plus whatever you call it
    • Unit - Add BEAR_ABIL to Trainer
    • Unit - Remove BEAR_ABIL from Trainer
 
there's no direct way to get the unit that is doing the training in the Unit - A unit finishes training a unit event. There, Triggering Unit gets you the trained unit, not the training one.
It works with Triggering Unit, and Trained Unit. Triggering Unit is the building.
 

Attachments

  • Finish Training.w3x
    13.2 KB · Views: 60
Level 2
Joined
Apr 19, 2018
Messages
13
I cannot test out IcemanBo's map on my World Editor. Also, I am replacing the training building to cancel the first unit in the queue. So, if somebody could just tell me how to cancel the first unit in the queue instead of what the Force UI Cancel/Esc does, that would be appreciated. I have yet to find a thread which has a sufficient solution to that problem.
 
Level 12
Joined
Nov 3, 2013
Messages
989
I cannot test out IcemanBo's map on my World Editor. Also, I am replacing the training building to cancel the first unit in the queue. So, if somebody could just tell me how to cancel the first unit in the queue instead of what the Force UI Cancel/Esc does, that would be appreciated. I have yet to find a thread which has a sufficient solution to that problem.
In that case, couldn't you save the queue, delete the entire queue, and then re-issue the training building to train all the units (except the first unit) in the same order?
 
Level 2
Joined
Apr 19, 2018
Messages
13
In that case, couldn't you save the queue, delete the entire queue, and then re-issue the training building to train all the units (except the first unit) in the same order?
How could I save the queue? A person would train whatever units they felt like. Also, they have a choice of five units instead of the normal three. If I knew how to save the queue, then that would solve my problems.
 
Level 2
Joined
Apr 19, 2018
Messages
13
I cannot test out IcemanBo's map on my World Editor.
@Death Adder read that^

I quite literally cannot open it in World Editor and know very little in Jass coding. I have an old version of the World Editor which doesn't recognize large chunks of IcemanBo's code as complete code. If there is any way that you could find a way to save the queue in Warcraft 3 version 1.21b, that would be much appreciated.
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
It works with Triggering Unit, and Trained Unit. Triggering Unit is the building.
Whaaaaaaaaat?? I swear that was missing functionality for years! Am I not remembering properly?
I quite literally cannot open it in World Editor
Wrong. You can open it but you can't save it.
Warcraft 3 version 1.21b
Running 1.21b is a REALLY bad idea. At the very least you should have 1.24b as that is when Blizzard introduced hashtables, added H2I natively, and fixed a few major security flaws/vulnerabilities. What good reason do you have for running an editor that old? If you are unwilling to update your editor you're going to have to dig up a copy of the JASSNewGenPack that works with 1.21b somewhere (best guess is Sharpcraft/WEX will not).

This sort of system is annoying to re-write in GUI or normal JASS without data structures, so it's unlikely anyone will just do it for you.
 
Last edited:
Level 12
Joined
Nov 3, 2013
Messages
989
@Death Adder read that^

I quite literally cannot open it in World Editor and know very little in Jass coding. I have an old version of the World Editor which doesn't recognize large chunks of IcemanBo's code as complete code. If there is any way that you could find a way to save the queue in Warcraft 3 version 1.21b, that would be much appreciated.
  • Events
    • Unit - A unit Begins training a unit
    • Unit - A unit Cancels training a unit
    • Unit - A unit Finishes training a unit
This sort of system is annoyingly to re-write in GUI or normal JASS without data structures, so it's unlikely anyone will just do it for you.[/I]
He probably doesn't need the system though, at least I would guess not.
 
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,010
Yeah definitely doesn't need all the functionality, but the meat of the system is what he would need: properly caching and regurgitating the training queue.

@Risk™Master, why specifically do you need to remove the next training unit from the queue after your specific unit is trained? If you can give a better description of why/what you're trying to accomplish perhaps there is a better way.
 
Postive is the order is correct, but not perfect is that it requires to cancel and re-train all others internally.

The method is to use native Cancel (cancels last one in queue), and to fetch canceled objectId. When repeating this cancel until queue is empty we can access correct order again.. and then re-order the building to train those objects in our wanted order, or just skip one element completly like done when we want to have 1st element removed.

I made in for GUI (without vjass), but only as standalone, meanng training queue access of buildings and things alike are not possible. Only removing first element is possible.^^

In demo type "1" to remove first training object, it works with defining the building and then firing the event:
  • Set TCF_Building = (Picked unit)
  • Set TCF_CancelTrainingFront = 1.00
  • TCF Run
    • Events
      • Game - TCF_CancelTrainingFront becomes Equal to 1.00
    • Conditions
    • Actions
      • Set TCF_QueueSize = 0
      • -------- ------------------ --------
      • Trigger - Turn on TCF Cancel <gen>
      • For each (Integer TCF_I) from 1 to 8, do (Actions)
        • Loop - Actions
          • Set TCF_Queue[TCF_I] = No unit-type
          • Custom script: call IssueImmediateOrderById(udg_TCF_Building, 851976)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • TCF_Queue[TCF_I] Equal to No unit-type
            • Then - Actions
              • Custom script: exitwhen true
            • Else - Actions
      • Set TCF_QueueSize = (TCF_I - 2)
      • -------- ------------------ --------
      • For each (Integer TCF_I) from (-1 x TCF_QueueSize) to -1, do (Actions)
        • Loop - Actions
          • Custom script: call IssueImmediateOrderById(udg_TCF_Building, udg_TCF_Queue[ udg_TCF_I * -1] )
      • -------- ------------------ --------
      • Set TCF_CancelTrainingFront = 0.00
      • Trigger - Turn off TCF Cancel <gen>
  • TCF Cancel
    • Events
      • Unit - A unit Cancels training a unit
      • Unit - A unit Cancels research
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Trained unit-type) Equal to No unit-type
        • Then - Actions
          • Custom script: set udg_TCF_Queue[udg_TCF_I] = GetResearched()
        • Else - Actions
          • Set TCF_Queue[TCF_I] = (Trained unit-type)
 

Attachments

  • TrainingCancelFront.w3x
    24.6 KB · Views: 65
Last edited:
Status
Not open for further replies.
Top