civHelo
This commit is contained in:
Christian Franz 2024-02-22 09:17:26 +01:00
parent 61f33561fc
commit a44f145218
11 changed files with 659 additions and 22 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,11 +1,11 @@
cfxZones = {}
cfxZones.version = "4.1.2"
cfxZones.version = "4.2.0"
-- cf/x zone management module
-- reads dcs zones and makes them accessible and mutable
-- by scripting.
--
-- Copyright (c) 2021 - 2023 by Christian Franz and cf/x AG
-- Copyright (c) 2021 - 2024 by Christian Franz and cf/x AG
--
--[[-- VERSION HISTORY
@ -44,6 +44,7 @@ cfxZones.version = "4.1.2"
- 4.1.0 - getBoolFromZoneProperty 'on/off' support for dml variant as well
- 4.1.1 - evalRemainder() updates
- 4.1.2 - hash property missing warning
- 4.2.0 - new createRandomPointInPopulatedZone()
--]]--
@ -425,6 +426,95 @@ function dmlZone:createRandomPointInPolyZone(onEdge)
return p, dx, dz
end
function dmlZone:createRandomPointInPopulatedZone(radius, maxTries)
if not maxTries then maxTries = 20 end
if not radius then radius = 10 end -- meters
local cnt = 0
local p, dx, dz
repeat
p, dx, dz = self:createRandomPointInZone() -- p is x, 0, z
local hits, collector = cfxZones.objectsInRange(p, radius)
if hits < 1 then return p, dx, dz end
if hits == 1 then
local o = collector[1]
local op = o:getPoint()
d = dcsCommon.distFlat(op, p)
-- trigger.action.outText("singleDist = " .. d, 30)
if d > radius/2 then
-- trigger.action.outText("good enough, will use", 30)
return p, dx, dz
end
end
cnt = cnt + 1
-- trigger.action.outText(hits .. "hits --> failed try " .. cnt, 30)
until cnt > maxTries
return p, dx, dz
end
function cfxZones.createRandomPointInPopulatedZone(theZone, radius, maxTries)
if not theZone then return nil, nil, nil end
local p, dx, dz = theZone:createRandomPointInPopulatedZone(radius, maxTries)
return p, dx, dz
end
--[[--
function dmlZone:createRandomPointInPopulatedZone(radius, maxTries)
if not maxTries then maxTries = 20 end
local cnt = 0
local p, dx, dz
p, dx, dz = self:createRandomPointInZone() -- p is x, 0, z
repeat
local hits = cfxZones.objectsInRange(p, radius)
if hits < 1 then return p, dx, dz end
-- move to the right by radius
p.z = p.z + radius
dz = dz + radius
cnt = cnt + 1
trigger.action.outText("failed try " .. cnt, 30)
until cnt > maxTries
return p, dx, dz
end
--]]--
function cfxZones.objectHandler(theObject, theCollector) -- for world.search
table.insert(theCollector, theObject)
return true
end
function cfxZones.objectsInRange(pt, range)
if not range then range = 100 end -- meters
local allCats = {1, 2, 3, 4, 5, 6} -- all cats
local lp = {x = pt.x, y = pt.z}
pt.y = land.getHeight(lp)
local collector = {}
-- now build the search argument
local args = {
id = world.VolumeType.SPHERE,
params = {
point = pt,
radius = range -- range
}
}
-- now call search
world.searchObjects(allCats, args, cfxZones.objectHandler, collector)
-- now filter for distance because search finds too many
local filtered = {}
for idx, anObject in pairs(collector) do
-- calc dist and filter
local op = anObject:getPoint()
local dist = dcsCommon.dist(pt, op)
if dist < range then
-- local e = {
-- dist = dist,
-- o = anObject
-- }
-- table.insert(filtered, e)
table.insert(filtered, anObject)
end
end
return #filtered, filtered
end
function cfxZones.addZoneToManagedZones(theZone)
local upperName = string.upper(theZone.name) -- newZone.name:upper()
cfxZones.zones[upperName] = theZone

474
modules/civHelo.lua Normal file
View File

