mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Added feature: select unit payload at spawn and visibility.
This commit is contained in:
parent
92eab6fd41
commit
036f70db34
@ -24,7 +24,8 @@ begin
|
||||
end;
|
||||
|
||||
[Registry]
|
||||
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "OLYMPUS"; ValueData: "{app}\Mods\Services\Olympus"; Flags: preservestringtype
|
||||
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "DCSOLYMPUS_PATH"; ValueData: "{app}\Mods\Services\Olympus"; Flags: preservestringtype
|
||||
; Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};DCSOLYMPUS_PATH\bin"
|
||||
|
||||
[Setup]
|
||||
; Tell Windows Explorer to reload the environment
|
||||
|
||||
Binary file not shown.
@ -5,34 +5,63 @@ function Olympus.notify(message, displayFor)
|
||||
trigger.action.outText(message, displayFor)
|
||||
end
|
||||
|
||||
function Olympus.move(unitName, lat, lng, v, category)
|
||||
Olympus.notify("Olympus.move " .. unitName .. " (" .. lat .. ", " .. lng ..")", 10)
|
||||
function Olympus.move(unitName, lat, lng, altitude, speed, category, targetName)
|
||||
Olympus.notify("Olympus.move " .. unitName .. " (" .. lat .. ", " .. lng ..") " .. altitude .. "m " .. speed .. "m/s " .. category .. " target " .. targetName, 10)
|
||||
local unit = Unit.getByName(unitName)
|
||||
if unit ~= nil then
|
||||
if category == 1 then
|
||||
local startPoint = mist.getLeadPos(unit:getGroup())
|
||||
if category == "Aircraft" then
|
||||
local startPoint = mist.getLeadPos(unit:getGroup())
|
||||
local endPoint = coord.LLtoLO(lat, lng, 0)
|
||||
|
||||
local task = nil
|
||||
if targetName ~= "" then
|
||||
targetID = Unit.getByName(targetName):getID()
|
||||
task = {
|
||||
id = 'EngageUnit',
|
||||
params = {
|
||||
unitId = targetID,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
local path = {}
|
||||
path[#path + 1] = mist.fixedWing.buildWP(startPoint, flyOverPoint, v, startPoint.y, 'BARO')
|
||||
path[#path + 1] = mist.fixedWing.buildWP(endPoint, turningPoint, v, startPoint.y, 'BARO')
|
||||
path[#path + 1] = mist.fixedWing.buildWP(startPoint, flyOverPoint, speed, altitude, 'BARO')
|
||||
if task ~= nil then
|
||||
path[#path].task = task
|
||||
end
|
||||
path[#path + 1] = mist.fixedWing.buildWP(endPoint, turningPoint, speed, altitude, 'BARO')
|
||||
if task ~= nil then
|
||||
path[#path].task = task
|
||||
end
|
||||
|
||||
mist.goRoute(unit:getGroup(), path)
|
||||
local missionTask = {
|
||||
id = 'Mission',
|
||||
params = {
|
||||
route = {
|
||||
points = mist.utils.deepCopy(path),
|
||||
},
|
||||
},
|
||||
}
|
||||
group = unit:getGroup()
|
||||
local groupCon = group:getController()
|
||||
if groupCon then
|
||||
groupCon:setTask(missionTask)
|
||||
end
|
||||
Olympus.notify("Olympus.move executed succesfully on a air unit", 10)
|
||||
elseif category == 2 then
|
||||
elseif category == "GroundUnit" then
|
||||
vars =
|
||||
{
|
||||
group = unit:getGroup(),
|
||||
point = coord.LLtoLO(lat, lng, 0),
|
||||
form = "Off Road",
|
||||
heading = 0,
|
||||
speed = v,
|
||||
speed = speed,
|
||||
disableRoads = true
|
||||
}
|
||||
mist.groupToRandomPoint(vars)
|
||||
Olympus.notify("Olympus.move executed succesfully on a ground unit", 10)
|
||||
else
|
||||
Olympus.notify("Olympus.move not implemented yet for navy units", 10)
|
||||
Olympus.notify("Olympus.move not implemented yet for " .. category, 10)
|
||||
end
|
||||
else
|
||||
Olympus.notify("Error in Olympus.move " .. unitName, 10)
|
||||
@ -90,23 +119,26 @@ function Olympus.spawnGround(coalition, type, lat, lng, ID)
|
||||
Olympus.notify("Olympus.spawnGround completed succesfully", 10)
|
||||
end
|
||||
|
||||
function Olympus.spawnAir(coalition, type, lat, lng, alt)
|
||||
Olympus.notify("Olympus.spawnAir " .. coalition .. " " .. type .. " (" .. lat .. ", " .. lng ..")", 10)
|
||||
function Olympus.spawnAir(coalition, unitType, lat, lng, payloadName)
|
||||
local alt = 5000
|
||||
Olympus.notify("Olympus.spawnAir " .. coalition .. " " .. unitType .. " (" .. lat .. ", " .. lng ..") " .. payloadName, 10)
|
||||
local spawnLocation = mist.utils.makeVec3GL(coord.LLtoLO(lat, lng, 0))
|
||||
local payload = {}
|
||||
if Olympus.unitPayloads[unitType][payloadName] ~= nil then
|
||||
payload = Olympus.unitPayloads[unitType][payloadName]
|
||||
end
|
||||
local unitTable =
|
||||
{
|
||||
[1] =
|
||||
{
|
||||
["type"] = type,
|
||||
["type"] = unitType,
|
||||
["x"] = spawnLocation.x,
|
||||
["y"] = spawnLocation.z,
|
||||
["alt"] = alt,
|
||||
["skill"] = "Excellent",
|
||||
["payload"] =
|
||||
{
|
||||
["pylons"] =
|
||||
{
|
||||
},
|
||||
["pylons"] = payload,
|
||||
["fuel"] = 4900,
|
||||
["flare"] = 60,
|
||||
["ammo_type"] = 1,
|
||||
@ -146,53 +178,4 @@ function Olympus.spawnAir(coalition, type, lat, lng, alt)
|
||||
Olympus.notify("Olympus.spawnAir completed succesfully", 10)
|
||||
end
|
||||
|
||||
function Olympus.attackUnit(unitName, targetName, lat, lng)
|
||||
Olympus.notify("Olympus.attackUnit " .. unitName .. " " .. targetName, 10)
|
||||
local targetID = Unit.getByName(targetName):getID()
|
||||
local unit = Unit.getByName(unitName)
|
||||
|
||||
|
||||
local category = 1
|
||||
|
||||
|
||||
if unit ~= nil then
|
||||
if category == 1 then
|
||||
local startPoint = mist.getLeadPos(unit:getGroup())
|
||||
local endPoint = coord.LLtoLO(lat, lng, 0)
|
||||
|
||||
local attackTask = {
|
||||
id = 'EngageUnit',
|
||||
params = {
|
||||
unitId = targetID,
|
||||
}
|
||||
}
|
||||
|
||||
local path = {}
|
||||
path[#path + 1] = mist.fixedWing.buildWP(startPoint, flyOverPoint, v, startPoint.y, 'BARO')
|
||||
path[#path].task = attackTask
|
||||
path[#path + 1] = mist.fixedWing.buildWP(endPoint, turningPoint, v, startPoint.y, 'BARO')
|
||||
path[#path].task = attackTask
|
||||
|
||||
local missionTask = {
|
||||
id = 'Mission',
|
||||
params = {
|
||||
route = {
|
||||
points = mist.utils.deepCopy(path),
|
||||
},
|
||||
},
|
||||
}
|
||||
group = unit:getGroup()
|
||||
local groupCon = group:getController()
|
||||
if groupCon then
|
||||
groupCon:setTask(missionTask)
|
||||
end
|
||||
Olympus.notify("Olympus.attackUnit completed succesfully", 10)
|
||||
elseif category == 2 then
|
||||
Olympus.notify("Olympus.attackUnit not implemented yet for ground units", 10)
|
||||
else
|
||||
Olympus.notify("Olympus.attackUnit not implemented yet for navy units", 10)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Olympus.notify("OlympusCommand script loaded correctly", 10)
|
||||
@ -5,29 +5,86 @@ function Olympus.notify(message, displayFor)
|
||||
end
|
||||
|
||||
function Olympus.setMissionData(arg, time)
|
||||
local missionData = {}
|
||||
|
||||
-- Bullseye data
|
||||
local bullseyeVec3 = coalition.getMainRefPoint(0)
|
||||
local bullseyeLatitude, bullseyeLongitude, bullseyeAltitude = coord.LOtoLL(bullseyeVec3)
|
||||
local command = "Olympus.missionData = " ..
|
||||
"{" ..
|
||||
"bullseye = {" ..
|
||||
"x = " .. bullseyeVec3.x .. "," ..
|
||||
"y = " .. bullseyeVec3.z .. "," ..
|
||||
"lat = " .. bullseyeLatitude .. "," ..
|
||||
"lng = " .. bullseyeLongitude .. "," ..
|
||||
"}," ..
|
||||
"}\n" ..
|
||||
"Olympus.OlympusDLL.setMissionData()"
|
||||
local bullseye = {}
|
||||
bullseye["x"] = bullseyeVec3.x
|
||||
bullseye["y"] = bullseyeVec3.z
|
||||
bullseye["lat"] = bullseyeLatitude
|
||||
bullseye["lng"] = bullseyeLongitude
|
||||
|
||||
for groupName, group in pairs(mist.DBs.groupsByName) do
|
||||
if groupName and group then
|
||||
local hasTask = Group.getByName(groupName):getController():hasTask()
|
||||
Olympus.notify(groupName .. ": " .. tostring(hasTask), 2)
|
||||
-- Units tactical data
|
||||
-- TODO find some way to spread the load of getting this data (split)
|
||||
local unitsData = {}
|
||||
for groupName, gp in pairs(mist.DBs.groupsByName) do
|
||||
if groupName ~= nil then
|
||||
local group = Group.getByName(groupName)
|
||||
if group ~= nil then
|
||||
local controller = group:getController()
|
||||
for index, unit in pairs(group:getUnits()) do
|
||||
local table = {}
|
||||
table["targets"] = {}
|
||||
table["targets"]["visual"] = controller:getDetectedTargets(1)
|
||||
table["targets"]["radar"] = controller:getDetectedTargets(4)
|
||||
table["targets"]["rwr"] = controller:getDetectedTargets(16)
|
||||
table["targets"]["other"] = controller:getDetectedTargets(2, 8, 32)
|
||||
|
||||
table["ammo"] = unit:getAmmo()
|
||||
table["fuel"] = unit:getFuel()
|
||||
table["life"] = unit:getLife() / unit:getLife0()
|
||||
unitsData[unit:getObjectID()] = table
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Assemble missionData table
|
||||
missionData["bullseye"] = bullseye
|
||||
missionData["unitsData"] = unitsData
|
||||
|
||||
local command = "Olympus.missionData = " .. Olympus.serializeTable(missionData) .. "\n" .. "Olympus.OlympusDLL.setMissionData()"
|
||||
net.dostring_in("export", command)
|
||||
return time + 5
|
||||
end
|
||||
|
||||
function Olympus.serializeTable(val, name, skipnewlines, depth)
|
||||
skipnewlines = skipnewlines or false
|
||||
depth = depth or 0
|
||||
|
||||
local tmp = string.rep(" ", depth)
|
||||
|
||||
|
||||
if name then
|
||||
if type(name) == "number" then
|
||||
tmp = tmp .. "[" .. name .. "]" .. " = "
|
||||
else
|
||||
tmp = tmp .. name .. " = "
|
||||
end
|
||||
end
|
||||
|
||||
if type(val) == "table" then
|
||||
tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")
|
||||
|
||||
for k, v in pairs(val) do
|
||||
tmp = tmp .. Olympus.serializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "")
|
||||
end
|
||||
|
||||
tmp = tmp .. string.rep(" ", depth) .. "}"
|
||||
elseif type(val) == "number" then
|
||||
tmp = tmp .. tostring(val)
|
||||
elseif type(val) == "string" then
|
||||
tmp = tmp .. string.format("%q", val)
|
||||
elseif type(val) == "boolean" then
|
||||
tmp = tmp .. (val and "true" or "false")
|
||||
else
|
||||
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
||||
end
|
||||
|
||||
return tmp
|
||||
end
|
||||
|
||||
timer.scheduleFunction(Olympus.setMissionData, {}, timer.getTime() + 1)
|
||||
Olympus.notify("OlympusMission script loaded correctly", 10)
|
||||
|
||||
75
scripts/generatePayloadTables.py
Normal file
75
scripts/generatePayloadTables.py
Normal file
@ -0,0 +1,75 @@
|
||||
from slpp import slpp as lua
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
|
||||
SEARCH_FOLDER = "D:\\Eagle Dynamics\\DCS World OpenBeta"
|
||||
|
||||
def dump_lua(data):
|
||||
if type(data) is str:
|
||||
return f'"{data}"'
|
||||
if type(data) in (int, float):
|
||||
return f'{data}'
|
||||
if type(data) is bool:
|
||||
return data and "true" or "false"
|
||||
if type(data) is list:
|
||||
l = "{"
|
||||
l += ",\n ".join([dump_lua(item) for item in data])
|
||||
l += "}"
|
||||
return l
|
||||
if type(data) is dict:
|
||||
t = "{"
|
||||
t += ",\n ".join([f'[{k}] = {dump_lua(v)}' if type(k) == int else f'["{k}"]={dump_lua(v)}' for k,v in data.items()])
|
||||
t += "}"
|
||||
return t
|
||||
|
||||
logging.error(f"Unknown type {type(data)}")
|
||||
|
||||
filenames = [os.path.join(dp, f) for dp, dn, filenames in os.walk(SEARCH_FOLDER) for f in filenames if os.path.splitext(f)[1] == '.lua']
|
||||
|
||||
for filename in list(filenames):
|
||||
with open(filename, 'r') as f:
|
||||
try:
|
||||
if f.read().find("unitPayloads") == -1:
|
||||
filenames.remove(filename)
|
||||
except:
|
||||
filenames.remove(filename)
|
||||
logging.warning(f"{filename} skipped...")
|
||||
pass
|
||||
|
||||
names = {}
|
||||
payloads = {}
|
||||
for filename in filenames:
|
||||
with open(os.path.join(os.getcwd(), filename), 'r') as f: # open in readonly mode
|
||||
try:
|
||||
lines = f.read()
|
||||
searchString = "local unitPayloads = {"
|
||||
start = lines.find(searchString)
|
||||
end = lines.rfind("}")
|
||||
tmp = lua.decode(lines[start + len(searchString) - 1: end + 1])
|
||||
if type(tmp['payloads']) == dict:
|
||||
src = tmp['payloads'].values()
|
||||
else:
|
||||
src = tmp['payloads']
|
||||
|
||||
names[tmp['unitType']] = []
|
||||
payloads[tmp['unitType']] = {}
|
||||
for payload in src:
|
||||
names[tmp['unitType']].append(payload['name'])
|
||||
if type(payload['pylons']) == dict:
|
||||
payloads[tmp['unitType']][payload['name']] = {payload['pylons'][key]['num']: {"CLSID" : payload['pylons'][key]['CLSID']} for key in payload['pylons']}
|
||||
else:
|
||||
payloads[tmp['unitType']][payload['name']] = {payload['pylons'][key]['num']: {"CLSID" : payload['pylons'][key]['CLSID']} for key in range(len(payload['pylons']))}
|
||||
except:
|
||||
pass
|
||||
|
||||
with open('payloadNames.js', 'w') as f:
|
||||
f.write("payloadNames = ")
|
||||
json.dump(names, f, ensure_ascii = False)
|
||||
|
||||
with open('unitPayloads.lua', 'w') as f:
|
||||
f.write("Olympus.unitPayloads = " + dump_lua(payloads))
|
||||
|
||||
|
||||
|
||||
|
||||
1
scripts/payloadNames.js
Normal file
1
scripts/payloadNames.js
Normal file
File diff suppressed because one or more lines are too long
12586
scripts/unitPayloads.lua
Normal file
12586
scripts/unitPayloads.lua
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,112 +17,21 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "olympus", "olympus\olympus.
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
MinSizeRel|x64 = MinSizeRel|x64
|
||||
MinSizeRel|x86 = MinSizeRel|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
RelWithDebInfo|x64 = RelWithDebInfo|x64
|
||||
RelWithDebInfo|x86 = RelWithDebInfo|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Debug|x64.Build.0 = Debug|x64
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Debug|x86.Build.0 = Debug|Win32
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.MinSizeRel|x86.ActiveCfg = Release|Win32
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.MinSizeRel|x86.Build.0 = Release|Win32
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Release|x64.ActiveCfg = Release|x64
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Release|x64.Build.0 = Release|x64
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Release|x86.ActiveCfg = Release|Win32
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Release|x86.Build.0 = Release|Win32
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.RelWithDebInfo|x86.Build.0 = Release|Win32
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Debug|x64.Build.0 = Debug|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Debug|x86.Build.0 = Debug|Win32
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.MinSizeRel|x86.ActiveCfg = Release|Win32
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.MinSizeRel|x86.Build.0 = Release|Win32
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Release|x64.ActiveCfg = Release|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Release|x64.Build.0 = Release|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Release|x86.ActiveCfg = Release|Win32
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Release|x86.Build.0 = Release|Win32
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.RelWithDebInfo|x86.Build.0 = Release|Win32
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Debug|x64.Build.0 = Debug|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Debug|x86.Build.0 = Debug|Win32
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.MinSizeRel|x86.ActiveCfg = Release|Win32
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.MinSizeRel|x86.Build.0 = Release|Win32
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Release|x64.Build.0 = Release|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Release|x86.ActiveCfg = Release|Win32
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Release|x86.Build.0 = Release|Win32
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.RelWithDebInfo|x86.Build.0 = Release|Win32
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Debug|x64.Build.0 = Debug|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Debug|x86.Build.0 = Debug|Win32
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.MinSizeRel|x86.ActiveCfg = Release|Win32
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.MinSizeRel|x86.Build.0 = Release|Win32
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Release|x64.ActiveCfg = Release|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Release|x64.Build.0 = Release|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Release|x86.ActiveCfg = Release|Win32
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Release|x86.Build.0 = Release|Win32
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.RelWithDebInfo|x86.Build.0 = Release|Win32
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Debug|x64.Build.0 = Debug|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Debug|x86.Build.0 = Debug|Win32
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.MinSizeRel|x86.ActiveCfg = Release|Win32
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.MinSizeRel|x86.Build.0 = Release|Win32
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Release|x64.ActiveCfg = Release|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Release|x64.Build.0 = Release|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Release|x86.ActiveCfg = Release|Win32
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Release|x86.Build.0 = Release|Win32
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.RelWithDebInfo|x86.Build.0 = Release|Win32
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Debug|x64.Build.0 = Debug|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Debug|x86.Build.0 = Debug|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Release|x64.ActiveCfg = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Release|x64.Build.0 = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Release|x86.ActiveCfg = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Release|x86.Build.0 = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
#include "pch.h"
|
||||
|
||||
@ -149,14 +149,14 @@
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>include; ..\..\third-party\lua\include; ..\utils\include; ..\shared\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>include;..\..\third-party\GeographicLib-2.1.1\include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>lua.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>lua.lib; GeographicLib-i.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@ -171,7 +171,7 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>include;..\..\third-party\GeographicLib-2.1.1\include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -181,7 +181,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>lua.lib; GeographicLib-i.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\third-party\lua; ..\..\third-party\GeographicLib-2.1.1\lib</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\..\third-party\lua; </AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
||||
@ -8,7 +8,7 @@ namespace CommandPriority {
|
||||
};
|
||||
|
||||
namespace CommandType {
|
||||
enum CommandTypes { NO_TYPE, MOVE, SMOKE, LASE, EXPLODE, SPAWN_AIR, SPAWN_GROUND, ATTACK_UNIT };
|
||||
enum CommandTypes { NO_TYPE, MOVE, SMOKE, LASE, EXPLODE, SPAWN_AIR, SPAWN_GROUND };
|
||||
};
|
||||
|
||||
/* Base command class */
|
||||
@ -17,7 +17,7 @@ class Command
|
||||
public:
|
||||
int getPriority() { return priority; }
|
||||
int getType() { return type; }
|
||||
virtual void execute(lua_State* L) {};
|
||||
virtual void execute(lua_State* L) = 0;
|
||||
|
||||
protected:
|
||||
int priority = CommandPriority::LOW;
|
||||
@ -28,11 +28,14 @@ protected:
|
||||
class MoveCommand : public Command
|
||||
{
|
||||
public:
|
||||
MoveCommand(int ID, wstring unitName, Coords destination, int unitCategory) :
|
||||
MoveCommand(int ID, wstring unitName, Coords destination, double speed, double altitude, wstring unitCategory, wstring targetName):
|
||||
ID(ID),
|
||||
unitName(unitName),
|
||||
destination(destination),
|
||||
unitCategory(unitCategory)
|
||||
speed(speed),
|
||||
altitude(altitude),
|
||||
unitCategory(unitCategory),
|
||||
targetName(targetName)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
type = CommandType::MOVE;
|
||||
@ -43,7 +46,10 @@ private:
|
||||
const int ID;
|
||||
const wstring unitName;
|
||||
const Coords destination;
|
||||
const int unitCategory;
|
||||
const wstring unitCategory;
|
||||
const double speed;
|
||||
const double altitude;
|
||||
const wstring targetName;
|
||||
};
|
||||
|
||||
/* Smoke command */
|
||||
@ -88,10 +94,11 @@ private:
|
||||
class SpawnAirCommand : public Command
|
||||
{
|
||||
public:
|
||||
SpawnAirCommand(wstring coalition, wstring unitType, Coords location) :
|
||||
SpawnAirCommand(wstring coalition, wstring unitType, Coords location, wstring payloadName) :
|
||||
coalition(coalition),
|
||||
unitType(unitType),
|
||||
location(location)
|
||||
location(location),
|
||||
payloadName(payloadName)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
type = CommandType::SPAWN_AIR;
|
||||
@ -102,24 +109,5 @@ private:
|
||||
const wstring coalition;
|
||||
const wstring unitType;
|
||||
const Coords location;
|
||||
const wstring payloadName;
|
||||
};
|
||||
|
||||
/* Attack unit command */
|
||||
class AttackUnitCommand : public Command
|
||||
{
|
||||
public:
|
||||
AttackUnitCommand(wstring unitName, wstring targetName, Coords location) :
|
||||
unitName(unitName),
|
||||
targetName(targetName),
|
||||
location(location)
|
||||
{
|
||||
priority = CommandPriority::MEDIUM;
|
||||
type = CommandType::ATTACK_UNIT;
|
||||
};
|
||||
virtual void execute(lua_State* L);
|
||||
|
||||
private:
|
||||
const wstring unitName;
|
||||
const wstring targetName;
|
||||
const Coords location;
|
||||
};
|
||||
@ -7,10 +7,6 @@
|
||||
#define GROUND_DEST_DIST_THR 100
|
||||
#define AIR_DEST_DIST_THR 2000
|
||||
|
||||
namespace UnitCategory {
|
||||
enum UnitCategories { NO_CATEGORY, AIR, GROUND, NAVY }; // Do not edit, this codes are tied to values in DCS
|
||||
};
|
||||
|
||||
class Unit
|
||||
{
|
||||
public:
|
||||
@ -21,6 +17,17 @@ public:
|
||||
|
||||
void setPath(list<Coords> path);
|
||||
void setAlive(bool newAlive) { alive = newAlive; }
|
||||
void setTarget(int targetID);
|
||||
wstring getTarget();
|
||||
wstring getCurrentTask();
|
||||
|
||||
void resetActiveDestination();
|
||||
|
||||
virtual void changeSpeed(wstring change) {};
|
||||
virtual void changeAltitude(wstring change) {};
|
||||
|
||||
virtual double getTargetSpeed() { return targetSpeed; };
|
||||
virtual double getTargetAltitude() { return targetAltitude; };
|
||||
|
||||
int getID() { return ID; }
|
||||
wstring getName() { return name; }
|
||||
@ -34,9 +41,10 @@ public:
|
||||
double getAltitude() { return altitude; }
|
||||
double getHeading() { return heading; }
|
||||
json::value getFlags() { return flags; }
|
||||
int getCategory();
|
||||
Coords getActiveDestination() { return activeDestination; }
|
||||
|
||||
virtual wstring getCategory() { return L"No category"; };
|
||||
|
||||
json::value json();
|
||||
|
||||
protected:
|
||||
@ -47,21 +55,131 @@ protected:
|
||||
wstring unitName = L"undefined";
|
||||
wstring groupName = L"undefined";
|
||||
json::value type = json::value::null();
|
||||
int country = 0;
|
||||
int coalitionID = 0;
|
||||
double latitude = 0;
|
||||
double longitude = 0;
|
||||
double altitude = 0;
|
||||
double heading = 0;
|
||||
int country = NULL;
|
||||
int coalitionID = NULL;
|
||||
double latitude = NULL;
|
||||
double longitude = NULL;
|
||||
double altitude = NULL;
|
||||
double heading = NULL;
|
||||
double speed = NULL;
|
||||
json::value flags = json::value::null();
|
||||
Coords oldPosition = Coords(0); // Used to approximate speed
|
||||
int targetID = NULL;
|
||||
bool holding = false;
|
||||
bool looping = false;
|
||||
|
||||
double targetSpeed = 0;
|
||||
double targetAltitude = 0;
|
||||
|
||||
list<Coords> activePath;
|
||||
Coords activeDestination = Coords(0);
|
||||
|
||||
private:
|
||||
virtual void AIloop();
|
||||
|
||||
double oldDist = 0;
|
||||
private:
|
||||
mutex mutexLock;
|
||||
};
|
||||
|
||||
class AirUnit : public Unit
|
||||
{
|
||||
public:
|
||||
AirUnit(json::value json, int ID);
|
||||
|
||||
virtual wstring getCategory() = 0;
|
||||
|
||||
protected:
|
||||
virtual void AIloop();
|
||||
};
|
||||
|
||||
class Aircraft : public AirUnit
|
||||
{
|
||||
public:
|
||||
Aircraft(json::value json, int ID);
|
||||
|
||||
virtual wstring getCategory() { return L"Aircraft"; };
|
||||
|
||||
virtual void changeSpeed(wstring change);
|
||||
virtual void changeAltitude(wstring change);
|
||||
virtual double getTargetSpeed() { return targetSpeed; };
|
||||
virtual double getTargetAltitude() { return targetAltitude; };
|
||||
|
||||
protected:
|
||||
double targetSpeed = 150;
|
||||
double targetAltitude = 5000;
|
||||
};
|
||||
|
||||
class Helicopter : public AirUnit
|
||||
{
|
||||
public:
|
||||
Helicopter(json::value json, int ID);
|
||||
|
||||
virtual wstring getCategory() { return L"Helicopter"; };
|
||||
|
||||
virtual void changeSpeed(wstring change);
|
||||
virtual void changeAltitude(wstring change);
|
||||
virtual double getTargetSpeed() { return targetSpeed; };
|
||||
virtual double getTargetAltitude() { return targetAltitude; };
|
||||
|
||||
protected:
|
||||
double targetSpeed = 50;
|
||||
double targetAltitude = 1000;
|
||||
};
|
||||
|
||||
class GroundUnit : public Unit
|
||||
{
|
||||
public:
|
||||
GroundUnit(json::value json, int ID);
|
||||
virtual void AIloop();
|
||||
|
||||
virtual wstring getCategory() { return L"GroundUnit"; };
|
||||
virtual void changeSpeed(wstring change);
|
||||
virtual void changeAltitude(wstring change) {};
|
||||
virtual double getTargetSpeed() { return targetSpeed; };
|
||||
|
||||
protected:
|
||||
double targetSpeed = 10;
|
||||
};
|
||||
|
||||
class NavyUnit : public Unit
|
||||
{
|
||||
public:
|
||||
NavyUnit(json::value json, int ID);
|
||||
virtual void AIloop();
|
||||
|
||||
virtual wstring getCategory() { return L"NavyUnit"; };
|
||||
virtual void changeSpeed(wstring change);
|
||||
virtual void changeAltitude(wstring change) {};
|
||||
virtual double getTargetSpeed() { return targetSpeed; };
|
||||
|
||||
protected:
|
||||
double targetSpeed = 10;
|
||||
};
|
||||
|
||||
class Weapon : public Unit
|
||||
{
|
||||
public:
|
||||
Weapon(json::value json, int ID);
|
||||
|
||||
virtual wstring getCategory() = 0;
|
||||
|
||||
protected:
|
||||
/* Weapons are not controllable and have no AIloop */
|
||||
virtual void AIloop() {};
|
||||
};
|
||||
|
||||
class Missile : public Weapon
|
||||
{
|
||||
public:
|
||||
Missile(json::value json, int ID);
|
||||
|
||||
virtual wstring getCategory() { return L"Missile"; };
|
||||
};
|
||||
|
||||
class Bomb : public Weapon
|
||||
{
|
||||
public:
|
||||
Bomb(json::value json, int ID);
|
||||
|
||||
virtual wstring getCategory() { return L"Bomb"; };
|
||||
};
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ void MoveCommand::execute(lua_State* L)
|
||||
{
|
||||
std::ostringstream command;
|
||||
command.precision(10);
|
||||
command << "Olympus.move(\"" << to_string(unitName) << "\", " << destination.lat << ", " << destination.lng << ", " << 10 << ", " << unitCategory << ")";
|
||||
command << "Olympus.move(\"" << to_string(unitName) << "\", " << destination.lat << ", " << destination.lng << ", " << altitude << ", " << speed << ", \"" << to_string(unitCategory) << "\", \"" << to_string(targetName) << "\")";
|
||||
|
||||
lua_getglobal(L, "net");
|
||||
lua_getfield(L, -1, "dostring_in");
|
||||
@ -69,7 +69,7 @@ void SpawnAirCommand::execute(lua_State* L)
|
||||
{
|
||||
std::ostringstream command;
|
||||
command.precision(10);
|
||||
command << "Olympus.spawnAir(\"" << to_string(coalition) << "\", \"" << to_string(unitType) << "\", " << location.lat << ", " << location.lng << ")";
|
||||
command << "Olympus.spawnAir(\"" << to_string(coalition) << "\", \"" << to_string(unitType) << "\", " << location.lat << ", " << location.lng << "," << "\"" << to_string(payloadName) << "\")";
|
||||
|
||||
lua_getglobal(L, "net");
|
||||
lua_getfield(L, -1, "dostring_in");
|
||||
@ -84,24 +84,3 @@ void SpawnAirCommand::execute(lua_State* L)
|
||||
log("SpawnAirCommand executed successfully");
|
||||
}
|
||||
}
|
||||
|
||||
/* Attack unit command */
|
||||
void AttackUnitCommand::execute(lua_State* L)
|
||||
{
|
||||
std::ostringstream command;
|
||||
command.precision(10);
|
||||
command << "Olympus.attackUnit(\"" << to_string(unitName) << "\", \"" << to_string(targetName) << "\", " << location.lat << ", " << location.lng << ")";
|
||||
|
||||
lua_getglobal(L, "net");
|
||||
lua_getfield(L, -1, "dostring_in");
|
||||
lua_pushstring(L, "server");
|
||||
lua_pushstring(L, command.str().c_str());
|
||||
if (lua_pcall(L, 2, 0, 0) != 0)
|
||||
{
|
||||
log("Error executing AttackUnitCommand");
|
||||
}
|
||||
else
|
||||
{
|
||||
log("AttackUnitCommand executed successfully");
|
||||
}
|
||||
}
|
||||
@ -64,13 +64,6 @@ void Scheduler::execute(lua_State* L)
|
||||
commands.remove(command);
|
||||
break;
|
||||
}
|
||||
case CommandType::ATTACK_UNIT:
|
||||
{
|
||||
AttackUnitCommand* attackCommand = dynamic_cast<AttackUnitCommand*>(command);
|
||||
attackCommand->execute(L);
|
||||
commands.remove(command);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
log("Unknown command of type " + to_string(command->getType()));
|
||||
commands.remove(command);
|
||||
@ -93,26 +86,30 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
||||
if (key.compare(L"setPath") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
wstring unitName = value[L"unitName"].as_string();
|
||||
json::value path = value[L"path"];
|
||||
list<Coords> newPath;
|
||||
for (auto const& e : path.as_object())
|
||||
Unit* unit = unitsFactory->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
{
|
||||
wstring WP = e.first;
|
||||
double lat = path[WP][L"lat"].as_double();
|
||||
double lng = path[WP][L"lng"].as_double();
|
||||
log(unitName + L" set path destination " + WP + L" (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
|
||||
Coords dest; dest.lat = lat; dest.lng = lng;
|
||||
newPath.push_back(dest);
|
||||
Unit* unit = unitsFactory->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
wstring unitName = unit->getUnitName();
|
||||
json::value path = value[L"path"];
|
||||
list<Coords> newPath;
|
||||
for (auto const& e : path.as_object())
|
||||
{
|
||||
unit->setPath(newPath);
|
||||
log(unitName + L" new path set successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
log(unitName + L" not found, request will be discarded");
|
||||
wstring WP = e.first;
|
||||
double lat = path[WP][L"lat"].as_double();
|
||||
double lng = path[WP][L"lng"].as_double();
|
||||
log(unitName + L" set path destination " + WP + L" (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
|
||||
Coords dest; dest.lat = lat; dest.lng = lng;
|
||||
newPath.push_back(dest);
|
||||
Unit* unit = unitsFactory->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
{
|
||||
unit->setPath(newPath);
|
||||
log(unitName + L" new path set successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
log(unitName + L" not found, request will be discarded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,9 +138,10 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
||||
wstring type = value[L"type"].as_string();
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
log(L"Spawning " + coalition + L" air unit of type " + type + L" at (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
command = dynamic_cast<Command*>(new SpawnAirCommand(coalition, type, loc));
|
||||
wstring payloadName = value[L"payloadName"].as_string();
|
||||
log(L"Spawning " + coalition + L" air unit of type " + type + L" with payload " + payloadName + L" at (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
|
||||
command = dynamic_cast<Command*>(new SpawnAirCommand(coalition, type, loc, payloadName));
|
||||
}
|
||||
else if (key.compare(L"attackUnit") == 0)
|
||||
{
|
||||
@ -155,12 +153,10 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
||||
|
||||
wstring unitName;
|
||||
wstring targetName;
|
||||
Coords loc;
|
||||
|
||||
if (unit != nullptr)
|
||||
{
|
||||
unitName = unit->getUnitName();
|
||||
loc = unit->getActiveDestination();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -170,10 +166,6 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
||||
if (target != nullptr)
|
||||
{
|
||||
targetName = target->getUnitName();
|
||||
if (loc == NULL)
|
||||
{
|
||||
loc = Coords(target->getLatitude(), target->getLongitude(), target->getAltitude());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -181,7 +173,25 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
||||
}
|
||||
|
||||
log(L"Unit " + unitName + L" attacking unit " + targetName);
|
||||
command = dynamic_cast<Command*>(new AttackUnitCommand(unitName, targetName, loc));
|
||||
unit->setTarget(targetID);
|
||||
}
|
||||
else if (key.compare(L"changeSpeed") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsFactory->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
{
|
||||
unit->changeSpeed(value[L"change"].as_string());
|
||||
}
|
||||
}
|
||||
else if (key.compare(L"changeAltitude") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsFactory->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
{
|
||||
unit->changeAltitude(value[L"change"].as_string());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -3,11 +3,14 @@
|
||||
#include "logger.h"
|
||||
#include "commands.h"
|
||||
#include "scheduler.h"
|
||||
#include "defines.h"
|
||||
#include "unitsFactory.h"
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
using namespace GeographicLib;
|
||||
|
||||
extern Scheduler* scheduler;
|
||||
extern UnitsFactory* unitsFactory;
|
||||
|
||||
const Geodesic& geod = Geodesic::WGS84();
|
||||
|
||||
@ -15,7 +18,6 @@ Unit::Unit(json::value json, int ID) :
|
||||
ID(ID)
|
||||
{
|
||||
log("Creating unit with ID: " + to_string(ID));
|
||||
update(json);
|
||||
}
|
||||
|
||||
Unit::~Unit()
|
||||
@ -23,23 +25,21 @@ Unit::~Unit()
|
||||
|
||||
}
|
||||
|
||||
int Unit::getCategory()
|
||||
{
|
||||
if (type.has_number_field(L"level1"))
|
||||
{
|
||||
return type[L"level1"].as_number().to_int32();
|
||||
}
|
||||
else
|
||||
{
|
||||
return UnitCategory::NO_CATEGORY;
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::update(json::value json)
|
||||
{
|
||||
/* Lock for thread safety */
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
|
||||
/* Compute speed (loGetWorldObjects does not provide speed, we compute it for better performance instead of relying on many lua calls) */
|
||||
if (oldPosition != NULL)
|
||||
{
|
||||
double dist = 0;
|
||||
geod.Inverse(latitude, longitude, oldPosition.lat, oldPosition.lng, dist);
|
||||
speed = speed * 0.95 + (dist / UPDATE_TIME_INTERVAL) * 0.05;
|
||||
}
|
||||
oldPosition = Coords(latitude, longitude, altitude);
|
||||
|
||||
/* Update all the internal fields from the input json file */
|
||||
if (json.has_string_field(L"Name"))
|
||||
name = json[L"Name"].as_string();
|
||||
if (json.has_string_field(L"UnitName"))
|
||||
@ -80,17 +80,81 @@ void Unit::update(json::value json)
|
||||
void Unit::setPath(list<Coords> path)
|
||||
{
|
||||
activePath = path;
|
||||
holding = false;
|
||||
}
|
||||
|
||||
void Unit::setTarget(int newTargetID)
|
||||
{
|
||||
targetID = newTargetID;
|
||||
resetActiveDestination();
|
||||
}
|
||||
|
||||
wstring Unit::getTarget()
|
||||
{
|
||||
if (targetID == NULL)
|
||||
{
|
||||
return L"";
|
||||
}
|
||||
|
||||
Unit* target = unitsFactory->getUnit(targetID);
|
||||
if (target != nullptr)
|
||||
{
|
||||
if (target->alive)
|
||||
{
|
||||
return target->getUnitName();
|
||||
}
|
||||
else
|
||||
{
|
||||
targetID = NULL;
|
||||
return L"";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
targetID = NULL;
|
||||
return L"";
|
||||
}
|
||||
}
|
||||
|
||||
wstring Unit::getCurrentTask()
|
||||
{
|
||||
if (activePath.size() == 0)
|
||||
{
|
||||
return L"Idle";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getTarget().empty())
|
||||
{
|
||||
if (looping)
|
||||
{
|
||||
return L"Looping";
|
||||
}
|
||||
else if (holding)
|
||||
{
|
||||
return L"Holding";
|
||||
}
|
||||
else
|
||||
{
|
||||
return L"Reaching destination";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return L"Attacking " + getTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::AIloop()
|
||||
{
|
||||
/* Set the active destination to be always equal to the first point of the active path */
|
||||
/* Set the active destination to be always equal to the first point of the active path. This is in common with all AI units */
|
||||
if (activePath.size() > 0)
|
||||
{
|
||||
if (activeDestination != activePath.front())
|
||||
{
|
||||
activeDestination = activePath.front();
|
||||
Command* command = dynamic_cast<Command*>(new MoveCommand(ID, unitName, activeDestination, getCategory()));
|
||||
Command* command = dynamic_cast<Command*>(new MoveCommand(ID, unitName, activeDestination, getTargetSpeed(), getTargetAltitude(), getCategory(), getTarget()));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
}
|
||||
@ -102,52 +166,13 @@ void Unit::AIloop()
|
||||
activeDestination = Coords(0); // Set the active path to NULL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ground unit AI Loop */
|
||||
if (getCategory() == UnitCategory::GROUND)
|
||||
{
|
||||
if (activeDestination != NULL)
|
||||
{
|
||||
double newDist = 0;
|
||||
geod.Inverse(latitude, longitude, activeDestination.lat, activeDestination.lng, newDist);
|
||||
if (newDist < GROUND_DEST_DIST_THR)
|
||||
{
|
||||
/* Destination reached */
|
||||
activePath.pop_front();
|
||||
log(unitName + L" destination reached");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Air unit AI Loop */
|
||||
if (getCategory() == UnitCategory::AIR)
|
||||
{
|
||||
if (activeDestination != NULL)
|
||||
{
|
||||
double newDist = 0;
|
||||
geod.Inverse(latitude, longitude, activeDestination.lat, activeDestination.lng, newDist);
|
||||
if (newDist < AIR_DEST_DIST_THR)
|
||||
{
|
||||
/* Destination reached */
|
||||
activePath.pop_front();
|
||||
log(name + L" destination reached");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Air units must ALWAYS have a destination or they will RTB and may become uncontrollable */
|
||||
Coords point1;
|
||||
Coords point2;
|
||||
Coords point3;
|
||||
geod.Direct(latitude, longitude, 45, 18520, point1.lat, point1.lng);
|
||||
geod.Direct(point1.lat, point1.lng, 135, 18520, point2.lat, point2.lng);
|
||||
geod.Direct(point2.lat, point2.lng, 225, 18520, point3.lat, point3.lng);
|
||||
activePath.push_back(point1);
|
||||
activePath.push_back(point2);
|
||||
activePath.push_back(point3);
|
||||
activePath.push_back(Coords(latitude, longitude));
|
||||
}
|
||||
}
|
||||
/* This function calls again the MoveCommand to reach the active destination. This is useful to change speed and altitude, for example */
|
||||
void Unit::resetActiveDestination()
|
||||
{
|
||||
log(unitName + L" resetting active destination");
|
||||
activeDestination = Coords(0);
|
||||
}
|
||||
|
||||
json::value Unit::json()
|
||||
@ -167,8 +192,11 @@ json::value Unit::json()
|
||||
json[L"latitude"] = latitude;
|
||||
json[L"longitude"] = longitude;
|
||||
json[L"altitude"] = altitude;
|
||||
json[L"speed"] = speed;
|
||||
json[L"heading"] = heading;
|
||||
json[L"flags"] = flags;
|
||||
json[L"category"] = json::value::string(getCategory());
|
||||
json[L"currentTask"] = json::value::string(getCurrentTask());
|
||||
|
||||
/* Send the active path as a json object */
|
||||
if (activePath.size() > 0) {
|
||||
@ -188,4 +216,223 @@ json::value Unit::json()
|
||||
return json;
|
||||
}
|
||||
|
||||
/* Air unit */
|
||||
AirUnit::AirUnit(json::value json, int ID) : Unit(json, ID)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
void AirUnit::AIloop()
|
||||
{
|
||||
/* Call the common AI loop */
|
||||
Unit::AIloop();
|
||||
|
||||
/* Air unit AI Loop */
|
||||
if (activeDestination != NULL)
|
||||
{
|
||||
double newDist = 0;
|
||||
geod.Inverse(latitude, longitude, activeDestination.lat, activeDestination.lng, newDist);
|
||||
if (newDist < AIR_DEST_DIST_THR)
|
||||
{
|
||||
/* Destination reached */
|
||||
if (holding || looping)
|
||||
{
|
||||
activePath.push_back(activePath.front());
|
||||
}
|
||||
activePath.pop_front();
|
||||
log(name + L" destination reached");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Air units must ALWAYS have a destination or they will RTB and may become uncontrollable */
|
||||
Coords point1;
|
||||
Coords point2;
|
||||
Coords point3;
|
||||
geod.Direct(latitude, longitude, 45, 10000, point1.lat, point1.lng);
|
||||
geod.Direct(point1.lat, point1.lng, 135, 10000, point2.lat, point2.lng);
|
||||
geod.Direct(point2.lat, point2.lng, 225, 10000, point3.lat, point3.lng);
|
||||
activePath.push_back(point1);
|
||||
activePath.push_back(point2);
|
||||
activePath.push_back(point3);
|
||||
activePath.push_back(Coords(latitude, longitude));
|
||||
holding = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Aircraft */
|
||||
Aircraft::Aircraft(json::value json, int ID) : AirUnit(json, ID)
|
||||
{
|
||||
log("New Aircraft created with ID: " + to_string(ID));
|
||||
};
|
||||
|
||||
void Aircraft::changeSpeed(wstring change)
|
||||
{
|
||||
if (change.compare(L"stop") == 0)
|
||||
{
|
||||
/* Air units can't hold a position, so we can only set them to hold. At the moment, this will erase any other command. TODO: helicopters should be able to hover in place */
|
||||
activePath.clear();
|
||||
}
|
||||
else if (change.compare(L"slow") == 0)
|
||||
{
|
||||
targetSpeed *= 0.9;
|
||||
resetActiveDestination();
|
||||
}
|
||||
else if (change.compare(L"fast") == 0)
|
||||
{
|
||||
targetSpeed *= 1.1;
|
||||
resetActiveDestination();
|
||||
}
|
||||
}
|
||||
|
||||
void Aircraft::changeAltitude(wstring change)
|
||||
{
|
||||
if (change.compare(L"descend") == 0)
|
||||
{
|
||||
targetAltitude *= 0.9;
|
||||
}
|
||||
else if (change.compare(L"climb") == 0)
|
||||
{
|
||||
targetAltitude *= 1.1;
|
||||
}
|
||||
resetActiveDestination();
|
||||
}
|
||||
|
||||
/* Helicopter */
|
||||
Helicopter::Helicopter(json::value json, int ID) : AirUnit(json, ID)
|
||||
{
|
||||
log("New Helicopter created with ID: " + to_string(ID));
|
||||
};
|
||||
|
||||
void Helicopter::changeSpeed(wstring change)
|
||||
{
|
||||
if (change.compare(L"stop") == 0)
|
||||
{
|
||||
/* Air units can't hold a position, so we can only set them to hold. At the moment, this will erase any other command. TODO: helicopters should be able to hover in place */
|
||||
activePath.clear();
|
||||
}
|
||||
else if (change.compare(L"slow") == 0)
|
||||
{
|
||||
targetSpeed *= 0.9;
|
||||
resetActiveDestination();
|
||||
}
|
||||
else if (change.compare(L"fast") == 0)
|
||||
{
|
||||
targetSpeed *= 1.1;
|
||||
resetActiveDestination();
|
||||
}
|
||||
}
|
||||
|
||||
void Helicopter::changeAltitude(wstring change)
|
||||
{
|
||||
if (change.compare(L"descend") == 0)
|
||||
{
|
||||
targetAltitude *= 0.9;
|
||||
}
|
||||
else if (change.compare(L"climb") == 0)
|
||||
{
|
||||
targetAltitude *= 1.1;
|
||||
}
|
||||
resetActiveDestination();
|
||||
}
|
||||
|
||||
|
||||
/* Ground unit */
|
||||
GroundUnit::GroundUnit(json::value json, int ID) : Unit(json, ID)
|
||||
{
|
||||
log("New Ground Unit created with ID: " + to_string(ID));
|
||||
};
|
||||
|
||||
void GroundUnit::AIloop()
|
||||
{
|
||||
/* Call the common AI loop */
|
||||
Unit::AIloop();
|
||||
|
||||
/* Ground unit AI Loop */
|
||||
if (activeDestination != NULL)
|
||||
{
|
||||
double newDist = 0;
|
||||
geod.Inverse(latitude, longitude, activeDestination.lat, activeDestination.lng, newDist);
|
||||
if (newDist < GROUND_DEST_DIST_THR)
|
||||
{
|
||||
/* Destination reached */
|
||||
activePath.pop_front();
|
||||
log(unitName + L" destination reached");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GroundUnit::changeSpeed(wstring change)
|
||||
{
|
||||
if (change.compare(L"stop") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
else if (change.compare(L"slow") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
else if (change.compare(L"fast") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Navy Unit */
|
||||
NavyUnit::NavyUnit(json::value json, int ID) : Unit(json, ID)
|
||||
{
|
||||
log("New Navy Unit created with ID: " + to_string(ID));
|
||||
};
|
||||
|
||||
void NavyUnit::AIloop()
|
||||
{
|
||||
/* Call the common AI loop */
|
||||
Unit::AIloop();
|
||||
|
||||
/* Navy unit AI Loop */
|
||||
if (activeDestination != NULL)
|
||||
{
|
||||
double newDist = 0;
|
||||
geod.Inverse(latitude, longitude, activeDestination.lat, activeDestination.lng, newDist);
|
||||
if (newDist < GROUND_DEST_DIST_THR)
|
||||
{
|
||||
/* Destination reached */
|
||||
activePath.pop_front();
|
||||
log(unitName + L" destination reached");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NavyUnit::changeSpeed(wstring change)
|
||||
{
|
||||
if (change.compare(L"stop") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
else if (change.compare(L"slow") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
else if (change.compare(L"fast") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Weapon */
|
||||
Weapon::Weapon(json::value json, int ID) : Unit(json, ID)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
/* Missile */
|
||||
Missile::Missile(json::value json, int ID) : Weapon(json, ID)
|
||||
{
|
||||
log("New Missile created with ID: " + to_string(ID));
|
||||
};
|
||||
|
||||
/* Bomb */
|
||||
Bomb::Bomb(json::value json, int ID) : Weapon(json, ID)
|
||||
{
|
||||
log("New Bomb created with ID: " + to_string(ID));
|
||||
};
|
||||
|
||||
@ -81,5 +81,36 @@ void registerLuaFunctions(lua_State* L)
|
||||
log("OlympusCommand.lua registered successfully");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ifstream f(modLocation + "\\Scripts\\unitPayloads.lua");
|
||||
string str;
|
||||
log("Reading unitPayloads.lua from " + modLocation + "\\Scripts\\unitPayloads.lua");
|
||||
if (f) {
|
||||
ostringstream ss;
|
||||
ss << f.rdbuf();
|
||||
str = ss.str();
|
||||
log("unitPayloads.lua read succesfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
log("Error reading unitPayloads.lua");
|
||||
return;
|
||||
}
|
||||
|
||||
lua_getglobal(L, "net");
|
||||
lua_getfield(L, -1, "dostring_in");
|
||||
lua_pushstring(L, "server");
|
||||
lua_pushstring(L, str.c_str());
|
||||
|
||||
if (lua_pcall(L, 2, 0, 0) != 0)
|
||||
{
|
||||
log("Error registering unitPayloads.lua");
|
||||
}
|
||||
else
|
||||
{
|
||||
log("unitPayloads.lua registered successfully");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,6 +4,8 @@
|
||||
#include "unit.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
|
||||
UnitsFactory::UnitsFactory(lua_State* L)
|
||||
{
|
||||
LogInfo(L, "Units Factory constructor called successfully");
|
||||
@ -34,9 +36,46 @@ void UnitsFactory::update(lua_State* L)
|
||||
int ID = p.first;
|
||||
if (units.count(ID) == 0)
|
||||
{
|
||||
units[ID] = new Unit(p.second, ID);
|
||||
json::value type = static_cast<json::value>(p.second)[L"Type"];
|
||||
if (type.has_number_field(L"level1"))
|
||||
{
|
||||
if (type[L"level1"].as_number().to_int32() == 1)
|
||||
{
|
||||
if (type[L"level2"].as_number().to_int32() == 1)
|
||||
{
|
||||
units[ID] = dynamic_cast<Unit*>(new Aircraft(p.second, ID));
|
||||
}
|
||||
else if (type[L"level2"].as_number().to_int32() == 2)
|
||||
{
|
||||
units[ID] = dynamic_cast<Unit*>(new Helicopter(p.second, ID));
|
||||
}
|
||||
}
|
||||
else if (type[L"level1"].as_number().to_int32() == 2)
|
||||
{
|
||||
units[ID] = dynamic_cast<Unit*>(new GroundUnit(p.second, ID));
|
||||
}
|
||||
else if (type[L"level1"].as_number().to_int32() == 3)
|
||||
{
|
||||
units[ID] = dynamic_cast<Unit*>(new NavyUnit(p.second, ID));
|
||||
}
|
||||
else if (type[L"level1"].as_number().to_int32() == 4)
|
||||
{
|
||||
if (type[L"level2"].as_number().to_int32() == 4)
|
||||
{
|
||||
units[ID] = dynamic_cast<Unit*>(new Missile(p.second, ID));
|
||||
}
|
||||
else if (type[L"level2"].as_number().to_int32() == 5)
|
||||
{
|
||||
units[ID] = dynamic_cast<Unit*>(new Bomb(p.second, ID));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Update the unit if present*/
|
||||
if (units.count(ID) != 0)
|
||||
{
|
||||
units[ID]->update(p.second);
|
||||
}
|
||||
units[ID]->update(p.second);
|
||||
}
|
||||
|
||||
/* Set the units that are not present in the JSON as dead (probably have been destroyed) */
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
||||
@ -56,8 +56,6 @@
|
||||
}
|
||||
|
||||
.unitmarker-unitName-div {
|
||||
width: 200px;
|
||||
left: -70px;
|
||||
top: -20px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
@ -68,8 +66,6 @@
|
||||
}
|
||||
|
||||
.unitmarker-name-div {
|
||||
width: 200px;
|
||||
left: -70px;
|
||||
bottom: -20px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
@ -91,6 +87,18 @@
|
||||
-webkit-text-stroke: 1px;
|
||||
}
|
||||
|
||||
.unitmarker-speed-div {
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
position: absolute;
|
||||
text-align: left;
|
||||
font: 800 12px Arial;
|
||||
white-space: nowrap;
|
||||
-webkit-text-fill-color: white;
|
||||
-webkit-text-stroke: 1px;
|
||||
}
|
||||
|
||||
.unitmarker-container-table-dead .unitmarker-name-div{
|
||||
opacity: 0;
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
.unit-info-panel {
|
||||
background-color: #202831;
|
||||
height: 100px;
|
||||
width: 400px;
|
||||
width: 800px;
|
||||
border: solid white 1px;
|
||||
font-size: 12px;
|
||||
position: fixed;
|
||||
@ -28,8 +28,19 @@
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
background-color: #202831;
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
.panel-table {
|
||||
text-shadow: 1px 1px #000, -1px -1px #000, 1px -1px #000, -1px 1px #000;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
@ -40,16 +51,20 @@
|
||||
.panel-label {
|
||||
font-size: 12px;
|
||||
color: #d3e9ff;
|
||||
margin: 5px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.panel-button {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
margin: 5px;
|
||||
color: #d3e9ff;
|
||||
font-size: 25px;
|
||||
display: flex;
|
||||
@ -77,4 +92,32 @@
|
||||
|
||||
.panel-button-disabled:active {
|
||||
color: #e1f0ff;
|
||||
}
|
||||
|
||||
.panel-select {
|
||||
-webkit-padding-start: 2px;
|
||||
margin: 10px;
|
||||
height: 25px;
|
||||
color: black;
|
||||
font-family: "Lucida Console", "Courier New", monospace;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.panel-select option {
|
||||
margin: 40px;
|
||||
color: black;
|
||||
font-family: "Lucida Console", "Courier New", monospace;
|
||||
height: 25px;
|
||||
margin: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#unit-info-table
|
||||
{
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
#tactical-info-table
|
||||
{
|
||||
width: 400px;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
BIN
www/img/units/bomb.png
Normal file
BIN
www/img/units/bomb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
BIN
www/img/units/missile.png
Normal file
BIN
www/img/units/missile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@ -18,12 +18,14 @@
|
||||
<script src="https://unpkg.com/leaflet@1.9.2/dist/leaflet.js"
|
||||
integrity="sha256-o9N1jGDZrf5tS+Ft4gbIK7mYMipq9lqpVJ91xHSyKhg="
|
||||
crossorigin=""></script>
|
||||
<script src="js/payloadNames.js"></script>
|
||||
<script src="js/ControlPanel.js"></script>
|
||||
<script src="js/DCSCommands.js"></script>
|
||||
<script src="js/Utils.js"></script>
|
||||
<script src="js/unitTypes.js"></script>
|
||||
<script src="js/PanelButton.js"></script>
|
||||
<script src="js/LeftPanel.js"></script>
|
||||
<script src="js/TopPanel.js"></script>
|
||||
<script src="js/UnitInfoPanel.js"></script>
|
||||
<script src="js/UnitControlPanel.js"></script>
|
||||
<script src="js/Map.js"></script>
|
||||
<script src="js/MissionData.js"></script>
|
||||
<script src="js/Unit.js"></script>
|
||||
@ -36,7 +38,8 @@
|
||||
<body>
|
||||
<table id="content-table">
|
||||
<tr id="header">
|
||||
<td colspan>
|
||||
<td>
|
||||
<div class="control-panel" id="top-control-panel"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
86
www/js/ControlPanel.js
Normal file
86
www/js/ControlPanel.js
Normal file
@ -0,0 +1,86 @@
|
||||
class ControlPanel
|
||||
{
|
||||
constructor(id)
|
||||
{
|
||||
this._panel = document.getElementById(id);
|
||||
/* Create all buttons, disabled by default */
|
||||
|
||||
this._humanIcon = "fa-user";
|
||||
this._AIIcon = "fa-desktop";
|
||||
this._weaponsIcon = "fa-bomb";
|
||||
this._labelsIcon = "fa-font";
|
||||
this._deadIcon = "fa-skull";
|
||||
|
||||
this._humanButton = new PanelButton(this._panel, this._humanIcon);
|
||||
this._AIButton = new PanelButton(this._panel, this._AIIcon);
|
||||
this._weaponsButton = new PanelButton(this._panel, this._weaponsIcon);
|
||||
this._deadAliveButton = new PanelButton(this._panel, this._deadIcon);
|
||||
|
||||
this._humanButton.addCallback(() => this._onHumanButton());
|
||||
this._AIButton.addCallback(() => this._onAIButton());
|
||||
this._weaponsButton.addCallback(() => this._onWeaponsButton());
|
||||
this._deadAliveButton.addCallback(() => this._cycleDeadAlive());
|
||||
|
||||
this._human = "labels";
|
||||
this._humanButton.setSubicon(this._labelsIcon);
|
||||
this._AI = "marker";
|
||||
this._weapons = "marker";
|
||||
this._deadAlive = "both";
|
||||
}
|
||||
|
||||
getSettings()
|
||||
{
|
||||
return {'human': this._human, 'AI': this._AI, 'weapons': this._weapons, 'deadAlive': this._deadAlive}
|
||||
}
|
||||
|
||||
_onHumanButton()
|
||||
{
|
||||
this._human = this._cycleVisibility(this._humanButton, this._human, this._humanIcon);
|
||||
}
|
||||
|
||||
_onAIButton()
|
||||
{
|
||||
this._AI = this._cycleVisibility(this._AIButton, this._AI, this._AIIcon);
|
||||
}
|
||||
|
||||
_onWeaponsButton()
|
||||
{
|
||||
this._weapons = this._cycleVisibility(this._weaponsButton, this._weapons, this._weaponsIcon);
|
||||
}
|
||||
|
||||
_cycleVisibility(button, variable, icon)
|
||||
{
|
||||
if (variable === "labels")
|
||||
{
|
||||
variable = "marker";
|
||||
button.setIcon(icon);
|
||||
button.setSlashed(false);
|
||||
}
|
||||
else if (variable === "marker")
|
||||
{
|
||||
variable = "none";
|
||||
button.setSlashed(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
variable = "labels";
|
||||
button.setSubicon(this._labelsIcon);
|
||||
button.setSlashed(false);
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
|
||||
_cycleDeadAlive()
|
||||
{
|
||||
if (this._deadAlive === "both")
|
||||
{
|
||||
this._deadAlive = "alive";
|
||||
this._deadAliveButton.setSlashed(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._deadAlive = "both";
|
||||
this._deadAliveButton.setSlashed(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,7 +32,7 @@ function spawnGroundUnit(type, latlng, coalition)
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function spawnAirUnit(type, latlng, coalition)
|
||||
function spawnAirUnit(type, latlng, coalition, payloadName)
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
@ -43,7 +43,7 @@ function spawnAirUnit(type, latlng, coalition)
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"type": type, "location": latlng, "coalition": coalition};
|
||||
var command = {"type": type, "location": latlng, "coalition": coalition, "payloadName": payloadName};
|
||||
var data = {"spawnAir": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
@ -56,7 +56,7 @@ function attackUnit(unitID, targetID)
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log("Unit " + unitsManager.units[unitID] + " attack ID " + unitsManager.units[targetID] );
|
||||
console.log("Unit " + unitsManager.getUnit(unitID).unitName + " attack " + unitsManager.getUnit(targetID).unitName );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -184,17 +184,32 @@ class Map
|
||||
this._selectionWheel = new SelectionWheel(e.originalEvent.x, e.originalEvent.y, options);
|
||||
}
|
||||
|
||||
/* Show unit selection for ground units */
|
||||
/* Show unit selection for air units */
|
||||
_unitSelectAir(e)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
var options = unitTypes.air;
|
||||
options.sort();
|
||||
this._selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (type) => {
|
||||
this._selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (unitType) => {
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
spawnAirUnit(type, e.latlng, this._activeCoalition);
|
||||
this._unitSelectPayload(unitType, e);
|
||||
});
|
||||
}
|
||||
|
||||
/* Show weapon selection for air units */
|
||||
_unitSelectPayload(unitType, e)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
var options = [];
|
||||
options = payloadNames[unitType]
|
||||
options.sort();
|
||||
this._selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (payloadName) => {
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
spawnAirUnit(unitType, e.latlng, this._activeCoalition, payloadName);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -2,25 +2,38 @@ class MissionData
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this.bullseye = undefined;
|
||||
this._bullseye = undefined;
|
||||
this._bullseyeMarker = undefined;
|
||||
}
|
||||
|
||||
update(data)
|
||||
{
|
||||
this.bullseye = data.missionData.bullseye;
|
||||
this._bullseye = data.missionData.bullseye;
|
||||
this._unitsData = data.missionData.unitsData;
|
||||
this._drawBullseye();
|
||||
}
|
||||
|
||||
getUnitData(ID)
|
||||
{
|
||||
if (ID in this._unitsData)
|
||||
{
|
||||
return this._unitsData[ID];
|
||||
}
|
||||
else
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
_drawBullseye()
|
||||
{
|
||||
if (this._bullseyeMarker === undefined)
|
||||
{
|
||||
this._bullseyeMarker = L.marker([this.bullseye.lat, this.bullseye.lng]).addTo(map.getMap());
|
||||
this._bullseyeMarker = L.marker([this._bullseye.lat, this._bullseye.lng]).addTo(map.getMap());
|
||||
}
|
||||
else
|
||||
{
|
||||
this._bullseyeMarker .setLatLng(new L.LatLng(this.bullseye.lat, this.bullseye.lng));
|
||||
this._bullseyeMarker .setLatLng(new L.LatLng(this._bullseye.lat, this._bullseye.lng));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,15 @@
|
||||
class PanelButton
|
||||
{
|
||||
constructor(parent, type)
|
||||
constructor(parent, icon)
|
||||
{
|
||||
this._div= document.createElement("div");
|
||||
this._div.innerHTML = `<i class="fa ${type}"></i>`
|
||||
this._div = document.createElement("div");
|
||||
this.setIcon(icon);
|
||||
this.setSlashed(false);
|
||||
|
||||
this._div.classList.add("panel-button");
|
||||
parent.appendChild(this._div);
|
||||
|
||||
this.setEnabled(false);
|
||||
this.setEnabled(true);
|
||||
|
||||
this._div.onclick = () => this._onClick();
|
||||
this._callbacks = [];
|
||||
@ -24,7 +26,6 @@ class PanelButton
|
||||
{
|
||||
this._div.classList.add("panel-button-disabled");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
addCallback(callback)
|
||||
@ -37,6 +38,30 @@ class PanelButton
|
||||
this._callbacks = [];
|
||||
}
|
||||
|
||||
setIcon(icon)
|
||||
{
|
||||
this._baseIcon = `<i class="fa ${icon}"></i>`;
|
||||
this._div.innerHTML = this._baseIcon;
|
||||
}
|
||||
|
||||
setSubicon(subicon)
|
||||
{
|
||||
this._baseIcon = `<div style="display: flex;">${this._baseIcon}<i style="font-size: 10px;" class="fa ${subicon}"></i></div>`;
|
||||
this._div.innerHTML = this._baseIcon;
|
||||
}
|
||||
|
||||
setSlashed(slashed)
|
||||
{
|
||||
if (slashed)
|
||||
{
|
||||
this._div.innerHTML = `<div style="display: flex; justify-content: center;">${this._baseIcon}<i style="position:fixed;" class="fa fa-slash"></i></div>`;
|
||||
}
|
||||
else
|
||||
{
|
||||
this._div.innerHTML = this._baseIcon;
|
||||
}
|
||||
}
|
||||
|
||||
_onClick()
|
||||
{
|
||||
if (this._enabled)
|
||||
@ -47,5 +72,4 @@ class PanelButton
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
336
www/js/Unit.js
336
www/js/Unit.js
@ -1,10 +1,14 @@
|
||||
class Unit
|
||||
{
|
||||
constructor(ID) {
|
||||
constructor(ID, marker)
|
||||
{
|
||||
this.ID = ID;
|
||||
this.marker = new L.Marker.UnitMarker([0, 0], {riseOnHover: true});
|
||||
this.marker.addTo(map.getMap()).on('click', (e) => this.onClick(e));
|
||||
this.marker.addTo(map.getMap()).on('contextmenu', (e) => this.onRightClick(e));
|
||||
this.selectable = true;
|
||||
|
||||
// The marker is set by the inherited class
|
||||
this.marker = marker;
|
||||
this.marker.on('click', (e) => this.onClick(e));
|
||||
this.marker.on('contextmenu', (e) => this.onRightClick(e));
|
||||
|
||||
this._selected = false;
|
||||
|
||||
@ -12,6 +16,8 @@ class Unit
|
||||
|
||||
this._pathPolyline = new L.Polyline([], {color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1});
|
||||
this._pathPolyline.addTo(map.getMap());
|
||||
|
||||
this._targetsPolylines = [];
|
||||
}
|
||||
|
||||
update(response)
|
||||
@ -27,21 +33,15 @@ class Unit
|
||||
this.alive = response["alive"];
|
||||
this.type = response["type"];
|
||||
this.flags = response["flags"];
|
||||
this.activePath = response["activePath"]
|
||||
this.speed = response["speed"];
|
||||
this.currentTask = response["currentTask"];
|
||||
|
||||
/* Only present if an active path is available */
|
||||
if ("activePath" in response)
|
||||
{
|
||||
this.activePath = response["activePath"]
|
||||
}
|
||||
this.missionData = missionData.getUnitData(this.ID)
|
||||
|
||||
this.setSelected(this.getSelected() & this.alive)
|
||||
this.drawMarker();
|
||||
|
||||
if (!this.alive)
|
||||
{
|
||||
this.setSelected(false);
|
||||
}
|
||||
|
||||
if (this._selected && this.activePath != undefined)
|
||||
if (this.getSelected() && this.activePath != undefined)
|
||||
{
|
||||
this.drawPath();
|
||||
}
|
||||
@ -49,32 +49,22 @@ class Unit
|
||||
{
|
||||
this.clearPath();
|
||||
}
|
||||
}
|
||||
|
||||
getCategory()
|
||||
{
|
||||
if (this.type.level1 == 1)
|
||||
this.clearTargets();
|
||||
this.missionData = missionData.getUnitData(this.ID);
|
||||
if (this.missionData != undefined)
|
||||
{
|
||||
return 'air';
|
||||
}
|
||||
else if (this.type.level1 == 2)
|
||||
{
|
||||
return 'ground';
|
||||
}
|
||||
else if (this.type.level1 == 3)
|
||||
{
|
||||
return 'navy';
|
||||
}
|
||||
else
|
||||
{
|
||||
return undefined;
|
||||
if (this.getSelected())
|
||||
{
|
||||
this.drawTargets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSelected(selected)
|
||||
{
|
||||
/* Only alive units can be selected */
|
||||
if (this.alive || !selected)
|
||||
// Only alive units can be selected. Some units are not selectable (weapons)
|
||||
if ((this.alive || !selected) && this.selectable && this._selected != selected)
|
||||
{
|
||||
this._selected = selected;
|
||||
this.marker.setSelected(selected);
|
||||
@ -89,6 +79,7 @@ class Unit
|
||||
|
||||
addDestination(latlng)
|
||||
{
|
||||
// TODO move in dedicated file
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
@ -103,11 +94,11 @@ class Unit
|
||||
{
|
||||
var newPath = this.activePath;
|
||||
newPath[(Object.keys(newPath).length + 1).toString()] = latlng;
|
||||
command = {"ID": this.ID, "unitName": this.unitName, "path": newPath}
|
||||
command = {"ID": this.ID, "path": newPath}
|
||||
}
|
||||
else
|
||||
{
|
||||
command = {"ID": this.ID, "unitName": this.unitName, "path": {"1": latlng}}
|
||||
command = {"ID": this.ID, "path": {"1": latlng}}
|
||||
}
|
||||
|
||||
var data = {"setPath": command}
|
||||
@ -134,27 +125,36 @@ class Unit
|
||||
unitsManager.onUnitRightClick(this.ID);
|
||||
}
|
||||
|
||||
drawMarker()
|
||||
drawMarker(settings)
|
||||
{
|
||||
var zIndex = this.marker.getZIndex();
|
||||
var newLatLng = new L.LatLng(this.latitude, this.longitude);
|
||||
this.marker.setLatLng(newLatLng);
|
||||
this.marker.setAngle(this.heading);
|
||||
this.marker.setZIndex(zIndex);
|
||||
this.marker.setAlive(this.alive);
|
||||
this.marker.setAltitude(this.altitude);
|
||||
this.marker.setHuman(this.flags.Human);
|
||||
this.marker.setCoalitionID(this.coalitionID);
|
||||
this.marker.setUnitName(this.unitName);
|
||||
this.marker.setName(this.name);
|
||||
|
||||
if (this.getCategory() == "air")
|
||||
// Hide the marker if disabled
|
||||
if ((settings === 'none' || (controlPanel.getSettings().deadAlive === "alive" && !this.alive)))
|
||||
{
|
||||
this.marker.setImage("img/units/air.png");
|
||||
// Remove the marker if present
|
||||
if (map.getMap().hasLayer(this.marker))
|
||||
{
|
||||
map.getMap().removeLayer(this.marker);
|
||||
}
|
||||
}
|
||||
else if (this.getCategory() == "ground")
|
||||
{
|
||||
this.marker.setImage("img/units/ground.png")
|
||||
else {
|
||||
// Add the marker if not present
|
||||
if (!map.getMap().hasLayer(this.marker))
|
||||
{
|
||||
this.marker.addTo(map.getMap());
|
||||
}
|
||||
|
||||
// Set the marker vibility
|
||||
this.marker.setLabelsVisibility((settings === 'labels' || this.getSelected()) && this.alive);
|
||||
|
||||
// Draw the marker
|
||||
var zIndex = this.marker.getZIndex();
|
||||
var newLatLng = new L.LatLng(this.latitude, this.longitude);
|
||||
this.marker.setLatLng(newLatLng);
|
||||
this.marker.setAngle(this.heading);
|
||||
this.marker.setZIndex(zIndex);
|
||||
this.marker.setAlive(this.alive);
|
||||
this.marker.setAltitude(this.altitude);
|
||||
this.marker.setSpeed(this.speed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,21 +163,21 @@ class Unit
|
||||
var _points = [];
|
||||
_points.push(new L.LatLng(this.latitude, this.longitude));
|
||||
|
||||
/* Add markers if missing */
|
||||
// Add markers if missing
|
||||
while (this._pathMarkers.length < Object.keys(this.activePath).length)
|
||||
{
|
||||
var marker = L.marker([0, 0]).addTo(map.getMap());
|
||||
this._pathMarkers.push(marker);
|
||||
}
|
||||
|
||||
/* Remove markers if too many */
|
||||
// Remove markers if too many
|
||||
while (this._pathMarkers.length > Object.keys(this.activePath).length)
|
||||
{
|
||||
map.getMap().removeLayer(this._pathMarkers[this._pathMarkers.length - 1]);
|
||||
this._pathMarkers.splice(this._pathMarkers.length - 1, 1)
|
||||
}
|
||||
|
||||
/* Update the position of the existing markers (to avoid creating markers uselessly) */
|
||||
// Update the position of the existing markers (to avoid creating markers uselessly)
|
||||
for (let WP in this.activePath)
|
||||
{
|
||||
var destination = this.activePath[WP];
|
||||
@ -197,8 +197,228 @@ class Unit
|
||||
this._pathPolyline.setLatLngs([]);
|
||||
}
|
||||
|
||||
drawTargets()
|
||||
{
|
||||
for (let typeIndex in this.missionData.targets)
|
||||
{
|
||||
for (let index in this.missionData.targets[typeIndex])
|
||||
{
|
||||
var targetData = this.missionData.targets[typeIndex][index];
|
||||
var target = unitsManager.getUnit(targetData.object["id_"])
|
||||
var startLatLng = new L.LatLng(this.latitude, this.longitude)
|
||||
var endLatLng = new L.LatLng(target.latitude, target.longitude)
|
||||
|
||||
var color;
|
||||
if (typeIndex === "radar")
|
||||
{
|
||||
color = "#FFFF00";
|
||||
}
|
||||
else if (typeIndex === "visual")
|
||||
{
|
||||
color = "#FF00FF";
|
||||
}
|
||||
else if (typeIndex === "rwr")
|
||||
{
|
||||
color = "#00FF00";
|
||||
}
|
||||
else
|
||||
{
|
||||
color = "#FFFFFF";
|
||||
}
|
||||
var targetPolyline = new L.Polyline([startLatLng, endLatLng], {color: color, weight: 3, opacity: 1, smoothFactor: 1});
|
||||
targetPolyline.addTo(map.getMap());
|
||||
this._targetsPolylines.push(targetPolyline)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearTargets()
|
||||
{
|
||||
for (let index in this._targetsPolylines)
|
||||
{
|
||||
map.getMap().removeLayer(this._targetsPolylines[index])
|
||||
}
|
||||
}
|
||||
|
||||
attackUnit(targetID)
|
||||
{
|
||||
// Call DCS attackUnit function
|
||||
attackUnit(this.ID, targetID);
|
||||
}
|
||||
|
||||
changeSpeed(speedChange)
|
||||
{
|
||||
// TODO move in dedicated file
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log(this.unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": this.ID, "change": speedChange}
|
||||
var data = {"changeSpeed": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
changeAltitude(altitudeChange)
|
||||
{
|
||||
// TODO move in dedicated file
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log(this.unitName + " altitude change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": this.ID, "change": altitudeChange}
|
||||
var data = {"changeAltitude": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
class AirUnit extends Unit
|
||||
{
|
||||
drawMarker()
|
||||
{
|
||||
if (this.flags.human)
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().human);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().AI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Aircraft extends AirUnit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
var marker = new L.Marker.UnitMarker.AirUnitMarker.AircraftMarker({
|
||||
riseOnHover: true,
|
||||
unitName: data.unitName,
|
||||
name: data.name,
|
||||
human: data.flags.Human,
|
||||
coalitionID: data.coalitionID
|
||||
});
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
|
||||
class Helicopter extends AirUnit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
var marker = new L.Marker.UnitMarker.AirUnitMarker.HelicopterMarker({
|
||||
riseOnHover: true,
|
||||
unitName: data.unitName,
|
||||
name: data.name,
|
||||
human: data.flags.Human,
|
||||
coalitionID: data.coalitionID
|
||||
});
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
|
||||
class GroundUnit extends Unit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
var marker = new L.Marker.UnitMarker.GroundMarker({
|
||||
riseOnHover: true,
|
||||
unitName: data.unitName,
|
||||
name: data.name,
|
||||
human: data.flags.Human,
|
||||
coalitionID: data.coalitionID
|
||||
});
|
||||
super(ID, marker);
|
||||
}
|
||||
|
||||
drawMarker()
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().AI);
|
||||
}
|
||||
}
|
||||
|
||||
class NavyUnit extends Unit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
var marker = new L.Marker.UnitMarker.NavyMarker({
|
||||
riseOnHover: true,
|
||||
unitName: data.unitName,
|
||||
name: data.name,
|
||||
human: data.flags.Human,
|
||||
coalitionID: data.coalitionID
|
||||
});
|
||||
super(ID, marker);
|
||||
}
|
||||
|
||||
drawMarker()
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().AI);
|
||||
}
|
||||
}
|
||||
|
||||
class Weapon extends Unit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
// Weapons can not be selected
|
||||
self.selectable = false;
|
||||
super(ID, data);
|
||||
}
|
||||
|
||||
drawMarker()
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().weapons);
|
||||
}
|
||||
|
||||
onClick(e)
|
||||
{
|
||||
// Weapons can not be clicked
|
||||
}
|
||||
|
||||
onRightClick(e)
|
||||
{
|
||||
// Weapons can not be clicked
|
||||
}
|
||||
}
|
||||
|
||||
class Missile extends Weapon
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
var marker = new L.Marker.UnitMarker.WeaponMarker.MissileMarker({
|
||||
riseOnHover: true,
|
||||
unitName: "",
|
||||
name: data.name,
|
||||
human: data.flags.Human,
|
||||
coalitionID: data.coalitionID
|
||||
});
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
|
||||
class Bomb extends Weapon
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
var marker = new L.Marker.UnitMarker.WeaponMarker.BombMarker({
|
||||
riseOnHover: true,
|
||||
unitName: "",
|
||||
name: data.name,
|
||||
human: data.flags.Human,
|
||||
coalitionID: data.coalitionID
|
||||
});
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
class TopPanel
|
||||
class UnitControlPanel
|
||||
{
|
||||
constructor(id)
|
||||
{
|
||||
@ -44,5 +44,4 @@ class TopPanel
|
||||
this._descendButton.setEnabled(false);
|
||||
this._climbButton.setEnabled(false);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
class LeftPanel
|
||||
class UnitInfoPanel
|
||||
{
|
||||
constructor(id)
|
||||
{
|
||||
@ -16,7 +16,8 @@ class LeftPanel
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
this._showUnitData();
|
||||
this._panel.style.bottom = "-80px";
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -30,8 +31,25 @@ class LeftPanel
|
||||
{
|
||||
if (selectedUnit !== undefined)
|
||||
{
|
||||
var loadout = "";
|
||||
for (let index in selectedUnit.missionData.ammo)
|
||||
{
|
||||
if (selectedUnit.missionData != undefined)
|
||||
{
|
||||
var ammo = selectedUnit.missionData.ammo[index];
|
||||
var displayName = ammo.desc.displayName;
|
||||
var amount = ammo.count;
|
||||
loadout += amount + "x" + displayName;
|
||||
if (parseInt(index) < Object.keys(selectedUnit.missionData.ammo).length - 1)
|
||||
{
|
||||
loadout += ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._panel.innerHTML = `
|
||||
<table class="panel-table">
|
||||
<div style="display: flex">
|
||||
<table class="panel-table" id="unit-info-table">
|
||||
<tr>
|
||||
<td colspan="4" class="panel-title">
|
||||
UNIT INFO
|
||||
@ -65,6 +83,20 @@ class LeftPanel
|
||||
${Math.floor(selectedUnit.altitude / 0.3048) + "ft"}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="panel-label">
|
||||
Ground speed:
|
||||
</td>
|
||||
<td class="panel-content">
|
||||
${Math.floor(selectedUnit.speed * 1.94384) + "kts"}
|
||||
</td>
|
||||
<td class="panel-label">
|
||||
Fuel:
|
||||
</td>
|
||||
<td class="panel-content">
|
||||
${Math.floor(selectedUnit.missionData.fuel * 100) + "%"}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="panel-label">
|
||||
Position:
|
||||
@ -76,6 +108,37 @@ class LeftPanel
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="panel-table" id="tactical-info-table">
|
||||
<tr>
|
||||
<td colspan="4" class="panel-title">
|
||||
TACTICAL INFO
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="panel-label">
|
||||
Current task:
|
||||
</td>
|
||||
<td class="panel-content" colspan="3">
|
||||
${selectedUnit.currentTask}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="panel-label">
|
||||
Weapons:
|
||||
</td>
|
||||
<td class="panel-content" colspan="3">
|
||||
${loadout}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
else
|
||||
@ -1,119 +1,108 @@
|
||||
L.Marker.UnitMarker = L.Marker.extend(
|
||||
{
|
||||
// Set the unit name and unit icon
|
||||
setUnitName: function(unitName)
|
||||
options: {
|
||||
unitName: "No name",
|
||||
name: "N/A",
|
||||
human: false,
|
||||
coalitionID: 2,
|
||||
iconSrc: "img/units/undefined.png"
|
||||
},
|
||||
|
||||
// Marker constructor
|
||||
initialize: function(options) {
|
||||
this._latlng = new L.LatLng(0, 0);
|
||||
L.setOptions(this, options);
|
||||
var icon = new L.DivIcon({
|
||||
html: `<table class="unitmarker-container-table" id="container-table">
|
||||
<tr>
|
||||
<td>
|
||||
<img class="unitmarker-selection-img" id="selection-img" src="img/selection.png">
|
||||
<img class="unitmarker-icon-img" id="icon-img">
|
||||
<div class="unitmarker-unitName-div" id="unitName"></div>
|
||||
<div class="unitmarker-altitude-div" id="altitude-div"></div>
|
||||
<div class="unitmarker-speed-div" id="speed-div"></div>
|
||||
<div class="unitmarker-name-div" id="name"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
className: 'unit-marker-icon'}); // Set the unit marker, className must be set to avoid white square
|
||||
this.setIcon(icon);
|
||||
},
|
||||
|
||||
// When the marker is added to the map, the source image and the style are set. This can not be done before.
|
||||
onAdd: function (map)
|
||||
{
|
||||
// TODO: move in constructor and call only once (does not work in addInitHook for some reason)
|
||||
L.Marker.prototype.onAdd.call(this, map);
|
||||
|
||||
this._icon.querySelector("#icon-img").src = this.options.iconSrc;
|
||||
|
||||
this._icon.style.outline = "transparent"; // Removes the rectangular outline
|
||||
|
||||
if (this.unitName !== unitName)
|
||||
{
|
||||
// Set the unit name in the marker
|
||||
var unitNameDiv = this._icon.querySelector("#unitName");
|
||||
if (unitNameDiv!== undefined)
|
||||
{
|
||||
if (this._human)
|
||||
{
|
||||
unitNameDiv.innerHTML = `<i class="fas fa-user"></i> ${unitName}`;
|
||||
}
|
||||
else
|
||||
{
|
||||
unitNameDiv.innerHTML = `${unitName}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.unitName = unitName;
|
||||
},
|
||||
|
||||
setName: function(name)
|
||||
{
|
||||
// TODO: move in constructor and call only once (does not work in addInitHook for some reason)
|
||||
this._icon.style.outline = "transparent"; // Removes the rectangular outline
|
||||
|
||||
if (this.name !== name)
|
||||
{
|
||||
// Set the unit name in the marker
|
||||
var nameDiv = this._icon.querySelector("#name");
|
||||
if (nameDiv!== undefined)
|
||||
{
|
||||
nameDiv.innerHTML = name;
|
||||
}
|
||||
}
|
||||
this.name = name;
|
||||
},
|
||||
|
||||
setCoalitionID: function(coalitionID)
|
||||
{
|
||||
var img = this._icon.querySelector("#icon-img");
|
||||
if (img!== undefined)
|
||||
// Set the unit name in the marker
|
||||
var unitNameDiv = this._icon.querySelector("#unitName");
|
||||
if (this.options.human)
|
||||
{
|
||||
if (coalitionID == 2)
|
||||
{
|
||||
img.classList.add("unitmarker-icon-img-blue");
|
||||
}
|
||||
else
|
||||
{
|
||||
img.classList.add("unitmarker-icon-img-red");
|
||||
}
|
||||
unitNameDiv.innerHTML = `<i class="fas fa-user"></i> ${this.options.unitName}`;
|
||||
}
|
||||
},
|
||||
|
||||
setImage: function(icon)
|
||||
{
|
||||
// Set the unit icon
|
||||
var img = this._icon.querySelector("#icon-img");
|
||||
if (img !== undefined)
|
||||
else
|
||||
{
|
||||
img.src = icon;
|
||||
unitNameDiv.innerHTML = `${this.options.unitName}`;
|
||||
}
|
||||
unitNameDiv.style.left = (-(unitNameDiv.offsetWidth - this._icon.querySelector("#icon-img").height) / 2) + "px";
|
||||
|
||||
// Set the unit name in the marker
|
||||
var nameDiv = this._icon.querySelector("#name");
|
||||
nameDiv.innerHTML = this.options.name;
|
||||
nameDiv.style.left = (-(nameDiv.offsetWidth - this._icon.querySelector("#icon-img").height) / 2) + "px";
|
||||
|
||||
// Set the coalitionID
|
||||
var img = this._icon.querySelector("#icon-img");
|
||||
if (this.options.coalitionID == 2)
|
||||
{
|
||||
img.classList.add("unitmarker-icon-img-blue");
|
||||
}
|
||||
else
|
||||
{
|
||||
img.classList.add("unitmarker-icon-img-red");
|
||||
}
|
||||
},
|
||||
|
||||
// If the unit is not alive it is drawn with darker colours
|
||||
setAlive: function(alive)
|
||||
{
|
||||
var table = this._icon.querySelector("#container-table");
|
||||
if (table!== undefined)
|
||||
if (alive)
|
||||
{
|
||||
if (alive)
|
||||
{
|
||||
table.classList.remove("unitmarker-container-table-dead");
|
||||
}
|
||||
else
|
||||
{
|
||||
table.classList.add("unitmarker-container-table-dead");
|
||||
}
|
||||
table.classList.remove("unitmarker-container-table-dead");
|
||||
}
|
||||
else
|
||||
{
|
||||
table.classList.add("unitmarker-container-table-dead");
|
||||
}
|
||||
this.alive = alive;
|
||||
},
|
||||
|
||||
// Set heading
|
||||
setAngle: function(angle)
|
||||
{
|
||||
if (this._angle !== angle){
|
||||
var img = this._icon.querySelector("#icon-img");
|
||||
if (img !== undefined)
|
||||
{
|
||||
img.style.transform = "rotate(" + angle + "rad)";
|
||||
}
|
||||
}
|
||||
this._angle = angle;
|
||||
var img = this._icon.querySelector("#icon-img");
|
||||
img.style.transform = "rotate(" + angle + "rad)";
|
||||
},
|
||||
|
||||
// Set altitude
|
||||
setAltitude: function(altitude)
|
||||
{
|
||||
if (this._altitude !== altitude){
|
||||
var div = this._icon.querySelector("#altitude-div");
|
||||
if (div !== undefined)
|
||||
{
|
||||
div.innerHTML = Math.round(altitude / 0.3048 / 100) / 10;
|
||||
}
|
||||
}
|
||||
this._altitude = altitude;
|
||||
var div = this._icon.querySelector("#altitude-div");
|
||||
div.innerHTML = Math.round(altitude / 0.3048 / 100) / 10;
|
||||
},
|
||||
|
||||
// Set speed
|
||||
setSpeed: function(speed)
|
||||
{
|
||||
|
||||
var div = this._icon.querySelector("#speed-div");
|
||||
div.innerHTML = Math.round(speed * 1.94384);
|
||||
},
|
||||
|
||||
// Set hovered (mouse cursor is over the marker)
|
||||
setHovered: function(hovered)
|
||||
{
|
||||
var img = this._icon.querySelector("#icon-img");
|
||||
@ -130,10 +119,11 @@ L.Marker.UnitMarker = L.Marker.extend(
|
||||
}
|
||||
},
|
||||
|
||||
// Set selected
|
||||
setSelected: function(selected)
|
||||
{
|
||||
var selectedImg = this._icon.querySelector("#selection-img");
|
||||
if (selectedImg!== undefined)
|
||||
if (selectedImg !== undefined)
|
||||
{
|
||||
if (selected)
|
||||
{
|
||||
@ -159,16 +149,23 @@ L.Marker.UnitMarker = L.Marker.extend(
|
||||
}
|
||||
},
|
||||
|
||||
setHuman: function(human)
|
||||
setLabelsVisibility(visibility)
|
||||
{
|
||||
this._human = human;
|
||||
this._icon.querySelector("#unitName").style.opacity = visibility ? "1": "0";
|
||||
this._icon.querySelector("#unitName").innerHTML = visibility ? this.options.unitName : "";
|
||||
//this._icon.querySelector("#name").style.opacity = visibility ? "1": "0";
|
||||
//this._icon.querySelector("#name").innerHTML = visibility ? this.options.name : "";
|
||||
this._icon.querySelector("#altitude-div").style.opacity = visibility ? "1": "0";
|
||||
this._icon.querySelector("#speed-div").style.opacity = visibility ? "1": "0";
|
||||
},
|
||||
|
||||
// Set the icon zIndex
|
||||
setZIndex: function(zIndex)
|
||||
{
|
||||
this._icon.style.zIndex = zIndex;
|
||||
},
|
||||
|
||||
// Get the icon zIndex
|
||||
getZIndex: function()
|
||||
{
|
||||
return this._icon.style.zIndex;
|
||||
@ -176,31 +173,72 @@ L.Marker.UnitMarker = L.Marker.extend(
|
||||
}
|
||||
)
|
||||
|
||||
// By default markers can be hovered and clicked
|
||||
L.Marker.UnitMarker.addInitHook(function()
|
||||
{
|
||||
var icon = new L.DivIcon({html: iconHtml, className: 'DCSUnit-marker-icon'}); // Set the unit marker, className must be set to avoid white square
|
||||
this.setIcon(icon);
|
||||
|
||||
this.on('mouseover',function(e) {
|
||||
this.on('mouseover', function(e) {
|
||||
if (e.target.alive)
|
||||
{
|
||||
e.target.setHovered(true);
|
||||
}
|
||||
});
|
||||
|
||||
this.on('mouseout',function(e) {
|
||||
this.on('mouseout', function(e) {
|
||||
e.target.setHovered(false);
|
||||
});
|
||||
});
|
||||
|
||||
var iconHtml = `<table class="unitmarker-container-table" id="container-table">
|
||||
<tr>
|
||||
<td>
|
||||
<img class="unitmarker-selection-img" id="selection-img" src="img/selection.png">
|
||||
<img class="unitmarker-icon-img" id="icon-img">
|
||||
<div class="unitmarker-unitName-div" id="unitName"></div>
|
||||
<div class="unitmarker-altitude-div" id="altitude-div"></div>
|
||||
<div class="unitmarker-name-div" id="name"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>`
|
||||
/* Air Units ***********************************/
|
||||
L.Marker.UnitMarker.AirUnitMarker = L.Marker.UnitMarker.extend({})
|
||||
L.Marker.UnitMarker.AirUnitMarker.addInitHook(function(){});
|
||||
|
||||
// Aircraft
|
||||
L.Marker.UnitMarker.AirUnitMarker.AircraftMarker = L.Marker.UnitMarker.AirUnitMarker.extend({});
|
||||
L.Marker.UnitMarker.AirUnitMarker.AircraftMarker.addInitHook(function()
|
||||
{
|
||||
this.options.iconSrc = "img/units/aircraft.png";
|
||||
});
|
||||
|
||||
// Helicopter
|
||||
L.Marker.UnitMarker.AirUnitMarker.HelicopterMarker = L.Marker.UnitMarker.AirUnitMarker.extend({})
|
||||
L.Marker.UnitMarker.AirUnitMarker.HelicopterMarker.addInitHook(function()
|
||||
{
|
||||
this.options.iconSrc = "img/units/helicopter.png";
|
||||
});
|
||||
|
||||
/* Ground Units ***********************************/
|
||||
L.Marker.UnitMarker.GroundMarker = L.Marker.UnitMarker.extend({});
|
||||
L.Marker.UnitMarker.GroundMarker.addInitHook(function()
|
||||
{
|
||||
this.options.iconSrc = "img/units/ground.png";
|
||||
});
|
||||
|
||||
/* Navy Units ***********************************/
|
||||
L.Marker.UnitMarker.NavyMarker = L.Marker.UnitMarker.extend({})
|
||||
L.Marker.UnitMarker.NavyMarker.addInitHook(function()
|
||||
{
|
||||
this.options.iconSrc = "img/units/navy.png";
|
||||
});
|
||||
|
||||
/* Weapon Units ***********************************/
|
||||
L.Marker.UnitMarker.WeaponMarker = L.Marker.UnitMarker.extend({})
|
||||
L.Marker.UnitMarker.WeaponMarker.addInitHook(function()
|
||||
{
|
||||
// Weapons are not selectable
|
||||
this.on('mouseover', function(e) {});
|
||||
this.on('mouseout', function(e) {});
|
||||
});
|
||||
|
||||
// Missile
|
||||
L.Marker.UnitMarker.WeaponMarker.MissileMarker = L.Marker.UnitMarker.WeaponMarker.extend({})
|
||||
L.Marker.UnitMarker.WeaponMarker.MissileMarker.addInitHook(function()
|
||||
{
|
||||
this.options.iconSrc = "img/units/missile.png";
|
||||
});
|
||||
|
||||
// Bomb
|
||||
L.Marker.UnitMarker.WeaponMarker.BombMarker = L.Marker.UnitMarker.WeaponMarker.extend({})
|
||||
L.Marker.UnitMarker.WeaponMarker.BombMarker.addInitHook(function()
|
||||
{
|
||||
this.options.iconSrc = "img/units/bomb.png";
|
||||
});
|
||||
|
||||
@ -5,14 +5,19 @@ class UnitsManager
|
||||
this._units = {};
|
||||
}
|
||||
|
||||
units()
|
||||
addUnit(ID, data)
|
||||
{
|
||||
return this._units;
|
||||
// The name of the unit category is exactly the same as the constructor name
|
||||
var constructor = eval(data.category);
|
||||
if (constructor != undefined)
|
||||
{
|
||||
this._units[ID] = new constructor(ID, data);
|
||||
}
|
||||
}
|
||||
|
||||
addUnit(ID)
|
||||
getUnit(ID)
|
||||
{
|
||||
this._units[ID] = new Unit(ID)
|
||||
return this._units[ID];
|
||||
}
|
||||
|
||||
removeUnit(ID)
|
||||
@ -35,7 +40,7 @@ class UnitsManager
|
||||
// Create the unit if missing from the local array, then update the data. Drawing is handled by leaflet.
|
||||
if (!(ID in this._units))
|
||||
{
|
||||
this.addUnit(parseInt(ID));
|
||||
this.addUnit(parseInt(ID), data["units"][ID]);
|
||||
}
|
||||
this._units[ID].update(data["units"][ID]);
|
||||
}
|
||||
@ -46,12 +51,12 @@ class UnitsManager
|
||||
if (this.getSelectedUnits().length > 0)
|
||||
{
|
||||
map.setState("UNIT_SELECTED");
|
||||
topPanel.enableButtons(true);
|
||||
unitControlPanel.enableButtons(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
map.setState("IDLE");
|
||||
topPanel.disableButtons();
|
||||
unitControlPanel.disableButtons();
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,38 +97,42 @@ class UnitsManager
|
||||
|
||||
addDestination(latlng)
|
||||
{
|
||||
for (let ID in this._units)
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
if (this._units[ID].getSelected())
|
||||
{
|
||||
this._units[ID].addDestination(latlng);
|
||||
}
|
||||
selectedUnits[idx].addDestination(latlng);
|
||||
}
|
||||
}
|
||||
|
||||
clearDestinations()
|
||||
{
|
||||
for (let ID in this._units)
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
if (this._units[ID].getSelected())
|
||||
{
|
||||
this._units[ID].clearDestinations();
|
||||
}
|
||||
selectedUnits[idx].clearDestinations();
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsMove()
|
||||
{
|
||||
var asd = 1;
|
||||
|
||||
}
|
||||
|
||||
selectedUnitsChangeSpeed(speedChange)
|
||||
{
|
||||
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].changeSpeed(speedChange);
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsChangeAltitude(altitudeChange)
|
||||
{
|
||||
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].changeAltitude(altitudeChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
var missionData;
|
||||
var controlPanel;
|
||||
var unitsManager;
|
||||
var leftPanel;
|
||||
var topPanel;
|
||||
var unitInfoPanel;
|
||||
var unitControlPanel;
|
||||
var map;
|
||||
var RESTaddress = "http://localhost:30000/restdemo";
|
||||
|
||||
@ -11,8 +12,9 @@ function setup()
|
||||
missionData = new MissionData();
|
||||
unitsManager = new UnitsManager();
|
||||
|
||||
leftPanel = new LeftPanel("left-panel");
|
||||
topPanel = new TopPanel("top-panel");
|
||||
unitInfoPanel = new UnitInfoPanel("left-panel");
|
||||
unitControlPanel = new UnitControlPanel("top-panel");
|
||||
controlPanel = new ControlPanel("top-control-panel");
|
||||
|
||||
map = new Map();
|
||||
|
||||
@ -22,8 +24,8 @@ function setup()
|
||||
|
||||
function resize()
|
||||
{
|
||||
var topPanelHeight = document.getElementById("header").offsetHeight;
|
||||
document.getElementById("map").style.height = `${window.innerHeight - topPanelHeight - 10}px`;
|
||||
var unitControlPanelHeight = document.getElementById("header").offsetHeight;
|
||||
document.getElementById("map").style.height = `${window.innerHeight - unitControlPanelHeight - 10}px`;
|
||||
document.getElementById("top-panel").style.left = `${window.innerWidth / 2 - document.getElementById("top-panel").offsetWidth / 2}px`
|
||||
}
|
||||
|
||||
@ -39,7 +41,7 @@ function update()
|
||||
|
||||
missionData.update(data);
|
||||
unitsManager.update(data);
|
||||
leftPanel.update(unitsManager.getSelectedUnits());
|
||||
unitInfoPanel.update(unitsManager.getSelectedUnits());
|
||||
};
|
||||
|
||||
xmlHttp.onerror = function () {
|
||||
|
||||
1
www/js/payloadNames.js
Normal file
1
www/js/payloadNames.js
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user