mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 1.2.6
TaxiPolice 1.0.0 Small bug fixes
This commit is contained in:
parent
1939f376c5
commit
52985a2d4c
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
cfxSSBClient = {}
|
||||
cfxSSBClient.version = "3.0.0"
|
||||
cfxSSBClient.version = "3.0.1"
|
||||
cfxSSBClient.verbose = false
|
||||
cfxSSBClient.singleUse = false -- set to true to block crashed planes
|
||||
-- NOTE: singleUse (true) requires SSB to disable immediate respawn after kick
|
||||
@ -47,6 +47,7 @@ Version History
|
||||
- open?
|
||||
- close?
|
||||
- also persists closed airfield list
|
||||
3.0.1 - ability to detect if an airfield doesn't exist (late activate)
|
||||
|
||||
|
||||
|
||||
@ -238,38 +239,46 @@ function cfxSSBClient.setSlotAccessForGroup(theGroup)
|
||||
-- and leave it as it is. Nothing to do at all now
|
||||
|
||||
elseif theMatchingAirfield ~= nil then
|
||||
local blockState = cfxSSBClient.enabledFlagValue -- we default to ALLOW the block
|
||||
local comment = "available"
|
||||
-- we have found a plane that is tied to an airfield
|
||||
-- so this group will receive a block/unblock
|
||||
-- we always set all block/unblock every time
|
||||
-- note: since caching, above guard not needed
|
||||
local airFieldSide = theMatchingAirfield:getCoalition()
|
||||
local groupCoalition = theGroup.coaNum
|
||||
local blockState = cfxSSBClient.enabledFlagValue -- we default to ALLOW the block
|
||||
local comment = "available"
|
||||
|
||||
-- see if airfield is closed
|
||||
local afName = theMatchingAirfield:getName()
|
||||
if cfxSSBClient.closedAirfields[afName] then
|
||||
-- airfield is closed. no take-offs
|
||||
|
||||
-- see if airfield currently exist (might be dead or late activate)
|
||||
if not Object.isExist(theMatchingAirfield) then
|
||||
-- airfield does not exits yet/any more
|
||||
blockState = cfxSSBClient.disabledFlagValue
|
||||
comment = "!closed airfield!"
|
||||
end
|
||||
comment = "!inactive airfield!"
|
||||
else
|
||||
local airFieldSide = theMatchingAirfield:getCoalition()
|
||||
local groupCoalition = theGroup.coaNum
|
||||
|
||||
-- on top of that, check coalitions
|
||||
if groupCoalition ~= airFieldSide then
|
||||
-- we have a problem. sides don't match
|
||||
if airFieldSide == 3
|
||||
or (cfxSSBClient.allowNeutralFields and airFieldSide == 0)
|
||||
then
|
||||
-- all is well, airfield is contested or neutral and
|
||||
-- we allow this plane to spawn here
|
||||
else
|
||||
-- DISALLOWED!!!!
|
||||
-- see if airfield is closed
|
||||
local afName = theMatchingAirfield:getName()
|
||||
if cfxSSBClient.closedAirfields[afName] then
|
||||
-- airfield is closed. no take-offs
|
||||
blockState = cfxSSBClient.disabledFlagValue
|
||||
comment = "!!!BLOCKED!!!"
|
||||
comment = "!closed airfield!"
|
||||
end
|
||||
|
||||
-- on top of that, check coalitions
|
||||
if groupCoalition ~= airFieldSide then
|
||||
-- we have a problem. sides don't match
|
||||
if airFieldSide == 3
|
||||
or (cfxSSBClient.allowNeutralFields and airFieldSide == 0)
|
||||
then
|
||||
-- all is well, airfield is contested or neutral and
|
||||
-- we allow this plane to spawn here
|
||||
else
|
||||
-- DISALLOWED!!!!
|
||||
blockState = cfxSSBClient.disabledFlagValue
|
||||
comment = "!!!BLOCKED!!!"
|
||||
end
|
||||
end
|
||||
end
|
||||
-- set the ssb flag for this group so the server can see it
|
||||
|
||||
-- now set the ssb flag for this group so the server can see it
|
||||
if cfxSSBClient.verbose then
|
||||
local lastState = trigger.misc.getUserFlag(theName)
|
||||
if lastState ~= blockState then
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
csarManager = {}
|
||||
csarManager.version = "2.2.3"
|
||||
csarManager.version = "2.2.4"
|
||||
csarManager.verbose = false
|
||||
csarManager.ups = 1
|
||||
|
||||
@ -60,6 +60,8 @@ csarManager.ups = 1
|
||||
- directions to closest safe zone
|
||||
- CSARBASE attribute now carries coalition
|
||||
- deprecated coalition attribute
|
||||
- 2.2.4 - CSAR attribute value defaults name
|
||||
- start? attribute for CSAR as startCSAR? synonym
|
||||
|
||||
INTEGRATES AUTOMATICALLY WITH playerScore IF INSTALLED
|
||||
|
||||
@ -1273,18 +1275,18 @@ end
|
||||
function csarManager.readCSARZone(theZone)
|
||||
-- zones have attribute "CSAR"
|
||||
-- gather data, and then create a mission from this
|
||||
local mName = cfxZones.getStringFromZoneProperty(theZone, "CSAR", "Lt. Unknown")
|
||||
if mName == "" then mName = theZone.name end
|
||||
local theSide = cfxZones.getCoalitionFromZoneProperty(theZone, "coalition", 0)
|
||||
theZone.csarSide = theSide
|
||||
theZone.csarName = cfxZones.getStringFromZoneProperty(theZone, "name", "<none>")
|
||||
theZone.csarName = theZone.name -- default CSAR Name
|
||||
if cfxZones.hasProperty(theZone, "csarName") then
|
||||
theZone.csarName = mName -- now deprecating name attributes
|
||||
if cfxZones.hasProperty(theZone, "name") then
|
||||
theZone.csarName = cfxZones.getStringFromZoneProperty(theZone, "name", "<none>")
|
||||
elseif cfxZones.hasProperty(theZone, "csarName") then
|
||||
theZone.csarName = cfxZones.getStringFromZoneProperty(theZone, "csarName", "<none>")
|
||||
end
|
||||
if cfxZones.hasProperty(theZone, "pilotName") then
|
||||
elseif cfxZones.hasProperty(theZone, "pilotName") then
|
||||
theZone.csarName = cfxZones.getStringFromZoneProperty(theZone, "pilotName", "<none>")
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(theZone, "victimName") then
|
||||
elseif cfxZones.hasProperty(theZone, "victimName") then
|
||||
theZone.csarName = cfxZones.getStringFromZoneProperty(theZone, "victimName", "<none>")
|
||||
end
|
||||
|
||||
@ -1302,6 +1304,11 @@ function csarManager.readCSARZone(theZone)
|
||||
theZone.lastCSARVal = cfxZones.getFlagValue(theZone.startCSAR, theZone)
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(theZone, "start?") then
|
||||
theZone.startCSAR = cfxZones.getStringFromZoneProperty(theZone, "start?", "*none")
|
||||
theZone.lastCSARVal = cfxZones.getFlagValue(theZone.startCSAR, theZone)
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(theZone, "startCSAR?") then
|
||||
theZone.startCSAR = cfxZones.getStringFromZoneProperty(theZone, "startCSAR?", "*none")
|
||||
theZone.lastCSARVal = cfxZones.getFlagValue(theZone.startCSAR, theZone)
|
||||
@ -1479,29 +1486,18 @@ end
|
||||
improvements
|
||||
- need to stay on ground for x seconds to load troops
|
||||
- hot lz
|
||||
- hover recover
|
||||
- limit on troops aboard for transport
|
||||
- delay for drop-off
|
||||
|
||||
- csar when: always, only on eject,
|
||||
|
||||
|
||||
- repair o'clock
|
||||
|
||||
- nearest csarBase
|
||||
- red/blue csarbases
|
||||
- weight
|
||||
|
||||
|
||||
- compatibility: side/owner - make sure it is compatible
|
||||
with FARP, and landing on a FARP with opposition ownership
|
||||
will not disembark
|
||||
|
||||
- suppress multi smoke
|
||||
|
||||
|
||||
- when unloading one by menu, update weight!!!
|
||||
|
||||
-- allow any airfied to be csarsafe by default, no longer *requires* csarbase
|
||||
|
||||
-- allow neutral pick-up
|
||||
|
||||
-- allow any airfied to be csarsafe by default, no longer requires csarbase
|
||||
-- get vector to closes csarbase
|
||||
|
||||
-- support quad zones and optionally non-random placement
|
||||
--]]--
|
||||
@ -1,5 +1,5 @@
|
||||
delicates = {}
|
||||
delicates.version = "1.1.1"
|
||||
delicates.version = "1.1.2"
|
||||
delicates.verbose = false
|
||||
delicates.ups = 1
|
||||
delicates.requiredLibs = {
|
||||
@ -18,7 +18,7 @@ delicates.inventory = {}
|
||||
- safetyMargin - safety margin. defaults to 10%
|
||||
1.1.1 - addGroupToInventoryForZone
|
||||
- verbose for zone will show update event from useDelicates
|
||||
|
||||
1.1.2 - fixed uncaught delayed explosion for nil object
|
||||
--]]--
|
||||
function delicates.adddDelicates(theZone)
|
||||
table.insert(delicates.theDelicates, theZone)
|
||||
@ -194,8 +194,21 @@ function delicates.scheduledBlow(args)
|
||||
theObject = StaticObject.getByName(oName)
|
||||
else
|
||||
-- can't handle at the moment
|
||||
if delicates.verbose then
|
||||
trigger.action.outText("+++Deli: can't handle delicate explosion for object cat <" .. desc.cat .. ">, name <" .. desc.oName .. ">", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- now, the object might have been removed by now. catch this before we proceed
|
||||
if not theObject then
|
||||
if delicates.verbose then
|
||||
trigger.action.outText("+++Deli: NIL delicate for object blow at cat <" .. desc.cat .. ">, name <" .. desc.oName .. ">", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local theZone = desc.theZone
|
||||
local p = theObject:getPoint()
|
||||
local power = desc.theZone.power
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
taxiPolice = {}
|
||||
taxiPolice.version = "0.0.0"
|
||||
taxiPolice.version = "1.0.0"
|
||||
taxiPolice.verbose = true
|
||||
taxiPolice.ups = 1 -- checks per second
|
||||
taxiPolice.requiredLibs = {
|
||||
@ -7,32 +7,32 @@ taxiPolice.requiredLibs = {
|
||||
"cfxZones", -- Zones, of course
|
||||
}
|
||||
--[[--
|
||||
-- ensure that a player doesn't overspeed on taxiways. uses speedLimit and violateDuration to determine if to fine
|
||||
|
||||
-- create runway polys here: https://wiki.hoggitworld.com/view/DCS_func_getRunways
|
||||
|
||||
-- works as follows:
|
||||
-- when a player's plane is not inAir, they are monitored.
|
||||
-- when on a runway or too far from airfield (only airfields are monitored) monitoring ends
|
||||
-- when monitored and overspeeding, they first receive a warning, and after n warnings they receive retribution
|
||||
Version History
|
||||
1.0.0 - Initial version
|
||||
|
||||
--]]--
|
||||
|
||||
taxiPolice.speedLimit = 14 -- m/s . 14 m/s = 50 km/h, 10 m/s = 36 kmh
|
||||
taxiPolice.triggerTime = 3 -- seconds until we register a speeding violation
|
||||
taxiPolice.rwyLeeway = 5 -- meters on each side
|
||||
taxiPolice.rwyExtend = 500 -- meters in front and at end
|
||||
taxiPolice.airfieldMaxDist = 3000 -- radius around airfield in which we operate
|
||||
taxiPolice.runways = {} -- indexed by airbase name, then by rwName
|
||||
-- if nil, that base is not policed
|
||||
taxiPolice.suspects = {} -- units that are currently behaving naughty
|
||||
taxiPolice.tickets = {} -- number of warnings per player
|
||||
taxiPolice.maxTickets = 3 -- number of tickes without retribution
|
||||
|
||||
taxiPolice.lastMessageTo = {} -- used to suppress messages if too soon
|
||||
function taxiPolice.buildRunways()
|
||||
local bases = world.getAirbases()
|
||||
local mId = 0
|
||||
for idb, aBase in pairs (bases) do -- i = 1, #base do
|
||||
local name = aBase:getName()
|
||||
local rny = aBase:getRunways()
|
||||
if rny then
|
||||
-- Note that Airbase.Category values are not obtained by calling airbase:getCategory() - that calls Object.getCategory(airbase) and will always return the value Object.Category.BASE. Instead you need to use airbase:getDesc().category to obtain the Airbase.Category!
|
||||
local cat = aBase:getDesc().category
|
||||
|
||||
if rny and (cat == 0) then
|
||||
local runways = {}
|
||||
for idx, rwy in pairs(rny) do -- j = 1, #rny do
|
||||
-- calcualte quad that encloses taxiway
|
||||
@ -71,6 +71,7 @@ function taxiPolice.buildRunways()
|
||||
|
||||
taxiPolice.runways[name] = runways
|
||||
if taxiPolice.verbose then
|
||||
-- mark center of airbase in a red 200x200 square
|
||||
local points = {}
|
||||
local pStart = aBase:getPoint()
|
||||
local pEnd = aBase:getPoint()
|
||||
@ -85,6 +86,10 @@ function taxiPolice.buildRunways()
|
||||
mId = mId + 1
|
||||
trigger.action.quadToAll(-1, mId, points[1], points[2], points[3], points[4], {1, 0, 0, 1}, {1, 0, 0, .5}, 3)
|
||||
end
|
||||
else
|
||||
if taxiPolice.verbose then
|
||||
trigger.action.outText("No runways proccing for base <" .. name .. ">, cat = <" .. cat .. ">", 30)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -108,6 +113,10 @@ end
|
||||
|
||||
function taxiPolice.checkUnit(theUnit, allAirfields)
|
||||
if not theUnit.getPlayerName then return end
|
||||
local theGroup = theUnit:getGroup()
|
||||
local cat = theGroup:getCategory()
|
||||
if cat ~= 0 then return end -- not a fixed wing, disregard
|
||||
|
||||
local player = theUnit:getPlayerName()
|
||||
if not player then return end
|
||||
|
||||
@ -131,14 +140,13 @@ function taxiPolice.checkUnit(theUnit, allAirfields)
|
||||
-- check if we are on a runway
|
||||
local myRunways = taxiPolice.runways[base:getName()]
|
||||
if not myRunways then
|
||||
-- this base is turned off
|
||||
--trigger.action.outText("unable to find raunways for <" .. base:getName() .. ">", 30)
|
||||
-- this base is not policed
|
||||
taxiPolice.suspects[player] = nil
|
||||
return
|
||||
end
|
||||
|
||||
for rwName, aRunway in pairs(myRunways) do
|
||||
if cfxZones.isPointInsidePoly(p, aRunway) then
|
||||
--trigger.action.outText("<" .. theUnit:getName() .. "> is on RWY <" .. rwName .. ">", 30)
|
||||
taxiPolice.suspects[player] = nil -- remove watched status
|
||||
return
|
||||
end
|
||||
@ -184,10 +192,29 @@ end
|
||||
---
|
||||
--- UPDATE
|
||||
---
|
||||
function taxiPolice.update() -- every second
|
||||
|
||||
function taxiPolice.update() -- every second/ups
|
||||
-- schedule next invocation
|
||||
timer.scheduleFunction(taxiPolice.update, {}, timer.getTime() + 1/taxiPolice.ups)
|
||||
|
||||
--trigger.action.outText("onpatrol flag is " .. taxiPolice.onPatrol .. " with val = " .. trigger.misc.getUserFlag(taxiPolice.onPatrol), 30)
|
||||
-- see if this has been turned on or offDuty
|
||||
if taxiPolice.onPatrol and
|
||||
cfxZones.testZoneFlag(taxiPolice, taxiPolice.onPatrol, "change", "lastOnPatrol") then
|
||||
taxiPolice.active = true
|
||||
local knots = math.floor(taxiPolice.speedLimit * 1.94384)
|
||||
local kmh = math.floor(taxiPolice.speedLimit * 3.6)
|
||||
trigger.action.outText("NOTAM:\ntarmac and taxiway speed limit of " .. knots .. " knots/" .. kmh .. " km/h is enforced on all air fields!", 30)
|
||||
end
|
||||
|
||||
if taxiPolice.offDuty and
|
||||
cfxZones.testZoneFlag(taxiPolice, taxiPolice.offDuty, "change", "lastOffDuty") then
|
||||
taxiPolice.active = false
|
||||
trigger.action.outText("NOTAM:\ntarmac and taxiway speed limit rescinded. Taxi responsibly!", 30)
|
||||
end
|
||||
|
||||
if not taxiPolice.active then return end
|
||||
|
||||
local allAirfields = dcsCommon.getAirbasesWhoseNameContains("*", 0) -- all fixed bases, no FARP nor ships. Pre-collect
|
||||
|
||||
-- check all player units
|
||||
@ -203,6 +230,55 @@ function taxiPolice.update() -- every second
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- ONEVENT
|
||||
--
|
||||
|
||||
function taxiPolice:onEvent(theEvent)
|
||||
--trigger.action.outText("txP event: <" .. theEvent.id .. ">", 30)
|
||||
if not taxiPolice.greetings then return end -- no warnings
|
||||
if not taxiPolice.active then return end -- no policing active
|
||||
|
||||
local ID = theEvent.id
|
||||
if not ID then return end
|
||||
if (ID ~= 15) and (ID ~= 4) then return end -- not birth nor land
|
||||
local theUnit = theEvent.initiator
|
||||
if not theUnit then return end
|
||||
if theUnit:inAir() then return end
|
||||
|
||||
-- make sure it's a plane. Helos are ignored
|
||||
local theGroup = theUnit:getGroup()
|
||||
local cat = theGroup:getCategory()
|
||||
if cat ~= 0 then return end
|
||||
|
||||
if not theUnit.getPlayerName then return end
|
||||
local pName = theUnit:getPlayerName()
|
||||
if not pName then return end
|
||||
local base, dist = dcsCommon.getClosestAirbaseTo(theUnit:getPoint(), 0)
|
||||
local bName = base:getName()
|
||||
if dist > taxiPolice.airfieldMaxDist then return end
|
||||
|
||||
local UID = theUnit:getID()
|
||||
-- check if this airfield is exempt
|
||||
local rwys = taxiPolice.runways[bName]
|
||||
local now = timer.getTime()
|
||||
local last = taxiPolice.lastMessageTo[pName] -- remember timestamp
|
||||
if not last then last = 0 end
|
||||
local tdiff = now - last
|
||||
-- make sure palyer receives only one such notice within 15 seconds
|
||||
-- but always when now = 0 (mission startup)
|
||||
if (now ~= 0) and (tdiff < 15) then return end -- to soon
|
||||
taxiPolice.lastMessageTo[pName] = now
|
||||
if not rwys then
|
||||
trigger.action.outTextForUnit(UID, "Welcome to " .. bName .. ", " .. pName .. "!\nAlthough a general taxiway speed limit is in effect, it does not apply here.", 30)
|
||||
return
|
||||
end
|
||||
|
||||
local knots = math.floor(taxiPolice.speedLimit * 1.94384)
|
||||
local kmh = math.floor(taxiPolice.speedLimit * 3.6)
|
||||
trigger.action.outTextForUnit(UID, "Welcome to " .. bName .. ", " .. pName .. "!\nBe advised: a speed limit of " .. knots .. " knots/" .. kmh .. " km/h is enforced on tarmac and taxiways.", 30)
|
||||
end
|
||||
|
||||
--
|
||||
-- START
|
||||
--
|
||||
@ -232,6 +308,8 @@ function taxiPolice.readConfigZone()
|
||||
trigger.action.outText("+++txPol: no config zone!", 30)
|
||||
end
|
||||
end
|
||||
taxiPolice.name = "taxiPoliceConfig" -- cfxZones compatibility
|
||||
|
||||
taxiPolice.verbose = theZone.verbose
|
||||
|
||||
taxiPolice.speedLimit = cfxZones.getNumberFromZoneProperty(theZone, "speedLimit", 14) -- 14 -- m/s. 14 m/s = 50 km/h, 10 m/s = 36 kmh
|
||||
@ -240,7 +318,19 @@ function taxiPolice.readConfigZone()
|
||||
taxiPolice.rwyExtend = cfxZones.getNumberFromZoneProperty(theZone, "extend", 500) --500 -- meters in front and at end
|
||||
taxiPolice.airfieldMaxDist = cfxZones.getNumberFromZoneProperty(theZone, "radius", 3000) -- 3000 -- radius around airfield in which we operate
|
||||
taxiPolice.maxTickets = cfxZones.getNumberFromZoneProperty(theZone, "maxTickets", 3) -- 3
|
||||
|
||||
|
||||
taxiPolice.active = cfxZones.getBoolFromZoneProperty(theZone, "active", true)
|
||||
taxiPolice.greetings = cfxZones.getBoolFromZoneProperty(theZone, "greetings", true)
|
||||
|
||||
if cfxZones.hasProperty(theZone, "onPatrol") then
|
||||
taxiPolice.onPatrol = cfxZones.getStringFromZoneProperty(theZone, "onPatrol", "<none>")
|
||||
taxiPolice.lastOnPatrol = cfxZones.getFlagValue(taxiPolice.onPatrol, taxiPolice)
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(theZone, "offDuty") then
|
||||
taxiPolice.offDuty = cfxZones.getStringFromZoneProperty(theZone, "offDuty", "<none>")
|
||||
taxiPolice.lastOffDuty = cfxZones.getFlagValue(taxiPolice.offDuty, taxiPolice)
|
||||
end
|
||||
end
|
||||
|
||||
function taxiPolice.start()
|
||||
@ -265,6 +355,9 @@ function taxiPolice.start()
|
||||
-- start update
|
||||
taxiPolice.update()
|
||||
|
||||
-- install envent handler to greet pilots on airfields
|
||||
world.addEventHandler(taxiPolice)
|
||||
|
||||
-- say hi!
|
||||
trigger.action.outText("cfx taxiPolice v" .. taxiPolice.version .. " started.", 30)
|
||||
return true
|
||||
@ -276,5 +369,10 @@ if not taxiPolice.start() then
|
||||
taxiPolice = nil
|
||||
end
|
||||
|
||||
|
||||
--[[--
|
||||
Possible improvements
|
||||
- other sanctions on violations like kick, ban etc
|
||||
- call nearest airfield for open rwys (needs 'commandForUnit' first
|
||||
- ability to persist offenders
|
||||
--]]--
|
||||
|
||||
|
||||
Binary file not shown.
BIN
tutorial & demo missions/demo - Taxi Police.miz
Normal file
BIN
tutorial & demo missions/demo - Taxi Police.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user