@ -0,0 +1,474 @@
civHelo = {}
civHelo.version = "1.0.0"
civHelo.requiredLibs = {
"dcsCommon", -- always
"cfxZones",
}
--[[--
Version History
1.0.0 - Initial version
--]]--
civHelo.flights = {} -- currently active flights
civHelo.ports = {} -- civHelo zones where flight can take off and land
civHelo.maxDist = 600000 -- 60 km
civHelo.minDist = 1000 -- 1 km
-- helos and liveries
civHelo.types = {"CH-47D", "CH-53E", "Ka-27", "Mi-24V", "Mi-26", "Mi-28N", "Mi-8MT","OH-58D", "SA342L", "SH-60B", "UH-1H", "UH-60A",} -- default set
civHelo.liveries = {
["CH-47D"] = {"Australia RAAF", "ch-47_green neth", "ch-47_green spain", "ch-47_green uk", "Greek Army", "standard", },
["CH-53E"] = {"standard",},
["Ka-27"] = {"China PLANAF", "standard", "ukraine camo 1",},
["Mi-24V"] = {"Abkhazia", "Algerian AF Black", "Algerian AF New Desert", "Algerian AF Old Desert", "Russia_FSB", "Russia_MVD", "South Ossetia", "standard", "standard 1", "standard 2 (faded and sun-bleached)", "ukraine", "Ukraine UN", },
["Mi-26"] = {"7th Separate Brigade of AA (Kalinov)", "Algerian Air Force SL-22", "China Flying Dragon Aviation", "RF Air Force", "Russia_FSB", "Russia_MVD", "United Nations", },
["Mi-28N"] = {"AAF SC-11", "AAF SC-12", "night", "standard", },
["Mi-8MT"] = {"China UN", "IR Iranian Special Police Forces", "Russia_Gazprom", "Russia_PF_Ambulance", "Russia_Police", "Russia_UN", "Russia_UTair", "Russia_Aeroflot", "Russia_KazanVZ", "Russia_LII_Gromov RA-25546", "Russia_Vertolety_Russia", "Russia_Vertolety_Russia_2", "Russia_Naryan-Mar", },
--["OH-58D"] = {"",},
--["SA342L"] = {"",},
["SH-60B"] = {"Hellenic Navy", "standard", },
["UH-1H"] = {"[Civilian] Medical", "[Civilian] NASA", "[Civilian] Standard", "[Civilian] VIP", "Greek Army Aviation Medic", "Italy 15B Stormo S.A.R -Soccorso", "Norwegian Coast Guard (235)", "Norwegian UN", "Spanish UN", "USA UN", },
["UH-60A"] = {"ISRAIL_UN", }
}
--
-- process civHelo zone
--
function civHelo.readCivHeloZone(theZone)
-- process properties
theZone.canLand = theZone:getBoolFromZoneProperty("land", true)
theZone.canStart = theZone:getBoolFromZoneProperty("start", true)
theZone.hotStart = theZone:getBoolFromZoneProperty("hot", true)
if theZone:hasProperty("types") then
local hTypes = theZone:getStringFromZoneProperty("types", "xxx")
local typeArray = dcsCommon.splitString(hTypes, ",")
typeArray = dcsCommon.trimArray(typeArray)
theZone.types = typeArray
end
-- set active flag
theZone.inUse = nil -- if true zone is in use for a flight
end
function civHelo.addCivHeloZone(theZone)
table.insert(civHelo.ports, theZone)
end
function civHelo.getPortNamed(name)
for idx, theZone in pairs(civHelo.ports) do
if theZone.name == name then return theZone end
end
if civHelo.verbose then
trigger.action.outText("+++civH: cannot find port <" .. name .. ">", 30)
end
return nil
end
function civHelo.getFreePort(source, dest, anchor)
collector = {}
local a
if anchor then a = anchor:getPoint() end -- for dist calc
for idx, theZone in pairs(civHelo.ports) do
if theZone.inUse then
else
if (source and theZone.canStart) or
(dest and theZone.canLand) then
if anchor then
-- must be at least minDist and at most maxDist away
local p = theZone:getPoint()
local d = dcsCommon.dist(a, p)
if d > civHelo.minDist and d < civHelo.maxDist then
table.insert(collector, theZone)
else
-- trigger.action.outText("+++civH: disregarded dest zone <" .. theZone.name .. ">: dist <" .. math.floor(d) / 1000 .. " km> out of bounds", 30)
end
else
table.insert(collector, theZone)
end
end
end
end
if #collector < 1 then return nil end
local theZone = dcsCommon.pickRandom(collector)
return theZone
end
function civHelo.getSourceAndDest()
local source = civHelo.getFreePort(true, false)
if not source then return nil, nil end
source.inUse = true
local dest = civHelo.getFreePort(false, true, source)
if not dest then
source.inUse = nil
return nil, nil
end
dest.inUse = true
return source, dest
end
function civHelo.createCommandTask(theCommand, num)
if not num then num = 1 end
local t = {}
t.enabled = true
t.auto = false
t.id = "WrappedAction"
t.number = num
local params = {}
t.params = params
local action = {}
params.action = action
action.id = "Script"
local p2 = {}
action.params = p2
p2.command = theCommand
return t
end
function civHelo.createLandTask(p, duration, num)
if not num then num = 1 end
local t = {}
t.enabled = true
t.auto = false
t.id = "ControlledTask"
t.number = num
local params = {}
t.params = params
local ptsk = {}
params.task = ptsk
ptsk.id = "Land"
local ptp = {}
ptsk.params = ptp
ptp.x = p.x
ptp.y = p.z
ptp.duration = "300" -- not sure why
ptp.durationFlag = false -- off anyway
local stopCon = {}
stopCon.duration = duration
params.stopCondition = stopCon
return t
end
function civHelo.createFlight(name, theType, fromZone, toZone) --, inAir)
if not fromZone then return nil end
if not toZone then return nil end
-- if not inAir then inAir = false end
local theGroup = dcsCommon.createEmptyAircraftGroupData (name)
local theHUnit = dcsCommon.createAircraftUnitData(name .. "-H", theType, false)
if fromZone.hdg then
end
-- add livery capability for this aircraft
--civHelo.processLiveriesFor(theHUnit, theType)
civHelo.getLiveryForType(theType, theHUnit)
-- enforce civ attribute
theHUnit.civil_plane = true
theHUnit.payload.fuel = 5000 -- 5t of fuel
dcsCommon.addUnitToGroupData(theHUnit, theGroup)
local A = fromZone:getPoint()
local B = toZone:getPoint()
-- unit is done, let's do the route
-- WP 1: take off
local fromWP, omwWP
fromWP = dcsCommon.createTakeOffFromGroundRoutePointData(fromZone:getPoint(true), fromZone.hotStart) -- last true = hot
fromWP.alt_type = "RADIO" -- AGL instead of MSL
theHUnit.alt = fromWP.alt
-- WP2: signal that we are 1km away so source can be freed from flight
local dir = dcsCommon.bearingFromAtoB(A, B) -- x0z coords
local omw = dcsCommon.pointInDirectionOfPointXYY(dir, 1000, A)
omwWP = dcsCommon.createSimpleRoutePointData(omw, civHelo.alt, civHelo.speed)
omwWP.alt_type = "RADIO"
-- create a command waypoint
local task = {}
task.id = "ComboTask"
task.params = {}
local ttsk = {}
local command = "civHelo.departedCB('" .. name .. "', '" .. fromZone:getName() .. "')"
ttsk[1] = civHelo.createCommandTask(command,1)
task.params.tasks = ttsk
omwWP.task = task
-- now set up destination point: land
-- at destination and add a small script
local toWP
-- add destination WP. this is common to both
toWP = dcsCommon.createSimpleRoutePointData(toZone:getPoint(), civHelo.alt, civHelo.speed)
toWP.alt_type = "RADIO"
local task = {}
task.id = "ComboTask"
task.params = {}
local ttsk = {}
local p = toZone:getPoint()
ttsk[1] = civHelo.createLandTask(p, civHelo.landingDuration, 1)
local command = "civHelo.landedCB('" .. name .. "', '" .. toZone:getName() .. "')"
ttsk[2] = civHelo.createCommandTask(command,2)
task.params.tasks = ttsk
toWP.task = task
-- move group to WP1 and add WP1 and WP2 to route
dcsCommon.moveGroupDataTo(theGroup,
fromWP.x,
fromWP.y)
dcsCommon.addRoutePointForGroupData(theGroup, fromWP)
if not inAir then
dcsCommon.addRoutePointForGroupData(theGroup, omwWP)
end
dcsCommon.addRoutePointForGroupData(theGroup, toWP)
-- spawn
local groupCat = Group.Category.HELICOPTER
local theSpawnedGroup = coalition.addGroup(civHelo.owner, groupCat, theGroup)
return theSpawnedGroup
end
function civHelo.openPort(where)
local thePort = civHelo.getPortNamed(where)
if thePort then
thePort.inUse = nil
end
if civHelo.verbose then trigger.action.outText("+++civH: opening port <" .. where .. ">", 30) end
end
function civHelo.openPortUsedBy(name)
for idx, theZone in pairs(civHelo.ports) do
if theZone.inUse == name then
theZone.inUse = nil
if civHelo.verbose then
trigger.action.outText("+++civH: clearing port <" .. theZone.name .. "> from flight <" .. name .. ">", 30)
end
end
end
end
function civHelo.departedCB(who, where)
-- free the port that we just took off from
civHelo.openPort(where)
end
function civHelo.landedCB(who, where)
-- step 1: remove the flight
local theGroup = Group.getByName(who)
if theGroup then
if Group.isExist(theGroup) then
Group.destroy(theGroup)
end
else
trigger.action.outText("+++civH: cannot find group <" .. who .. ">", 30)
end
civHelo.flights[who] = nil
-- step 2: schedule opening the port
-- do it immediately first
civHelo.openPort(where)
end
--
-- new flight
--
function civHelo.getType(theZone)
local types = civHelo.types -- load default
if theZone.types then types = theZone.types end
local hType = dcsCommon.pickRandom(types)
return hType
end
function civHelo.getLiveryForType(theType, theData)
if civHelo.liveries[theType] then
local available = civHelo.liveries[theType]
local chosen = dcsCommon.pickRandom(available)
theData.livery_id = chosen
end
end
function civHelo.newFlight()
local source, dest = civHelo.getSourceAndDest()
if source and dest then
-- source and dest "inUse" already have been marked inUse
-- but still need the name of the flight
local theType = civHelo.getType(source)
local name = source:getName() .. "-" .. dest:getName()
local theFlight = civHelo.createFlight(name, theType, source, dest)
if theFlight then
civHelo.flights[name] = theFlight
source.inUse = name
dest.inUse = name
if civHelo.verbose then
trigger.action.outText("+++civH: created new flight <" .. name .. ">", 30)
end
else
trigger.action.outText("+++civH: cant create flight <" .. name .. ">", 30)
source.inUse = nil
dest.inUse = nil
end
else
if civHelo.verbose then
trigger.action.outText("+++civH: no ports available, can't create new flight. Numflights = <" .. dcsCommon.getSizeOfTable(civHelo.flights) .. ">", 30)
end
end
end
--
-- event handler
--
function civHelo:onEvent(theEvent)
-- trigger.action.outText("event", 30)
if not theEvent.initiator then return end
local theUnit = theEvent.initiator
if not theUnit.getGroup then return end
local theGroup = theUnit:getGroup()
if not theGroup then return end
local gName = theGroup:getName()
-- see if it's an event for one of mine
local mine = false
for name, aGroup in pairs(civHelo.flights) do
if name == gName then mine = true end
end
if not mine then
return
end
local id = theEvent.id
if id == 9 or -- pilot dead
id == 30 or -- unit lost
id == 5 -- crash
then
if civHelo.verbose then
trigger.action.outText("+++civH: cancelling flight <" .. gName .. ">: mishap", 30)
end
civHelo.openPortUsedBy(gName)
civHelo.flights[gName] = nil
end
end
--
-- update
--
function civHelo.update()
-- schedule again
timer.scheduleFunction(civHelo.update, {}, timer.getTime() + 1/civHelo.ups )
-- see how many flights are live
if dcsCommon.getSizeOfTable(civHelo.flights) < civHelo.maxFlights then
civHelo.newFlight()
end
end
--
-- Config
--
function civHelo.addTypesAndLiveries(rawIn)
local newTypes = {}
local newLiveries = {}
-- now iterate the input table, and generate new types and
-- liveries from it
for theType, liveries in pairs (rawIn) do
if civHelo.verbose then
trigger.action.outText("+++civH: processing type <" .. theType .. ">:<" .. liveries .. ">", 30)
end
local livA = dcsCommon.splitString(liveries, ',')
livA = dcsCommon.trimArray(livA)
table.insert(newTypes, theType)
newLiveries[theType] = livA
end
return newTypes, newLiveries
end
function civHelo.readConfigZone()
local theZone = cfxZones.getZoneByName("civHeloConfig")
if not theZone then
theZone = cfxZones.createSimpleZone("civHeloConfig")
end
civHelo.verbose = theZone.verbose
civHelo.owner = theZone:getNumberFromZoneProperty("country", 82) --82 -- UN peacekeepers
civHelo.ups = theZone:getNumberFromZoneProperty("ups", 1 / 30)
civHelo.maxFlights = theZone:getNumberFromZoneProperty("maxFlights", 5)
civHelo.landingDuration = theZone:getNumberFromZoneProperty("landingDuration", 180) -- seconds = 3 minutes
civHelo.alt = theZone:getNumberFromZoneProperty("alt", 100) -- 100 m
civHelo.speed = theZone:getNumberFromZoneProperty("speed", 30)
civHelo.maxDist = theZone:getNumberFromZoneProperty("maxDist", 60000)
civHelo.minDist = theZone:getNumberFromZoneProperty("minDist", 1000)
if theZone:hasProperty("types") then
local hTypes = theZone:getStringFromZoneProperty("types", "xxx")
local typeArray = dcsCommon.splitString(hTypes, ",")
typeArray = dcsCommon.trimArray(typeArray)
civHelo.types = typeArray
end
-- now get types and liveries from 'helo_liveries' if present
local livZone = cfxZones.getZoneByName("helo_liveries")
if livZone then
if civHelo.verbose then
trigger.action.outText("civH: found and processing 'helo_liveries' zone data.", 30)
end
-- read all into my types registry, replacing whatever is there
local rawLiver = cfxZones.getAllZoneProperties(livZone)
local newTypes, newLiveries = civAir.addTypesAndLiveries(rawLiver)
-- now types to existing types if not already there
for idx, aType in pairs(newTypes) do
dcsCommon.addToTableIfNew(civHelo.types, aType)
if civHelo.verbose then
trigger.action.outText("+++civH: processed and added helo <" .. aType .. "> to civHelo", 30)
end
end
-- now replace liveries or add if not already there
for aType, liveries in pairs(newLiveries) do
civHelo.liveries[aType] = liveries
if civHelo.verbose then
trigger.action.outText("+++civH: replaced/added liveries for helicopter <" .. aType .. ">", 30)
end
end
end
end
--
-- start
--
function civHelo.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("cfx civ helo requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx civ helo", civHelo.requiredLibs) then
return false
end
-- read config
civHelo.readConfigZone()
-- process civHelo Zones
-- old style
local attrZones = cfxZones.getZonesWithAttributeNamed("civHelo")
for k, aZone in pairs(attrZones) do
civHelo.readCivHeloZone(aZone) -- process attributes
civHelo.addCivHeloZone(aZone) -- add to list
end
-- start update in 5 seconds
timer.scheduleFunction(civHelo.update, {}, timer.getTime() + 5)
-- install event handler
world.addEventHandler(civHelo)
-- say hi
trigger.action.outText("civHelo v" .. civHelo.version .. " started.", 30)
return true
end
if not civHelo.start() then
trigger.action.outText("civHelo failed to start.")
civHelo = nil
end

