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

War 1 Road System, Help

Status
Not open for further replies.
I am creating a War 1 custom map, more information and images you can find in the link at my signature. Now, I have a problem- I don't know how I can recreate that kind of a road system from Warcraft 1.

I already have created a building road with no-collision and pathing of "Circle of Power", the main building will be able to build the road at the targeted location.
 
Buildings can only be built near a road, a road also has to be build near an existing road.

Road = Building.
Pretty much exactly what was in Warcraft 1, in my map I have already created the road building in object editor and it can be built atm by a peasant or a peon. Without road nearby, you can't build buildings (barracks, farms).

gfs_29845_2_1.jpg
 
Would this idea fit your needs?

You create one global region "road region"(jass), and each time when you create a road, you create a new rect. (size of one piece of road)
You add the newly created rect to your region.
When you build a new building/road, you make some checks to ensure that there exists a point in range of targeted point that is contained by your region "road region".

Edit: If there is a possibility to destroy roads, you can link the road-rects with the road-unit, and also remove it, if needed.
 
Would this idea fit your needs?

You create one global region "road region"(jass), and each time when you create a road, you create a new rect. (size of one piece of road)
You add the newly created rect to your region.
When you build a new building/road, you make some checks to ensure that there exists a point in range of targeted point that is contained by your region "road region".

Edit: If there is a possibility to destroy roads, you can link the road-rects with the road-unit, and also remove it, if needed.

Yeah, pretty much thats it. Though I am terrible at JASS. It seems you know how to do it, can I ask you to create these triggers? I would credit you. :)
 
I really don't know now, if it works or not. But you can test it, and we'll see later. ^^

Code:
JASS:
scope RoadSystem
    
    globals
    
        private constant integer ROAD_ID = 'xxxx'   // <- Rawcode of road.
        
        private region RoadRegion = CreateRegion()
        
        private constant integer ORDER_STOP = 851972
        
        private constant real OFFSET = 128.
        private constant real OFFSET_HALF = OFFSET/2
    endglobals
    
    private module init
        private static method onInit takes nothing returns nothing
            call Road.create('xxxx')  // <- Rawcode of building, that requires road in range.
        endmethod
    endmodule
    
    struct Road
    
        private static key k
        private static Table table = k
        readonly integer orderId
        
        static method create takes integer order returns thistype
            local thistype this = allocate()
            set table[order] = this
            set this.orderId = order
            return this
        endmethod
        
        static method operator [] takes integer i returns thistype
            return table[i]
        endmethod
        
        private static method RoadInRange takes real x, real y, real offset returns boolean
            local real angle = 0
            local real change = bj_PI/4
            loop
                if IsPointInRegion(RoadRegion, x + OFFSET * Cos(angle), y + OFFSET * Sin(angle)) then
                    return true
                endif
                set angle = angle + change
                exitwhen angle > (2*bj_PI)
            endloop
            return false
        endmethod
        
        private static method onOrder takes nothing returns boolean
            local integer orderId = GetIssuedOrderId()
            
            if (orderId != ROAD_ID) and (thistype[orderId] != 0) and not(RoadInRange(GetOrderPointX(), GetOrderPointY(), OFFSET)) then
                call IssueImmediateOrderById(GetTriggerUnit(), ORDER_STOP)
            endif
            
            return false
        endmethod
        
        private static method roadBuilded takes nothing returns boolean
            local unit u = GetTriggerUnit()
            local real x
            local real y
            
            if (GetUnitTypeId(u) == ROAD_ID) then
                set x = GetUnitX(u)
                set y = GetUnitY(u)
                call RegionAddRect(RoadRegion, Rect(x - OFFSET_HALF, y - OFFSET_HALF, x + OFFSET_HALF, y + OFFSET_HALF))
            endif
            
            set u = null
            return false
        endmethod
        
        private static method gameStart takes nothing returns nothing
            local group g = CreateGroup()
            local unit u
            local real x
            local real y
            
            call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, null)
            loop
                set u = FirstOfGroup(g)
                call GroupRemoveUnit(g, u)
                exitwhen u == null
                if GetUnitTypeId(u) == ROAD_ID then
                    set x = GetUnitX(u)
                    set y = GetUnitY(u)
                    call RegionAddRect(RoadRegion, Rect(x - OFFSET_HALF, y - OFFSET_HALF, x + OFFSET_HALF, y + OFFSET_HALF))
                endif
            endloop
            call DestroyTimer(GetExpiredTimer())
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
            call TriggerAddCondition(t, Filter(function thistype.onOrder))
            
            set t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH )
            call TriggerAddCondition(t, Filter(function thistype.roadBuilded))
            
            call TimerStart(CreateTimer(),0.0,false,function thistype.gameStart)
        endmethod
    
        implement init
    endstruct
    
