diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 8c456137d..55ba4ffda 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1205,13 +1205,18 @@ do -- COORDINATE return self:GetClosestParkingSpot(airbase, terminaltype, false) end - --- Gets the nearest coordinate to a road. + --- Gets the nearest coordinate to a road (or railroad). -- @param #COORDINATE self + -- @param #boolean Railroad (Optional) If true, closest point to railroad is returned rather than closest point to conventional road. Default false. -- @return #COORDINATE Coordinate of the nearest road. - function COORDINATE:GetClosestPointToRoad() - local x,y = land.getClosestPointOnRoads("roads", self.x, self.z) - local vec2={ x = x, y = y } - return COORDINATE:NewFromVec2(vec2) + function COORDINATE:GetClosestPointToRoad(Railroad) + local roadtype="roads" + if Railroad==true then + roadtype="railroads" + end + local x,y = land.getClosestPointOnRoads(roadtype, self.x, self.z) + local vec2={ x = x, y = y } + return COORDINATE:NewFromVec2(vec2) end diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 12a611250..6a284ab73 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -4735,10 +4735,20 @@ function SET_ZONE:New() return self end +--- Add ZONE to SET_ZONE. +-- @param Core.Set#SET_ZONE self +-- @param Core.Zone#ZONE Zone Zone to add to the set. +-- @return #SET_ZONE self +function SET_ZONE:AddZone(Zone) + self:Add(Zone:GetName(), Zone) + return self +end + + --- Add ZONEs to SET_ZONE. -- @param Core.Set#SET_ZONE self -- @param #string AddZoneNames A single name or an array of ZONE_BASE names. --- @return self +-- @return #SET_ZONE self function SET_ZONE:AddZonesByName( AddZoneNames ) local AddZoneNamesArray = ( type( AddZoneNames ) == "table" ) and AddZoneNames or { AddZoneNames } @@ -4753,7 +4763,7 @@ end --- Remove ZONEs from SET_ZONE. -- @param Core.Set#SET_ZONE self -- @param Core.Zone#ZONE_BASE RemoveZoneNames A single name or an array of ZONE_BASE names. --- @return self +-- @return #SET_ZONE self function SET_ZONE:RemoveZonesByName( RemoveZoneNames ) local RemoveZoneNamesArray = ( type( RemoveZoneNames ) == "table" ) and RemoveZoneNames or { RemoveZoneNames } @@ -4779,8 +4789,7 @@ end --- Get a random zone from the set. -- @param #SET_ZONE self --- @return Core.Zone#ZONE_BASE The random Zone. --- @return #nil if no zone in the collection. +-- @return Core.Zone#ZONE_BASE The random Zone or #nil if no zone in the collection. function SET_ZONE:GetRandomZone() if self:Count() ~= 0 then @@ -4806,6 +4815,7 @@ end --- Set a zone probability. -- @param #SET_ZONE self -- @param #string ZoneName The name of the zone. +-- @param #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. function SET_ZONE:SetZoneProbability( ZoneName, ZoneProbability ) local Zone = self:FindZone( ZoneName ) Zone:SetZoneProbability( ZoneProbability ) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 82c7a0be7..d0e368d3a 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -317,7 +317,8 @@ end --- Set the randomization probability of a zone to be selected. -- @param #ZONE_BASE self --- @param ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. +-- @param #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. +-- @return #ZONE_BASE self function ZONE_BASE:SetZoneProbability( ZoneProbability ) self:F( { self:GetName(), ZoneProbability = ZoneProbability } ) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index cf134349b..54c75cc50 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -117,8 +117,10 @@ WAREHOUSE.Descriptor = { ATTRIBUTE="attribute", } ---- Warehouse unit categories. These are used for +--- Warehouse generalited categories. -- @type WAREHOUSE.Attribute +-- @field #string TRANSPORT_PLANE Airplane with transport capability. Usually bigger. +-- @field #string TRANSPORT_HELO Helicopter with transport capability. WAREHOUSE.Attribute = { TRANSPORT_PLANE="Transport_Plane", TRANSPORT_HELO="Transport_Helo", @@ -132,6 +134,7 @@ WAREHOUSE.Attribute = { BOMBER="Bomber", TANK="Tank", TRUCK="Truck", + TRAIN="Train", SHIP="Ship", OTHER="Other", } @@ -504,23 +507,30 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) -- Set a marker for the spawned group. spawncoord:MarkToAll(string.format("Spawnpoint %s",_alias)) + + local _attribute=_assetitem.attribute if _assetitem.category==Group.Category.GROUND then -- Spawn ground troops. _group=_spawn:SpawnFromCoordinate(spawncoord) - env.info(string.format("FF spawning group %s", _alias)) + env.info(string.format("FF spawning group %s", _alias)) elseif _assetitem.category==Group.Category.AIRPLANE or _assetitem.category==Group.Category.HELICOPTER then -- Spawn air units. local _takeoff=SPAWN.Takeoff.Cold local _terminal=AIRBASE.TerminalType.OpenBig - if _assetitem.attribute==WAREHOUSE.Attribute.FIGHTER then + if _attribute==WAREHOUSE.Attribute.FIGHTER then _terminal=AIRBASE.TerminalType.FighterAircraft - elseif _assetitem.attribute==WAREHOUSE.Attribute.BOMBER then + elseif _attribute==WAREHOUSE.Attribute.BOMBER or _attribute==WAREHOUSE.Attribute.TRANSPORT_PLANE or _attribute==WAREHOUSE.Attribute.TANKER or _attribute==WAREHOUSE.Attribute.AWACS then _terminal=AIRBASE.TerminalType.OpenBig + elseif _attribute==WAREHOUSE.Attribute.TRANSPORT_HELO or _attribute==WAREHOUSE.Attribute.ATTACKHELICOPTER then + _terminal=AIRBASE.TerminalType.HelicopterUsable end _group=_spawn:InitUnControlled(true):SpawnAtAirbase(self.homebase,_takeoff, nil,_terminal, true) elseif _assetitem.category==Group.Category.TRAIN then - + local _railroad=self.coordinate:GetClosestPointToRoad(true) + if _railroad then + _group=_spawn:SpawnFromCoordinate(_railroad) + end end if _group then @@ -561,7 +571,7 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) elseif _cargocategory==Group.Category.SHIP then elseif _cargocategory==Group.Category.TRAIN then - + self:_RouteTrain(group, ToCoordinate) end end @@ -581,8 +591,10 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) -- Pickup and depoly locations. local PickupAirbaseSet = SET_AIRBASE:New():AddAirbase(self.homebase) local DeployAirbaseSet = SET_AIRBASE:New():AddAirbase(Request.airbase) - local DeployZoneSet = SET_ZONE:New():FilterPrefixes("Deploy"):FilterStart() - --local bla=SET_ZONE:New():AddZonesByName(AddZoneNames) + --local DeployZoneSet = SET_ZONE:New():FilterPrefixes("Deploy"):FilterStart() + --local DeployZoneSet = SET_ZONE:New():AddZonesByName(Request.airbase:GetZone():GetName()) + local DeployZoneSet = SET_ZONE:New():AddZone(Request.airbase:GetZone()) + local CargoTransport --AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER -- Filter the requested transport assets. @@ -651,6 +663,8 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) TransportSet:AddGroup(spawngroup) table.insert(_delid,_assetitem.id) + else + env.info("FF error spawngroup helo transport does not exist!") end end @@ -918,6 +932,32 @@ function WAREHOUSE:_RouteAir(Aircraft, ToAirbase, Speed) end end +--- Route trains to their destination - or at least to the closest point on rail of the desired final destination. +-- @param #WAREHOUSE self +-- @param Wrapper.Group#GROUP Group The train group. +-- @param Core.Point#COORDINATE Coordinate of the destination. Tail will be routed to the closest point +-- @param #number Speed Speed in km/h to drive to the destination coordinate. Default is 60% of max possible speed the unit can go. +function WAREHOUSE:_RouteTrain(Group, Coordinate, Speed) + + if Group and Group:IsAlive() then + + local _speed=Speed or Group:GetSpeedMax()*0.6 + + -- Create a + local Waypoints = Group:TaskGroundOnRailRoads(Coordinate, Speed) + + -- Task function triggering the arrived event. + local TaskFunction = Group:TaskFunction("WAREHOUSE._Arrived", self) + + -- Put task function on last waypoint. + local Waypoint = Waypoints[#Waypoints] + Group:SetTaskWaypoint( Waypoint, TaskFunction ) + + -- Route group to destination. + Group:Route(Waypoints, 1) + end +end + --- Filter stock assets by table entry. -- @param #WAREHOUSE self -- @param #table stock Table holding all assets in stock of the warehouse. Each entry is of type @{#WAREHOUSE.Stockitem}. @@ -997,7 +1037,8 @@ function WAREHOUSE:_GetAttribute(groupname) local attackhelicopter=group:HasAttribute("Attack helicopters") local bomber=group:HasAttribute("Bombers") local tank=group:HasAttribute("Old Tanks") or group:HasAttribute("Modern Tanks") - local truck=group:HasAttribute("Trucks") + local truck=group:HasAttribute("Trucks") and not group:GetCategory()==Group.Category.TRAIN + local train=group:GetCategory()==Group.Category.TRAIN -- Debug output. --[[ @@ -1039,6 +1080,8 @@ function WAREHOUSE:_GetAttribute(groupname) attribute=WAREHOUSE.Attribute.TANK elseif truck then attribute=WAREHOUSE.Attribute.TRUCK + elseif train then + attribute=WAREHOUSE.Attribute.TRAIN else attribute=WAREHOUSE.Attribute.OTHER end diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 84c25a1f4..767845e21 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1996,6 +1996,28 @@ do -- Route methods return self end + + --- Make the TRAIN Controllable to drive towards a specific point using railroads. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param #number Speed (Optional) Speed in km/h. The default speed is 20 km/h. + -- @param #number DelaySeconds (Optional) Wait for the specified seconds before executing the Route. Default is one second. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:RouteGroundOnRailRoads( ToCoordinate, Speed, DelaySeconds) + + -- Defaults. + Speed=Speed or 20 + DelaySeconds=DelaySeconds or 1 + + -- Get the route task. + local route=self:TaskGroundOnRailRoads(ToCoordinate, Speed) + + -- Route controllable to destination. + self:Route( route, DelaySeconds ) + + return self + end + --- Make a task for a GROUND Controllable to drive towards a specific point using (mostly) roads. @@ -2077,7 +2099,40 @@ do -- Route methods return route end + --- Make a task for a TRAIN Controllable to drive towards a specific point using railroad. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param #number Speed (Optional) Speed in km/h. The default speed is 20 km/h. + -- @return Task + function CONTROLLABLE:TaskGroundOnRailRoads(ToCoordinate, Speed) + self:F2({ToCoordinate=ToCoordinate, Speed=Speed}) + + -- Defaults. + Speed=Speed or 20 + -- Current coordinate. + local FromCoordinate = self:GetCoordinate() + + -- Get path and path length on railroad. + local PathOnRail, LengthOnRail=FromCoordinate:GetPathOnRoad(ToCoordinate, false, true) + + -- Debug info. + self:T(string.format("Length on railroad = %.3f km", LengthOnRail/1000)) + + -- Route, ground waypoints along road. + local route={} + + -- Check if a valid path on railroad could be found. + if PathOnRail then + + table.insert(route, PathOnRail[1]:WaypointGround(Speed, "On Railroad")) + table.insert(route, PathOnRail[2]:WaypointGround(Speed, "On Railroad")) + + end + + return route + end + --- Make the AIR Controllable fly towards a specific point. -- @param #CONTROLLABLE self -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.