View File

@ -303,7 +303,9 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
if theZone:hasProperty("wholeGroups") then
theZone.centerOnly = theZone:getBoolFromZoneProperty( "wholeGroups", false)
end
if theZone:hasProperty("inBuiltup") then
theZone.inBuiltup = theZone:getNumberFromZoneProperty("inBuiltup", 10) -- 10 meter radius must be free -- small houses
end
theZone.rndHeading = theZone:getBoolFromZoneProperty("rndHeading", false)
theZone.onRoad = theZone:getBoolFromZoneProperty("onRoad", false)
@ -1063,6 +1065,8 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
local loc, dx, dy
if spawnZone.onPerimeter then
loc, dx, dy = spawnZone:createRandomPointOnZoneBoundary()
elseif spawnZone.inBuiltup then
loc, dx, dy = spawnZone:createRandomPointInPopulatedZone(spawnZone.inBuiltup)
else
loc, dx, dy = spawnZone:createRandomPointInZone() -- also supports polygonal zones
end
@ -1072,6 +1076,8 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
-- *every unit's displacement is randomized
if spawnZone.onPerimeter then
loc, dx, dy = spawnZone:createRandomPointOnZoneBoundary()
elseif spawnZone.inBuiltup then
loc, dx, dy = spawnZone:createRandomPointInPopulatedZone(spawnZone.inBuiltup)
else
loc, dx, dy = spawnZone:createRandomPointInZone()
end
@ -1322,6 +1328,8 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
local loc, dx, dy
if spawnZone.onPerimeter then
loc, dx, dy = spawnZone:createRandomPointOnZoneBoundary()
elseif spawnZone.inBuiltup then
loc, dx, dy = spawnZone:createRandomPointInPopulatedZone(spawnZone.inBuiltup)
else
loc, dx, dy = spawnZone:createRandomPointInZone() -- also supports polygonal zones
end

