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

[Extension] BuildUtils

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Some time ago I was in need of script that could tell me the current status of given building. Unfortunately I haven't found nothing interesting untill I went to wc3c.net and saw Troll-Brain's ConstructionStatus. I decided to improve that one in case it was a bit old and didn't feature all the things I've needed.

This simple library is able to detect if unit is currently being constructed, upgrading or if it's training troops. I've also added function which enables user to retrieve worker who started the construction process. Two additional function are here to check if building is 'free', meaning it's status is somewhat empty and another function, just to tell if structure is 'completed' - neither under construction nor is uder upgrade process.

New: Simple Extension that adds additional API to BuildEvent.

JASS:
/*****************************************************************************
*
*    BuildUtils v3.1.0.0
*        by Bannar aka Spinnaker
*
*      Allows one to get information about current building status.
*
******************************************************************************
*
*    Requirements:
*
*       UnitDex by TriggerHappy
*           hiveworkshop.com/forums/submissions-414/system-unitdex-unit-indexer-248209/
*
*       Optionaly uses UnitEvent by Nestharus which helps getting rid of rare build-process issue
*           hiveworkshop.com/forums/jass-functions-413/extension-unit-event-172365/
*
*       RegisterPlayerUnitEvent library - supports:
*
*        | RegisterPlayerUnitEvent by Bannar
*        |    hiveworkshop.com/forums/submissions-414/snippet-registerevent-pack-250266/
*        |
*        | RegisterPlayerUnitEvent by Magtheridon96
*        |    hiveworkshop.com/forums/jass-resources-412/snippet-registerplayerunitevent-203338/
*
*
*        Credits to Troll-Brain for original project idea
*        Special thanks to Magtheridon96
*
******************************************************************************
*
*    Functions:
*       function IsUnitIdle takes integer index returns boolean
*           - Checks if given structure isn't currently performing any action
*       function IsUnitFinished takes integer index returns boolean
*           - Checks if unit nethier is upgrading nor under construction
*       function IsUnitBeingBuilt takes integer var returns boolean
*           - Checks if structure is being built
*       function IsUnitUpgrading takes integer var returns boolean
*           - Checks if structure currently being upgraded
*       function IsUnitTraining takes integer var returns boolean
*           - Checks if building currently training unit
*       function IsUnitRevivng takes integer var returns boolean
*           - Checks if structure currently resurrects a hero
*       function IsUnitResearching takes integer var returns boolean
*           - Checks if structure currently researching an upgrade
*
*****************************************************************************/
library BuildUtils requires UnitDex optional UnitEvent optional RegisterPlayerUnitEvent

    native UnitAlive takes unit id returns boolean

    //! textmacro BUILD_UTILS_MACRO takes NAME, TYPE, KEY, NODE
    function IsBuilding$NAME$ takes $TYPE$ var returns boolean
        return BuildUtils$KEY$.$NODE$
    endfunction
    //! endtextmacro

    function IsBuildingFinished takes integer var returns boolean
        return UnitAlive(GetUnitById(var)) and not (BuildUtils(var).cU or BuildUtils(var).uU)
    endfunction

    //! runtextmacro BUILD_UTILS_MACRO("BeingBuilt","integer","(var)","cU")
    //! runtextmacro BUILD_UTILS_MACRO("Upgrading","integer","(var)","uU")
    //! runtextmacro BUILD_UTILS_MACRO("Training","integer","(var)","tU")
    //! runtextmacro BUILD_UTILS_MACRO("Revivng","integer","(var)","oU")
    //! runtextmacro BUILD_UTILS_MACRO("Researching","integer","(var)","rU")

    function IsBuildingIdle takes integer v returns boolean
        return UnitAlive(GetUnitById(v)) and not (BuildUtils(v).cU or BuildUtils(v).uU or BuildUtils(v).tU or BuildUtils(v).oU or BuildUtils(v).rU)
    endfunction

    module BuildUtilsModule
        //! textmacro BUILD_UTILS_MACRO_EV takes TYPE, NODE, VALUE
        static method onEvent$TYPE$ takes nothing returns nothing
            set thistype[GetUnitId(GetTriggerUnit())].$NODE$ = $VALUE$
        endmethod
        //! endtextmacro

        //! runtextmacro BUILD_UTILS_MACRO_EV("CS","cU","true")
        //! runtextmacro BUILD_UTILS_MACRO_EV("CE","cU","false")
        //! runtextmacro BUILD_UTILS_MACRO_EV("US","uU","true")
        //! runtextmacro BUILD_UTILS_MACRO_EV("UE","uU","false")
        //! runtextmacro BUILD_UTILS_MACRO_EV("TS","tU","true")
        //! runtextmacro BUILD_UTILS_MACRO_EV("TE","tU","false")
        //! runtextmacro BUILD_UTILS_MACRO_EV("OS","oU","true")
        //! runtextmacro BUILD_UTILS_MACRO_EV("OE","oU","false")
        //! runtextmacro BUILD_UTILS_MACRO_EV("RS","rU","true")
        //! runtextmacro BUILD_UTILS_MACRO_EV("RE","rU","false")
    endmodule

    private function RegisterAnyUnitEvent takes playerunitevent e, code c returns nothing
        static if LIBRARY_RegisterPlayerUnitEvent then
            static if LIBRARY_RegisterNativeEvent then
                call RegisterAnyPlayerUnitEvent(e, c)
            else
                call RegisterPlayerUnitEvent(e, c)
            endif
        else
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, e)
            call TriggerAddCondition(t, Condition(c))
            set t = null
        endif
    endfunction

    private module RegisterEvents
        private static method onInit takes nothing returns nothing
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_START,  function thistype.onEventCS)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function thistype.onEventCE)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_START,    function thistype.onEventUS)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_FINISH,   function thistype.onEventUE)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_CANCEL,   function thistype.onEventUE)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_TRAIN_START,      function thistype.onEventTS)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_TRAIN_FINISH,     function thistype.onEventTE)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_TRAIN_CANCEL,     function thistype.onEventTE)
            call RegisterAnyUnitEvent(EVENT_PLAYER_HERO_REVIVE_START,     function thistype.onEventOS)
            call RegisterAnyUnitEvent(EVENT_PLAYER_HERO_REVIVE_CANCEL,    function thistype.onEventOE)
            call RegisterAnyUnitEvent(EVENT_PLAYER_HERO_REVIVE_FINISH,    function thistype.onEventOE)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_RESEARCH_START,   function thistype.onEventRS)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_RESEARCH_CANCEL,  function thistype.onEventRE)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_RESEARCH_FINISH,  function thistype.onEventRE)
            call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_DEATH,            function thistype.onDeath)
            call RegisterUnitIndexEvent(Condition(function thistype.deindex), EVENT_UNIT_DEINDEX)
        endmethod
    endmodule

    struct BuildUtils extends array
        readonly boolean cU
        readonly boolean uU
        readonly boolean tU
        readonly boolean oU
        readonly boolean rU

        private static method reset takes integer index returns nothing
            set thistype(index).cU = false
            set thistype(index).uU = false
            set thistype(index).tU = false
            set thistype(index).oU = false
            set thistype(index).rU = false
        endmethod

        private static method deindex takes nothing returns boolean
            if IsUnitType(GetIndexedUnit(), UNIT_TYPE_STRUCTURE) then
                call thistype.reset(GetIndexedUnitId())
            endif
            return false
        endmethod

        implement BuildUtilsModule

        static if LIBRARY_UnitEvent then
            private method reincarnate takes nothing returns nothing
                if IsUnitType(unit, UNIT_TYPE_STRUCTURE) then
                    call thistype.reset(this)
                endif
            endmethod
        endif

        static method onDeath takes nothing returns nothing
            if IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) then
                call thistype.reset(GetUnitId(GetTriggerUnit()))
            endif
        endmethod

        implement optional UnitEventStruct
        implement RegisterEvents
    endstruct

