Scenery targets refactored and updated (#65)
Changed scenery targets to now be taken from trigger zones instead based on object ID
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 146 KiB |
@@ -1,68 +1,72 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Spearhead Missions</title>
|
||||
<link rel="stylesheet" href="/style/style.css">
|
||||
<script src="/js/site.js"></script>
|
||||
<style>
|
||||
.side-nav a.active {
|
||||
font-weight: bold;
|
||||
color: #4fc3f7;
|
||||
}
|
||||
</style>
|
||||
<script type="module" src="/js/components.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<app-header></app-header>
|
||||
</header>
|
||||
<main>
|
||||
<div class="reference-container">
|
||||
<app-sidebar></app-sidebar>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<h1>Advanced Tutorial: Missions</h1>
|
||||
<h2 id="strike">Strike</h2>
|
||||
<p>
|
||||
Naming: <span class="inline-lua"><span class="lua-variable">MISSION_STRIKE_[Name]</span></span> <br>
|
||||
</p>
|
||||
<h3 id="specific_targets">Specific Targets</h3>
|
||||
<p>TBD</p>
|
||||
|
||||
|
||||
<h3 id="scenery_targets">Scenery Targets</h3>
|
||||
<p>
|
||||
Bridges, buildings or other type of targets that are baked into the map are awesome targets.<br>
|
||||
We wanted to make sure they were easily integrated in Spearhead.
|
||||
|
||||
All you will need to do is right click on the scenery object you want added. <br>
|
||||
You will then get the option to "Assign as...", click this and you'll see a new trigger zone created. <br>
|
||||
It's best not to edit the triggerzone, but you can rename it however you like. <br>
|
||||
|
||||
Scenery objects will always be a specific "target" in the mission.
|
||||
|
||||
</p>
|
||||
|
||||
<note-box type="warning" title="Changing IDs">
|
||||
Be aware that Object IDs can change when maps are updated and edited and the "Assign as..." action will have to be performed again.
|
||||
</note-box>
|
||||
|
||||
|
||||
<p>Here's two images showing how a bridge is added to a mission.</p>
|
||||
<img src="/img/bridge.png" style="max-height: 35remrem;"/>
|
||||
<img src="/img/bridge_added.png" style="max-height: 35remrem;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
<footer>
|
||||
<p>© 2025 Spearhead Project</p>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Spearhead Missions</title>
|
||||
<link rel="stylesheet" href="/style/style.css">
|
||||
<script src="/js/site.js"></script>
|
||||
<style>
|
||||
.side-nav a.active {
|
||||
font-weight: bold;
|
||||
color: #4fc3f7;
|
||||
}
|
||||
</style>
|
||||
<script type="module" src="/js/components.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<app-header></app-header>
|
||||
</header>
|
||||
<main>
|
||||
<div class="reference-container">
|
||||
<app-sidebar></app-sidebar>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<h1>Advanced Tutorial: Missions</h1>
|
||||
<h2 id="strike">Strike</h2>
|
||||
<p>
|
||||
Naming: <span class="inline-lua"><span class="lua-variable">MISSION_STRIKE_[Name]</span></span> <br>
|
||||
</p>
|
||||
<h3 id="specific_targets">Specific Targets</h3>
|
||||
<p>TBD</p>
|
||||
|
||||
|
||||
<h3 id="scenery_targets">Scenery Targets</h3>
|
||||
<p>
|
||||
Bridges, buildings or other type of targets that are baked into the map are awesome targets.<br>
|
||||
We wanted to make sure they were easily integrated in Spearhead.
|
||||
</p>
|
||||
|
||||
<note-box type="info" title="Implementation details">
|
||||
Spearhead detects scenery targets by the trigger zone name. A zone named <strong>scenerytarget_[freeform]</strong> or
|
||||
<strong>scenerytargets</strong> (case-insensitive) will be scanned and any scenery objects that has the attribute "Buildings" inside the zone
|
||||
will be added as mission scenery targets.
|
||||
</note-box>
|
||||
|
||||
<p>
|
||||
Scenery targets are treated like mission targets: they are included in the mission completion calculation
|
||||
(their `IsAlive()` state is checked) and their state is persisted/updated when missions spawn or resume.
|
||||
</p>
|
||||
|
||||
<note-box type="warning" title="Changing IDs">
|
||||
Due to Object IDs changing when maps are updated and edited the "Assign as..." functionality does not work for scenery targets.
|
||||
Hence the need to use trigger zones to define them.
|
||||
</note-box>
|
||||
|
||||
|
||||
<p>Here's two images showing how a bridge is added to a mission.</p>
|
||||
<img src="/img/bridge.png" style="max-height: 35remrem;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
<footer>
|
||||
<p>© 2025 Spearhead Project</p>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
Binary file not shown.
@@ -979,6 +979,90 @@ do -- INIT DCS_UTIL
|
||||
|
||||
end
|
||||
|
||||
---@param zone SpearheadTriggerZone
|
||||
---@return Array<SpearheadSceneryObject> sceneryObjects
|
||||
function DCS_UTIL.getSceneryObjectsInZone(zone)
|
||||
---@type Volume
|
||||
local volume
|
||||
|
||||
if(zone.zone_type == "Cilinder") then
|
||||
local y = land.getHeight({ x = zone.location.x, y = zone.location.y })
|
||||
---@type Sphere
|
||||
local sphere = {
|
||||
id = world.VolumeType.SPHERE,
|
||||
params = {
|
||||
point = { x = zone.location.x, y = y, z = zone.location.y },
|
||||
radius = zone.radius
|
||||
}
|
||||
}
|
||||
volume = sphere
|
||||
else
|
||||
local minX = nil
|
||||
local maxX = nil
|
||||
local minZ = nil
|
||||
local maxZ = nil
|
||||
|
||||
for _, point in pairs(zone.verts) do
|
||||
if minX == nil or point.x < minX then
|
||||
minX = point.x
|
||||
end
|
||||
if maxX == nil or point.x > maxX then
|
||||
maxX = point.x
|
||||
end
|
||||
if minZ == nil or point.y < minZ then
|
||||
minZ = point.y
|
||||
end
|
||||
if maxZ == nil or point.y > maxZ then
|
||||
maxZ = point.y
|
||||
end
|
||||
end
|
||||
|
||||
if(minX == nil or maxX == nil or minZ == nil or maxZ == nil) then
|
||||
return {}
|
||||
end
|
||||
|
||||
---@type Vec3
|
||||
local min = {
|
||||
x = minX,
|
||||
y = land.getHeight({ x = minX, y = minZ }) - 100,
|
||||
z = minZ
|
||||
}
|
||||
|
||||
---@type Vec3
|
||||
local max = {
|
||||
x = maxX,
|
||||
y = land.getHeight({ x = maxX, y = maxZ }) + 500,
|
||||
z = maxZ
|
||||
}
|
||||
|
||||
---@type Box
|
||||
local box = {
|
||||
id = world.VolumeType.BOX,
|
||||
params = {
|
||||
min = min,
|
||||
max = max
|
||||
}
|
||||
}
|
||||
volume = box
|
||||
end
|
||||
|
||||
---@type Array<SpearheadSceneryObject>
|
||||
local sceneryObjects = {}
|
||||
|
||||
---@param object SceneryObject
|
||||
local onFound = function(object)
|
||||
if object and object:isExist() and
|
||||
object:hasAttribute("Buildings")
|
||||
then
|
||||
local obj = Spearhead.classes.stageClasses.Groups.SpearheadSceneryObject.New(object["id_"])
|
||||
table.insert(sceneryObjects, obj)
|
||||
end
|
||||
end
|
||||
|
||||
world.searchObjects(Object.Category.SCENERY, volume, onFound)
|
||||
return sceneryObjects
|
||||
end
|
||||
|
||||
---@param group Group
|
||||
function DCS_UTIL.getUnitTypeFromGroup(group)
|
||||
for _, unit in pairs(group:getUnits()) do
|
||||
|
||||
@@ -186,18 +186,12 @@ function Database.New(Logger)
|
||||
table.insert(self._tables.SupplyHubZones, zone_name)
|
||||
end
|
||||
|
||||
if zone_data.properties then
|
||||
for _, kvPair in pairs(zone_data.properties) do
|
||||
if kvPair.key and kvPair.key == "OBJECT ID" then
|
||||
local objectID = tonumber(kvPair.value)
|
||||
if objectID then
|
||||
local sceneryObject = Spearhead.classes.stageClasses.Groups.SpearheadSceneryObject.New(objectID)
|
||||
table.insert(self._tables.AllSceneryObjects, sceneryObject)
|
||||
end
|
||||
end
|
||||
if lowered == "scenerytarget" or lowered == "scenerytargets" then
|
||||
local sceneryObjects = Spearhead.DcsUtil.getSceneryObjectsInZone(zone_data)
|
||||
for _, sceneryObject in pairs(sceneryObjects) do
|
||||
table.insert(self._tables.AllSceneryObjects, sceneryObject)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,77 +1,77 @@
|
||||
---@class SpearheadSceneryObject
|
||||
---@field private persistentName string The persistent name of the scenery object
|
||||
---@field private objectID number The ID of the scenery object
|
||||
---@field private internalObj table
|
||||
---@field private isDead boolean Indicates if the scenery object is dead
|
||||
local SpearheadSceneryObject = {}
|
||||
SpearheadSceneryObject.__index = SpearheadSceneryObject
|
||||
|
||||
---comment
|
||||
---@param objectID number
|
||||
---@return SpearheadSceneryObject?
|
||||
function SpearheadSceneryObject.New(objectID)
|
||||
|
||||
local self = setmetatable({}, SpearheadSceneryObject)
|
||||
|
||||
if objectID == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
self.persistentName = "SpearheadSceneryObject_" .. objectID
|
||||
self.objectID = objectID
|
||||
self.isDead = false
|
||||
self.internalObj = {
|
||||
["id_"] = objectID
|
||||
}
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
function SpearheadSceneryObject:IsAlive()
|
||||
|
||||
if Object.isExist(self.internalObj) == false then
|
||||
self:MarkDead()
|
||||
return false
|
||||
end
|
||||
|
||||
if SceneryObject.getLife(self.internalObj) <= 0.10 then
|
||||
self:MarkDead()
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---@private
|
||||
function SpearheadSceneryObject:MarkDead()
|
||||
if self.isDead == true then return end
|
||||
self.isDead = true
|
||||
Spearhead.classes.persistence.Persistence.UnitKilled(self.persistentName, self:GetPoint(), 0, "Scenery")
|
||||
end
|
||||
|
||||
function SpearheadSceneryObject:UpdateStatePersistently()
|
||||
if self.isDead == true then
|
||||
return
|
||||
end
|
||||
|
||||
local state = Spearhead.classes.persistence.Persistence.UnitState(self.persistentName)
|
||||
if state and state.isDead == true then
|
||||
trigger.action.explosion(self:GetPoint(), 1000)
|
||||
self.isDead = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function SpearheadSceneryObject:GetPersistentName()
|
||||
return self.persistentName
|
||||
end
|
||||
|
||||
function SpearheadSceneryObject:GetPoint()
|
||||
return Object.getPoint(self.internalObj)
|
||||
end
|
||||
|
||||
if not Spearhead.classes then Spearhead.classes = {} end
|
||||
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
|
||||
if not Spearhead.classes.stageClasses.Groups then Spearhead.classes.stageClasses.Groups = {} end
|
||||
Spearhead.classes.stageClasses.Groups.SpearheadSceneryObject = SpearheadSceneryObject
|
||||
---@class SpearheadSceneryObject
|
||||
---@field private persistentName string The persistent name of the scenery object
|
||||
---@field private objectID number The ID of the scenery object
|
||||
---@field private internalObj table
|
||||
---@field private isDead boolean Indicates if the scenery object is dead
|
||||
local SpearheadSceneryObject = {}
|
||||
SpearheadSceneryObject.__index = SpearheadSceneryObject
|
||||
|
||||
---comment
|
||||
---@param objectID number
|
||||
---@return SpearheadSceneryObject?
|
||||
function SpearheadSceneryObject.New(objectID)
|
||||
|
||||
local self = setmetatable({}, SpearheadSceneryObject)
|
||||
|
||||
if objectID == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
self.persistentName = "SpearheadSceneryObject_" .. objectID
|
||||
self.objectID = objectID
|
||||
self.isDead = false
|
||||
self.internalObj = {
|
||||
["id_"] = objectID
|
||||
}
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
function SpearheadSceneryObject:IsAlive()
|
||||
|
||||
if Object.isExist(self.internalObj) == false then
|
||||
self:MarkDead()
|
||||
return false
|
||||
end
|
||||
|
||||
if SceneryObject.getLife(self.internalObj) <= 0.10 then
|
||||
self:MarkDead()
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---@private
|
||||
function SpearheadSceneryObject:MarkDead()
|
||||
if self.isDead == true then return end
|
||||
self.isDead = true
|
||||
Spearhead.classes.persistence.Persistence.UnitKilled(self.persistentName, self:GetPoint(), 0, "Scenery")
|
||||
end
|
||||
|
||||
function SpearheadSceneryObject:UpdateStatePersistently()
|
||||
if self.isDead == true then
|
||||
return
|
||||
end
|
||||
|
||||
local state = Spearhead.classes.persistence.Persistence.UnitState(self.persistentName)
|
||||
if state and state.isDead == true then
|
||||
trigger.action.explosion(self:GetPoint(), 1000)
|
||||
self.isDead = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function SpearheadSceneryObject:GetPersistentName()
|
||||
return self.persistentName
|
||||
end
|
||||
|
||||
function SpearheadSceneryObject:GetPoint()
|
||||
return Object.getPoint(self.internalObj)
|
||||
end
|
||||
|
||||
if not Spearhead.classes then Spearhead.classes = {} end
|
||||
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
|
||||
if not Spearhead.classes.stageClasses.Groups then Spearhead.classes.stageClasses.Groups = {} end
|
||||
Spearhead.classes.stageClasses.Groups.SpearheadSceneryObject = SpearheadSceneryObject
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user