View File

@ -1,5 +1,5 @@
csarManager = {}
csarManager.version = "3.1.0"
csarManager.version = "3.2.0"
csarManager.ups = 1
--[[-- VERSION HISTORY
@ -28,9 +28,14 @@ csarManager.ups = 1
- inflight status reflects time limit but will not time out
- pickupSound option
- lostSound option
- 3.1.1 - birth clears troopsOnBoard
- 3.2.0 - inPopulated csar option
- clearance csar attribute
- maxTries csar attribute
INTEGRATES AUTOMATICALLY WITH playerScore IF INSTALLED
INTEGRATES WITH LIMITED AIRFRAMES IF INSTALLED
INTEGRATES AUTOMATICALLY WITH playerScore
INTEGRATES WITH LIMITED AIRFRAMES
INTEGRATES AUTOMATICALLY WITH SCRIBE
--]]--
-- modules that need to be loaded BEFORE I run
@ -297,17 +302,26 @@ function csarManager:onEvent(event)
csarManager.heloLanded(theUnit)
end
if ID == 3 then -- take off
if ID == 3 or ID == 55 then -- take off, postponed take-off
csarManager.heloDeparted(theUnit)
end
if ID == 5 then -- crash
csarManager.heloCrashed(theUnit)
-- note: maybe not called in network missions.
-- correction: is called in 2.9
end
if ID == 15 then -- player helicopter birth
-- we need to set up comms for this unit
csarManager.setCommsMenu(theUnit)
-- we also need to make sure that there are no
-- more troopsOnBoard
local conf = csarManager.getUnitConfig(theUnit)
conf.unit = theUnit
conf.troopsOnBoard = {}
end
end
@ -421,7 +435,7 @@ function csarManager.heloLanded(theUnit)
end
for idx, msn in pairs(conf.troopsOnBoard) do
-- each troopsOnboard is actually the
-- each troopsOnBoard is actually the
-- csar mission that I picked up
csarManager.successMission(myName, base.name, msn)
end
@ -792,7 +806,7 @@ function csarManager.doStatusCarrying(args)
local evacMission = conf.troopsOnBoard[i]
report = report .. "\n".. i .. ") " .. evacMission.name
if evacMission.expires then
delta = math.floor ((mission.expires - now) / 60)
delta = math.floor ((evacMission.expires - now) / 60)
if delta > 20 then
report = report .. " is hurt but stable"
elseif delta > 10 then
@ -1207,6 +1221,9 @@ function csarManager.createCSARMissionFromZone(theZone)
if theZone.rndLoc then mPoint = theZone:createRandomPointInZone() end
if theZone.onRoad then
mPoint.x, mPoint.z = land.getClosestPointOnRoads('roads',mPoint.x, mPoint.z)
elseif theZone.inPopulated then
local aPoint = theZone:createRandomPointInPopulatedZone(theZone.clearance, theZone.maxTries)
mPoint = aPoint -- safety in case we need to mod aPoint
end
local theMission = csarManager.createCSARMissionData(
mPoint,
@ -1218,6 +1235,7 @@ function csarManager.createCSARMissionFromZone(theZone)
theZone.csarMapMarker, -- mapMarker
0.1, --theZone.radius) -- radius
nil) -- parashoo unit
theMission.inPopulated = theZone.inPopulated -- transfer for csarFX
return theMission
end
@ -1338,12 +1356,22 @@ function csarManager.readCSARZone(theZone)
theZone.triggerMethod = theZone:getStringFromZoneProperty("triggerMethod", "change")
theZone.rndLoc = theZone:getBoolFromZoneProperty("rndLoc", true)
theZone.onRoad = theZone:getBoolFromZoneProperty("onRoad", false)
theZone.inPopulated = theZone:getBoolFromZoneProperty("inPopulated", false)
theZone.clearance = theZone:getNumberFromZoneProperty("clearance", 10)
theZone.maxTries = theZone:getNumberFromZoneProperty("maxTries", 20)
if theZone.onRoad and theZone.inPopulated then
trigger.action.outText("warning: competing 'onRoad' and 'inPopulated' attributes in zone <" .. theZone.name .. ">. Using 'onRoad'.", 30)
end
if (not deferred) then
local mPoint = theZone:getPoint()
if theZone.rndLoc then mPoint = theZone:createRandomPointInZone() end
if theZone.onRoad then
mPoint.x, mPoint.z = land.getClosestPointOnRoads('roads',mPoint.x, mPoint.z)
elseif theZone.inPopulated then
local aPoint = theZone:createRandomPointInPopulatedZone(theZone.clearance, theZone.maxTries)
mPoint = aPoint -- safety in case we need to mod aPoint
end
local theMission = csarManager.createCSARMissionData(
mPoint,

View File

@ -1,5 +1,5 @@
dcsCommon = {}
dcsCommon.version = "3.0.2"
dcsCommon.version = "3.0.3"
--[[-- VERSION HISTORY
3.0.0 - removed bad bug in stringStartsWith, only relevant if caseSensitive is false
- point2text new intsOnly option
@ -11,6 +11,8 @@ dcsCommon.version = "3.0.2"
3.0.1 - clone: better handling of string type
3.0.2 - new getPlayerUnit()
3.0.3 - createStaticObjectForCoalitionInRandomRing() returns x and z
- isTroopCarrier() also supports 'helo' keyword
- new createTakeOffFromGroundRoutePointData()
--]]--
-- dcsCommon is a library of common lua functions
@ -1285,6 +1287,25 @@ dcsCommon.version = "3.0.2"
return route
end
function dcsCommon.createTakeOffFromGroundRoutePointData(pt, isHot) -- vec 3!
if not pt then return nil end
local rp = {}
rp.x = pt.x
rp.y = pt.z
rp.alt = pt.y
if isHot then
rp.action = "From Ground Area Hot"
rp.type = "TakeOffGroundHot"
else
rp.action = "From Ground Area" -- add " Hot" if hot
rp.type = "TakeOffGround" -- add "Hot" (NO blank) if hot
end
rp.speed = 10 -- that's 36 km/h
rp.alt_type = "BARO"
return rp
end
function dcsCommon.createTakeOffFromParkingRoutePointData(aerodrome)
if not aerodrome then return nil end
@ -2701,6 +2722,15 @@ end
function dcsCommon.isTroopCarrier(theUnit, carriers)
-- return true if conf can carry troups
if not theUnit then return false end
-- see if carriers contains "helo" and theUnit is a helo
if dcsCommon.arrayContainsString(carriers, "helo") or dcsCommon.arrayContainsString(carriers, "helos")then
local grp = theUnit:getGroup()
if grp:getCategory() == 1 then -- NOT category bug prone, is a group check
return true
end
end
local uType = theUnit:getTypeName()
return dcsCommon.isTroopCarrierType(uType, carriers)
end

View File

@ -1,5 +1,5 @@
scribe = {}
scribe.version = "1.0.0"
scribe.version = "1.0.1"
scribe.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
@ -9,7 +9,8 @@ scribe.requiredLibs = {
--[[--
Player statistics package
VERSION HISTORY
1.0.0 Initial Version
1.0.0 Initial Version
1.0.1 postponed land, postponed takeoff, unit_lost
--]]--
scribe.verbose = true
scribe.db = {} -- indexed by player name
@ -234,8 +235,9 @@ function scribe.playerEjected(playerName)
end
function scribe.playerDied(playerName)
-- trigger.action.outText("+++scb: player <" .. playerName .. "> DEAD event, handing off to crashS", 30)
-- counts as a crash
if scribe.verbose then
trigger.action.outText("+++scb: player <" .. playerName .. "> DEAD event, handing off to crashS", 30)
end -- counts as a crash
local theEntry = scribe.getPlayerNamed(playerName)
if not theEntry.isActive then
if scribe.verbose then
@ -365,7 +367,9 @@ function scribe:onEvent(theEvent)
scribe.playerUnits[uName] = playerName -- for crash helo detection
end
if theEvent.id == 8 or theEvent.id == 9 then -- dead, pilot_dead
if theEvent.id == 8 or
theEvent.id == 9 or
theEvent.id == 30 then -- dead, pilot_dead, unit_lost
scribe.playerDied(playerName)
end
@ -373,15 +377,17 @@ function scribe:onEvent(theEvent)
scribe.playerEjected(playerName)
end
if theEvent.id == 5 then -- crash
if theEvent.id == 5 then -- crash, maybe not called in MP
scribe.playerCrashed(playerName)
end
if theEvent.id == 4 then -- landed
if theEvent.id == 4 or -- landed
theEvent.id == 56 then
scribe.playerLanded(playerName)
end
if theEvent.id == 3 then -- take-off
if theEvent.id == 3 or -- take-off
theEvent.id == 55 then -- postponed take-off
scribe.playerDeparted(playerName)
-- trigger.action.outText("departure detected", 30)
end

View File

@ -1,5 +1,5 @@
valet = {}
valet.version = "1.0.2"
valet.version = "1.0.3"
valet.verbose = false
valet.requiredLibs = {
"dcsCommon", -- always
@ -12,6 +12,7 @@ valet.valets = {}
1.0.0 - initial version
1.0.1 - typos in verbosity corrected
1.0.2 - also scan birth events
1.0.3 - outSoundFile now working correctly
--]]--
@ -41,7 +42,7 @@ function valet.createValetWithZone(theZone)
theZone.firstInSoundFile = cfxZones.getStringFromZoneProperty(theZone, "firstInSoundFile", "<none>")
end
theZone.outSoundFile = cfxZones.getStringFromZoneProperty(theZone, "outSoundFile", "<none>")
theZone.outSoundFile = cfxZones.getStringFromZoneProperty(theZone, "outSoundFile", theZone.inSoundFile)
-- greeting/first greeting, handle if "" = no text out
if cfxZones.hasProperty(theZone, "firstGreeting") then
@ -195,7 +196,7 @@ function valet.sendOffPlayer(playerName, aPlayerUnit, theZone, theDesc)
-- player has left the area
local msg = theZone.goodbye or ""
local dur = theZone.duration
local fileName = "l10n/DEFAULT/" .. theZone.inSoundFile
local fileName = "l10n/DEFAULT/" .. theZone.outSoundFile
local ID = aPlayerUnit:getID()
if msg == "<none>" then msg = "" end

Binary file not shown.