endlibrary
 
Last edited:
Looks great :D

Couple of things:

JASS:
    private function isFree takes integer i returns boolean
        return not cU[i] and not uU[i] and not tU[i]
    endfunction
    private function isFinished takes integer i returns boolean
       return not cU[i] and not uU[i]
    endfunction

These functions could be part of the API if you give them names like IsStructureFreeById and IsStructureFinishedById :D

You can also add -ById functions for these:

JASS:
    function IsStructureBeingBuilt takes unit u returns boolean
        return cU[GetUnitUserData(u)]
    endfunction
    function IsStructureUpgrading takes unit u returns boolean
        return uU[GetUnitUserData(u)]
    endfunction
    function IsStructureTraining takes unit u returns boolean
        return tU[GetUnitUserData(u)]
    endfunction
    function GetBuilder takes unit u returns unit
         return b[GetUnitUserData(u)]
    endfunction

IsStructureBeingBuiltById
IsStructureUpgradingById
IsStructureTrainingById
GetBuilderById

These are faster and could be useful if the user already got the id of the unit in scope (DamageEvent.sourceId is a good example)
Why should you call IsStructureFinished(DamageEvent.source) when you could call the more efficient: IsStructureFinishedById(DamageEvent.sourceId)

edit
And here's an idea I just thought of, instead of using only one function 'onEvent' for all those events,
you can use one function per event, which shouldn't be a problem since you're using RegisterPlayerUnitEvent.

