mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 2.0.2
New scribe, names, better csarManager
This commit is contained in:
parent
38d6487de7
commit
61f33561fc
Binary file not shown.
Binary file not shown.
@ -18,7 +18,8 @@ VERSION HISTORY
|
||||
interpolate hits on dead when looking at kills and projectile does
|
||||
not exist
|
||||
also sampling kill events
|
||||
|
||||
1.1.1 - fixed reading smoke color for zone
|
||||
minor clean-up
|
||||
--]]--
|
||||
bombRange.bombs = {} -- live tracking
|
||||
bombRange.collector = {} -- post-impact collections for 0.5 secs
|
||||
@ -63,6 +64,7 @@ function bombRange.createRange(theZone) -- has bombRange attribte to mark it
|
||||
theZone.reportName = theZone:getBoolFromZoneProperty("reportName", false)
|
||||
theZone.smokeHits = theZone:getBoolFromZoneProperty("smokeHits", false)
|
||||
theZone.smokeColor = theZone:getSmokeColorStringFromZoneProperty("smokeColor", "blue")
|
||||
theZone.smokeColor = dcsCommon.smokeColor2Num(theZone.smokeColor)
|
||||
theZone.flagHits = theZone:getBoolFromZoneProperty("flagHits", false)
|
||||
theZone.flagType = theZone:getStringFromZoneProperty("flagType", "Red_Flag")
|
||||
theZone.clipDist = theZone:getNumberFromZoneProperty("clipDist", 2000) -- when further way, the drop will be disregarded
|
||||
@ -99,7 +101,6 @@ function bombRange.getPlayerData(name)
|
||||
theData.totalHits = 0
|
||||
theData.totalPercentage = 0 -- sum, must be divided by drops
|
||||
bombRange.playerData[name] = theData
|
||||
-- trigger.action.outText("created new player data for " .. name, 30)
|
||||
end
|
||||
return theData
|
||||
end
|
||||
@ -173,13 +174,12 @@ function bombRange.showStatsForPlayer(pName, gID, unitName)
|
||||
end
|
||||
end
|
||||
trigger.action.outTextForGroup(gID, msg, 30)
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- unit UI
|
||||
--
|
||||
|
||||
function bombRange.initCommsForUnit(theUnit)
|
||||
local uName = theUnit:getName()
|
||||
local pName = theUnit:getPlayerName()
|
||||
@ -261,7 +261,7 @@ function bombRange.suspectedHit(weapon, target)
|
||||
|
||||
local theDesc = target:getDesc()
|
||||
local theType = theDesc.typeName -- getTypeName gets display name
|
||||
-- filter statics that we want to ignore
|
||||
-- filter statics that we want to ignore
|
||||
for idx, aType in pairs(bombRange.filterTypes) do
|
||||
if theType == aType then
|
||||
return
|
||||
@ -285,7 +285,6 @@ function bombRange.suspectedHit(weapon, target)
|
||||
bombRange.impacted(b, target) -- use this for impact
|
||||
theID = b.ID
|
||||
hasfound = true
|
||||
-- trigger.action.outText("susHit: filtering COLLECTED b <" .. b.name .. ">", 30)
|
||||
end
|
||||
end
|
||||
if hasfound then
|
||||
@ -305,8 +304,6 @@ function bombRange.suspectedHit(weapon, target)
|
||||
b.pos = weapon:getPoint()
|
||||
b.v = weapon:getVelocity()
|
||||
bombRange.impacted(b, target)
|
||||
|
||||
-- trigger.action.outText("susHit: filtering live b <" .. b.name .. ">", 30)
|
||||
else
|
||||
table.insert(filtered, b)
|
||||
end
|
||||
@ -363,7 +360,6 @@ function bombRange.suspectedKill(target)
|
||||
end
|
||||
bombRange.bombs = filtered
|
||||
if hasfound then
|
||||
-- trigger.action.outText("protocol: removed LIVING weapon from roster after impacted() invocation for non-nil target in suspectedKill", 30)
|
||||
return
|
||||
end
|
||||
|
||||
@ -383,7 +379,6 @@ function bombRange.suspectedKill(target)
|
||||
end
|
||||
if hasfound then -- remove from collector, hit attributed
|
||||
bombRange.collector[theID] = nil -- remove from collector
|
||||
-- trigger.action.outText("protocol: removed COLL weapon from roster after impacted() invocation for non-nil target in suspectedKill", 30)
|
||||
return
|
||||
end
|
||||
end
|
||||
@ -478,14 +473,8 @@ function bombRange.impacted(weapon, target, finalPass)
|
||||
if not targetName then targetName = target:getTypeName() end
|
||||
end
|
||||
|
||||
-- local s = "Entering impacted() with weapon = <" .. weapon.name .. ">"
|
||||
-- if target then
|
||||
-- s = s .. " AND target = <" .. targetName .. ">"
|
||||
-- end
|
||||
|
||||
-- when we enter, weapon has ipacted target - if target is non-nil
|
||||
-- what we need to determine is if that target is inside a zone
|
||||
|
||||
-- what we need to determine is if that target is inside a zone
|
||||
local ipos = weapon.pos -- default to weapon location
|
||||
if target then
|
||||
ipos = target:getPoint() -- we make the target loc the impact point
|
||||
@ -542,32 +531,7 @@ function bombRange.impacted(weapon, target, finalPass)
|
||||
end
|
||||
|
||||
local impactInside = theRange:pointInZone(ipos)
|
||||
--[[--
|
||||
if target and (not impactInside) then
|
||||
trigger.action.outText("Hit on target <" .. targetName .. "> outside of zone <" .. theRange.name .. ">. should exit unless final impact", 30)
|
||||
-- find closest range to object that was hit
|
||||
local closest = nil
|
||||
local shortest = math.huge
|
||||
local tp = target:getPoint()
|
||||
for idx, aRange in pairs(bombRange.ranges) do
|
||||
local zp = aRange:getPoint()
|
||||
local zDist = dcsCommon.distFlat(zp, tp)
|
||||
if zDist < shortest then
|
||||
shortest = zDist
|
||||
closest = aRange
|
||||
end
|
||||
end
|
||||
|
||||
trigger.action.outText("re-check: closest range to target now is <" .. closest.name ..">", 30)
|
||||
if closest:pointInZone(tp) then
|
||||
trigger.action.outText("target <" .. targetName .. "> is INSIDE this range, d = <" .. math.floor(shortest) .. ">", 30)
|
||||
else
|
||||
trigger.action.outText("targed indeed outside, d = <" .. math.floor(shortest) .. ">", 30)
|
||||
end
|
||||
|
||||
if finalPass then trigger.action.outText("IS final pass.", 30) end
|
||||
end
|
||||
--]]--
|
||||
|
||||
if theRange.reporter and theRange.details then
|
||||
local ipc = weapon.impacted
|
||||
if not ipc then ipc = timer.getTime() end
|
||||
@ -604,8 +568,7 @@ function bombRange.impacted(weapon, target, finalPass)
|
||||
|
||||
bombRange.addImpactForWeapon(weapon, true, percentage)
|
||||
else
|
||||
msg = "Outside target area"
|
||||
-- if target then msg = msg .. " (EVEN THOUGH TGT = " .. target:getName() .. ")" end
|
||||
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
|
||||
msg = msg .. ", no hit."
|
||||
@ -623,7 +586,6 @@ function bombRange.uncollect(theID)
|
||||
if b then
|
||||
bombRange.collector[theID] = nil
|
||||
bombRange.impacted(b, nil, true) -- final pass
|
||||
-- trigger.action.outText("(final impact)", 30)
|
||||
end
|
||||
end
|
||||
|
||||
@ -640,7 +602,6 @@ function bombRange.updateBombs()
|
||||
else
|
||||
-- put on collector to time out in 1 seconds to allow
|
||||
-- asynch hits to still register for this weapon in MP
|
||||
-- bombRange.impacted(theWeapon)
|
||||
theWeapon.impacted = timer.getTime()
|
||||
bombRange.collector[theWeapon.ID] = theWeapon --
|
||||
timer.scheduleFunction(bombRange.uncollect, theWeapon.ID, timer.getTime() + 1)
|
||||
@ -766,6 +727,6 @@ if not bombRange.start() then
|
||||
bombRange = nil
|
||||
end
|
||||
|
||||
--
|
||||
-- To Do:
|
||||
-- add persistence
|
||||
--
|
||||
@ -1,5 +1,5 @@
|
||||
cfxMX = {}
|
||||
cfxMX.version = "2.0.0"
|
||||
cfxMX.version = "2.0.1"
|
||||
cfxMX.verbose = false
|
||||
--[[--
|
||||
Mission data decoder. Access to ME-built mission structures
|
||||
@ -11,6 +11,8 @@ cfxMX.verbose = false
|
||||
- train carve-outs for vehicles
|
||||
2.0.0 - clean-up
|
||||
- harmonized with cfxGroups
|
||||
2.0.1 - groupHotByName
|
||||
|
||||
|
||||
--]]--
|
||||
cfxMX.groupNamesByID = {}
|
||||
@ -19,6 +21,7 @@ cfxMX.unitIDbyName = {}
|
||||
cfxMX.groupDataByName = {}
|
||||
cfxMX.groupTypeByName = {} -- category of group: "helicopter", "plane", "ship"...
|
||||
cfxMX.groupCoalitionByName = {}
|
||||
cfxMX.groupHotByName = {}
|
||||
cfxMX.countryByName ={} -- county of group named
|
||||
cfxMX.linkByName = {}
|
||||
cfxMX.allFixedByName = {}
|
||||
@ -205,10 +208,17 @@ function cfxMX.createCrossReferences()
|
||||
local aID = group_data.groupId
|
||||
-- get linkUnit info if it exists
|
||||
local linkUnit = nil
|
||||
local isHot = false
|
||||
if group_data and group_data.route and group_data.route and group_data.route.points[1] then
|
||||
linkUnit = group_data.route.points[1].linkUnit
|
||||
cfxMX.linkByName[aName] = linkUnit
|
||||
local action = group_data.route.points[1].action
|
||||
if action then
|
||||
isHot = dcsCommon.stringEndsWith(action, "Hot")
|
||||
end
|
||||
end
|
||||
|
||||
cfxMX.groupHotByName[aName] = isHot
|
||||
if group_data.units[1] and group_data.units[1].type == "Train" then
|
||||
category = "train"
|
||||
obj_type_name = "train"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
csarManager = {}
|
||||
csarManager.version = "3.0.0"
|
||||
csarManager.version = "3.1.0"
|
||||
csarManager.ups = 1
|
||||
|
||||
--[[-- VERSION HISTORY
|
||||
@ -18,9 +18,19 @@ csarManager.ups = 1
|
||||
- new event manager
|
||||
- no longer single-proccing pilots
|
||||
- can also handle aircraft - isTroopCarrier
|
||||
- 3.1.0 - integration with scribe
|
||||
- expanded internal API: newMissionCB, invoked at addMission
|
||||
- expanded internal API: removedMissionCB
|
||||
- added *rnd as option for csarName (requires "names")
|
||||
- missions are sorted by distance
|
||||
- mission timeLimit range implemented
|
||||
- update handles time limit (pickup only)
|
||||
- inflight status reflects time limit but will not time out
|
||||
- pickupSound option
|
||||
- lostSound option
|
||||
|
||||
INTEGRATES AUTOMATICALLY WITH playerScore IF INSTALLED
|
||||
INTEGRATES WITH LIMITE AIRFRAMES IF INSTALLED
|
||||
INTEGRATES WITH LIMITED AIRFRAMES IF INSTALLED
|
||||
|
||||
--]]--
|
||||
-- modules that need to be loaded BEFORE I run
|
||||
@ -55,7 +65,9 @@ csarManager.vectoring = true -- provide bearing and range
|
||||
-- callbacks
|
||||
--
|
||||
csarManager.csarCompleteCB = {}
|
||||
|
||||
csarManager.csarCreatedCB = {}
|
||||
csarManager.csarRemoveCB = {}
|
||||
csarManager.csarPickupCB = {}
|
||||
--
|
||||
-- CREATING A CSAR
|
||||
--
|
||||
@ -84,7 +96,7 @@ function csarManager.createDownedPilot(theMission, existingUnit)
|
||||
aLocation.z = newTargetZone.point.z
|
||||
aHeading = math.random(360)/360 * 2 * 3.1415
|
||||
end
|
||||
|
||||
theMission.locations = {}
|
||||
local theBoyGroup = dcsCommon.createSingleUnitGroup(theMission.name,
|
||||
"Soldier M4 GRG", -- "Soldier M4 GRG",
|
||||
aLocation.x,
|
||||
@ -96,12 +108,17 @@ function csarManager.createDownedPilot(theMission, existingUnit)
|
||||
Group.Category.GROUND,
|
||||
theBoyGroup)
|
||||
if theBoyGroup then
|
||||
|
||||
table.insert(theMission.locations, aLocation)
|
||||
else
|
||||
trigger.action.outText("+++csar: FAILED to create csar!", 30)
|
||||
end
|
||||
else
|
||||
theMission.group = existingUnit:getGroup()
|
||||
local allUnits = theMission.group:getUnits()
|
||||
for idx, aUnit in pairs(allUnits) do
|
||||
local loc = aUnit:getPoint() -- warning: won't work if group newly allocated!
|
||||
table.insert(theMission.locations, loc)
|
||||
end
|
||||
end
|
||||
|
||||
-- we now use commands to send radio transmissions
|
||||
@ -117,10 +134,19 @@ end
|
||||
|
||||
function csarManager.createCSARMissionData(point, theSide, freq, name, numCrew, timeLimit, mapMarker, inRadius, parashootUnit) -- if parashootUnit is set, will not allocate new
|
||||
-- create a type
|
||||
if not timeLimit then timeLimit = -1 end
|
||||
-- if not timeLimit then timeLimit = -1 end
|
||||
if not point then return nil end
|
||||
local newMission = {}
|
||||
newMission.side = theSide
|
||||
-- if "names" module active, allow random names if name
|
||||
-- equals "*rnd"
|
||||
if names and names.uniqueFullName and name == "*rnd" then
|
||||
name = names.uniqueFullName()
|
||||
elseif name == "*rnd" then
|
||||
trigger.action.outText("+++scar: '*rnd' name requires the 'name' module for randomization. Using 'John Smith'", 30)
|
||||
name = "John Smith"
|
||||
end
|
||||
|
||||
if dcsCommon.stringStartsWith(name, "downed ") then
|
||||
-- remove "downed" - it will be added again later
|
||||
name = dcsCommon.removePrefix(name, "downed ")
|
||||
@ -129,7 +155,7 @@ function csarManager.createCSARMissionData(point, theSide, freq, name, numCrew,
|
||||
end
|
||||
end
|
||||
if not inRadius then inRadius = csarManager.rescueRadius end
|
||||
newMission.name = name .. "-" .. csarManager.missionID -- make it uuid-capable
|
||||
newMission.name = name .. " (ID#" .. csarManager.missionID .. ")" -- make it uuid-capable
|
||||
if csarManager.addPrefix then
|
||||
newMission.name = "downed " .. newMission.name
|
||||
end
|
||||
@ -145,22 +171,40 @@ function csarManager.createCSARMissionData(point, theSide, freq, name, numCrew,
|
||||
-- allocate units
|
||||
csarManager.createDownedPilot(newMission, parashootUnit)
|
||||
|
||||
newMission.timeStamp = timer.getTime() -- now
|
||||
|
||||
-- set timeLimit if enabled
|
||||
if timeLimit then
|
||||
local theLimit = cfxZones.randomDelayFromPositiveRange(timeLimit[1], timeLimit[2]) * 60
|
||||
-- trigger.action.outText("set time limit for mission to "..theLimit, 30)
|
||||
newMission.expires = timer.getTime() + theLimit
|
||||
end
|
||||
|
||||
-- update counter and return
|
||||
csarManager.missionID = csarManager.missionID + 1
|
||||
|
||||
return newMission
|
||||
end
|
||||
|
||||
function csarManager.addMission(theMission)
|
||||
-- trigger.action.outText("enter addMission", 30)
|
||||
table.insert(csarManager.openMissions, theMission)
|
||||
csarManager.invokeNewMissionCallbacks(theMission)
|
||||
end
|
||||
|
||||
function csarManager.removeMission(theMission)
|
||||
function csarManager.removeMission(theMission, pickup)
|
||||
if not pickup then pickup = false end
|
||||
-- invoked when evacuee is PICKED UP!
|
||||
if not theMission then return end
|
||||
local newMissions = {}
|
||||
for idx, aMission in pairs (csarManager.openMissions) do
|
||||
if aMission ~= theMission then
|
||||
table.insert(newMissions, aMission)
|
||||
else
|
||||
-- csarManager.invokeRemovedMissionCallbacks(theMission)
|
||||
if pickup then
|
||||
csarManager.invokePickUpCallbacks(theMission)
|
||||
end
|
||||
end
|
||||
end
|
||||
csarManager.openMissions = newMissions -- this is the new batch
|
||||
@ -291,15 +335,24 @@ function csarManager.successMission(who, where, theMission)
|
||||
end
|
||||
end
|
||||
|
||||
-- scribe.integration
|
||||
if scribe then
|
||||
local theUnit = Unit.getByName(who)
|
||||
if theUnit and theUnit.getPlayerName then
|
||||
local pName = theUnit:getPlayerName()
|
||||
scribe.playerRescueComplete(pName)
|
||||
end
|
||||
end
|
||||
|
||||
trigger.action.outTextForCoalition(theMission.side,
|
||||
who .. " successfully evacuated " .. theMission.name .. " to " .. where .. "!",
|
||||
30)
|
||||
|
||||
-- now call callback for coalition side
|
||||
-- callback has format callback(coalition, success true/false, numberSaved, descriptionText)
|
||||
csarManager.invokeCallbacks(theMission.side, true, 1, "success")
|
||||
-- callback has format callback(coalition, success true/false, numberSaved, descriptionText, theMission)
|
||||
csarManager.invokeCallbacks(theMission.side, true, 1, "success", theMission)
|
||||
|
||||
trigger.action.outSoundForCoalition(theMission.side, csarManager.actionSound) -- "Quest Snare 3.wav")
|
||||
trigger.action.outSoundForCoalition(theMission.side, csarManager.successSound)
|
||||
|
||||
if csarManager.csarRedDelivered and theMission.side == 1 then
|
||||
cfxZones.pollFlag(csarManager.csarRedDelivered, "inc", csarManager.configZone)
|
||||
@ -324,7 +377,6 @@ function csarManager.heloLanded(theUnit)
|
||||
conf.unit = theUnit
|
||||
local theGroup = theUnit:getGroup()
|
||||
conf.id = theGroup:getID()
|
||||
--conf.id = theUnit:getID()
|
||||
conf.currentState = 0
|
||||
local thePoint = theUnit:getPoint()
|
||||
local mySide = theUnit:getCoalition()
|
||||
@ -435,7 +487,7 @@ function csarManager.heloLanded(theUnit)
|
||||
args.unitName = myName
|
||||
timer.scheduleFunction(csarManager.asynchSuccess, args, timer.getTime() + 3)
|
||||
|
||||
csarManager.removeMission(theMission)
|
||||
csarManager.removeMission(theMission, true) -- picked up
|
||||
table.insert(conf.troopsOnBoard, theMission)
|
||||
theMission.group:destroy() -- will shut up radio as well
|
||||
theMission.group = nil
|
||||
@ -466,7 +518,7 @@ function csarManager.asynchSuccess(args)
|
||||
end
|
||||
|
||||
function csarManager.asynchSound(args)
|
||||
trigger.action.outSoundForCoalition(args.mySide, csarManager.actionSound)
|
||||
trigger.action.outSoundForCoalition(args.mySide, csarManager.pickupSound)
|
||||
end
|
||||
--
|
||||
--
|
||||
@ -663,6 +715,7 @@ function csarManager.openMissionsForSide(theSide)
|
||||
end
|
||||
|
||||
function csarManager.doListCSARRequests(args)
|
||||
local now = timer.getTime()
|
||||
local conf = args[1]
|
||||
local param = args[2]
|
||||
local theUnit = conf.unit
|
||||
@ -675,14 +728,34 @@ function csarManager.doListCSARRequests(args)
|
||||
if #openMissions < 1 then
|
||||
report = report .. "\nNo requests, all crew are safe."
|
||||
else
|
||||
-- iterate through all troops onboard to get their status
|
||||
-- iterate through all missions and calc distance
|
||||
for idx, mission in pairs(openMissions) do
|
||||
local d = dcsCommon.distFlat(point, mission.zone.point) * 0.000539957
|
||||
d = math.floor(d * 10) / 10
|
||||
mission.dist = d
|
||||
end
|
||||
-- sort openMissions by dist
|
||||
table.sort(openMissions,
|
||||
function (e1, e2) return e1.dist < e2.dist end
|
||||
)
|
||||
|
||||
-- we may want to limit to n nearest missions
|
||||
local maxM = #openMissions
|
||||
if maxM > csarManager.maxMissions then maxM = csarManager.maxMissions end
|
||||
for i=1,maxM do --in pairs(openMissions) do
|
||||
local mission = openMissions[i]
|
||||
local b = dcsCommon.bearingInDegreesFromAtoB(point, mission.zone.point)
|
||||
local status = "alive"
|
||||
if mission.expires then
|
||||
delta = math.floor ((mission.expires - now) / 60)
|
||||
if delta < 10 then status = "+deteriorating+" end
|
||||
if delta < 5 then status = "*critical*" end
|
||||
if csarManager.verbose then
|
||||
status = status .. "[" .. delta .. "]" -- remove me
|
||||
end
|
||||
end
|
||||
if csarManager.vectoring then
|
||||
report = report .. "\n".. mission.name .. ", bearing " .. b .. ", " ..d .."nm, " .. " ADF " .. mission.freq * 10 .. " kHz - " .. status
|
||||
report = report .. "\n".. mission.name .. ", bearing " .. b .. ", " ..mission.dist .."nm, " .. " ADF " .. mission.freq * 10 .. " kHz - " .. status
|
||||
else
|
||||
-- leave out vectoring
|
||||
report = report .. "\n".. mission.name .. " ADF " .. mission.freq * 10 .. " kHz - " .. status
|
||||
@ -707,6 +780,7 @@ function csarManager.doStatusCarrying(args)
|
||||
local conf = args[1]
|
||||
local param = args[2]
|
||||
local theUnit = conf.unit
|
||||
local now = timer.getTime()
|
||||
|
||||
-- build status report
|
||||
local report = "\nCrew Rescue Status:\n"
|
||||
@ -717,7 +791,18 @@ function csarManager.doStatusCarrying(args)
|
||||
for i=1, #conf.troopsOnBoard do
|
||||
local evacMission = conf.troopsOnBoard[i]
|
||||
report = report .. "\n".. i .. ") " .. evacMission.name
|
||||
report = report .. " is stable" -- or 'beat up, but will live'
|
||||
if evacMission.expires then
|
||||
delta = math.floor ((mission.expires - now) / 60)
|
||||
if delta > 20 then
|
||||
report = report .. " is hurt but stable"
|
||||
elseif delta > 10 then
|
||||
report = report .. " is badly hurt"
|
||||
else
|
||||
report = report .. " is in critical condition" -- or 'beat up, but will live'
|
||||
end
|
||||
else
|
||||
report = report .. " is stable" -- or 'beat up, but will live'
|
||||
end
|
||||
end
|
||||
|
||||
report = report .. "\n\nTotal added weigth: " .. 10 + #conf.troopsOnBoard * csarManager.pilotWeight .. "kg"
|
||||
@ -886,16 +971,31 @@ end
|
||||
--
|
||||
function csarManager.updateCSARMissions()
|
||||
local newMissions = {}
|
||||
local now = timer.getTime()
|
||||
for idx, aMission in pairs (csarManager.openMissions) do
|
||||
-- see if mission timed out
|
||||
local now = timer.getTime()
|
||||
local stillRunning = true
|
||||
if aMission.expires then stillRunning = aMission.expires > now end
|
||||
local stillAlive = dcsCommon.isGroupAlive(aMission.group)
|
||||
-- now check if a timer was running to rescue this group
|
||||
|
||||
-- if dead, set stillAlive to false
|
||||
if stillAlive then
|
||||
if stillRunning and stillAlive then
|
||||
table.insert(newMissions, aMission)
|
||||
elseif stillAlive then
|
||||
local msg = aMission.name .. " is no longer responding. Abort rescue."
|
||||
trigger.action.outTextForCoalition(aMission.side, msg, 30)
|
||||
trigger.action.outSoundForCoalition(aMission.side, csarManager.lostSound)
|
||||
csarManager.invokeCallbacks(aMission.side, false, 1, "lost", aMission)
|
||||
if aMission.group and Group.isExist(aMission.group) then
|
||||
-- trigger.action.outText("removing group", 30)
|
||||
Group.destroy(aMission.group)
|
||||
end
|
||||
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) -- "Quest Snare 3.wav")
|
||||
trigger.action.outSoundForCoalition(aMission.side, csarManager.actionSound)
|
||||
csarManager.invokeCallbacks(aMission.side, false, 1, "KIA", aMission)
|
||||
end
|
||||
end
|
||||
csarManager.openMissions = newMissions -- this is the new batch
|
||||
@ -926,12 +1026,11 @@ function csarManager.update() -- every second
|
||||
|
||||
-- now scan through all helo groups and see if they are close to a
|
||||
-- CSAR zone and initiate the help sequence
|
||||
-- local allPlayerGroups = cfxPlayerGroups -- cfxPlayerGroups is a global, don't fuck with it!
|
||||
|
||||
local allPlayerUnits = dcsCommon.getAllExistingPlayersAndUnits() -- indexed by player name
|
||||
--old -- contains per group a player record, use prime unit to access player's unit
|
||||
|
||||
for pname, aUnit in pairs(allPlayerUnits) do
|
||||
if --aUnit:isExist() and
|
||||
aUnit:inAir() and
|
||||
if aUnit:inAir() and
|
||||
dcsCommon.isTroopCarrier(aUnit, csarManager.troopCarriers)
|
||||
then -- troop carrier and is flying
|
||||
local uPoint = aUnit:getPoint()
|
||||
@ -1044,7 +1143,7 @@ function csarManager.update() -- every second
|
||||
end
|
||||
|
||||
--trigger.action.outTextForGroup(uID, hoverMsg, 30, true)
|
||||
trigger.action.outSoundForGroup(uID, csarManager.actionSound)
|
||||
trigger.action.outSoundForGroup(uID, csarManager.pickupSound)
|
||||
|
||||
--return -- we only ever rescue one
|
||||
end -- hovered long enough
|
||||
@ -1209,8 +1308,15 @@ function csarManager.readCSARZone(theZone)
|
||||
if theZone.csarFreq < 0.01 then theZone.csarFreq = nil end
|
||||
theZone.numCrew = 1
|
||||
theZone.csarMapMarker = nil
|
||||
theZone.timeLimit = theZone:getNumberFromZoneProperty("timeLimit", 0)
|
||||
if theZone.timeLimit == 0 then theZone.timeLimit = nil else theZone.timeLimit = timeLimit * 60 end
|
||||
if theZone:hasProperty("timeLimit") then
|
||||
local tmin, tmax = theZone:getPositiveRangeFromZoneProperty("timeLimit", 1)
|
||||
-- trigger.action.outText("Read time limit for <" .. theZone.name .. ">: <" .. tmin .. ">, <" .. tmax .. ">", 30)
|
||||
theZone.timeLimit = {tmin, tmax}
|
||||
else
|
||||
theZone.timeLimit = nil
|
||||
end
|
||||
-- theZone.timeLimit = theZone:getNumberFromZoneProperty("timeLimit", 0)
|
||||
-- if theZone.timeLimit == 0 then theZone.timeLimit = nil else theZone.timeLimit = timeLimit * 60 end
|
||||
|
||||
local deferred = theZone:getBoolFromZoneProperty("deferred", false)
|
||||
|
||||
@ -1255,7 +1361,7 @@ function csarManager.readCSARZone(theZone)
|
||||
-- add to list of startable csar
|
||||
if theZone.startCSAR then
|
||||
csarManager.addCSARZone(theZone)
|
||||
trigger.action.outText("csar: added <".. theZone.name .."> to deferred csar missions", 30)
|
||||
-- trigger.action.outText("csar: added <".. theZone.name .."> to deferred csar missions", 30)
|
||||
end
|
||||
|
||||
if deferred and not theZone.startCSAR then
|
||||
@ -1276,11 +1382,29 @@ end
|
||||
-- Init & Start
|
||||
--
|
||||
|
||||
function csarManager.invokeCallbacks(theCoalition, success, numRescued, notes)
|
||||
-- mission complete cs(coalition, success, numberRescued, notes, data)
|
||||
function csarManager.invokeCallbacks(theCoalition, success, numRescued, notes, theMission)
|
||||
-- invoke anyone who wants to know that a group
|
||||
-- of people was rescued.
|
||||
for idx, cb in pairs(csarManager.csarCompleteCB) do
|
||||
cb(theCoalition, success, numRescued, notes)
|
||||
cb(theCoalition, success, numRescued, notes, theMission)
|
||||
end
|
||||
end
|
||||
|
||||
-- mission created cb(theMission)
|
||||
function csarManager.invokeNewMissionCallbacks(theMission)
|
||||
--trigger.action.outText("enter invoke new mission cb", 30)
|
||||
-- invoke anyone who wants to know that a new mission was created
|
||||
for idx, cb in pairs(csarManager.csarCreatedCB) do
|
||||
cb(theMission)
|
||||
end
|
||||
end
|
||||
|
||||
-- mission: picking up the evacuee
|
||||
function csarManager.invokePickUpCallbacks(theMission)
|
||||
-- invoke anyone who wants to know that a new mission was created
|
||||
for idx, cb in pairs(csarManager.csarPickupCB) do
|
||||
cb(theMission)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1288,6 +1412,14 @@ function csarManager.installCallback(theCB)
|
||||
table.insert(csarManager.csarCompleteCB, theCB)
|
||||
end
|
||||
|
||||
function csarManager.installNewMissionCallback(theCB)
|
||||
table.insert(csarManager.csarCreatedCB, theCB)
|
||||
end
|
||||
|
||||
function csarManager.installPickupCallback(theCB)
|
||||
table.insert(csarManager.csarPickupCB, theCB)
|
||||
end
|
||||
|
||||
function csarManager.readConfigZone()
|
||||
csarManager.name = "csarManagerConfig" -- compat with cfxZones
|
||||
local theZone = cfxZones.getZoneByName("csarManagerConfig")
|
||||
@ -1331,7 +1463,10 @@ function csarManager.readConfigZone()
|
||||
csarManager.rescueScore = theZone:getNumberFromZoneProperty( "rescueScore", 100)
|
||||
|
||||
csarManager.actionSound = theZone:getStringFromZoneProperty( "actionSound", "Quest Snare 3.wav")
|
||||
csarManager.successSound = theZone:getStringFromZoneProperty("successSound", csarManager.actionSound)
|
||||
csarManager.pickupSound = theZone:getStringFromZoneProperty("pickupSound", csarManager.actionSound)
|
||||
csarManager.vectoring = theZone:getBoolFromZoneProperty("vectoring", true)
|
||||
csarManager.lostSound = theZone:getStringFromZoneProperty("lostSound", csarManager.actionSound)
|
||||
|
||||
-- add own troop carriers
|
||||
if theZone:hasProperty("troopCarriers") then
|
||||
@ -1348,6 +1483,7 @@ function csarManager.readConfigZone()
|
||||
|
||||
csarManager.addPrefix = theZone:getBoolFromZoneProperty("addPrefix", true)
|
||||
|
||||
csarManager.maxMissions = theZone:getNumberFromZoneProperty("maxMissions", 15)
|
||||
if csarManager.verbose then
|
||||
trigger.action.outText("+++csar: read config", 30)
|
||||
end
|
||||
@ -1415,4 +1551,6 @@ end
|
||||
|
||||
-- minFreq, maxFreq settings for config and mission-individual
|
||||
|
||||
-- may want to change if time limit was exceeded on return to tell
|
||||
player that they did not survive the transport
|
||||
--]]--
|
||||
@ -1,5 +1,5 @@
|
||||
dcsCommon = {}
|
||||
dcsCommon.version = "3.0.1"
|
||||
dcsCommon.version = "3.0.2"
|
||||
--[[-- VERSION HISTORY
|
||||
3.0.0 - removed bad bug in stringStartsWith, only relevant if caseSensitive is false
|
||||
- point2text new intsOnly option
|
||||
@ -8,7 +8,9 @@ dcsCommon.version = "3.0.1"
|
||||
- new pointInDirectionOfPointXYY()
|
||||
- createGroundGroupWithUnits now supports liveries
|
||||
- new getAllExistingPlayersAndUnits()
|
||||
3.0.1 - clone: better handling of string type
|
||||
3.0.1 - clone: better handling of string type
|
||||
3.0.2 - new getPlayerUnit()
|
||||
3.0.3 - createStaticObjectForCoalitionInRandomRing() returns x and z
|
||||
--]]--
|
||||
|
||||
-- dcsCommon is a library of common lua functions
|
||||
@ -1934,7 +1936,7 @@ dcsCommon.version = "3.0.1"
|
||||
function dcsCommon.createStaticObjectForCoalitionAtLocation(theCoalition, loc, name, objType, heading, dead)
|
||||
if not heading then heading = math.random(360) * 3.1415 / 180 end
|
||||
local theData = dcsCommon.createStaticObjectDataAt(loc, name, objType, heading, dead)
|
||||
local theStatic = coalition.addStaticObject(theCoalition, theData)
|
||||
local theStatic = coalition.addStaticObject(theCoalition, theData) -- warning! coalition is not country!
|
||||
return theStatic
|
||||
end
|
||||
|
||||
@ -1947,8 +1949,8 @@ dcsCommon.version = "3.0.1"
|
||||
theData.x = p.x
|
||||
theData.y = p.z
|
||||
|
||||
local theStatic = coalition.addStaticObject(theCoalition, theData)
|
||||
return theStatic
|
||||
local theStatic = coalition.addStaticObject(theCoalition, theData) -- warning! coalition is not country
|
||||
return theStatic, p.x, p.z
|
||||
end
|
||||
|
||||
|
||||
@ -2703,6 +2705,19 @@ function dcsCommon.isTroopCarrier(theUnit, carriers)
|
||||
return dcsCommon.isTroopCarrierType(uType, carriers)
|
||||
end
|
||||
|
||||
function dcsCommon.getPlayerUnit(playerName)
|
||||
if not playerName then return nil end
|
||||
for idx, theSide in pairs(dcsCommon.coalitionSides) do
|
||||
local thePlayers = coalition.getPlayers(theSide)
|
||||
for idy, theUnit in pairs (thePlayers) do
|
||||
if theUnit and theUnit:isExist() and theUnit.getPlayerName
|
||||
and theUnit:getPlayerName() == playerName then
|
||||
return theUnit
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function dcsCommon.getAllExistingPlayerUnitsRaw()
|
||||
local apu = {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxHeloTroops = {}
|
||||
cfxHeloTroops.version = "3.0.0"
|
||||
cfxHeloTroops.version = "3.0.2"
|
||||
cfxHeloTroops.verbose = false
|
||||
cfxHeloTroops.autoDrop = true
|
||||
cfxHeloTroops.autoPickup = false
|
||||
@ -37,6 +37,8 @@ cfxHeloTroops.requestRange = 500 -- meters
|
||||
- harmonized spawning invocations across cloners and spawners
|
||||
- dmlZones
|
||||
- requestRange attribute
|
||||
3.0.1 - fixed a bug with legalTroops attribute
|
||||
3.0.2 - fixed a typo in in-air menu
|
||||
|
||||
--]]--
|
||||
--
|
||||
@ -337,7 +339,7 @@ function cfxHeloTroops.addAirborneMenu(conf)
|
||||
-- let's begin by assuming no troops aboard
|
||||
local commandTxt = "(To load troops, land in proximity to them)"
|
||||
if conf.troopsOnBoardNum > 0 then
|
||||
commandTxt = "(You are carrying " .. conf.troopsOnBoardNum .. " Assault Troops. Land to deploy them"
|
||||
commandTxt = "(You are carrying " .. conf.troopsOnBoardNum .. " Assault Troops. Land to deploy them)"
|
||||
end
|
||||
local theCommand = missionCommands.addCommandForGroup(
|
||||
conf.id,
|
||||
@ -887,7 +889,7 @@ function cfxHeloTroops.readConfigZone()
|
||||
|
||||
if theZone:hasProperty("legalTroops") then
|
||||
local theTypesString = theZone:getStringFromZoneProperty("legalTroops", "")
|
||||
local unitTypes = dcsCommon.splitString(aSpawner.types, ",")
|
||||
local unitTypes = dcsCommon.splitString(theTypesString, ",")
|
||||
if #unitTypes < 1 then
|
||||
unitTypes = {"Soldier AK", "Infantry AK", "Infantry AK ver2", "Infantry AK ver3", "Infantry AK Ins", "Soldier M249", "Soldier M4 GRG", "Soldier M4", "Soldier RPG", "Paratrooper AKS-74", "Paratrooper RPG-16", "Stinger comm dsr", "Stinger comm", "Soldier stinger", "SA-18 Igla-S comm", "SA-18 Igla-S manpad", "Igla manpad INS", "SA-18 Igla comm", "SA-18 Igla manpad",} -- default
|
||||
else
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
messenger = {}
|
||||
messenger.version = "3.0.0"
|
||||
messenger.version = "3.1.0"
|
||||
messenger.verbose = false
|
||||
messenger.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
@ -11,6 +11,8 @@ messenger.messengers = {}
|
||||
2.3.0 - cfxZones OOP switch
|
||||
2.3.1 - triggering message AFTER the on/off switches are tested
|
||||
3.0.0 - removed messenger, in?, f? attributes, harmonized on messenger?
|
||||
3.1.0 - msgGroup supports multiple groups, separated by comma
|
||||
- msgUnit supports multiple units, separated by comma
|
||||
--]]--
|
||||
|
||||
function messenger.addMessenger(theZone)
|
||||
@ -166,18 +168,12 @@ end
|
||||
-- reat attributes
|
||||
--
|
||||
function messenger.createMessengerWithZone(theZone)
|
||||
-- start val - a range
|
||||
|
||||
local aMessage = theZone:getStringFromZoneProperty("message", "")
|
||||
theZone.message = aMessage -- refactoring: messenger.preProcMessage(aMessage, theZone) removed
|
||||
|
||||
theZone.message = aMessage
|
||||
theZone.spaceBefore = theZone:getBoolFromZoneProperty("spaceBefore", false)
|
||||
theZone.spaceAfter = theZone:getBoolFromZoneProperty("spaceAfter", false)
|
||||
|
||||
theZone.soundFile = theZone:getStringFromZoneProperty("soundFile", "<none>")
|
||||
|
||||
theZone.clearScreen = theZone:getBoolFromZoneProperty("clearScreen", false)
|
||||
|
||||
theZone.duration = theZone:getNumberFromZoneProperty("duration", 30)
|
||||
if theZone:hasProperty("messageDuration") then
|
||||
theZone.duration = theZone:getNumberFromZoneProperty( "messageDuration", 30)
|
||||
@ -188,28 +184,8 @@ function messenger.createMessengerWithZone(theZone)
|
||||
if theZone:hasProperty("msgTriggerMethod") then
|
||||
theZone.msgTriggerMethod = theZone:getStringFromZoneProperty("msgTriggerMethod", "change")
|
||||
end
|
||||
|
||||
if theZone:hasProperty("f?") then
|
||||
theZone.triggerMessagerFlag = theZone:getStringFromZoneProperty("f?", "none")
|
||||
end
|
||||
-- can also use in? for counting. we always use triggerMessagerFlag
|
||||
if theZone:hasProperty("in?") then
|
||||
theZone.triggerMessagerFlag = theZone:getStringFromZoneProperty("in?", "none")
|
||||
end
|
||||
--[[--
|
||||
if theZone:hasProperty("messageOut?") then
|
||||
theZone.triggerMessagerFlag = theZone:getStringFromZoneProperty("messageOut?", "none")
|
||||
end
|
||||
--]]--
|
||||
-- try default only if no other is set
|
||||
if not theZone.triggerMessagerFlag then
|
||||
if not theZone:hasProperty("messenger?") then
|
||||
trigger.action.outText("*** Note: messenger in <" .. theZone.name .. "> can't be triggered", 30)
|
||||
end
|
||||
theZone.triggerMessagerFlag = theZone:getStringFromZoneProperty( "messenger?", "none")
|
||||
end
|
||||
|
||||
theZone.lastMessageTriggerValue = theZone:getFlagValue(theZone.triggerMessagerFlag)-- save last value
|
||||
theZone.triggerMessagerFlag = theZone:getStringFromZoneProperty( "messenger?", "none")
|
||||
theZone.lastMessageTriggerValue = theZone:getFlagValue(theZone.triggerMessagerFlag) -- save last value
|
||||
|
||||
theZone.messageOff = theZone:getBoolFromZoneProperty("mute", false) --false
|
||||
if theZone:hasProperty("messageMute") then
|
||||
@ -235,15 +211,42 @@ function messenger.createMessengerWithZone(theZone)
|
||||
end
|
||||
|
||||
if theZone:hasProperty("group") then
|
||||
theZone.msgGroup = theZone:getStringFromZoneProperty("group", "<none>")
|
||||
-- now supporting multiple groups
|
||||
local theGroups = {}
|
||||
local rawGroups = theZone:getStringFromZoneProperty("group", "<none>")
|
||||
if dcsCommon.containsString(rawGroups, ",") then
|
||||
theGroups = dcsCommon.splitString(rawGroups, ",")
|
||||
theGroups = dcsCommon.trimArray(theGroups)
|
||||
theZone.msgGroup = theGroups
|
||||
else
|
||||
theZone.msgGroup = {rawGroups}
|
||||
end
|
||||
|
||||
elseif theZone:hasProperty("msgGroup") then
|
||||
theZone.msgGroup = theZone:getStringFromZoneProperty("msgGroup", "<none>")
|
||||
local rawGroups = theZone:getStringFromZoneProperty("msgGroup", "<none>")
|
||||
if dcsCommon.containsString(rawGroups, ",") then
|
||||
theGroups = dcsCommon.splitString(rawGroups, ",")
|
||||
theGroups = dcsCommon.trimArray(theGroups)
|
||||
theZone.msgGroup = theGroups
|
||||
else
|
||||
theZone.msgGroup = {rawGroups,}
|
||||
end
|
||||
end
|
||||
|
||||
if theZone:hasProperty("unit") then
|
||||
theZone.msgUnit = theZone:getStringFromZoneProperty("unit", "<none>")
|
||||
elseif theZone:hasProperty("msgUnit") then
|
||||
theZone.msgUnit = theZone:getStringFromZoneProperty("msgUnit", "<none>")
|
||||
if theZone:hasProperty("unit") or theZone:hasProperty("msgUnit") then
|
||||
local rawUnits = "err"
|
||||
if theZone:hasProperty("unit") then
|
||||
rawUnits = theZone:getStringFromZoneProperty("unit", "<none>")
|
||||
else
|
||||
rawUnits = theZone:getStringFromZoneProperty("msgUnit", "<none>")
|
||||
end
|
||||
if dcsCommon.containsString(rawUnits, ",") then
|
||||
local theUnits = dcsCommon.splitString(rawUnits, ",")
|
||||
theUnits = dcsCommon.trimArray(theUnits)
|
||||
theZone.msgUnit = theUnits
|
||||
else
|
||||
theZone.msgUnit = {rawUnits,}
|
||||
end
|
||||
end
|
||||
|
||||
if (theZone.msgGroup and theZone.msgUnit) or
|
||||
@ -337,24 +340,28 @@ function messenger.isTriggered(theZone)
|
||||
end
|
||||
trigger.action.outSoundForCoalition(theZone.msgCoalition, fileName)
|
||||
elseif theZone.msgGroup then
|
||||
local theGroup = Group.getByName(theZone.msgGroup)
|
||||
if theGroup and Group.isExist(theGroup) then
|
||||
local ID = theGroup:getID()
|
||||
msg = messenger.dynamicGroupProcessing(msg, theZone, theGroup)
|
||||
if #msg > 0 or theZone.clearScreen then
|
||||
trigger.action.outTextForGroup(ID, msg, theZone.duration, theZone.clearScreen)
|
||||
for idx, aGroupName in pairs(theZone.msgGroup) do
|
||||
local theGroup = Group.getByName(aGroupName)
|
||||
if theGroup and Group.isExist(theGroup) then
|
||||
local ID = theGroup:getID()
|
||||
msg = messenger.dynamicGroupProcessing(msg, theZone, theGroup)
|
||||
if #msg > 0 or theZone.clearScreen then
|
||||
trigger.action.outTextForGroup(ID, msg, theZone.duration, theZone.clearScreen)
|
||||
end
|
||||
trigger.action.outSoundForGroup(ID, fileName)
|
||||
end
|
||||
trigger.action.outSoundForGroup(ID, fileName)
|
||||
end
|
||||
elseif theZone.msgUnit then
|
||||
local theUnit = Unit.getByName(theZone.msgUnit)
|
||||
if theUnit and Unit.isExist(theUnit) then
|
||||
local ID = theUnit:getID()
|
||||
msg = messenger.dynamicUnitProcessing(msg, theZone, theUnit)
|
||||
if #msg > 0 or theZone.clearScreen then
|
||||
trigger.action.outTextForUnit(ID, msg, theZone.duration, theZone.clearScreen)
|
||||
end
|
||||
trigger.action.outSoundForUnit(ID, fileName)
|
||||
for idx, aUnitName in pairs (theZone.msgUnit) do
|
||||
local theUnit = Unit.getByName(aUnitName)
|
||||
if theUnit and Unit.isExist(theUnit) then
|
||||
local ID = theUnit:getID()
|
||||
msg = messenger.dynamicUnitProcessing(msg, theZone, theUnit)
|
||||
if #msg > 0 or theZone.clearScreen then
|
||||
trigger.action.outTextForUnit(ID, msg, theZone.duration, theZone.clearScreen)
|
||||
end
|
||||
trigger.action.outSoundForUnit(ID, fileName)
|
||||
end
|
||||
end
|
||||
elseif theZone:getLinkedUnit() then
|
||||
-- this only works if the zone is linked to a unit
|
||||
|
||||
1234
modules/names.lua
Normal file
1234
modules/names.lua
Normal file
File diff suppressed because it is too large
Load Diff
@ -136,7 +136,7 @@ end
|
||||
function ownAll.start()
|
||||
-- lib check
|
||||
if not dcsCommon.libCheck then
|
||||
trigger.action.outText("cfx ownAlll requires dcsCommon", 30)
|
||||
trigger.action.outText("cfx ownAll requires dcsCommon", 30)
|
||||
return false
|
||||
end
|
||||
if not dcsCommon.libCheck("cfx ownAll", ownAll.requiredLibs) then
|
||||
|
||||
@ -30,7 +30,6 @@ persistence.requiredLibs = {
|
||||
persistence.flagsToSave = {} -- simple table
|
||||
persistence.callbacks = {} -- cbblocks, dictionary by name
|
||||
|
||||
|
||||
--
|
||||
-- modules register here
|
||||
--
|
||||
@ -76,7 +75,6 @@ function persistence.getSavedDataForModule(name)
|
||||
return persistence.missionData[name] -- simply get the modules data block
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Shared Data API
|
||||
--
|
||||
@ -113,7 +111,6 @@ function persistence.isDir(path) -- check if path is a directory
|
||||
return success
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Main save meths
|
||||
--
|
||||
@ -189,7 +186,6 @@ function persistence.saveTable(theTable, fileName, shared, append)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function persistence.loadText(fileName) -- load file as text
|
||||
if not persistence.active then return nil end
|
||||
if not fileName then return nil end
|
||||
@ -218,8 +214,6 @@ function persistence.loadTable(fileName) -- load file as table
|
||||
return tab
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data Load on Start
|
||||
--
|
||||
@ -401,7 +395,6 @@ end
|
||||
--
|
||||
-- config & start
|
||||
--
|
||||
|
||||
function persistence.collectFlagsFromZone(theZone)
|
||||
local theFlags = theZone:getStringFromZoneProperty("saveFlags", "*dummy")
|
||||
persistence.registerFlagsToSave(theFlags, theZone)
|
||||
@ -409,7 +402,7 @@ end
|
||||
|
||||
function persistence.readConfigZone()
|
||||
if not _G["lfs"] then
|
||||
trigger.action.outText("+++persistence: DCS correctly not 'desanitized'. Persistence disabled", 30)
|
||||
trigger.action.outText("+++persistence: DCS currently not 'desanitized'. Persistence disabled", 30)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
radioMenu = {}
|
||||
radioMenu.version = "2.2.0"
|
||||
radioMenu.version = "2.2.1"
|
||||
radioMenu.verbose = false
|
||||
radioMenu.ups = 1
|
||||
radioMenu.requiredLibs = {
|
||||
@ -18,6 +18,7 @@ radioMenu.menus = {}
|
||||
full wildcard support for ack and cooldown
|
||||
2.1.1 - outMessage now works correctly
|
||||
2.2.0 - clean-up
|
||||
2.2.1 - corrected ackD
|
||||
--]]--
|
||||
|
||||
function radioMenu.addRadioMenu(theZone)
|
||||
@ -299,7 +300,7 @@ function radioMenu.createRadioMenuWithZone(theZone)
|
||||
theZone.outValD = theZone:getStringFromZoneProperty("valD", 1)
|
||||
end
|
||||
if theZone:hasProperty("ackD") then
|
||||
theZone.ackC = theZone:getStringFromZoneProperty("ackD", "Acknowledged: D")
|
||||
theZone.ackD = theZone:getStringFromZoneProperty("ackD", "Acknowledged: D")
|
||||
end
|
||||
|
||||
if theZone:hasProperty("removeMenu?") then
|
||||
|
||||
628
modules/scribe.lua
Normal file
628
modules/scribe.lua
Normal file
@ -0,0 +1,628 @@
|
||||
scribe = {}
|
||||
scribe.version = "1.0.0"
|
||||
scribe.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
"cfxZones", -- Zones, of course
|
||||
"cfxMX",
|
||||
}
|
||||
|
||||
--[[--
|
||||
Player statistics package
|
||||
VERSION HISTORY
|
||||
1.0.0 Initial Version
|
||||
--]]--
|
||||
scribe.verbose = true
|
||||
scribe.db = {} -- indexed by player name
|
||||
scribe.playerUnits = {} -- indexed by unit name. for crash detection
|
||||
|
||||
--[[--
|
||||
unitEntry:
|
||||
ttime -- total time in seconds
|
||||
airTime -- total air time
|
||||
landings -- number of landings
|
||||
lastLanding -- time of last landing OR DEPARTURE.
|
||||
departures -- toital take-offs
|
||||
crashes -- number of total crashes, deaths etc
|
||||
--]]--
|
||||
|
||||
function scribe.createUnitEntry()
|
||||
local theEntry = {}
|
||||
theEntry.ttime = 0
|
||||
theEntry.lastTime = 99999999 -- NOT math.huge because json
|
||||
theEntry.landings = 0
|
||||
theEntry.lastLanding = 99999999 -- not math.huge -- in the future
|
||||
theEntry.departures = 0
|
||||
theEntry.crashes = 0
|
||||
theEntry.startUps = 0
|
||||
theEntry.rescues = 0
|
||||
return theEntry
|
||||
end
|
||||
|
||||
--[[--
|
||||
playerEntry:
|
||||
units[] -- by type name indexed types the player has flown
|
||||
-- each entry has
|
||||
lastUnitName -- name of the unit player was last seen in
|
||||
-- used to determine if player is still in-game
|
||||
lastUnitType
|
||||
isActive -- used to detect if player has left and close down record
|
||||
--]]--
|
||||
|
||||
function scribe.createPlayerEntry(name)
|
||||
local theEntry = {}
|
||||
theEntry.playerName = name -- for easy access
|
||||
local theUnit = dcsCommon.getPlayerUnit(name)
|
||||
local theType = theUnit:getTypeName()
|
||||
local unitName = theUnit:getName()
|
||||
theEntry.units = {}
|
||||
theEntry.lastUnitName = "cfxNone" -- don't ever use that name
|
||||
theEntry.lastUnitType = "none"
|
||||
theEntry.isActive = false -- is player in game?
|
||||
return theEntry
|
||||
end
|
||||
|
||||
function scribe.getPlayerNamed(name) -- lazy allocation
|
||||
local theEntry = scribe.db[name]
|
||||
if not theEntry then
|
||||
theEntry = scribe.createPlayerEntry(name)
|
||||
scribe.db[name] = theEntry
|
||||
end
|
||||
return theEntry
|
||||
end
|
||||
|
||||
function scribe.sumPlayerEntry(theEntry, theField)
|
||||
local sum = 0
|
||||
for idx, aUnit in pairs(theEntry.units) do
|
||||
if aUnit[theField] then sum = sum + aUnit[theField] end
|
||||
end
|
||||
return sum
|
||||
end
|
||||
|
||||
function scribe.tickEntry(theEntry)
|
||||
if not theEntry then return 0 end
|
||||
local now = timer.getTime()
|
||||
local uEntry = theEntry.units[theEntry.lastUnitType]
|
||||
if not uEntry then return 0 end -- can happen on idling server that has reloaded. all last players have invalid last units
|
||||
local delta = now - uEntry.lastTime
|
||||
if delta < 0 then delta = 0 end
|
||||
uEntry.lastTime = now
|
||||
uEntry.ttime = uEntry.ttime + delta
|
||||
return delta
|
||||
end
|
||||
|
||||
|
||||
function scribe.finalizeEntry(theEntry)
|
||||
-- player no longer in game. finalize last entry
|
||||
-- and make it inactive
|
||||
theEntry.isActive = false
|
||||
local delta = scribe.tickEntry(theEntry) -- on LAST flown aircraft
|
||||
local uEntry = theEntry.units[theEntry.lastUnitType]
|
||||
if uEntry then
|
||||
uEntry.lastTime = 99999999 -- NOT math.huge
|
||||
|
||||
local deltaTime = dcsCommon.processHMS("<:h>:<:m>:<:s>", delta)
|
||||
local fullTime = dcsCommon.processHMS("<:h>:<:m>:<:s>", uEntry.ttime)
|
||||
if scribe.byePlayer then
|
||||
trigger.action.outText("Player " .. theEntry.playerName .. " left " .. theEntry.lastUnitName .. " (a " .. theEntry.lastUnitType .. "), total time in aircraft " .. fullTime ..".", 30)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function scribe.entry2text(uEntry, totals)
|
||||
-- validate uEntry, lazy init of missing fields
|
||||
if not uEntry then uEntry = {} end
|
||||
if not uEntry.ttime then uEntry.ttime = 0 end
|
||||
if not uEntry.departures then uEntry.departures = 0 end
|
||||
if not uEntry.landings then uEntry.landings = 0 end
|
||||
if not uEntry.crashes then uEntry.crashes = 0 end
|
||||
if not uEntry.startups then uEntry.startups = 0 end
|
||||
if not uEntry.rescues then uEntry.rescues = 0 end
|
||||
|
||||
local t = ""
|
||||
if not totals.ttime then totals.ttime = 0 end
|
||||
t = t .. scribe.lTime .. " " .. dcsCommon.processHMS("<:h>:<:m>:<:s>", uEntry.ttime) .. " hrs"
|
||||
totals.ttime = totals.ttime + uEntry.ttime
|
||||
if scribe.departures then
|
||||
t = t .. ", " .. scribe.lDeparture .. " " .. uEntry.departures
|
||||
if not totals.departures then totals.departures = 0 end
|
||||
totals.departures = totals.departures + uEntry.departures
|
||||
end
|
||||
if scribe.landings then
|
||||
t = t .. ", " .. scribe.lLanding .. " " .. uEntry.landings
|
||||
if not totals.landings then totals.landings = 0 end
|
||||
totals.landings = totals.landings + uEntry.landings
|
||||
end
|
||||
if scribe.crashes then
|
||||
t = t .. ", " .. scribe.lCrash .. " " .. uEntry.crashes
|
||||
if not totals.crashes then totals.crashes = 0 end
|
||||
totals.crashes = totals.crashes + uEntry.crashes
|
||||
end
|
||||
if scribe.startUps then
|
||||
t = t .. ", " .. scribe.lStartUp .. " " .. uEntry.startUps
|
||||
if not totals.startUps then totals.startUps = 0 end
|
||||
totals.startUps = totals.startUps + uEntry.startUps
|
||||
end
|
||||
if scribe.rescues then
|
||||
t = t .. ", " .. scribe.lRescue .. " " .. uEntry.rescues
|
||||
if not totals.rescues then totals.rescues = 0 end
|
||||
totals.rescues = totals.rescues + uEntry.rescues
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
--
|
||||
-- Event handling
|
||||
--
|
||||
function scribe.playerBirthedIn(playerName, theUnit)
|
||||
-- access db
|
||||
local theEntry = scribe.getPlayerNamed(playerName) -- can be new
|
||||
local myType = theUnit:getTypeName()
|
||||
local uName = theUnit:getName()
|
||||
local theGroup = theUnit:getGroup()
|
||||
local gID = theGroup:getID()
|
||||
-- check if this player is still active
|
||||
if theEntry.isActive then
|
||||
-- do something to remedy this
|
||||
scribe.finalizeEntry(theEntry)
|
||||
end
|
||||
|
||||
-- check if player switched airframes
|
||||
if theEntry.lastUnitName == uName and scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. playerName .. "> reappeard in same unit <" .. uName .. ">", 30)
|
||||
else
|
||||
|
||||
end
|
||||
theEntry.lastUnitName = uName
|
||||
theEntry.lastUnitType = myType
|
||||
theEntry.isActive = true -- activate player
|
||||
|
||||
-- set us up to track this player in this unit
|
||||
local myTypeEntry = theEntry.units[myType]
|
||||
if not myTypeEntry then
|
||||
myTypeEntry = scribe.createUnitEntry()
|
||||
local uGroup = theUnit:getGroup()
|
||||
local gName = uGroup:getName()
|
||||
myTypeEntry.gName = gName
|
||||
theEntry.units[myType] = myTypeEntry
|
||||
end
|
||||
|
||||
myTypeEntry.lastTime = timer.getTime()
|
||||
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. playerName .. "> entered aircraft <" .. uName .. "> (a " .. myType .. ")", 30)
|
||||
end
|
||||
|
||||
if scribe.greetPlayer then
|
||||
local msg = "\nWelcome " .. theEntry.playerName .. " to your " .. myType .. ". Your stats currently are:\n\n"
|
||||
msg = msg .. scribe.entry2data(theEntry) .. "\n"
|
||||
trigger.action.outTextForGroup(gID, msg, 30)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function scribe.playerCrashed(playerName)
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: enter crash for <" .. playerName .. ">", 30)
|
||||
end
|
||||
|
||||
local theEntry = scribe.getPlayerNamed(playerName)
|
||||
if not theEntry.isActive then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. playerName .. "> CRASH event ignored: player not active", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
local uEntry = theEntry.units[theEntry.lastUnitType]
|
||||
uEntry.crashes = uEntry.crashes + 1
|
||||
scribe.finalizeEntry(theEntry)
|
||||
end
|
||||
|
||||
function scribe.playerEjected(playerName)
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: enter eject for <" .. playerName .. ">, handing off to crash", 30)
|
||||
end
|
||||
-- counts as a crash
|
||||
local theEntry = scribe.getPlayerNamed(playerName)
|
||||
if not theEntry.isActive then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. playerName .. "> EJECT event ignored: player not active", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
scribe.playerCrashed(playerName)
|
||||
end
|
||||
|
||||
function scribe.playerDied(playerName)
|
||||
-- trigger.action.outText("+++scb: player <" .. playerName .. "> DEAD event, handing off to crashS", 30)
|
||||
-- counts as a crash
|
||||
local theEntry = scribe.getPlayerNamed(playerName)
|
||||
if not theEntry.isActive then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. playerName .. "> DEAD event ignored: player not active", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
scribe.playerCrashed(playerName)
|
||||
end
|
||||
|
||||
function scribe.engineStarted(playerName)
|
||||
local theEntry = scribe.getPlayerNamed(playerName)
|
||||
if not theEntry.isActive then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. playerName .. "> STARTUP event ignored: player not active", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local uEntry = theEntry.units[theEntry.lastUnitType]
|
||||
uEntry.startUps = uEntry.startUps + 1
|
||||
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: startup registered for <" .. playerName .. ">.", 30)
|
||||
end
|
||||
end
|
||||
|
||||
function scribe.playerLanded(playerName)
|
||||
local theEntry = scribe.getPlayerNamed(playerName)
|
||||
if not theEntry.isActive then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. playerName .. "> landing event ignored: player not active", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local uEntry = theEntry.units[theEntry.lastUnitType]
|
||||
-- see if last landing is at least xx seconds old
|
||||
local now = timer.getTime()
|
||||
delta = now - uEntry.lastLanding
|
||||
if delta > scribe.landingCD or delta < 0 then
|
||||
uEntry.landings = uEntry.landings + 1
|
||||
else
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: landing ignored: cooldown active", 30)
|
||||
end
|
||||
end
|
||||
uEntry.lastLanding = now
|
||||
|
||||
end
|
||||
|
||||
function scribe.playerDeparted(playerName)
|
||||
local theEntry = scribe.getPlayerNamed(playerName)
|
||||
if not theEntry.isActive then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. playerName .. "> take-off event ignored: player not active", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local uEntry = theEntry.units[theEntry.lastUnitType]
|
||||
-- see if last landing is at least xx seconds old
|
||||
local now = timer.getTime()
|
||||
delta = now - uEntry.lastLanding -- we use laastLanding for BOTH!
|
||||
if delta > scribe.landingCD or delta < 0 then
|
||||
uEntry.departures = uEntry.departures + 1
|
||||
else
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: departure ignored: cooldown active", 30)
|
||||
end
|
||||
end
|
||||
uEntry.lastLanding = now -- also for Departures!
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- API
|
||||
--
|
||||
-- invoked from other modules
|
||||
function scribe.playerRescueComplete(playerName)
|
||||
local theEntry = scribe.getPlayerNamed(playerName)
|
||||
if not theEntry.isActive then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. playerName .. "> rescue complete event ignored: player not active", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
local uEntry = theEntry.units[theEntry.lastUnitType]
|
||||
if not uEntry then
|
||||
-- this should not happen
|
||||
trigger.action.outText("+scb: unknown unit for player <" .. playerName .. "> in recue complete. Ignored", 30)
|
||||
return
|
||||
end
|
||||
if not uEntry.rescues then uEntry.rescues = 0 end
|
||||
uEntry.rescues = uEntry.rescues + 1
|
||||
end
|
||||
|
||||
function scribe:onEvent(theEvent)
|
||||
if not theEvent.initiator then return end
|
||||
local theUnit = theEvent.initiator
|
||||
if not theUnit then return end
|
||||
local uName = theUnit:getName()
|
||||
if scribe.playerUnits[uName] and scribe.verbose then
|
||||
trigger.action.outText("+++scb: event <" .. theEvent.id .. " = " .. dcsCommon.event2text(theEvent.id) .. ">, concerns player unit named <" .. uName .. ">.", 30)
|
||||
end
|
||||
|
||||
if not theUnit.getPlayerName then
|
||||
if scribe.playerUnits[uName] and scribe.verbose then
|
||||
trigger.action.outText("+++scb no more a player unit (case A: getPlanerName not implemented), event = <" .. theEvent.id .. ">, unit named <" .. uName .. ">", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local playerName = theUnit:getPlayerName()
|
||||
if not playerName then
|
||||
if scribe.playerUnits[uName] and scribe.verbose then
|
||||
trigger.action.outText("+++scb no more a player unit (case B: nilplayer name), event = <" .. theEvent.id .. ">, unit named <" .. uName .. ">", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
-- when we get here we have a player event
|
||||
|
||||
-- players can only ever activate by birth event
|
||||
if theEvent.id == 15 then -- birth
|
||||
scribe.playerBirthedIn(playerName, theUnit)
|
||||
scribe.playerUnits[uName] = playerName -- for crash helo detection
|
||||
end
|
||||
|
||||
if theEvent.id == 8 or theEvent.id == 9 then -- dead, pilot_dead
|
||||
scribe.playerDied(playerName)
|
||||
end
|
||||
|
||||
if theEvent.id == 6 then -- ejected
|
||||
scribe.playerEjected(playerName)
|
||||
end
|
||||
|
||||
if theEvent.id == 5 then -- crash
|
||||
scribe.playerCrashed(playerName)
|
||||
end
|
||||
|
||||
if theEvent.id == 4 then -- landed
|
||||
scribe.playerLanded(playerName)
|
||||
end
|
||||
|
||||
if theEvent.id == 3 then -- take-off
|
||||
scribe.playerDeparted(playerName)
|
||||
-- trigger.action.outText("departure detected", 30)
|
||||
end
|
||||
|
||||
if theEvent.id == 18 then -- engine start
|
||||
-- make sure group isn't on hotstart
|
||||
local theGroup = theUnit:getGroup()
|
||||
local gName = theGroup:getName()
|
||||
if cfxMX.groupHotByName[gName] then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("scb: ignored engine start: hot start for <" .. playerName .. ">", 30)
|
||||
end
|
||||
else
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("scb: engine start for <" .. playerName .. ">", 30)
|
||||
end
|
||||
scribe.engineStarted(playerName)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- GUI
|
||||
--
|
||||
function scribe.redirectCheckData(args)
|
||||
timer.scheduleFunction(scribe.doCheckData, args, timer.getTime() + 0.1)
|
||||
end
|
||||
|
||||
function scribe.doCheckData(unitInfo)
|
||||
local unitName = unitInfo.uName
|
||||
|
||||
-- we now try and match player to the unit by rummaning through db
|
||||
local thePlayerEntry = nil
|
||||
for pName, theEntry in pairs(scribe.db) do
|
||||
if unitName == theEntry.lastUnitName and theEntry.isActive then
|
||||
thePlayerEntry = theEntry
|
||||
end
|
||||
end
|
||||
|
||||
if (not thePlayerEntry) then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: cannot retrieve player for unit <" .. unitName .. ">", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- tick over so we have updated time
|
||||
scribe.tickEntry(thePlayerEntry)
|
||||
local msg = "Player " .. thePlayerEntry.playerName .. ":\n"
|
||||
msg = msg .. scribe.entry2data(thePlayerEntry)
|
||||
trigger.action.outTextForGroup(unitInfo.gID, msg, 30)
|
||||
end
|
||||
|
||||
function scribe.entry2data(thePlayerEntry)
|
||||
local msg = ""
|
||||
local totals = {}
|
||||
for aType, uEntry in pairs (thePlayerEntry.units) do
|
||||
msg = msg .. aType .. " -- " .. scribe.entry2text(uEntry, totals) .. "\n"
|
||||
end
|
||||
if dcsCommon.getSizeOfTable(thePlayerEntry.units) > 1 then
|
||||
local dummy = {}
|
||||
msg = msg .. "\nTotals -- " .. scribe.entry2text(totals, dummy) .. "\n"
|
||||
end
|
||||
return msg
|
||||
end
|
||||
|
||||
--
|
||||
-- GC -- detect player leaving
|
||||
--
|
||||
function scribe.GC()
|
||||
timer.scheduleFunction(scribe.GC, {}, timer.getTime() + 1)
|
||||
-- iterate through all players in DB and see if they
|
||||
-- are still on-line.
|
||||
for pName, theEntry in pairs(scribe.db) do
|
||||
if theEntry.isActive then
|
||||
-- this player is on the books as in the game
|
||||
local theUnit = Unit.getByName(theEntry.lastUnitName)
|
||||
if theUnit and Unit.isExist(theUnit) and theUnit:getLife() >= 1 then
|
||||
-- all is fine, go on
|
||||
else
|
||||
-- this unit no longer exists and we finalize player
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: player <" .. pName .. "> left <" .. theEntry.lastUnitName .. "> unit, finalizing", 30)
|
||||
end
|
||||
scribe.finalizeEntry(theEntry)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- start
|
||||
--
|
||||
function scribe.startPlayerGUI()
|
||||
-- scan all mx players
|
||||
-- note: currently assumes single-player groups
|
||||
-- in preparation of single-player 'commandForUnit'
|
||||
-- ASSUMES SINGLE-UNIT PLAYER GROUPS!
|
||||
for uName, uData in pairs(cfxMX.playerUnitByName) do
|
||||
local unitInfo = {}
|
||||
-- try and access each unit even if we know that the
|
||||
-- unit does not exist in-game right now
|
||||
local gData = cfxMX.playerUnit2Group[uName]
|
||||
local gName = gData.name
|
||||
local coa = cfxMX.groupCoalitionByName[gName]
|
||||
local theType = uData.type
|
||||
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("unit <" .. uName .. ">: type <" .. theType .. "> coa <" .. coa .. ">, group <" .. gName .. ">", 30)
|
||||
end
|
||||
|
||||
unitInfo.uName = uName -- needed for reverse-lookup
|
||||
unitInfo.gName = gName -- also needed for reverse lookup
|
||||
unitInfo.coa = coa
|
||||
unitInfo.gID = gData.groupId
|
||||
unitInfo.uID = uData.unitId
|
||||
unitInfo.theType = theType
|
||||
unitInfo.cat = cfxMX.groupTypeByName[gName]
|
||||
unitInfo.root = missionCommands.addSubMenuForGroup(unitInfo.gID, scribe.uiMenu)
|
||||
unitInfo.checkData = missionCommands.addCommandForGroup(unitInfo.gID, "Get Pilot's Statistics", unitInfo.root, scribe.redirectCheckData, unitInfo)
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Config
|
||||
--
|
||||
function scribe.readConfigZone()
|
||||
local theZone = cfxZones.getZoneByName("scribeConfig")
|
||||
if not theZone then
|
||||
theZone = cfxZones.createSimpleZone("scribeConfig")
|
||||
end
|
||||
scribe.verbose = theZone.verbose
|
||||
scribe.hasGUI = theZone:getBoolFromZoneProperty("hasGUI", true)
|
||||
scribe.uiMenu = theZone:getStringFromZoneProperty("uiMenu", "Mission Logbook")
|
||||
scribe.greetPlayer = theZone:getBoolFromZoneProperty("greetPlayer", true)
|
||||
scribe.byePlayer = theZone:getBoolFromZoneProperty("byebyePlayer", true)
|
||||
scribe.landings = theZone:getBoolFromZoneProperty("landings", true)
|
||||
scribe.lLanding = theZone:getStringFromZoneProperty("lLandings", "landings:")
|
||||
scribe.departures = theZone:getBoolFromZoneProperty("departures", true)
|
||||
scribe.lDeparture = theZone:getStringFromZoneProperty("lDepartures", "take-offs:")
|
||||
scribe.startUps = theZone:getBoolFromZoneProperty("startups", true)
|
||||
scribe.lStartUp = theZone:getStringFromZoneProperty("lStartups", "starts:")
|
||||
scribe.crashes = theZone:getBoolFromZoneProperty("crashes", true)
|
||||
scribe.lCrash = theZone:getStringFromZoneProperty("lCrashes", "crashes:")
|
||||
scribe.rescues = theZone:getBoolFromZoneProperty("rescues", false)
|
||||
scribe.lRescue = theZone:getStringFromZoneProperty("lRescues", "rescues:")
|
||||
scribe.lTime = theZone:getStringFromZoneProperty("lTime", "time:")
|
||||
scribe.landingCD = theZone:getNumberFromZoneProperty("landingCD", 60) -- seconds between stake-off, landings, or either
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- load / save (game data)
|
||||
--
|
||||
function scribe.saveData()
|
||||
local theData = {}
|
||||
-- tick over all player entry recors so we can save
|
||||
-- most recent data
|
||||
for planerName, thePlayerEntry in pairs(scribe.db) do
|
||||
if thePlayerEntry then scribe.tickEntry(thePlayerEntry) end
|
||||
end
|
||||
|
||||
-- save current log. simple clone
|
||||
local theLog = dcsCommon.clone(scribe.db)
|
||||
theData.theLog = theLog
|
||||
|
||||
return theData
|
||||
end
|
||||
|
||||
function scribe.loadData()
|
||||
if not persistence then return end
|
||||
local theData = persistence.getSavedDataForModule("scribe")
|
||||
if not theData then
|
||||
if scribe.verbose then
|
||||
trigger.action.outText("+++scb: no save date received, skipping.", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local theLog = theData.theLog
|
||||
scribe.db = theLog
|
||||
|
||||
-- post-proc: set all to inactive, no player can be in game at start
|
||||
for pName, theEntry in pairs(scribe.db) do
|
||||
if theEntry.isActive then
|
||||
theEntry.isActive = false
|
||||
theEntry.lastUnitName = "cfxNone"
|
||||
theEntry.lastUnitType = "xxx"
|
||||
for uName, uEntry in pairs (theEntry.units) do
|
||||
uEntry.lastTime = 99999999 -- NOT math.huge
|
||||
uEntry.lastLanding = 99999999 -- NOT math.huge!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- start
|
||||
--
|
||||
function scribe.start()
|
||||
-- lib check
|
||||
if not dcsCommon.libCheck then
|
||||
trigger.action.outText("cfx scribe requires dcsCommon", 30)
|
||||
return false
|
||||
end
|
||||
if not dcsCommon.libCheck("cfx scribe", scribe.requiredLibs) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- install event handler
|
||||
world.addEventHandler(scribe)
|
||||
|
||||
-- get config
|
||||
scribe.readConfigZone()
|
||||
|
||||
-- install menus to all player units
|
||||
if scribe.hasGUI then
|
||||
scribe.startPlayerGUI()
|
||||
end
|
||||
|
||||
-- now load all save data and populate map with troops that
|
||||
-- we deployed last save.
|
||||
if persistence then
|
||||
-- sign up for persistence
|
||||
callbacks = {}
|
||||
callbacks.persistData = scribe.saveData
|
||||
persistence.registerModule("scribe", callbacks)
|
||||
-- now load my data
|
||||
scribe.loadData()
|
||||
end
|
||||
|
||||
-- start GC
|
||||
timer.scheduleFunction(scribe.GC, {}, timer.getTime() + 1)
|
||||
|
||||
-- say hi!
|
||||
trigger.action.outText("cfx scribe v" .. scribe.version .. " started.", 30)
|
||||
return true
|
||||
end
|
||||
|
||||
-- let's go
|
||||
if not scribe.start() then
|
||||
trigger.action.outText("cfx scribe module failed to launch.", 30)
|
||||
end
|
||||
BIN
tutorial & demo missions/demo - On the Record.miz
Normal file
BIN
tutorial & demo missions/demo - On the Record.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user