endscope
In line: private constant integer ROAD_ID = 'xxxx' you have to modify the "xxxx" to your rawcode of road.

call Road.create('xxxx') <- Like this you have to add all buildings that need a road in range. Do so, where my example is.

I might have forgotten something, ... as I said that I can't test it atm.

To get this code to work, you have to import a library into your map. Just create a new trigger and copy&paste following code into it: (you don't have to touch it)

JASS:
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.0.1
    
    One map, one hashtable. Welcome to NewTable 3.1
    
    This library was originally called NewTable so it didn't conflict with
    the API of Table by Vexorian. However, the damage is done and it's too
    late to change the library name now. To help with damage control, I
    have provided an extension library called TableBC, which bridges all
    the functionality of Vexorian's Table except for 2-D string arrays &
    the ".flush(integer)" method. I use ".flush()" to flush a child hash-
    table, because I wanted the API in NewTable to reflect the API of real
    hashtables (I thought this would be more intuitive).
    
    API
    
    ------------
    struct Table
    | static method create takes nothing returns Table
    |     create a new Table
    |    
    | method destroy takes nothing returns nothing
    |     destroy it
    |    
    | method flush takes nothing returns nothing
    |     flush all stored values inside of it
    |    
    | method remove takes integer key returns nothing
    |     remove the value at index "key"
    |    
    | method operator []= takes integer key, $TYPE$ value returns nothing
    |     assign "value" to index "key"
    |    
    | method operator [] takes integer key returns $TYPE$
    |     load the value at index "key"
    |    
    | method has takes integer key returns boolean
    |     whether or not the key was assigned
    |
    ----------------
    struct TableArray
    | static method operator [] takes integer array_size returns TableArray
    |     create a new array of Tables of size "array_size"
    |
    | method destroy takes nothing returns nothing
    |     destroy it
    |
    | method flush takes nothing returns nothing
    |     flush and destroy it
    |
    | method operator size takes nothing returns integer
    |     returns the size of the TableArray
    |
    | method operator [] takes integer key returns Table
    |     returns a Table accessible exclusively to index "key"
*/
    
globals
    private integer less = 0    //Index generation for TableArrays (below 0).
    private integer more = 8190 //Index generation for Tables.
    //Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
    
    private hashtable ht = InitHashtable()
    private key sizeK
    private key listK
endglobals
    
private struct dex extends array
    static method operator size takes nothing returns Table
        return sizeK
    endmethod
    static method operator list takes nothing returns Table
        return listK
    endmethod
endstruct
    
private struct handles extends array
    method has takes integer key returns boolean
        return HaveSavedHandle(ht, this, key)
    endmethod
    method remove takes integer key returns nothing
        call RemoveSavedHandle(ht, this, key)
    endmethod
endstruct
    
private struct agents extends array
    method operator []= takes integer key, agent value returns nothing
        call SaveAgentHandle(ht, this, key, value)
    endmethod
endstruct
    
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
    method operator [] takes integer key returns $TYPE$
        return Load$FUNC$(ht, this, key)
    endmethod
    method operator []= takes integer key, $TYPE$ value returns nothing
        call Save$FUNC$(ht, this, key, value)
    endmethod
    method has takes integer key returns boolean
        return HaveSaved$SUPER$(ht, this, key)
    endmethod
    method remove takes integer key returns nothing
        call RemoveSaved$SUPER$(ht, this, key)
    endmethod
endstruct
private module $TYPE$m
    method operator $TYPE$ takes nothing returns $TYPE$s
        return this
    endmethod
endmodule
//! endtextmacro
    
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
    method operator [] takes integer key returns $TYPE$
        return Load$FUNC$Handle(ht, this, key)
    endmethod
    method operator []= takes integer key, $TYPE$ value returns nothing
        call Save$FUNC$Handle(ht, this, key, value)
    endmethod
endstruct
private module $TYPE$m
    method operator $TYPE$ takes nothing returns $TYPE$s
        return this
    endmethod
endmodule
//! endtextmacro
    
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
    
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
    
struct Table extends array
    
    // Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
    implement realm
    implement booleanm
    implement stringm
    implement playerm
    implement widgetm
    implement destructablem
    implement itemm
    implement unitm
    implement abilitym
    implement timerm
    implement triggerm
    implement triggerconditionm
    implement triggeractionm
    implement eventm
    implement forcem
    implement groupm
    implement locationm
    implement rectm
    implement boolexprm
    implement soundm
    implement effectm
    implement unitpoolm
    implement itempoolm
    implement questm
    implement questitemm
    implement defeatconditionm
    implement timerdialogm
    implement leaderboardm
    implement multiboardm
    implement multiboarditemm
    implement trackablem
    implement dialogm
    implement buttonm
    implement texttagm
    implement lightningm
    implement imagem
    implement ubersplatm
    implement regionm
    implement fogstatem
    implement fogmodifierm
    implement hashtablem
    
    method operator handle takes nothing returns handles
        return this
    endmethod
    
    method operator agent takes nothing returns agents
        return this
    endmethod
    
    //set this = tb[GetSpellAbilityId()]
    method operator [] takes integer key returns Table
        return LoadInteger(ht, this, key)
    endmethod
    
    //set tb[389034] = 8192
    method operator []= takes integer key, Table tb returns nothing
        call SaveInteger(ht, this, key, tb)
    endmethod
    
    //set b = tb.has(2493223)
    method has takes integer key returns boolean
        return HaveSavedInteger(ht, this, key)
    endmethod
    
    //call tb.remove(294080)
    method remove takes integer key returns nothing
        call RemoveSavedInteger(ht, this, key)
    endmethod
    
    //Remove all data from a Table instance
    method flush takes nothing returns nothing
        call FlushChildHashtable(ht, this)
    endmethod
    
    //local Table tb = Table.create()
    static method create takes nothing returns Table
        local Table this = dex.list[0]
        
        if this == 0 then
            set this = more + 1
            set more = this
        else
            set dex.list[0] = dex.list[this]
            call dex.list.remove(this) //Clear hashed memory
        endif
        
        debug set dex.list[this] = -1
        return this
    endmethod
    
    // Removes all data from a Table instance and recycles its index.
    //
    //     call tb.destroy()
    //
    method destroy takes nothing returns nothing
        debug if dex.list[this] != -1 then
            debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
            debug return
        debug endif
        
        call this.flush()
        
        set dex.list[this] = dex.list[0]
        set dex.list[0] = this
    endmethod
    
    //! runtextmacro optional TABLE_BC_METHODS()
endstruct
    
//! runtextmacro optional TABLE_BC_STRUCTS()
    
struct TableArray extends array
    
    //Returns a new TableArray to do your bidding. Simply use:
    //
    //    local TableArray ta = TableArray[array_size]
    //
    static method operator [] takes integer array_size returns TableArray
        local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
        local TableArray this = tb[0]         //The last-destroyed TableArray that had this array size
        
        debug if array_size <= 0 then
            debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
            debug return 0
        debug endif
        
        if this == 0 then
            set this = less - array_size
            set less = this
        else
            set tb[0] = tb[this]  //Set the last destroyed to the last-last destroyed
            call tb.remove(this)  //Clear hashed memory
        endif
        
        set dex.size[this] = array_size //This remembers the array size
        return this
    endmethod
    
    //Returns the size of the TableArray
    method operator size takes nothing returns integer
        return dex.size[this]
    endmethod
    
    //This magic method enables two-dimensional[array][syntax] for Tables,
    //similar to the two-dimensional utility provided by hashtables them-
    //selves.
    //
    //ta[integer a].unit[integer b] = unit u
    //ta[integer a][integer c] = integer d
    //
    //Inline-friendly when not running in debug mode
    //
    method operator [] takes integer key returns Table
        static if DEBUG_MODE then
            local integer i = this.size
            if i == 0 then
                call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
                return 0
            elseif key < 0 or key >= i then
                call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
                return 0
            endif
        endif
        return this + key
    endmethod
    
    //Destroys a TableArray without flushing it; I assume you call .flush()
    //if you want it flushed too. This is a public method so that you don't
    //have to loop through all TableArray indices to flush them if you don't
    //need to (ie. if you were flushing all child-keys as you used them).
    //
    method destroy takes nothing returns nothing
        local Table tb = dex.size[this.size]
        
        debug if this.size == 0 then
            debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
            debug return
        debug endif
        
        if tb == 0 then
            //Create a Table to index recycled instances with their array size
            set tb = Table.create()
            set dex.size[this.size] = tb
        endif
        
        call dex.size.remove(this) //Clear the array size from hash memory
        
        set tb[this] = tb[0]
        set tb[0] = this
    endmethod
    
    private static Table tempTable
    private static integer tempEnd
    
    //Avoids hitting the op limit
    private static method clean takes nothing returns nothing
        local Table tb = .tempTable
        local integer end = tb + 0x1000
        if end < .tempEnd then
            set .tempTable = end
            call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
        else
            set end = .tempEnd
        endif
        loop
            call tb.flush()
            set tb = tb + 1
            exitwhen tb == end
        endloop
    endmethod
    
    //Flushes the TableArray and also destroys it. Doesn't get any more
    //similar to the FlushParentHashtable native than this.
    //
    method flush takes nothing returns nothing
        debug if this.size == 0 then
            debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
            debug return
        debug endif
        set .tempTable = this
        set .tempEnd = this + this.size
        call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
        call this.destroy()
    endmethod
    
endstruct
    
endlibrary
 
Hehe, my idea was a bit fail anyway. Try this one: (still Table library needed)

Code:
JASS:
scope RoadSystem initializer Init
    
    globals
    
        private constant integer ROAD_ID = 'xxxx'   // <- Rawcode of road.
        
        private constant real    OFFSET  = 128.
        
        private group g = CreateGroup()  
        
        private constant integer ORDER_STOP = 851972
    endglobals
    
    private module init
        private static method onInit takes nothing returns nothing
            call Road.create('xxyy')  // <- Rawcode of building, that requires road in range.
            call Road.create('yyxx')
        endmethod
    endmodule
    
    struct Road
   
        private static key k
        private static Table table = k
        readonly integer orderId
       
        static method create takes integer order returns thistype
            local thistype this = allocate()
            set table[order] = this
            set this.orderId = order
            return this
        endmethod
       
        static method operator [] takes integer i returns thistype
            return table[i]
        endmethod
        
        implement init
    endstruct
        
    private function Order takes nothing returns boolean
        local unit u
        local unit iterator
        local boolean b = false
        
        if (Road[GetIssuedOrderId()] != 0) then
        
            set u = GetTriggerUnit()
            call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), OFFSET, null)
            
            loop
                set iterator = FirstOfGroup(g)
                call GroupRemoveUnit(g, iterator)
                exitwhen iterator == null
                if (GetUnitTypeId(iterator) == ROAD_ID) then
                       set b = false
                endif
            endloop
                
            if (b) then
                call IssueImmediateOrderById(u, ORDER_STOP)
            endif
        endif
        return false
    endfunction
        
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
        call TriggerAddCondition(t, Filter(function Order))
    endfunction    