This would make it uberfast ;D
You'd cancel out tons of comparisons ^_^
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
I was thinking about cutting those comparisong to functions already but I thought that small, multiple functions will be eventually too much just for that :p Thats np for me. Versions below 1.0 had multiple functions anyways.

Btw, if we make those as 'ById'; are the 'non ById' realy needed? -.-
If someone owns UnitIndexer he can call for exampleif IsStructureUpgrading(GetUnitUserData(GetTriggeringUnit())) theninstead ofif IsStructureUpgrading(GetTriggerUnit()) thenanyways.
 
Uberfast = Ubergood = Win! =>

Code:
Bribe               Nes             Troll-Brain             Magtheridon96
 :D                 :O                  :)                      <:'D

Uberfail =

Code:
Bribe               Nes             Troll-Brain             Magtheridon96
 -.-                >.>                 :(                      ...

edit
I know I'm going to regret this, but:

cU -> C
uU -> U
tU -> T

edit

Btw, if we make those as 'ById'; are the 'non ById' realy needed? -.-

You don't NEED them, but having them is better :p
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
I will stay with my boolean names;
cU -> contructionUnits
uU -> upgradingUnits
tU -> trainingUnits

That 1 additional letter won't increase script's speed by noticable amount D;

I'll wait what other ppl out here think about removing the 'takes unit u' and replace that will 'takes integer i'. Unit Indexer is requirement anyways, thus passing unit's id shouldn't be a problem. But doubling the amount of api for such issue in my eyes is.
JASS:
library StructureStatus uses UnitIndexer, RegisterPlayerUnitEvent
    globals
        private boolean array cU
        private boolean array uU
        private boolean array tU
        private unit array b
    endglobals
    private function onEventCS takes nothing returns nothing
        set cU[GetUnitUserData(GetConstructingStructure())] = true
        set b[GetUnitUserData(GetConstructingStructure())] = GetTriggerUnit()
    endfunction
    private function onEventCE takes nothing returns nothing
        set cU[GetUnitUserData(GetConstructedStructure())] = false
        set b[GetUnitUserData(GetConstructedStructure())] = null
    endfunction
    private function onEventUS takes nothing returns nothing
        set uU[GetUnitUserData(GetTriggerUnit())] = true
    endfunction
    private function onEventUE takes nothing returns nothing
        set uU[GetUnitUserData(GetTriggerUnit())] = false
    endfunction
    private function onEventTS takes nothing returns nothing
            set tU[GetUnitUserData(GetTriggerUnit())] = true
    endfunction
    private function onEventTE takes nothing returns nothing
        set tU[GetUnitUserData(GetTriggerUnit())] = false
    endfunction
    private function onDeath takes nothing returns nothing
        local integer i = GetUnitUserData(GetTriggerUnit())
        set cU[i] = false
        set uU[i] = false
        set tU[i] = false
        set b[i] = null
    endfunction
    function IsStructureFreeById takes integer i returns boolean
        return not cU[i] and not uU[i] and not tU[i]
    endfunction
    function IsStructureFinishedById takes integer i returns boolean
       return not cU[i] and not uU[i]
    endfunction
    function IsStructureBeingBuiltById takes integer i returns boolean
        return cU[i]
    endfunction
    function IsStructureUpgradingById takes integer i returns boolean
        return uU[i]
    endfunction
    function IsStructureTrainingById takes integer i returns boolean
        return tU[i]
    endfunction
    function GetBuilderById takes integer i returns unit
         return b[i]
    endfunction
    function IsStructureFree takes unit u returns boolean
        return IsStructureFreeById(GetUnitUserData(u))
    endfunction
    function IsStructureFinished takes unit u returns boolean
        return IsStructureFinishedById(GetUnitUserData(u))
    endfunction
    function IsStructureBeingBuilt takes unit u returns boolean
        return cU[GetUnitUserData(u)]
    endfunction
    function IsStructureUpgrading takes unit u returns boolean
        return uU[GetUnitUserData(u)]
    endfunction
    function IsStructureTraining takes unit u returns boolean
        return tU[GetUnitUserData(u)]
    endfunction
    function GetBuilder takes unit u returns unit
         return b[GetUnitUserData(u)]
    endfunction
    private module M
        static method onInit takes nothing returns nothing
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_START, function onEventCS)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function onEventCE)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_START, function onEventUS)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_FINISH, function onEventUE)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_CANCEL, function onEventUE)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_START, function onEventTS)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_FINISH, function onEventTE)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_CANCEL, function onEventTE)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function onDeath)
        endmethod
    endmodule
    private struct T extends array
        implement M
    endstruct
