DML/modules/duel.lua
Christian Franz 7c6deec7a6 Version 1.4.1
Civ Air off-map locations
Guardian Angel updates
Recon Mode updates
2023-08-10 11:45:07 +02:00

254 lines
7.2 KiB
Lua

duel = {}
duel.version = "1.0.0"
duel.verbose = false
duel.requiredLibs = {
"dcsCommon",
"cfxZones",
"cfxMX",
}
--[[--
Version History
1.0.0 - Initial Version
--]]--
--[[--
ATTENTION!
- REQUIRES that SSB is running on the host
- REQUIRTES that SSB is confgured that '0' (zero) means slot is enabled (this is SSB default)
- This script must run at MISSION START and will enable SSB
--]]--
duel.duelZones = {}
duel.activeDuelists = {}
duel.allDuelists = {}
--
-- reading attributes
--
function duel.createDuelZone(theZone)
theZone.duelists = {} -- all player units in this zone
-- iterate all players and find any unit that is placed in this zone
for unitName, unitData in pairs(cfxMX.playerUnitByName) do
local p = {}
p.x = unitData.x
p.z = unitData.y -- !!
p.y = 0
if theZone:pointInZone(p) then
-- this is a player aircraft in this zone
local duelist = {}
duelist.data = unitData
duelist.name = unitName
duelist.type = unitData.type
local groupData = cfxMX.playerUnit2Group[unitName]
duelist.groupName = groupData.name
duelist.coa = cfxMX.groupCoalitionByName[duelist.groupName]
if duel.verbose then
trigger.action.outText("Detected player unit <" .. duelist.name .. ">, type <" .. duelist.type .. "> of group <" .. duelist.groupName .. "> of coa <" .. duelist.coa .. "> in zone <" .. theZone.name .. "> as duelist", 30)
end
duelist.active = false
duelist.arena = theZone.name
duelist.zone = theZone
-- enter into global table
-- player can only be in at maximum one duelist zones
if duel.allDuelists[unitName] then
trigger.action.outText("+++WARNING: overlapping duelists! Overwriting previous data", 30)
end
duel.allDuelists[unitName] = duelist
theZone.duelists[unitName] = duelist
end
end
theZone.state = "waiting" -- FSM, init to waiting state
end
--
-- Event processing
--
function duel.closeSlotsForZoneAndCoaExceptGroupNamed(theZone, coa, groupName)
-- iterate this zone's duelist groups and tell SSB to close them now
local allDuelists = theZone.duelists
for unitName, theDuelist in pairs(allDuelists) do
local dgName = theDuelist.groupName
if (theDuelist.coa == coa) and (dgName ~= groupName) then
if duel.verbose then
trigger.action.outText("+++duel: closing SSB slot for group <" .. dgName .. ">, coa <" .. theDuelist.coa .. ">", 30)
trigger.action.setUserFlag(dgName,100) -- anything but 0 means closed
end
end
end
end
function duel.openSlotsForZoneAndCoa(theZone, coa)
local allDuelists = theZone.duelists
for unitName, theDuelist in pairs(allDuelists) do
if (theDuelist.coa == coa) then
if duel.verbose then
trigger.action.outText("+++duel: opening SSB slot for group <" .. theDuelist.groupName .. ">, coa <" .. theDuelist.coa .. ">", 30)
trigger.action.setUserFlag(theDuelist.groupName, 0) -- 0 means OPEN
end
end
end
end
function duel.checkReopenSlotsForZoneAndCoa(theZone, coa)
-- test if one side can reopen all slots to enter the duel
-- if so, will reset FSM for zone
local allDuelists = theZone.duelists
local allUnengaged = true
for unitName, theDuelist in pairs(allDuelists) do
if (theDuelist.coa == coa) then
local theUnit = Unit.getByName(unitName)
if theUnit and Unit.isExist(theUnit) then
-- unit is still alive on this side, can't reopen
allUnengaged = false
end
end
end
if allUnengaged then
duel.openSlotsForZoneAndCoa(theZone, coa)
theZone.state = "waiting"
end
end
function duel.duelistEnteredArena(theUnit, theDuelist)
-- we connect the player with duelist slot
theDuelist.playerName = theUnit:getPlayerName()
theDuelist.active = true
local player = theUnit:getPlayerName()
local unitName = theUnit:getName()
local groupName = theDuelist.groupName
local theZone = theDuelist.zone --duel.duelZones[theDuelist.arena]
local coa = theDuelist.coa
if duel.verbose then
trigger.action.outText("Player <" .. player .. "> entered arena <" .. theZone:getName() .. "> in unit <" .. unitName .. "> of group <" .. groupName .. "> type <" .. theDuelist.type .. ">, belongs to coalition <" .. coa .. ">", 30)
end
-- close all slots for this zone and coalition
duel.closeSlotsForZoneAndCoaExceptGroupNamed(theZone, coa, groupName)
end
function duel:onEvent(event)
if not event then return end
if duel.verbose then
--trigger.action.outText("Event: " .. event.id .. " (" .. dcsCommon.event2text(event.id) .. ")", 30)
end
local theUnit = event.initiator
if not theUnit then return end
if event.id == 15 then -- birth
local unitName = theUnit:getName()
-- see if this is a duelist that has spawned
if not duel.allDuelists[unitName] then
return -- not a duelist, not my problem
end
-- unit that entered is player controlled, and duelist
duel.duelistEnteredArena(theUnit, duel.allDuelists[unitName])
end
end
--
-- update
--
function duel.update()
-- call me in a second to poll triggers
timer.scheduleFunction(duel.update, {}, timer.getTime() + 1/duel.ups)
-- find units that have disappeared, and react accordingly
for unitName, theDuelist in pairs (duel.allDuelists) do
local theZone = theDuelist.zone
if theDuelist.active then
-- trigger.action.outText("+++duel: unit <" .. unitName .. "> is active in zone <" .. theZone:getName() .. ">, controlled by <" .. theDuelist.playerName .. ">", 30)
local theUnit = Unit.getByName(unitName)
if theUnit and Unit.isExist(theUnit) then
-- all is well
else
if duel.verbose then
trigger.action.outText("+++duel: unit <" .. unitName .. "> controlled by <" .. theDuelist.playerName .. "> has disappeared, starting cleanup", 30)
end
theDuelist.playerName = nil
theDuelist.active = false
duel.checkReopenSlotsForZoneAndCoa(theZone, theDuelist.coa)
end
end
end
-- now handle FSM for each zone separately
for zoneName, theZone in pairs(duel.duelZones) do
end
end
--
-- Config & start
--
function duel.readConfigZone()
local theZone = cfxZones.getZoneByName("duelConfig")
if not theZone then
theZone = cfxZones.createSimpleZone("duelConfig")
end
duel.verbose = theZone.verbose
duel.ups = theZone:getNumberFromZoneProperty("ups", 1)
duel.inside = theZone:getBoolFromZoneProperty("inside", true)
duel.gracePeriod = theZone:getNumberFromZoneProperty("gracePeriod", 30)
duel.keepScore = theZone:getBoolFromZoneProperty("score", true)
if duel.verbose then
trigger.action.outText("+++duel: read config", 30)
end
end
function duel.start()
if not dcsCommon.libCheck then
trigger.action.outText("cfx duel requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx Duel", duel.requiredLibs) then
return false
end
-- turn on SSB
trigger.action.setUserFlag("SSB",100)
-- read config
duel.readConfigZone()
-- process cloner Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("duel")
for k, aZone in pairs(attrZones) do
duel.createDuelZone(aZone) -- process attributes
duel.duelZones[aZone.name] = aZone -- add to list
end
-- connect event handler
world.addEventHandler(duel)
-- start update
duel.update()
trigger.action.outText("cfx Duel v" .. duel.version .. " started.", 30)
return true
end
if not duel.start() then
trigger.action.outText("cfx Duel aborted: missing libraries", 30)
duel = nil
end