endscope
Note, that you can not register all buildings in 1 one line, how you did. You need 1 line for each new rawcode.
 
Hehe, my idea was a bit fail anyway. Try this one: (still Table library needed)

Code:
JASS:
scope RoadSystem initializer Init
    
    globals
    
        private constant integer ROAD_ID = 'xxxx'   // <- Rawcode of road.
        
        private constant real    OFFSET  = 128.
        
        private group g = CreateGroup()  
        
        private constant integer ORDER_STOP = 851972
    endglobals
    
    private module init
        private static method onInit takes nothing returns nothing
            call Road.create('xxyy')  // <- Rawcode of building, that requires road in range.
            call Road.create('yyxx')
        endmethod
    endmodule
    
    struct Road
   
        private static key k
        private static Table table = k
        readonly integer orderId
       
        static method create takes integer order returns thistype
            local thistype this = allocate()
            set table[order] = this
            set this.orderId = order
            return this
        endmethod
       
        static method operator [] takes integer i returns thistype
            return table[i]
        endmethod
        
        implement init
    endstruct
        
    private function Order takes nothing returns boolean
        local unit u
        local unit iterator
        local boolean b = false
        
        if (Road[GetIssuedOrderId()] != 0) then
        
            set u = GetTriggerUnit()
            call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), OFFSET, null)
            
            loop
                set iterator = FirstOfGroup(g)
                call GroupRemoveUnit(g, iterator)
                exitwhen iterator == null
                if (GetUnitTypeId(iterator) == ROAD_ID) then
                       set b = false
                endif
            endloop
                
            if (b) then
                call IssueImmediateOrderById(u, ORDER_STOP)
            endif
        endif
        return false
    endfunction
        
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
        call TriggerAddCondition(t, Filter(function Order))
    endfunction    