endlibrary
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
Well, i've found new motivations about this, so i made few tests :

I remember why i didn't used the cancel construct event.

1) It fires only when the unit which was being built is canceled by the cancel button or by the escape keyboard key (which is basically the same).
It doesn't fire when the unit die before the end of the construction, and probably also not when it's removed by RemoveUnit.

2) It never fires when the unit which is being built is not a structure, such as a footman.

3 ) A canceled structure == a removed unit without a corpse

4) The death event fires before the cancel one.

So for all these reasons you should use the deindex event, in other words when an unit is being removed.
Maybe you could keep the death event for completness reason.
As i suppose it fires before the deindex event. (even if on a such event it's obvious that the unit is not being built anymore ...)

Using an unit indexer instead of GroupUtils is an improvement, even if speed doesn't really matter here, but the deindex event is needed.
Also, i don't really like the code split, but i don't hope you will change your mind.

Short senseless name + speedfreak for no real reason =>

Code:
Bribe               Nes             Troll-Brain             Magtheridon96
 :(                 :O                  >.>                      <:'D

Oh, and also as stated in the thread you have linked :
If a structure which is being built die with a passive reincarnation ability, when the structure will be revived it will be finished, but the finish construct event won't fire.
To be honest i don't think it's worth to handle it, but at least that should be mentionned.
You should also mention that you can't use these functions on the unit index event.

Btw, StructureStatus doesn't fit with the purpose of the library, as you also care about training units (i don't see why, but maybe i miss something).
Maybe just use the same name : ConstructionStatus (or a better one if you find it)
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
I remember why i didn't used the cancel construct event.

1) It fires only when the unit which was being built is canceled by the cancel button or by the escape keyboard key (which is basically the same).
It doesn't fire when the unit die before the end of the construction, and probably also not when it's removed by RemoveUnit.
The fact that I did not added that event doesn't mean that I haven't been testing all the events :p
I was testing if something glitchy is also hidden with TRAIN_CANCEL, but had found nothing.

