mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 2.2.4
Slotty and friends
This commit is contained in:
parent
07a32bd051
commit
8b4080c218
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
FARPZones = {}
|
||||
FARPZones.version = "2.1.0"
|
||||
FARPZones.version = "2.1.1"
|
||||
FARPZones.verbose = false
|
||||
--[[--
|
||||
Version History
|
||||
@ -24,7 +24,7 @@ FARPZones.verbose = false
|
||||
2.0.2 - clean-up
|
||||
verbosity enhancements
|
||||
2.1.0 - integration with camp: needs repairs, produceResourceVehicles()
|
||||
|
||||
2.1.1 - loading a farp from data respaws all defenders and resource vehicles
|
||||
|
||||
--]]--
|
||||
|
||||
@ -547,6 +547,8 @@ function FARPZones.loadMission()
|
||||
local theAB = theFARP.mainFarp
|
||||
theAB:setCoalition(theFARP.owner) -- FARP is in lockup.
|
||||
theFARP.defenderData = dcsCommon.clone(fData.defenderData)
|
||||
|
||||
--[[--
|
||||
local groupData = fData.defenderData
|
||||
if groupData and #groupData.units > 0 then
|
||||
local cty = groupData.cty
|
||||
@ -560,11 +562,13 @@ function FARPZones.loadMission()
|
||||
local cat = groupData.cat
|
||||
theFARP.resources = coalition.addGroup(cty, cat, groupData)
|
||||
end
|
||||
--]]--
|
||||
FARPZones.produceVehicles(theFARP) -- do full defender and resource cycle
|
||||
FARPZones.drawFARPCircleInMap(theFARP) -- mark in map
|
||||
if (not theFARP.defenders) and (not theFARP.resources) then
|
||||
-- if (not theFARP.defenders) and (not theFARP.resources) then
|
||||
-- we instigate a resource and defender drop
|
||||
FARPZones.produceVehicles(theFARP)
|
||||
end
|
||||
-- FARPZones.produceVehicles(theFARP)
|
||||
-- end
|
||||
else
|
||||
trigger.action.outText("frpZ: persistence: FARP <" .. fName .. "> no longer exists in mission, skipping", 30)
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxSSBClient = {}
|
||||
cfxSSBClient.version = "4.0.0"
|
||||
cfxSSBClient.version = "4.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
|
||||
@ -16,6 +16,8 @@ cfxSSBClient.requiredLibs = {
|
||||
Version History
|
||||
4.0.0 - dmlZones
|
||||
- cfxMX instead of cfxGroups
|
||||
4.0.1 - check slot availability immediately upon start
|
||||
- ssb autoenable option
|
||||
--]]--
|
||||
|
||||
cfxSSBClient.enabledFlagValue = 0 -- DO NOT CHANGE, MUST MATCH SSB
|
||||
@ -490,33 +492,31 @@ function cfxSSBClient.readConfigZone()
|
||||
-- note: must match exactly!!!!
|
||||
local theZone = cfxZones.getZoneByName("SSBClientConfig")
|
||||
if not theZone then
|
||||
trigger.action.outText("+++SSBC: no config zone!", 30)
|
||||
return
|
||||
theZone = cfxZones.createSimpleZone("SSBClientConfig")
|
||||
end
|
||||
|
||||
trigger.action.outText("+++SSBC: found config zone!", 30)
|
||||
|
||||
cfxSSBClient.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
|
||||
cfxSSBClient.verbose = theZone.verbose
|
||||
|
||||
-- single-use
|
||||
cfxSSBClient.singleUse = cfxZones.getBoolFromZoneProperty(theZone, "singleUse", false) -- use airframes only once? respawn after kick must be disabled in ssb
|
||||
cfxSSBClient.reUseAfter = cfxZones.getNumberFromZoneProperty(theZone, "reUseAfter", -1)
|
||||
cfxSSBClient.singleUse = theZone:getBoolFromZoneProperty("singleUse", false) -- use airframes only once? respawn after kick must be disabled in ssb
|
||||
cfxSSBClient.reUseAfter = theZone:getNumberFromZoneProperty( "reUseAfter", -1)
|
||||
|
||||
-- airfield availability
|
||||
cfxSSBClient.allowNeutralFields = cfxZones.getBoolFromZoneProperty(theZone, "allowNeutralFields", false)
|
||||
cfxSSBClient.allowNeutralFields = theZone:getBoolFromZoneProperty( "allowNeutralFields", false)
|
||||
|
||||
cfxSSBClient.maxAirfieldRange = cfxZones.getNumberFromZoneProperty(theZone, "maxAirfieldRange", 3000) -- meters, to find attached airfield
|
||||
cfxSSBClient.maxAirfieldRange = theZone:getNumberFromZoneProperty("maxAirfieldRange", 3000) -- meters, to find attached airfield
|
||||
|
||||
-- optimization
|
||||
|
||||
cfxSSBClient.keepInAirGroups = cfxZones.getBoolFromZoneProperty(theZone, "keepInAirGroups", false)
|
||||
cfxSSBClient.keepInAirGroups = theZone:getBoolFromZoneProperty("keepInAirGroups", false)
|
||||
|
||||
-- SSB direct control.
|
||||
-- USE ONLY WHEN YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
|
||||
cfxSSBClient.enabledFlagValue = cfxZones.getNumberFromZoneProperty(theZone, "enabledFlagValue", 0)
|
||||
cfxSSBClient.enabledFlagValue = theZone:getNumberFromZoneProperty("enabledFlagValue", 0)
|
||||
|
||||
cfxSSBClient.disabledFlagValue = cfxZones.getNumberFromZoneProperty(theZone, "disabledFlagValue", cfxSSBClient.enabledFlagValue + 100)
|
||||
cfxSSBClient.disabledFlagValue = theZone:getNumberFromZoneProperty("disabledFlagValue", cfxSSBClient.enabledFlagValue + 100)
|
||||
|
||||
cfxSSBClient.ssbAutoenable = theZone:getBoolFromZoneProperty("ssbAutoenable", true)
|
||||
end
|
||||
|
||||
--
|
||||
@ -601,13 +601,18 @@ function cfxSSBClient.start()
|
||||
|
||||
-- install a timed update just to make sure
|
||||
-- and start NOW
|
||||
timer.scheduleFunction(cfxSSBClient.update, {}, timer.getTime() + 1)
|
||||
-- timer.scheduleFunction(cfxSSBClient.update, {}, timer.getTime() + 1)
|
||||
cfxSSBClient.update()
|
||||
|
||||
-- start dml update (on a different timer
|
||||
cfxSSBClient.dmlUpdate()
|
||||
|
||||
-- now turn on ssb
|
||||
if cfxSSBClient.ssbAutoenable then
|
||||
trigger.action.setUserFlag("SSB",100)
|
||||
else
|
||||
trigger.action.outText("WARNING: cfxSSBClient did !!NOT!! auto-enable SSB for mission.", 30)
|
||||
end
|
||||
|
||||
-- persistence: load states
|
||||
if persistence then
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
bombRange = {}
|
||||
bombRange.version = "1.1.2"
|
||||
bombRange.version = "1.1.3"
|
||||
bombRange.dh = 1 -- meters above ground level burst
|
||||
|
||||
bombRange.requiredLibs = {
|
||||
@ -21,6 +21,7 @@ VERSION HISTORY
|
||||
1.1.1 - fixed reading smoke color for zone
|
||||
minor clean-up
|
||||
1.1.2 - corrected bug when no bomb range is detected
|
||||
1.1.3 - added meters/feet distance when reporting impact
|
||||
|
||||
--]]--
|
||||
bombRange.bombs = {} -- live tracking
|
||||
@ -543,7 +544,8 @@ function bombRange.impacted(weapon, target, finalPass)
|
||||
tDist = math.floor(tDist*100) /100
|
||||
trigger.action.outTextForGroup(weapon.gID, "impact of " .. weapon.type .. " released by " .. weapon.pName .. " from " .. weapon.uType .. " after traveling " .. tDist .. " km in " .. t .. " sec, impact velocity at impact is " .. v .. " m/s!", 30)
|
||||
end
|
||||
|
||||
local meters = math.floor(minDist * 10) / 10
|
||||
local feet = math.floor(minDist * 3.28084 * 10) / 10
|
||||
local msg = ""
|
||||
if impactInside then
|
||||
local percentage = 0
|
||||
@ -553,15 +555,17 @@ function bombRange.impacted(weapon, target, finalPass)
|
||||
percentage = 1 - (minDist / theRange.radius)
|
||||
percentage = math.floor(percentage * 100)
|
||||
end
|
||||
|
||||
|
||||
msg = "INSIDE target area"
|
||||
if theRange.reportName then msg = msg .. " " .. theRange.name end
|
||||
if (not targetName) and theRange.details then msg = msg .. ", off-center by " .. math.floor(minDist *10)/10 .. " m" end
|
||||
if (not targetName) and theRange.details then msg = msg .. ", off-center by " .. meters .. "m/" .. feet .. "ft" end--math.floor(minDist *10)/10 .. " m" end
|
||||
if targetName then msg = msg .. ", hit on " .. targetName end
|
||||
|
||||
if not theRange.usePercentage then
|
||||
percentage = 100
|
||||
else
|
||||
msg = msg .. " (Quality " .. percentage .."%)"
|
||||
msg = msg .. " (Quality " .. percentage .."%)" --, off-center by " .. meters .. "m/" .. feet .. "ft)"
|
||||
end
|
||||
|
||||
if theRange.hitOut then
|
||||
@ -572,7 +576,7 @@ function bombRange.impacted(weapon, target, finalPass)
|
||||
else
|
||||
msg = "Outside target area"
|
||||
if theRange.reportName then msg = msg .. " " .. theRange.name end
|
||||
if theRange.details then msg = msg .. " (off-center by " .. math.floor(minDist *10)/10 .. " m)" end
|
||||
if theRange.details then msg = msg .. " (off-center by " .. meters .. "m/" .. feet .. "ft)" end --math.floor(minDist *10)/10 .. " m)" end
|
||||
msg = msg .. ", no hit."
|
||||
bombRange.addImpactForWeapon(weapon, false, 0)
|
||||
end
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
-- *** EXTENDS ZONES: 'pathing' attribute
|
||||
--
|
||||
cfxCommander = {}
|
||||
cfxCommander.version = "1.1.4"
|
||||
cfxCommander.version = "2.0.0"
|
||||
--[[-- VERSION HISTORY
|
||||
- 1.0.5 - createWPListForGroupToPointViaRoads: detect no road found
|
||||
- 1.0.6 - build in more group checks in assign wp list
|
||||
@ -30,7 +30,11 @@ cfxCommander.version = "1.1.4"
|
||||
- 1.1.3 - isExist() guard improvements for multiple methods
|
||||
- cleaned up comments
|
||||
- 1.1.4 - hardened makeGroupGoThere()
|
||||
|
||||
- 2.0.0 - dml zones
|
||||
- units now can move with moveFormation
|
||||
- hardened performCommands()
|
||||
- createWPListForGroupToPoint() supports moveFormation
|
||||
- makeGroupGoTherePreferringRoads() supports moveFormation
|
||||
--]]--
|
||||
|
||||
cfxCommander.requiredLibs = {
|
||||
@ -72,16 +76,11 @@ function cfxCommander.readConfigZone()
|
||||
-- note: must match exactly!!!!
|
||||
local theZone = cfxZones.getZoneByName("CommanderConfig")
|
||||
if not theZone then
|
||||
trigger.action.outText("+++cmdr: no config zone!", 30)
|
||||
return
|
||||
theZone = cfxZones.createSimpleZone("CommanderConfig")
|
||||
end
|
||||
|
||||
trigger.action.outText("+++cmdr: found config zone!", 30)
|
||||
|
||||
cfxCommander.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
|
||||
cfxCommander.forceOffRoad = cfxZones.getBoolFromZoneProperty(theZone, "forceOffRoad", false) -- if true, vehicles path follow roads, but may drive offroad
|
||||
cfxCommander.noRoadsAtAll = cfxZones.getBoolFromZoneProperty(theZone, "noRoadsAtAll", false)
|
||||
|
||||
cfxCommander.verbose = theZone.verbose
|
||||
cfxCommander.forceOffRoad = theZone:getBoolFromZoneProperty("forceOffRoad", false) -- if true, vehicles path follow roads, but may drive offroad
|
||||
cfxCommander.noRoadsAtAll = theZone:getBoolFromZoneProperty("noRoadsAtAll", false)
|
||||
end
|
||||
|
||||
--
|
||||
@ -118,8 +117,14 @@ function cfxCommander.performCommands(commandData)
|
||||
if not commandData.group then
|
||||
commandData.group = Group.getByName(commandData.name) -- better be inited!
|
||||
end
|
||||
if not Group.isExist(commandData.group) then
|
||||
-- something bad is happening
|
||||
return nil
|
||||
end
|
||||
-- get the AI
|
||||
local theController = commandData.group:getController()
|
||||
if not theController then return nil end
|
||||
|
||||
for i=1, #commandData.commands do
|
||||
if cfxCommander.verbose then
|
||||
trigger.action.outText("Commander: performing " .. commandData.commands[i].id, 30)
|
||||
@ -204,7 +209,6 @@ function cfxCommander.doScheduledTask(data)
|
||||
local theGroup = data.group
|
||||
if not theGroup then return end
|
||||
if not Group.isExist(theGroup) then return end
|
||||
-- if not theGroup.isExist then return end
|
||||
|
||||
local theController = theGroup:getController()
|
||||
theController:pushTask(data.task)
|
||||
@ -262,7 +266,7 @@ function cfxCommander.createBasicWaypoint(point, speed, formation)
|
||||
|
||||
if not formation then formation = "Off Road" end
|
||||
-- legal formations:
|
||||
-- Off road
|
||||
-- Off Road
|
||||
-- On Road -- second letter upper case?
|
||||
-- Cone
|
||||
-- Rank
|
||||
@ -300,21 +304,22 @@ function cfxCommander.assignWPListToGroup(group, wpList, delay)
|
||||
local theTask = cfxCommander.buildTaskFromWPList(wpList)
|
||||
local ctrl = group:getController()
|
||||
|
||||
--[[--
|
||||
if delay < 0.001 then -- immediate action
|
||||
if ctrl then
|
||||
ctrl:setTask(theTask)
|
||||
end
|
||||
else
|
||||
-- delay execution of this command by the specified amount
|
||||
-- of seconds
|
||||
cfxCommander.scheduleTaskForGroup(group, theTask, delay)
|
||||
end
|
||||
--]]--
|
||||
cfxCommander.scheduleTaskForGroup(group, theTask, delay)
|
||||
end
|
||||
|
||||
function cfxCommander.createWPListForGroupToPoint(group, point, speed, formation)
|
||||
--[[--
|
||||
Formations and their "action" keywords
|
||||
Line Abreast = "Rank"
|
||||
Cone = "Cone"
|
||||
Vee = "Vee"
|
||||
Diamond = "Diamond"
|
||||
Echelon Left = "EchelonL"
|
||||
Echelon Right = "EchelonR"
|
||||
Custom = "Custom"
|
||||
|
||||
--]]--
|
||||
|
||||
function cfxCommander.createWPListForGroupToPoint(group, point, speed, moveFormation)
|
||||
if type(group) == 'string' then -- group name
|
||||
group = Group.getByName(group)
|
||||
end
|
||||
@ -323,8 +328,8 @@ function cfxCommander.createWPListForGroupToPoint(group, point, speed, formation
|
||||
-- here we are, and we want to go there. In DCS, this means that
|
||||
-- we need to create a wp list consisting of here and there
|
||||
local here = dcsCommon.getGroupLocation(group)
|
||||
local wpHere = cfxCommander.createBasicWaypoint(here, speed, formation)
|
||||
local wpThere = cfxCommander.createBasicWaypoint(point, speed, formation)
|
||||
local wpHere = cfxCommander.createBasicWaypoint(here, speed, moveFormation)
|
||||
local wpThere = cfxCommander.createBasicWaypoint(point, speed, moveFormation)
|
||||
wpList[1] = wpHere
|
||||
wpList[2] = wpThere
|
||||
return wpList
|
||||
@ -398,12 +403,9 @@ function cfxCommander.createWPListForGroupToPointViaRoads(group, point, speed)
|
||||
|
||||
if pathLength > (2 * direct) then
|
||||
-- road takes too long, take direct approach
|
||||
--trigger.action.outText("+++ road path (" .. pathLength .. ") > twice direct route(" .. direct .. "), commencing direct off-road", 30)
|
||||
return cfxCommander.createWPListForGroupToPoint(group, point, speed)
|
||||
end
|
||||
|
||||
--trigger.action.outText("+++ ".. group:getName() .. ": choosing road path l=" .. pathLength .. " over direct route d=" .. direct, 30)
|
||||
|
||||
-- if we are here, the road trip is valid
|
||||
for idx, wp in pairs(rawRoadPoints) do
|
||||
-- createBasic... supports w.xy format
|
||||
@ -422,16 +424,17 @@ function cfxCommander.createWPListForGroupToPointViaRoads(group, point, speed)
|
||||
return wpList
|
||||
end
|
||||
|
||||
function cfxCommander.makeGroupGoTherePreferringRoads(group, there, speed, delay)
|
||||
function cfxCommander.makeGroupGoTherePreferringRoads(group, there, speed, delay, moveFormation)
|
||||
if type(group) == 'string' then -- group name
|
||||
group = Group.getByName(group)
|
||||
end
|
||||
if not delay then delay = 0 end
|
||||
|
||||
if not moveFormation then moveFormation = "Off Road" end
|
||||
|
||||
if cfxCommander.noRoadsAtAll then
|
||||
-- we don't even follow roads, completely forced off
|
||||
cfxCommander.makeGroupGoThere(group, there, speed, "Off Road", delay)
|
||||
cfxCommander.makeGroupGoThere(group, there, speed, moveFormation, delay)
|
||||
return
|
||||
end
|
||||
|
||||
@ -443,7 +446,7 @@ function cfxCommander.makeGroupGoTherePreferringRoads(group, there, speed, delay
|
||||
local oRide = cfxCommander.hasPathZoneFor(here, there)
|
||||
if oRide and oRide.pathing == "offroad" then
|
||||
-- yup, override road preference
|
||||
cfxCommander.makeGroupGoThere(group, there, speed, "Off Road", delay)
|
||||
cfxCommander.makeGroupGoThere(group, there, speed, moveFormation, delay)
|
||||
return
|
||||
end
|
||||
end
|
||||
@ -498,9 +501,6 @@ function cfxCommander.start()
|
||||
|
||||
-- identify and process all 'pathing' zones
|
||||
local pathZones = cfxZones.getZonesWithAttributeNamed("pathing")
|
||||
|
||||
-- now create a spawner for all, add them to the spawner updater, and spawn for all zones that are not
|
||||
-- paused
|
||||
for k, aZone in pairs(pathZones) do
|
||||
cfxCommander.processPathingZone(aZone) -- process attribute and add to zone
|
||||
cfxCommander.addPathingZone(aZone) -- remember it so we can smoke it
|
||||
|
||||
@ -1075,7 +1075,7 @@ function csarManager.updateCSARMissions()
|
||||
else
|
||||
local msg = aMission.name .. " confirmed KIA, repeat KIA. Abort CSAR."
|
||||
trigger.action.outTextForCoalition(aMission.side, msg, 30)
|
||||
trigger.action.outSoundForCoalition(aMission.side, csarManager.actionSound)
|
||||
trigger.action.outSoundForCoalition(aMission.side, csarManager.lostSound)
|
||||
csarManager.invokeCallbacks(aMission.side, false, 1, "KIA", aMission)
|
||||
end
|
||||
end
|
||||
@ -1765,4 +1765,6 @@ end
|
||||
|
||||
-- may want to change if time limit was exceeded on return to tell
|
||||
player that they did not survive the transport
|
||||
|
||||
- randomize smoke color if smoke color has more than one entries
|
||||
--]]--
|
||||
@ -1,5 +1,5 @@
|
||||
dcsCommon = {}
|
||||
dcsCommon.version = "3.0.6"
|
||||
dcsCommon.version = "3.0.7"
|
||||
--[[-- VERSION HISTORY
|
||||
3.0.0 - removed bad bug in stringStartsWith, only relevant if caseSensitive is false
|
||||
- point2text new intsOnly option
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
cfxGroundTroops = {}
|
||||
cfxGroundTroops.version = "2.0.1"
|
||||
cfxGroundTroops.ups = 1
|
||||
cfxGroundTroops.version = "2.2.0"
|
||||
cfxGroundTroops.ups = 0.25 -- every 4 seconds
|
||||
cfxGroundTroops.verbose = false
|
||||
cfxGroundTroops.requiredLibs = {
|
||||
"dcsCommon", -- common is of course needed for everything
|
||||
@ -29,10 +29,11 @@ cfxGroundTroops.jtacCB = {} -- jtac callbacks, to be implemented
|
||||
|
||||
2.0.0 - dmlZones
|
||||
- jtacSound
|
||||
- clanup
|
||||
- cleanup
|
||||
- jtacVerbose
|
||||
2.0.1 - small fiex ti checkPileUp()
|
||||
|
||||
2.1.0 - captureandhold - oneshot attackowned
|
||||
2.2.0 - moveFormation support
|
||||
|
||||
an entry into the deployed troop table has the following attributes
|
||||
- group - the group
|
||||
@ -41,6 +42,8 @@ cfxGroundTroops.jtacCB = {} -- jtac callbacks, to be implemented
|
||||
"laze" - will stay in place and try to laze visible vehicles in range
|
||||
"attackOwnedZone" - interface to cfxOwnedZones module, seeks out
|
||||
enemy zones to attack and capture them
|
||||
"captureandhold" - interface to ownedZones, seeks out nearest enemy
|
||||
or neutral owned zone. once captured, it stays there
|
||||
"wait-<some other orders>" do nothing. the "wait" prefix will be removed some time and <some other order> then revealed. Used at least by heloTroops
|
||||
"train" - target dummies. ROE=HOLD, no ground loop
|
||||
"attack" - transition to destination, once there, stop and
|
||||
@ -53,6 +56,7 @@ cfxGroundTroops.jtacCB = {} -- jtac callbacks, to be implemented
|
||||
- lazeTarget - target currently lazing
|
||||
- lazeCode - laser code. default is 1688
|
||||
- moving - has been given orders to move somewhere already. used for first movement order with attack orders
|
||||
-- reduced ups to 0.24, updating troops every 4 seconds is fast enough
|
||||
|
||||
|
||||
usage:
|
||||
@ -169,9 +173,9 @@ function cfxGroundTroops.makeTroopsEngageEnemies(troop)
|
||||
|
||||
-- we lerp to 2/3 of enemy location
|
||||
there = dcsCommon.vLerp(from, there, 0.66)
|
||||
|
||||
local moveFormation = troop.moveFormation
|
||||
local speed = 10 -- m/s = 10 km/h -- wait. 10 m/s is 36 km/h
|
||||
cfxCommander.makeGroupGoThere(group, there, speed)
|
||||
cfxCommander.makeGroupGoThere(group, there, speed, moveFormation)
|
||||
local attask = cfxCommander.createAttackGroupCommand(enemies)
|
||||
cfxCommander.scheduleTaskForGroup(group, attask, 0.5)
|
||||
troop.moving = true
|
||||
@ -189,15 +193,20 @@ function cfxGroundTroops.makeTroopsEngageZone(troop)
|
||||
local enemyZone = troop.destination -- must be cfxZone
|
||||
local from = dcsCommon.getGroupLocation(group)
|
||||
if not from then return end -- the group died
|
||||
local there = enemyZone.point -- access zone position
|
||||
local there = enemyZone:getPoint() -- access zone position
|
||||
if not there then return end
|
||||
|
||||
local speed = 14 -- m/s; 10 m/s = 36 km/h
|
||||
|
||||
-- make troops stop in 1 second, then start in 5 seconds to give AI respite
|
||||
cfxCommander.makeGroupHalt(group, 1) -- 1 second delay
|
||||
cfxCommander.makeGroupGoTherePreferringRoads(group, there, speed, 5)
|
||||
|
||||
if troop.orders == "captureandhold" then
|
||||
-- direct capture never uses roads
|
||||
cfxCommander.makeGroupGoThere(group, there, speed, troop.moveFormation, 5)
|
||||
else
|
||||
-- when we attack any owned zone, we prefer roads
|
||||
cfxCommander.makeGroupGoTherePreferringRoads(group, there, speed, 5, troop.moveFormation)
|
||||
end
|
||||
-- remember that we have issued a move order
|
||||
troop.moving = true
|
||||
end
|
||||
@ -236,6 +245,10 @@ end
|
||||
-- are heading for is already owned by their side, then look for
|
||||
-- the closest enemy zone, and cut attack orders to move there
|
||||
function cfxGroundTroops.getClosestEnemyZone(troop)
|
||||
if not cfxOwnedZones then
|
||||
trigger.action.outText("+++groundT: WARNING! ownedZones is not loaded, which is required.", 30)
|
||||
return nil
|
||||
end
|
||||
local p = dcsCommon.getGroupLocation(troop.group)
|
||||
local tempZone = cfxZones.createSimpleZone("tz", p, 100)
|
||||
tempZone.owner = troop.side
|
||||
@ -251,6 +264,17 @@ function cfxGroundTroops.updateZoneAttackers(troop)
|
||||
end
|
||||
troop.insideDestination = false -- mark as not inside
|
||||
|
||||
-- we *have* a destination, but not yet isued move orders,
|
||||
-- meaning that we just spawned, probably from helo.
|
||||
-- do not look for new location, issue move orders instead
|
||||
if not troop.hasMovedOrders and troop.destination then
|
||||
troop.hasMovedOrders = true
|
||||
cfxGroundTroops.makeTroopsEngageZone(troop)
|
||||
troop.lastOrderDate = timer.getTime()
|
||||
troop.speedWarning = 0
|
||||
return
|
||||
end
|
||||
|
||||
local newTargetZone = cfxGroundTroops.getClosestEnemyZone(troop)
|
||||
if not newTargetZone then
|
||||
-- all target zones are friendly, go to guard mode
|
||||
@ -259,6 +283,12 @@ function cfxGroundTroops.updateZoneAttackers(troop)
|
||||
end
|
||||
|
||||
if newTargetZone ~= troop.destination then
|
||||
if troop.destination and troop.orders == "captureandhold" then
|
||||
troop.lastOrderDate = timer.getTime() -- we may even dismiss them
|
||||
-- from troop array. But orders should remain when picked up by helo
|
||||
-- we never change target. Stay.
|
||||
return
|
||||
end
|
||||
troop.destination = newTargetZone
|
||||
cfxGroundTroops.makeTroopsEngageZone(troop)
|
||||
troop.lastOrderDate = timer.getTime()
|
||||
@ -532,6 +562,10 @@ function cfxGroundTroops.updateWait(troop)
|
||||
end
|
||||
|
||||
function cfxGroundTroops.updateTroops(troop)
|
||||
if cfxGroundTroops.verbose then
|
||||
trigger.action.outText("+++GTroop: enter updateTroopps for <" .. troop.name .. ">", 30)
|
||||
end
|
||||
|
||||
-- if orders start with "wait-" then the troops
|
||||
-- simply do nothing
|
||||
if dcsCommon.stringStartsWith(troop.orders, "wait-") then
|
||||
@ -547,6 +581,9 @@ function cfxGroundTroops.updateTroops(troop)
|
||||
elseif troop.orders == "attackownedzone" then
|
||||
cfxGroundTroops.updateZoneAttackers(troop)
|
||||
|
||||
elseif troop.orders == "captureandhold" then
|
||||
cfxGroundTroops.updateZoneAttackers(troop)
|
||||
|
||||
elseif troop.orders == "laze" then
|
||||
cfxGroundTroops.updateLaze(troop)
|
||||
|
||||
@ -880,14 +917,16 @@ end
|
||||
-- createGroundTroop
|
||||
-- use this to create a cfxGroundTroops from a dcs group
|
||||
--
|
||||
function cfxGroundTroops.createGroundTroops(inGroup, range, orders)
|
||||
function cfxGroundTroops.createGroundTroops(inGroup, range, orders, moveFormation)
|
||||
local newTroops = {}
|
||||
if not orders then
|
||||
orders = "guard"
|
||||
end
|
||||
if not moveFormation then moveFormation = "Custom" end
|
||||
if orders:lower() == "lase" then
|
||||
orders = "laze" -- we use WRONG spelling here, cause we're cool. yeah, right.
|
||||
end
|
||||
trigger.action.outText("Enter createGT group <" .. inGroup:getName() .. "> with o=<" .. orders .. ">, mf=<" .. moveFormation .. ">", 30)
|
||||
newTroops.insideDestination = false
|
||||
newTroops.unscheduleCount = 0 -- will count up as we aren't scheduled
|
||||
newTroops.speedWarning = 0
|
||||
@ -897,6 +936,7 @@ function cfxGroundTroops.createGroundTroops(inGroup, range, orders)
|
||||
newTroops.coalition = inGroup:getCoalition()
|
||||
newTroops.side = newTroops.coalition -- because we'e been using both.
|
||||
newTroops.name = inGroup:getName()
|
||||
newTroops.moveFormation = moveFormation
|
||||
newTroops.moving = false -- set to not have received move orders yet
|
||||
newTroops.signature = "cfx" -- to verify this is groundTroop group, not dcs groups
|
||||
if not range then range = 300 end
|
||||
@ -912,6 +952,7 @@ function cfxGroundTroops.addGroundTroopsToPool(troops) -- troops MUST be a table
|
||||
end
|
||||
if not troops.orders then troops.orders = "guard" end
|
||||
troops.orders = troops.orders:lower()
|
||||
if not troops.moveFormation then troops.moveFormation = "Custom" end
|
||||
troops.reschedule = true -- in case we use scheduled update
|
||||
-- we now add to internal array. this is worked on by all
|
||||
-- update meths, on scheduled upadtes, it is only used to
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxHeloTroops = {}
|
||||
cfxHeloTroops.version = "3.0.3"
|
||||
cfxHeloTroops.version = "3.0.4"
|
||||
cfxHeloTroops.verbose = false
|
||||
cfxHeloTroops.autoDrop = true
|
||||
cfxHeloTroops.autoPickup = false
|
||||
@ -40,6 +40,7 @@ cfxHeloTroops.requestRange = 500 -- meters
|
||||
3.0.1 - fixed a bug with legalTroops attribute
|
||||
3.0.2 - fixed a typo in in-air menu
|
||||
3.0.3 - pointInZone check for insertion rather than radius
|
||||
3.0.4 - also handles picking up troops with orders "captureandhold"
|
||||
|
||||
--]]--
|
||||
--
|
||||
@ -52,8 +53,6 @@ cfxHeloTroops.requestRange = 500 -- meters
|
||||
|
||||
cfxHeloTroops.requiredLibs = {
|
||||
"dcsCommon", -- common is of course needed for everything
|
||||
-- pretty stupid to check for this since we
|
||||
-- need common to invoke the check, but anyway
|
||||
"cfxZones", -- Zones, of course
|
||||
"cfxCommander", -- to make troops do stuff
|
||||
"cfxGroundTroops", -- generic when dropping troops
|
||||
@ -641,6 +640,7 @@ function cfxHeloTroops.deployTroopsFromHelicopter(conf)
|
||||
local orders = conf.troopsOnBoard.orders
|
||||
local dest = conf.troopsOnBoard.destination
|
||||
local theName = conf.troopsOnBoard.name
|
||||
local moveFormation = conf.troopsOnBoard.moveFormation
|
||||
|
||||
if not orders then orders = "guard" end
|
||||
|
||||
@ -670,7 +670,15 @@ function cfxHeloTroops.deployTroopsFromHelicopter(conf)
|
||||
troopData.destination = dest -- only for attackzone orders
|
||||
cfxHeloTroops.deployedTroops[theData.name] = troopData
|
||||
|
||||
local troop = cfxGroundTroops.createGroundTroops(theGroup, range, orders)
|
||||
local troop = cfxGroundTroops.createGroundTroops(theGroup, range, orders, moveFormation)
|
||||
if orders == "captureandhold" then
|
||||
-- we get the target zone NOW!!! before we flip the zone and
|
||||
-- and make them run to the wrong zone
|
||||
dest = cfxGroundTroops.getClosestEnemyZone(troop)
|
||||
troopData.destination = dest
|
||||
trigger.action.outText("Inserting troops to capture zone <" .. dest.name .. ">", 30)
|
||||
end
|
||||
|
||||
troop.destination = dest -- transfer target zone for attackzone oders
|
||||
cfxGroundTroops.addGroundTroopsToPool(troop) -- will schedule move orders
|
||||
trigger.action.outTextForGroup(conf.id, "<" .. theGroup:getName() .. "> have deployed to the ground with orders " .. orders .. "!", 30)
|
||||
@ -735,8 +743,13 @@ function cfxHeloTroops.doLoadGroup(args)
|
||||
conf.troopsOnBoard.orders = pooledGroup.orders
|
||||
conf.troopsOnBoard.range = pooledGroup.range
|
||||
conf.troopsOnBoard.destination = pooledGroup.destination -- may be nil
|
||||
conf.troopsOnBoard.moveFormation = pooledGroup.moveFormation
|
||||
if pooledGroup.orders and pooledGroup.orders == "captureandhold" then
|
||||
conf.troopsOnBoard.destination = nil -- forget last destination so they can be helo-redeployed
|
||||
end
|
||||
cfxGroundTroops.removeTroopsFromPool(pooledGroup)
|
||||
trigger.action.outTextForGroup(conf.id, "Team '".. conf.troopsOnBoard.name .."' loaded and has orders <" .. conf.troopsOnBoard.orders .. ">", 30)
|
||||
-- trigger.action.outText("and mf = <" .. conf.troopsOnBoard.moveFormation .. ">", 30)
|
||||
--trigger.action.outSoundForGroup(conf.id, cfxHeloTroops.actionSound) -- "Quest Snare 3.wav")
|
||||
else
|
||||
if cfxHeloTroops.verbose then
|
||||
|
||||
@ -65,10 +65,12 @@ function income.update()
|
||||
has, balance = bank.getBalance(1)
|
||||
tick = string.gsub(income.tickMessage, "<i>", redI)
|
||||
trigger.action.outTextForCoalition(1, "\n" .. tick .. "\nNew balance: §" .. balance .. "\n", 30)
|
||||
trigger.action.outSoundForCoalition(1, income.reportSound)
|
||||
|
||||
has, balance = bank.getBalance(2)
|
||||
tick = string.gsub(income.tickMessage, "<i>", blueI)
|
||||
trigger.action.outTextForCoalition(2, "\n" .. tick .. "\nNew balance: §" .. balance .. "\n", 30)
|
||||
trigger.action.outSoundForCoalition(2, income.reportSound)
|
||||
end
|
||||
|
||||
end
|
||||
@ -88,6 +90,8 @@ function income.readConfigZone()
|
||||
income.interval = theZone:getNumberFromZoneProperty("interval", 10 * 60) -- every 10 minutes
|
||||
income.tickMessage = theZone:getStringFromZoneProperty("tickMessage", "New funds from income available: §<i>")
|
||||
income.announceTicks = theZone:getBoolFromZoneProperty("announceTicks", true)
|
||||
income.reportSound = theZone:getStringFromZoneProperty("reportSound", "<none>")
|
||||
|
||||
income.verbose = theZone.verbose
|
||||
end
|
||||
|
||||
|
||||
254
modules/launchPlatform.lua
Normal file
254
modules/launchPlatform.lua
Normal file
@ -0,0 +1,254 @@
|
||||
launchPlatform = {}
|
||||
launchPlatform.version = "0.0.0"
|
||||
launchPlatform.requiredLibs = {
|
||||
"dcsCommon",
|
||||
"cfxZones",
|
||||
}
|
||||
launchPlatform.zones = {}
|
||||
launchPlatform.redLaunchers = {}
|
||||
launchPlatform.blueLaunchers = {}
|
||||
|
||||
-- weapon types currently known
|
||||
-- 52613349374 = tomahawk
|
||||
|
||||
function launchPlatform.addLaunchPlatform(theZone)
|
||||
launchPlatform.zones[theZone.name] = theZone
|
||||
if theZone.coa == 1 or theZone.coa == 0 then
|
||||
launchPlatform.redLaunchers[theZone.name] = theZone
|
||||
end
|
||||
if theZone.coa == 2 or theZone.coa == 0 then
|
||||
launchPlatform.blueLaunchers[theZone.name] = theZone
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function launchPlatform.readLaunchPlatform(theZone)
|
||||
theZone.coa = theZone:getCoalitionFromZoneProperty("coalition", 0)
|
||||
theZone.impactRadius = theZone:getNumberFromZoneProperty("radius", 1000)
|
||||
if theZone:hasProperty("salvos") then
|
||||
theZone.num = theZone:getNumberFromZoneProperty("salvos", 1)
|
||||
end
|
||||
if theZone:hasProperty("salvo") then
|
||||
theZone.num = theZone:getNumberFromZoneProperty("salvo", 1)
|
||||
end
|
||||
-- possible extensions: missile. currently tomahawk launched from a missile cruiser that beams in and vanishes later
|
||||
-- later versions could support SCUDS and some long-range arty,
|
||||
-- perhaps even aircraft
|
||||
|
||||
end
|
||||
|
||||
-- note - the tomahawks don't care who they belong to, we do not
|
||||
-- need them to belong to anyone, it may be a visibility thing though
|
||||
|
||||
function launchPlatform.launchForPlatform(coa, theZone, tgtPoint, tgtZone)
|
||||
local launchPoint = theZone:createRandomPointInZone()
|
||||
local gData = launchPlatform.createData(launchPoint, tgtPoint, tgtZone, theZone.impactRadius, theZone.name, theZone.num)
|
||||
return gData
|
||||
end
|
||||
|
||||
function launchPlatform.launchAtTargetZone(coa, tgtZone, theType) -- gets closest platform for target
|
||||
-- type currently not supported
|
||||
local platforms = launchPlatform.redLaunchers
|
||||
if coa == 2 then platforms = launchPlatform.blueLaunchers end
|
||||
local cty = dcsCommon.getACountryForCoalition(coa)
|
||||
|
||||
-- get closest launcher for target
|
||||
local tgtPoint = tgtZone:getPoint()
|
||||
local src, dist = cfxZones.getClosestZone(tgtPoint, platforms)
|
||||
trigger.action.outText("+++LP: chosen <" .. src.name .. "> as launch platform", 30)
|
||||
|
||||
local theLauncher = launchPlatform.launchForPlatform(coa, src, tgtPoint, tgtZone)
|
||||
if not theLauncher then
|
||||
trigger.action.outText("NO LAUNCHER", 30)
|
||||
return nil
|
||||
end
|
||||
-- if type is tomahawk, the platform is ship = 3
|
||||
local theGroup = coalition.addGroup(cty, 3, theLauncher)
|
||||
if not theGroup then
|
||||
trigger.action.outText("!!!!!!!!!!!!!NOPE", 30)
|
||||
return
|
||||
end
|
||||
-- we remove the group in some time
|
||||
local now = timer.getTime()
|
||||
timer.scheduleFunction(launchPlatform.asynchRemovePlatform, theGroup:getName(), now + 300)
|
||||
end
|
||||
|
||||
function launchPlatform.asynchRemovePlatform(args)
|
||||
trigger.action.outText("LP: asynch remove for group <" .. args .. ">", 30)
|
||||
local theGroup = Group.getByName(args)
|
||||
if not theGroup then return end
|
||||
Group.destroy(theGroup)
|
||||
end
|
||||
|
||||
function launchPlatform.createData(thePoint, theTarget, targetZone, radius, name, num, wType)
|
||||
-- if present, we can use targetZone with some intelligence
|
||||
if not thePoint then
|
||||
trigger.action.outText("NO POINT", 30)
|
||||
return nil
|
||||
end
|
||||
if not theTarget then
|
||||
trigger.action.outText("NO TARGET", 30)
|
||||
return nil
|
||||
end
|
||||
|
||||
if not wType then wType = 52613349374 end
|
||||
if not radius then radius = 1000 end
|
||||
local useQty = true
|
||||
if not num then num = 15 end
|
||||
if num > 30 then num = 30 end -- max 30 missiles
|
||||
|
||||
if not name then name = "launcherDML" end
|
||||
local gData = {
|
||||
["visible"] = false,
|
||||
["tasks"] = {},
|
||||
["uncontrollable"] = false,
|
||||
["route"] = {
|
||||
["points"] = {
|
||||
[1] = {
|
||||
["alt"] = 0,
|
||||
["type"] = "Turning Point",
|
||||
["ETA"] = 0,
|
||||
["alt_type"] = "BARO",
|
||||
["formation_template"] = "",
|
||||
["y"] = thePoint.z,
|
||||
["x"] = thePoint.x,
|
||||
["ETA_locked"] = true,
|
||||
["speed"] = 0,
|
||||
["action"] = "Turning Point",
|
||||
["task"] = {
|
||||
["id"] = "ComboTask",
|
||||
["params"] = {
|
||||
["tasks"] = {
|
||||
[1] = {
|
||||
["number"] = 1,
|
||||
["auto"] = false,
|
||||
["id"] = "FireAtPoint",
|
||||
["enabled"] = true,
|
||||
["params"] = {
|
||||
["y"] = theTarget.z,
|
||||
["x"] = theTarget.x,
|
||||
["expendQtyEnabled"] = true,
|
||||
["alt_type"] = 1,
|
||||
["templateId"] = "",
|
||||
["expendQty"] = 2,
|
||||
["weaponType"] = wType,
|
||||
["zoneRadius"] = radius,
|
||||
}, -- end of ["params"]
|
||||
}, -- end of [1]
|
||||
}, -- end of ["tasks"]
|
||||
}, -- end of ["params"]
|
||||
}, -- end of ["task"]
|
||||
["speed_locked"] = true,
|
||||
}, -- end of [1]
|
||||
}, -- end of ["points"]
|
||||
}, -- end of ["route"]
|
||||
["hidden"] = false,
|
||||
["units"] = {
|
||||
[1] = {
|
||||
["modulation"] = 0,
|
||||
["skill"] = "Average",
|
||||
["type"] = "USS_Arleigh_Burke_IIa",
|
||||
["y"] = thePoint.z,
|
||||
["x"] = thePoint.x,
|
||||
["name"] = dcsCommon.uuid(name),
|
||||
["heading"] = 2.2925180610373,
|
||||
["frequency"] = 127500000,
|
||||
}, -- end of [1]
|
||||
}, -- end of ["units"]
|
||||
["y"] = thePoint.z,
|
||||
["x"] = thePoint.x,
|
||||
["name"] = dcsCommon.uuid(name),
|
||||
["start_time"] = 0,
|
||||
}
|
||||
|
||||
-- now create the tasks block replacements
|
||||
-- create random target locations inside
|
||||
-- target point with radius and launch 2 per salvo
|
||||
-- perhaps add some inteligence to target resource points
|
||||
-- if inside camp
|
||||
local hiPrioTargets
|
||||
if targetZone and targetZone.cloners and #targetZone.cloners > 0 then
|
||||
trigger.action.outText("+++LP: detected <" .. targetZone.name .. "> is camp with <" .. #targetZone.cloners .. "> res-points, re-targeting hi-prio", 30)
|
||||
hiPrioTargets = targetZone.cloners
|
||||
radius = radius / 10 -- much smaller error
|
||||
end
|
||||
local tasks = {}
|
||||
for i=1, num do
|
||||
local dp = dcsCommon.randomPointInCircle(radius, 0)
|
||||
if hiPrioTargets then
|
||||
-- choose one of the
|
||||
local thisCloner = dcsCommon.pickRandom(hiPrioTargets)
|
||||
local tp = thisCloner:getPoint()
|
||||
dp.x = dp.x + tp.x
|
||||
dp.z = dp.z + tp.z
|
||||
|
||||
else
|
||||
dp.x = dp.x + theTarget.x
|
||||
dp.z = dp.z + theTarget.z
|
||||
end
|
||||
local telem = {
|
||||
["number"] = i,
|
||||
["auto"] = false,
|
||||
["id"] = "FireAtPoint",
|
||||
["enabled"] = true,
|
||||
["params"] = {
|
||||
["y"] = dp.z,
|
||||
["x"] = dp.x,
|
||||
["expendQtyEnabled"] = true,
|
||||
["alt_type"] = 1,
|
||||
["templateId"] = "",
|
||||
["expendQty"] = 1,
|
||||
["weaponType"] = wType,
|
||||
["zoneRadius"] = radius,
|
||||
}, -- end of ["params"]
|
||||
} -- end of [1]
|
||||
-- table.insert(tasks, telem)
|
||||
tasks[i] = telem
|
||||
end
|
||||
|
||||
-- now replace old task with new
|
||||
gData.route.points[1].task.params.tasks = tasks
|
||||
return gData
|
||||
end
|
||||
|
||||
--
|
||||
-- start up
|
||||
--
|
||||
function launchPlatform.readConfigZone()
|
||||
local theZone = cfxZones.getZoneByName("launchPlatformConfig")
|
||||
if not theZone then
|
||||
theZone = cfxZones.createSimpleZone("launchPlatformConfig")
|
||||
end
|
||||
launchPlatform.verbose = theZone.verbose
|
||||
end
|
||||
|
||||
|
||||
function launchPlatform.start()
|
||||
-- lib check
|
||||
if not dcsCommon.libCheck then
|
||||
trigger.action.outText("cfx launchPlatform requires dcsCommon", 30)
|
||||
return false
|
||||
end
|
||||
if not dcsCommon.libCheck("cfx launchPlatform", launchPlatform.requiredLibs) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- read config
|
||||
launchPlatform.readConfigZone()
|
||||
|
||||
-- process launchPlatform Zones
|
||||
local attrZones = cfxZones.getZonesWithAttributeNamed("launchPlatform")
|
||||
for k, aZone in pairs(attrZones) do
|
||||
launchPlatform.readLaunchPlatform(aZone) -- process attributes
|
||||
launchPlatform.addLaunchPlatform(aZone) -- add to list
|
||||
end
|
||||
|
||||
-- say hi
|
||||
trigger.action.outText("launchPlatform v" .. launchPlatform.version .. " started.", 30)
|
||||
return true
|
||||
end
|
||||
|
||||
if not launchPlatform.start() then
|
||||
trigger.action.outText("launchPlatform failed to start.", 30)
|
||||
launchPlatform = nil
|
||||
end
|
||||
@ -678,7 +678,9 @@ end
|
||||
|
||||
function milHelo.GCcollected(gName)
|
||||
-- do some housekeeping?
|
||||
if milHelo.verbose then
|
||||
trigger.action.outText("removed flight <" .. gName .. ">", 30)
|
||||
end
|
||||
end
|
||||
|
||||
function milHelo.GC()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
noGap = {}
|
||||
noGap.version = "1.0.0"
|
||||
noGap.version = "1.0.1"
|
||||
|
||||
noGap.verbose = false
|
||||
noGap.ignoreMe = "-ng" -- ignore altogether
|
||||
@ -37,6 +37,7 @@ noGap.requiredLibs = {
|
||||
|
||||
Version History
|
||||
1.0.0 - Initial version
|
||||
1.0.1 - added "from runway"
|
||||
|
||||
--]]--
|
||||
|
||||
@ -80,6 +81,7 @@ function noGap.isGroundStart(theGroup)
|
||||
if action == "Fly Over Point" then return false end
|
||||
if action == "Turning Point" then return false end
|
||||
if action == "Landing" then return false end
|
||||
if action == "From Runway" then return false end
|
||||
-- aircraft is on the ground - but is it in water (carrier)?
|
||||
local u1 = theGroup.units[1]
|
||||
local sType = land.getSurfaceType(u1) -- has fields x and y
|
||||
|
||||
74
modules/slotty.lua
Normal file
74
modules/slotty.lua
Normal file
@ -0,0 +1,74 @@
|
||||
slotty = {}
|
||||
slotty.version = "1.1.0"
|
||||
--[[--
|
||||
Single-player slot blocking and slot blocking fallback
|
||||
for multiplayer when SSB is not installed on server.
|
||||
Uses SSB's method of marking groups with flags
|
||||
(c) 2024 by Christian Franz
|
||||
|
||||
Slotty can be disabled by setting the value of the flag named "noSlotty" to
|
||||
a value greater than zero
|
||||
|
||||
Version history
|
||||
1.0.0 - Initial version
|
||||
1.1.0 - "noSlotty" global disable flag, anti-mirror SSB flag
|
||||
|
||||
--]]--
|
||||
|
||||
function slotty:onEvent(event)
|
||||
if not event.initiator then return end
|
||||
local theUnit = event.initiator
|
||||
if not theUnit.getPlayerName then return end
|
||||
local pName = theUnit:getPlayerName()
|
||||
if not pName then return end
|
||||
local uName = theUnit:getName()
|
||||
local theGroup = theUnit:getGroup()
|
||||
local gName = theGroup:getName()
|
||||
if event.id == 15 then -- birth
|
||||
if trigger.misc.getUserFlag("noSlotty") > 0 then return end
|
||||
local np = net.get_player_list() -- retruns a list of PID
|
||||
local isSP = false
|
||||
if not np or (#np < 1) then
|
||||
isSP = true -- we are in single-player mode
|
||||
end
|
||||
-- now see if that group name is currently blocked
|
||||
local blockstate = false
|
||||
if trigger.misc.getUserFlag(gName) > 0 then
|
||||
trigger.action.outText("Group <" .. gName .. "> is currently blocked and can't be entered", 30)
|
||||
blockstate = true
|
||||
end
|
||||
|
||||
if not blockstate then return end -- nothing left to do, all is fine
|
||||
|
||||
-- interface with SSBClient for compatibility
|
||||
if cfxSSBClient and cfxSSBClient.occupiedUnits then
|
||||
cfxSSBClient.occupiedUnits[uName] = nil
|
||||
end
|
||||
|
||||
if isSP then
|
||||
theUnit:destroy() -- SP kill, works only in Single-player
|
||||
return
|
||||
end
|
||||
|
||||
-- we would leave the rest to SSB, but if we get here, SSB is
|
||||
-- not installed on host, so we proceed with invoking netAPI
|
||||
for idx,pid in pairs(np) do
|
||||
local netName = net.get_name(pid)
|
||||
if netName == pName then
|
||||
timer.scheduleFunction(slotty.kick, pid, timer.getTime() + 0.1)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function slotty.kick(pid)
|
||||
net.force_player_slot(pid, 0, '') -- '', thanks Dz!
|
||||
end
|
||||
|
||||
function slotty.start()
|
||||
world.addEventHandler(slotty)
|
||||
trigger.action.outText("slotty v " .. slotty.version .. " running.", 30)
|
||||
end
|
||||
|
||||
slotty.start()
|
||||
@ -1,5 +1,5 @@
|
||||
cfxSpawnZones = {}
|
||||
cfxSpawnZones.version = "2.0.1"
|
||||
cfxSpawnZones.version = "2.0.2"
|
||||
cfxSpawnZones.requiredLibs = {
|
||||
"dcsCommon", -- common is of course needed for everything
|
||||
-- pretty stupid to check for this since we
|
||||
@ -27,6 +27,8 @@ cfxSpawnZones.spawnedGroups = {}
|
||||
- baseName defaults to zone name, as it is safe for naming
|
||||
- spawnWithSpawner direct link in spawner to spawnZones
|
||||
2.0.1 - fix in verifySpawnOwnership() when not master zone found
|
||||
2.0.2 - new "moveFormation" attribute
|
||||
|
||||
--]]--
|
||||
|
||||
cfxSpawnZones.allSpawners = {}
|
||||
@ -128,6 +130,13 @@ function cfxSpawnZones.createSpawner(inZone)
|
||||
theSpawner.count = 1 -- used to create names, and count how many groups created
|
||||
theSpawner.theSpawn = nil -- link to last spawned group
|
||||
theSpawner.formation = inZone:getStringFromZoneProperty("formation", "circle_out")
|
||||
theSpawner.moveFormation = inZone:getStringFromZoneProperty("moveFormation", "Custom")
|
||||
|
||||
if theSpawner.moveFormation == "Custom" or theSpawner.moveFormation == "EchelonR" or theSpawner.moveFormation == "EchelonL" or theSpawner.moveFormation == "Diamond" or theSpawner.moveFormation == "Vee" or theSpawner.moveFormation == "Cone" or theSpawner.moveFormation == "Rank" then -- all fine, do nothing
|
||||
else
|
||||
trigger.action.outText("+++SpwZ: unknown moveFormation <" .. theSpawner.moveFormation .. "> in spawn zone <" .. inZone.name .. ">, defaulting to 'Custom'", 30)
|
||||
theSpawner.moveFormation = "Custom"
|
||||
end
|
||||
theSpawner.paused = inZone:getBoolFromZoneProperty("paused", false)
|
||||
-- orders are always converted to all lower case
|
||||
theSpawner.orders = inZone:getStringFromZoneProperty("orders", "guard"):lower()
|
||||
@ -297,6 +306,7 @@ function cfxSpawnZones.spawnWithSpawner(aSpawner)
|
||||
troopData.groupData = theData
|
||||
troopData.orders = aSpawner.orders -- always set
|
||||
troopData.side = theCoalition
|
||||
troopData.moveFormation = aSpawner.moveFormation
|
||||
troopData.target = aSpawner.target -- can be nil!
|
||||
troopData.tracker = theZone.trackWith -- taken from ZONE!!, can be nil
|
||||
troopData.range = aSpawner.range
|
||||
@ -318,7 +328,7 @@ function cfxSpawnZones.spawnWithSpawner(aSpawner)
|
||||
AI.Option.Ground.val.ROE.WEAPON_HOLD,
|
||||
1.0)
|
||||
else
|
||||
local newTroops = cfxGroundTroops.createGroundTroops(theGroup, aSpawner.range, aSpawner.orders)
|
||||
local newTroops = cfxGroundTroops.createGroundTroops(theGroup, aSpawner.range, aSpawner.orders, aSpawner.moveFormation)
|
||||
cfxGroundTroops.addGroundTroopsToPool(newTroops)
|
||||
|
||||
-- see if we have defined a target zone as destination
|
||||
@ -576,6 +586,7 @@ function cfxSpawnZones.loadData()
|
||||
for gName, gdTroop in pairs (allTroopData) do
|
||||
local gData = gdTroop.groupData
|
||||
local orders = gdTroop.orders
|
||||
local moveFormation = gdTroop.moveFormation
|
||||
local target = gdTroop.target
|
||||
local tracker = gdTroop.tracker
|
||||
local side = gdTroop.side
|
||||
@ -598,7 +609,7 @@ function cfxSpawnZones.loadData()
|
||||
1.0)
|
||||
else
|
||||
-- add to groundTroops
|
||||
local newTroops = cfxGroundTroops.createGroundTroops(theGroup, range, orders)
|
||||
local newTroops = cfxGroundTroops.createGroundTroops(theGroup, range, orders, moveFormation)
|
||||
cfxGroundTroops.addGroundTroopsToPool(newTroops)
|
||||
-- engage a target zone
|
||||
if target then
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
-- theDebugger 2.x
|
||||
debugger = {}
|
||||
debugger.version = "2.1.0"
|
||||
debugger.version = "2.1.1"
|
||||
debugDemon = {}
|
||||
debugDemon.version = "2.1.0"
|
||||
|
||||
@ -39,6 +39,7 @@ debugger.log = ""
|
||||
debug invocation on clone of data structure
|
||||
readback verification of flag set
|
||||
fixed getProperty() in debugger with zone
|
||||
2.1.1 - removed bug that skipped events? when zone not verbose
|
||||
|
||||
--]]--
|
||||
|
||||
@ -267,13 +268,15 @@ function debugger.createEventMonWithZone(theZone)
|
||||
end
|
||||
for idx, aFlag in pairs(flagArray) do
|
||||
local evt = tonumber(aFlag)
|
||||
if evt and (debugger.verbose or theZone.verbose) then
|
||||
if evt then
|
||||
if evt < 0 then evt = 0 end
|
||||
if evt > 57 then evt = 57 end
|
||||
debugger.showEvents[evt] = debugDemon.eventList[tostring(evt)]
|
||||
if (debugger.verbose or theZone.verbose) then
|
||||
debugger.outText(" monitoring event <" .. debugger.showEvents[evt] .. ">", 30)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
unitPersistence = {}
|
||||
unitPersistence.version = '2.0.0'
|
||||
unitPersistence.version = '2.0.1'
|
||||
unitPersistence.verbose = false
|
||||
unitPersistence.updateTime = 60 -- seconds. Once every minute check statics
|
||||
unitPersistence.requiredLibs = {
|
||||
@ -21,6 +21,7 @@ unitPersistence.requiredLibs = {
|
||||
- fixed air spawn (fixed wing)
|
||||
2.0.0 - dmlZones, OOP
|
||||
cleanup
|
||||
2.0.1 - cosmetic verbosity during save
|
||||
|
||||
REQUIRES PERSISTENCE AND MX
|
||||
|
||||
@ -162,7 +163,9 @@ function unitPersistence.saveData()
|
||||
end
|
||||
else
|
||||
theUnitData.isDead = true
|
||||
if unitPersistence.verbose then
|
||||
trigger.action.outText("+++unitPersistence - unit <" .. uName .. "> of group <" .. groupName .. "> is dead or non-existant", 30)
|
||||
end
|
||||
end -- is alive and exists?
|
||||
end -- unit maybe not dead
|
||||
end -- iterate units in group
|
||||
|
||||
Binary file not shown.
BIN
tutorial & demo missions/demo - non SSB & SP slot blocking.miz
Normal file
BIN
tutorial & demo missions/demo - non SSB & SP slot blocking.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user