endscope
Note, that you can not register all buildings in 1 one line, how you did. You need 1 line for each new rawcode.

I still get the same error about "endmethod" or something. See the image attachment. :/
 
I had some mistakes, but it compiled for me. And it works for me. Ensure you have JassHelper enabled, by Vexorian or Cohader.

Now, you also have to set the range, which is needed to road. See in example. I did this, because some buildings need more place than others... so they also need a different range. (see your examples)

JASS:
scope RoadSystem initializer Init
    
    globals
    
        private constant integer ROAD_ID    = 'h000'   // <- Rawcode of road.
        private constant string  CANT_BUILD = "No road in range."   // <- Displays if no road is in range
        
        private group g = CreateGroup()  
        private constant integer ORDER_STOP = 851972
    endglobals
    
    private module init
        private static method onInit takes nothing returns nothing
            call Road.create('hhou', 140)  // Rawcode of building / Range needed to road
            call Road.create('hbar', 300)
        endmethod
    endmodule
    
    struct Road
   
        private static key k
        private static Table table = k
        readonly integer orderId
        readonly real offset
       
        static method create takes integer order, real offSet returns thistype
            local thistype this = allocate()
            set table[order] = this
            set this.orderId = order
            set this.offset = offSet
            return this
        endmethod
       
        static method operator [] takes integer i returns thistype
            return table[i]
        endmethod
        
        implement init
    endstruct
        
    private function Order takes nothing returns boolean
        local unit u
        local unit builder
        local boolean b = true
        
        if (Road[GetIssuedOrderId()] != 0) then
            call GroupEnumUnitsInRange(g, GetOrderPointX(), GetOrderPointY(), Road[GetIssuedOrderId()].offset, null)
            
            loop
                set u = FirstOfGroup(g)
                call GroupRemoveUnit(g, u)
                exitwhen u == null
                if (GetUnitTypeId(u) == ROAD_ID) then
                       set b = false
                endif
            endloop
                
            if (b) then
                set builder = GetTriggerUnit()
                call PauseUnit(builder, true)
                call IssueImmediateOrderById(builder, ORDER_STOP)
                call PauseUnit(builder, false)
                call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 7, CANT_BUILD)
            endif
        endif
        return false
    endfunction
        
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
        call TriggerAddCondition(t, Filter(function Order))
    endfunction    