2) It never fires when the unit which is being built is not a structure, such as a footman.

3 ) A canceled structure == a removed unit without a corpse

4) The death event fires before the cancel one.

So for all these reasons you should use the deindex event, in other words when an unit is being removed.
Maybe you could keep the death event for completness reason.
As i suppose it fires before the deindex event. (even if on a such event it's obvious that the unit is not being built anymore ...)
I dont get the second statement to be honest.
A canceled structure == unit which plays 'death' animation (without decay one).

Whenever player cancels the structure, he kills it actually, so yeah cancel order is fired right after that. I'll think about deindex event. I was doing it right after you told me that for the first time.

Using an unit indexer instead of GroupUtils is an improvement, even if speed doesn't really matter here, but the deindex event is needed.
Also, i don't really like the code split, but i don't hope you will change your mind.
Every opinion is important for me, especialy those which are valueable, like yours, Troll-Brain. Feel free to show me how you would like code to be split, although about RegisterPlayerUnitEvent - I've decided that making it optional doesn't feel right for me.

Oh, and also as stated in the thread you have linked :
If a structure which is being built die with a passive reincarnation ability, when the structure will be revived it will be finished, but the finish construct event won't fire.
To be honest i don't think it's worth to handle it, but at least that should be mentionned.
You should also mention that you can't use these functions on the unit index event.
I've been reading that part at wc3c.net. I'm trying to find a way to solve that issue, but till now, I failed. I'll mention that as soon as I abbadon the 'fix' thing.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I dont get the second statement to be honest.
A canceled structure == unit which plays 'death' animation (without decay one).

When the cancel event fire the unit will be removed without leaving a corpse (even if the unit was supposed to die leaving a corpse), you can't ressurect it in any way when this even fire.
So basically cancel event = remove event (deindex).
Remember that you can build not-structure-units such as footman, even if it's unusual.
All you have to do is include the footman in the build list (note that for humans and elves workers and maybe also neutral ones : you will also have to edit the repair ability)


Every opinion is important for me, especialy those which are valueable, like yours, Troll-Brain. Feel free to show me how you would like code to be split, although about RegisterPlayerUnitEvent - I've decided that making it optional doesn't feel right for me.

The previous way was fine for me, as there is not a speed issue here, i mean one function with all events, but it's not that important.
All these functions for a such simple thing just hurts my eyes.

I've been reading that part at wc3c.net. I'm trying to find a way to solve that issue, but till now, I failed. I'll mention that as soon as I abbadon the 'fix' thing.

I think we have these custom events somewhere here ("death" event with a passive ressurect ability, and the "revive" event), so that would be easy with ... moar requirements :p
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Now I understood! I've forgotten that for example in TDs units are buildings (towers) and you say that non structure cunstrcutions may not be detected? I shall fix that as soon as possible.
Btw. what do you mean: 'include footman in the build list'? Meaby just use dummy locust unit with removed 'Amov' for player(15) with repair ability.
The previous way was fine for me, as there is not a speed issue here, i mean one function with all events, but it's not that important.
All these functions for a such simple thing just hurts my eyes.
Look what I've written at 2rd post:
Spinnaker said:
I was thinking about cutting those comparisong to functions already but I thought that small, multiple functions will be eventually too much just for that :p
I won't add that untill more ppl agree that it would be nice to do so. Personaly: I share the one function idea.
I think we have these custom events somewhere here ("death" event with a passive ressurect ability, and the "revive" event), so that would be easy with ... moar requirements :p
After reading that you don't like 'more' requrements so much I tried non requirement way..
I know what with Unit Event it would be easy >.<
Meaby make that optional? I think it'd be fair.

@Nes Done. Btw, I was more eager to hear from you, what's your opinion about splitting that one function to many or your voice about other issues rather than url advice D;
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
Split up into different functions. Putting it all into one function is an eyesore.
JASS:
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_START, function onEvent)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function onEvent)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_START, function onEvent)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_FINISH, function onEvent)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_CANCEL, function onEvent)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_START, function onEvent)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_FINISH, function onEvent)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_CANCEL, function onEvent)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function onDeath)

