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

Need Correction with Auto-Train trigger (can't upgrade building)

Status
Not open for further replies.
Level 1
Joined
Feb 26, 2015
Messages
5
i try to make castle fight like map.

  • TrainStart
    • Events
      • Unit - A unit Finishes construction
    • Conditions
      • (Unit-type of (Constructed structure)) Equal to Ranger House
    • Actions
      • Unit - Order (Triggering unit) to train/upgrade to a Archer
  • TrainLoop
    • Events
      • Unit - A unit Finishes training a unit
    • Conditions
      • ((Triggering unit) belongs to an ally of Player 1 (Red)) Equal to True
    • Actions
      • Unit - Order (Triggering unit) to train/upgrade to a (Unit-type of (Trained unit))
      • Unit - Order (Trained unit) to Attack-Move To (Center of Demonic Stone <gen>)
TrainStart and TrainLoop trigger worked. it begin to train unit and auto-move. the problem is, every time the building finish trained the first unit, and begin to train the next unit, i can't upgrade to its advance building (yes i know, i already cancel the units train progress, but still didn't work. the button looks passive, can't click the upgrade button).

but somehow when the first unit is in training then i try to cancel the progress, then the upgrade button works. there must be some bug when the second unit begin to train. can anyone help me fix it?
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
I have seen this problem before... Forgot what it was called though.

Anyway it is indeed a bug but I am not quite sure how to solve it.
Maybe if you let it train after a little delay. Just 0.01 seconds.
Maybe that will solve it.
 
Level 1
Joined
Feb 26, 2015
Messages
5
i just follow your suggestion, the button works! the bug fixed when i add 'wait' trigger. thanks a lot!
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Ok now that I know how it can be done... lets head on towards what you have to do to optimize the code :D

Using a regular wait is always bad.
Normal waits: Do not work parralel to the gametime.
Wait timers: Leak a local timer variable.

What you actually want to do is use a (countdown) timer.
To be able to do this perfectly I recommend you to just copy and paste this in the header file of your map:
(The header file is in the list of triggers. At the very top you see a blue WE icon with the name of the map behind it. Click on that and you open a text file. Paste the following to that file.)
JASS:
function IssueOrderCallback takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId(t)
    local unit whichUnit = LoadUnitHandle(udg_DelayedOrder_Hashtable, id, 0)
    local integer orderType = LoadInteger(udg_DelayedOrder_Hashtable, id, 1)
    local string order = LoadStr(udg_DelayedOrder_Hashtable, id, 2)
    local widget targetWidget
    local location targetLocation
    local integer unitTypeId
    
    if orderType == udg_DelayedOrder_TypeTarget then
        set targetWidget = LoadWidgetHandle(udg_DelayedOrder_Hashtable, id, 3)
        call IssueTargetOrder(whichUnit, order, targetWidget)
        set targetWidget = null
    elseif orderType == udg_DelayedOrder_TypePointTarget then
        set targetLocation = LoadLocationHandle(udg_DelayedOrder_Hashtable, id, 3)
        call IssuePointOrder(whichUnit, order, GetLocationX(targetLocation), GetLocationY(targetLocation))
        call RemoveLocation(targetLocation)
        set targetLocation = null
    elseif orderType == udg_DelayedOrder_TypeTrain then
        set unitTypeId = LoadInteger(udg_DelayedOrder_Hashtable, id, 3)
        call IssueImmediateOrderById(whichUnit, unitTypeId)
    endif
    elseif orderType == udg_DelayedOrder_TypeNoTarget then
        call IssueImmediateOrder(whichUnit, order)
    endif
    
    call FlushChildHashtable(udg_DelayedOrder_Hashtable, id)
    call DestroyTimer(t)
    set t = null
    set whichUnit = null
endfunction
function IssueTargetOrderDelayed takes unit whichUnit, string order, widget targetWidget, real delay returns nothing
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    
    call TimerStart(t, delay, false, function IssueOrderCallback)
    call SaveUnitHandle(udg_DelayedOrder_Hashtable, id, 0, whichUnit)
    call SaveInteger(udg_DelayedOrder_Hashtable, id, 1, udg_DelayedOrder_TypeTarget)
    call SaveStr(udg_DelayedOrder_Hashtable, id, 2, order)
    call SaveWidgetHandle(udg_DelayedOrder_Hashtable, id, 3, targetWidget)
    
    set t = null
endfunction
function IssuePointOrderDelayed takes unit whichUnit, string order, location targetLocation, real delay returns nothing
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    
    call TimerStart(t, delay, false, function IssueOrderCallback)
    call SaveUnitHandle(udg_DelayedOrder_Hashtable, id, 0, whichUnit)
    call SaveInteger(udg_DelayedOrder_Hashtable, id, 1, udg_DelayedOrder_TypePointTarget)
    call SaveStr(udg_DelayedOrder_Hashtable, id, 2, order)
    call SaveLocationHandle(udg_DelayedOrder_Hashtable, id, 3, targetLocation)
    
    set t = null
endfunction
function IssueTrainOrderDelayed takes unit whichUnit, integer unitTypeId, real delay returns nothing
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    
    call TimerStart(t, delay, false, function IssueOrderCallback)
    call SaveUnitHandle(udg_DelayedOrder_Hashtable, id, 0, whichUnit)
    call SaveInteger(udg_DelayedOrder_Hashtable, id, 1, udg_DelayedOrder_TypeNoTarget)
    call SaveInteger(udg_DelayedOrder_Hashtable, id, 3, unitTypeId)
    
    set t = null
endfunction
function IssueImmediateOrderDelayed takes unit whichUnit, string order, real delay returns nothing
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    
    call TimerStart(t, delay, false, function IssueOrderCallback)
    call SaveUnitHandle(udg_DelayedOrder_Hashtable, id, 0, whichUnit)
    call SaveInteger(udg_DelayedOrder_Hashtable, id, 1, udg_DelayedOrder_TypeNoTarget)
    call SaveStr(udg_DelayedOrder_Hashtable, id, 2, order)
    
    set t = null
endfunction

Don't be afraid that you do not know what to do with it because you don't have to understand what it does... well... what it does is just issue an order after a given amount of time. In your case, we use 0 as delay. (Yes 0 is not immediately.)

Now you have to make that code working.
So you have to make a trigger that configures the variables used to make it work.
Make this trigger:
  • Delayed Order Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set DelayedOrder_Hashtable = (Last created hashtable)
      • Set DelayedOrder_TypeNoTarget = 1
      • Set DelayedOrder_TypeTarget = 2
      • Set DelayedOrder_TypePointTarget = 3
      • Set DelayedOrder_TypeTrain = 4
Now you have to use a custom script to give the actual order so you want to set the training unit and training unittype in global variables to make it easier for you to use the command.
  • Train Loop
    • Events
      • Unit - A unit Finishes training a unit
    • Conditions
      • ((Triggering unit) belongs to an ally of Player 1 (Red)) Equal to True
    • Actions
      • Unit - Order (Trained unit) to Attack-Move To (Center of (Playable map area))
      • Set TempUnit = (Triggering unit)
      • Set TempUnitType = (Unit-type of (Trained unit))
      • Custom script: call IssueTrainOrderDelayed(udg_TempUnit, udg_TempUnitType, 0)
As you can see I just set 2 global variables that are parameters for the order.
You can indeed set the "triggering unit" and "unit type of trained unit" inside the custom script but then you have to know their corresponding functions.
 
Level 1
Joined
Feb 26, 2015
Messages
5
sorry for late reply, i have problem with the connection. and thanks again for replied.

i'm still new with world editor, especially with the variable. what type of variable should i make with these?

Set DelayedOrder_Hashtable = (Last created hashtable)
Set DelayedOrder_TypeNoTarget = 1
Set DelayedOrder_TypeTarget = 2
Set DelayedOrder_TypePointTarget = 3
Set DelayedOrder_TypeTrain = 4
 
Level 1
Joined
Feb 26, 2015
Messages
5
i mean from where can i make these trigger?

DelayedOrder_Hashtable
DelayedOrder_TypeNoTarget
DelayedOrder_TypeTarget
DelayedOrder_TypePointTarget
DelayedOrder_TypeTrain

is it from "set variable"? if so, what the variable type should i create first, so i can set the right variable on the trigger?
 
Level 1
Joined
Feb 26, 2015
Messages
5
and this variable type must be...

TempUnit = unit?
TempUnitType = unit type?
 
Status
Not open for further replies.
Top