endscope
 

Attachments

  • TestRoad.w3x
    42.8 KB · Views: 62
I had some mistakes, but it compiled for me. And it works for me. Ensure you have JassHelper enabled, by Vexorian or Cohader.

Now, you also have to set the range, which is needed to road. See in example. I did this, because some buildings need more place than others... so they also need a different range. (see your examples)

JASS:
scope RoadSystem initializer Init
    
    globals
    
        private constant integer ROAD_ID    = 'h000'   // <- Rawcode of road.
        private constant string  CANT_BUILD = "No road in range."   // <- Displays if no road is in range
        
        private group g = CreateGroup()  
        private constant integer ORDER_STOP = 851972
    endglobals
    
    private module init
        private static method onInit takes nothing returns nothing
            call Road.create('hhou', 140)  // Rawcode of building / Range needed to road
            call Road.create('hbar', 300)
        endmethod
    endmodule
    
    struct Road
   
        private static key k
        private static Table table = k
        readonly integer orderId
        readonly real offset
       
        static method create takes integer order, real offSet returns thistype
            local thistype this = allocate()
            set table[order] = this
            set this.orderId = order
            set this.offset = offSet
            return this
        endmethod
       
        static method operator [] takes integer i returns thistype
            return table[i]
        endmethod
        
        implement init
    endstruct
        
    private function Order takes nothing returns boolean
        local unit u
        local unit builder
        local boolean b = true
        
        if (Road[GetIssuedOrderId()] != 0) then
            call GroupEnumUnitsInRange(g, GetOrderPointX(), GetOrderPointY(), Road[GetIssuedOrderId()].offset, null)
            
            loop
                set u = FirstOfGroup(g)
                call GroupRemoveUnit(g, u)
                exitwhen u == null
                if (GetUnitTypeId(u) == ROAD_ID) then
                       set b = false
                endif
            endloop
                
            if (b) then
                set builder = GetTriggerUnit()
                call PauseUnit(builder, true)
                call IssueImmediateOrderById(builder, ORDER_STOP)
                call PauseUnit(builder, false)
                call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 7, CANT_BUILD)
            endif
        endif
        return false
    endfunction
        
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
        call TriggerAddCondition(t, Filter(function Order))
    endfunction    