These should all have ById equivalents. In the API, just put them together in pairs of 2.
JASS:
    function IsStructureFree takes unit u returns boolean
        return isFree(GetUnitUserData(u))
    endfunction
    function IsStructureFinished takes unit u returns boolean
        return isFinished(GetUnitUserData(u))
    endfunction
    function IsStructureBeingBuilt takes unit u returns boolean
        return cU[GetUnitUserData(u)]
    endfunction
    function IsStructureUpgrading takes unit u returns boolean
        return uU[GetUnitUserData(u)]
    endfunction
    function IsStructureTraining takes unit u returns boolean
        return tU[GetUnitUserData(u)]
    endfunction
    function GetBuilder takes unit u returns unit
         return b[GetUnitUserData(u)]
    endfunction

Structures may be built by multiple units. Furthermore, this is misleading as the builder may have stopped constructing the structure.

Make it more accurate and try to get all units working on the structure.
JASS:
    function GetBuilder takes unit u returns unit
         return b[GetUnitUserData(u)]
    endfunction

This can be simplified
return not cU[i] and not uU[i] and not tU[i]

to

not (cU[i] or uU[i] or tU[i])

Same goes for this
not cU[i] and not uU[i]

to

not (cU[i] or uU[i])


This is a very poor way to do this
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function onDeath)

What if the unit is removed?



Also, I normally don't comment on very simple libs like this one ; )
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Now I understood! I've forgotten that for example in TDs units are buildings (towers) and you say that non structure cunstrcutions may not be detected? I shall fix that as soon as possible.

No, i'm simply saying that non structure units never fire the CANCEL construct event.
But as previously said this event is pointless anyway, because not enough by itself.

Btw. what do you mean: 'include footman in the build list'? Meaby just use dummy locust unit with removed 'Amov' for player(15) with repair ability.

I just said that you can build not structures units, if you add this unit in the build list of the worker.
As it seems you didn't get that we can build non structure units.

Look what I've written at 2rd post:I won't add that untill more ppl agree that it would be nice to do so. Personaly: I share the one function idea.

You should split in several functions instead of a big one however.
One function for construct events and one for upgrade ones.
This way you keep the code clear and handles less.

After reading that you don't like 'more' requrements so much I tried non requirement way..
I know what with Unit Event it would be easy >.<
Meaby make that optional? I think it'd be fair.

Well, i was talking about RegisterPlayerUnitEvent, as it can be easily inlined.
But it's also fine to make it as a requirement, as it is also supposed to improve the code performance.
And with Unit Event that's really different, you can't seriously inline it ...
But since it's a really specific thing to handle, optional is fine.
But it must be mentionned in the documentation that it will bug if you don't have it in the described case above.

I still don't get why you are handling trained units, as far i know a trained unit is created only on TRAIN finish event.
Plus, i'm pretty sure that you can't detect all canceled training unit (when you click on the unit icon which is being trained for example)

Oh and also really forgot about GetBuilder, it's really trickier than that.
Elves', neutrals', Orcs' workers are "easy" to handle, but that's clearly not the case with human (power building) and undead (no way to know which one was the builder, even with orders checking)
 
Level 17
Joined
Apr 27, 2008
Messages
2,455

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Omg, Troll-Brain, don't repeat yourself since no update came up. I know what issues are left here. I have rewritten whole system, but I was trying to find save method for detecting all the workers for last few days. I will upload the newest version today, without the "GetAllWorkers" or something, but I will leave function for getting the unit which started the construction.

@Bribe - new version has highly improved description.

