• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • Vote for the theme of Hive's HD Modeling Contest #7! Click here to vote! - Please only vote if you plan on participating❗️

Fluke Bug?

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
I experienced a bug while testing my map, but every other "copy" of my system was working and it is designed in such a way that either "all" or "none" will work.

I haven't been able to recreate this bug and I can see no reason for its existence what could've caused such a thing?

Should I just carry on and pretend it never happened or how should I solve something I can't recreate nor logically understand.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,266
Random stuff happens from time to time. I have even seen WC3 twice suffer a trigger timing fail (all timing completely broken, as if everything expired 100 times faster).

As such I would make a record of the bug occurrence but ignore it. If it occurs again or is reported as having occurred then it is worth investigating. The record can help find its occurrence as it allows you to try and understand the sequence of events needed for the bug.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
Okey, thanks for your advice. It is as you say, it feels too random to be something in the script. Guess time will tell how random it truly was.

Maybe i should write some debug triggers to be able to investigate the variables if it happens again.

Speaking of which, can I use textmacro to write debug functions that i can disable enable?
 
Last edited:
Level 15
Joined
Nov 30, 2007
Messages
1,202
I have an idea what could actually cause it, when a building is ordered to build someplace a dummy acolyte is instantly moved and ordered to build there. Which builder started the construction is retracted through selection events.

However, sometimes this might be delayed a microsecond or something and thus causing it not to be registered properly.

The solution would be to detect the triggering acolyte of a construction being built instead, but as far as I know, no such thing is possible. Perhaps by getting the closest acolyte though...

how to pass this filter into the function GetClosestUnit?

JASS:
private function filter takes nothing returns boolean
        return GetUnitTypeId(GetFilterUnit()) == CITY_BUILDER
    endfunction
    
    private function OnConstructionStart takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local unit builder 
        local integer pid = GetPlayerId(GetOwningPlayer(u))
        local integer b = BT.getBuildingIndexByUnit(u)
        local integer i = curSelection[pid]
        set owningCity[GetUnitUserData(u)] = i
        call city[i].addBuildingCountWip(b, 1)
        call city[i].addBuildingCountTot(b, 1)
        call GroupAddUnit(beingBuilt, u)
        call GroupAddUnit(city[i].g, u)
        call building[b].refresh(curSelection[pid])
        
        set builder = GetClosestUnit(GetUnitX(u), GetUnitY(u), 600, null) // How to pass the above filter here?
        call KillUnit(builder)
    
        set u = null
        return false 
    endfunction

JASS:
private function Enum takes nothing returns nothing
        local unit u = GetEnumUnit()
        local real dx = GetUnitX(u) - centerX 
        local real dy = GetUnitY(u) - centerY
        local real d = (dx*dx + dy*dy) / 10000.
        if d < currentDistance then
            set currentDistance = d
            set pickedUnit = u
        endif
        set u = null
    endfunction
    
    function GetClosestUnit takes real x, real y, real radius, boolexpr filter returns unit 
        local group g = CreateGroup()
        set pickedUnit = null
        set centerX = x
        set centerY = y
        set currentDistance = radius + 1000
        call GroupEnumUnitsInRange(g, x, y, radius, filter)
        call ForGroup(g, function Enum)
        call DestroyGroup(g)
        set g = null
        return pickedUnit
    endfunction
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,266
Selection events are subject to synchronization latency. Hence should not be used in such a case.

In your case you need to detect the "building unit" in the event. This is very difficult and never exact. The only way I found to get semi-reliable results was to record the actual build order target location, type and ordering unit. When a unit begins construction you then match up its metrics to ones expected by orders until you find a match (same type, at same location with ordered unit nearby). The system I made that did this years ago was completely accurate under normal use case unless people specifically tried to break it (order same building at same location from two different units nearly equally far apart) in which case it might credit the wrong builder as starting to build the unit.

Do note that the built unit might be at a slightly different location from the order target location. With grid buildings (normal buildings) this is due to floating point error resulting in slightly different numbers. With non-grid buildings (eg building a unit) this is due to some form of forced alignment. The solution is to add a sub-grid tolerance which convers both problems while still allowing it to be used to match reliably.

I just wish I got around to finishing that builder hero now...
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
I think geting the closest unit of type builder is the best and simplest solution in my case as it will be right ontop of the building and after it has summoned the building it will be killed.

Only issue is that I don't know how to use boolexpr...

I want to pass this into the function GetClosestUnit( ... ) to substitute filter in this call: GroupEnumUnitsInRange(g, x, y, radius, filter)

JASS:
private function filter takes nothing returns boolean
        return GetUnitTypeId(GetFilterUnit()) == CITY_BUILDER
    endfunction

SOLVED:
JASS:
set builder = GetClosestUnit(GetUnitX(u), GetUnitY(u), 600, Condition(function filter))
 
Last edited:
Status
Not open for further replies.
Top