endscope

I can't save the map. I have JassHelper enabled, it still shows the error with "endmethod".
 

Attachments

  • dd.png
    dd.png
    102.8 KB · Views: 83
I use JNGP. (but still 1.5e) And for me it looks like this..

Ok, I am gonna reinstall my JNGP, btw how can I make it to play Error sound when the player builds too far from the road? :)

Edit : It works now, but I need it to play a sound (error), when the player builds too far. Also how can you see what building needs what kind of range?
 
Last edited:
For sound: Go in sound editor, and mark error sound as used. Then add one line in this block:
JASS:
if (b) then
    set builder = GetTriggerUnit()
    call PauseUnit(builder, true)
    call IssueImmediateOrderById(builder, ORDER_STOP)
    call PauseUnit(builder, false)
    call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 7, CANT_BUILD)
    call StartSound(gg_snd_Error)    //<- NEW
endif
^Watch the last operation, it's new.
Also how can you see what building needs what kind of range?
I don't know. I just tested it.
 
For sound: Go in sound editor, and mark error sound as used. Then add one line in this block:
JASS:
if (b) then
    set builder = GetTriggerUnit()
    call PauseUnit(builder, true)
    call IssueImmediateOrderById(builder, ORDER_STOP)
    call PauseUnit(builder, false)
    call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 7, CANT_BUILD)
    call StartSound(gg_snd_Error)    //<- NEW
endif
^Watch the last operation, it's new.

I don't know. I just tested it.

Thank You, I will credit you in my map. This has been solved. +rep
 
Status
Not open for further replies.
Top