Sorry, here in Poland there are somewhat christmas, aka "Day of the Dead" (I'm not sure how it's called in English), so I'm visiting graveyards day by day now -.- Plus I still have three project lefts for my studies.
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
I simply thought that you had miss what i've said, because you didn't anwser me, but just to the very next comment.
God is for nothing here.
But if you take suggestions or critics like that, i will simply leave at it is, next time.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Troll-Brain, you are one of people on Hive I respect the most, and holy shit because of you, I know that I have to update BOTH (yeah, I haven't forgotten about GCW) of my libraries. There are just ton of things going on in my RL and I can't take Hive over that. I hope you understand it.

If that sentence was offense, I'm sorry. I've said that only because I couldn't understand why you're repeating yourself while there was no update. lol.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Double post, how tragic! (Bribe: it's just to "bump" thread because of an update).

~Version 2.0.0.0 uploaded:
Renamed: to BuildTools (Bribe pls change the Title if possible).
System has been rewritten. After hours (actually days) I haven't found save method to get the buildies for human race, thus I decided not to upload anything related to such subject yet.

GetBuildier/GetBuildierById is here only to retrieve the unit who STARTED the construction of given structure.

@Troll-Brain I couldn't understand the "why you handle trained units" statement, since those functions only check if BUILDING is currently performing TRAIN action - and thats all.

Feel free to lay down your criticism.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Humans are not the worst problem, the worst is with undead since there is no way to get the worker.
Ofc you can do approximations like checking the unit which is near when the build appear, but it's such innacurate.

In fact if you want a perfect GetWorker (which is working as intented...) you will have to trigger all constructions (or use build abilities).

About the trained unit, i think you've missed the part that in some cases when you remove an unit from the training process, the event don't fire. (or any order, or something).

A player has 2 ways for removing a training unit :
- cancel it (button or escape key)
- click on the unit.

One of these don't fire any order event.
But it has to be tested again, since it's old.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Ofc you can do approximations like checking the unit which is near when the build appear, but it's such innacurate.
Yeah, distance depends on building's size. From 'Farm' worker is about 120 units away, but from 'TownHall' it's more than 280 >.<
About the trained unit, i think you've missed the part that in some cases when you remove an unit from the training process, the event don't fire. (or any order, or something).
I'll surely test it out (but tomorrow ;3), although I haven't met any problems at all. Meaby my tests were inaccurate. And it's not TRAINED unit Troll-Brain!!!

It's all about detecting if build currently produces unit or not - and thats it. Use "Training" or something since I lost previously about 2 hours to get what you mean by "Trained" <3

Thank you for responces, Troll-Brain, you're realy helpful person out here.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
As I have said, today I again tested IsUnitTraining(+ById) feature.
Troll-Brain said:
A player has 2 ways for removing a training unit :
- cancel it (button or escape key)
- click on the unit.
I have found that system works perfectly, no matter which event occured. However, I would be grateful if someone can prove this too (so it's not just me). Thank you for your time.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
There is no safe way to get the builder for human and especially undead workers.
I know i repeat myself, but GetBuilder and all similar functions should just be removed.

Nothing forbid to make a special library for this feature, i wish good luck, but i don't bet that much on it, i've already tried myself.
You can do something, but not enough accurate (at least for me).
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Well if you check the description he said "the unit which started construction". Not necessarily the one who is currently building it.


But even that can't be accurate for human and undead, believe me, or try it yourself.

Well, for human you could check about the order repair, but that will fire after the construct event.
It won't work if the human worker can't repair the structure (not in repair targets) but i suppose we can ignore it.
(Yes for example an human worker can place an elf structure, but won't start the construction if you don't allow the ancient target or whatever in the repair ability)
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
It's safe, but it is providing just the "yes/no" functionality for structure status i.e if it's training something, whether it is upgrading etc.

It's very simple one, as you can see. However, it is no longer supported by my ConstructEvent (new "BuildEvent") - the "GetBuilder/Id" stuff has been moved there as it fits the other lib better than this one.
I'll try to upload new version within few days to provide additional functionality which I have been working on lately.

Just for you, I've updated this lib to be functional without any errors related to non existant "BuildEvent" and properly list optional and required libraries. See the first post.
Again, this is just temporal solution.
 
Last edited:
Top