WIP on CAP, and AI units can starts from ground uncontrolled instead of using late activation.

This commit is contained in:
Khopa 2020-06-03 00:45:44 +02:00
parent c73290eebb
commit 4373d89661
6 changed files with 310 additions and 170 deletions

View File

@ -1,12 +1,12 @@
from dcs.action import ActivateGroup
from dcs.action import ActivateGroup, AITaskPush
from dcs.condition import TimeAfter, CoalitionHasAirdrome
from dcs.helicopters import UH_1H
from dcs.terrain.terrain import NoParkingSlotError
from dcs.triggers import TriggerOnce, Event
from game.settings import Settings
from gen.flights.ai_flight_planner import FlightPlanner
from gen.flights.flight import Flight, FlightType
from gen.flights.ai_flight_planner import FlightPlanner, CAP_DEFAULT_ENGAGE_DISTANCE, nm_to_meter
from gen.flights.flight import Flight, FlightType, FlightWaypointType
from .conflictgen import *
from .naming import *
from .triggergen import TRIGGER_WAYPOINT_OFFSET
@ -354,23 +354,48 @@ class AircraftConflictGenerator:
def setup_group_activation_trigger(self, flight, group):
if flight.scheduled_in > 0 and flight.client_count == 0:
group.late_activation = True
activation_trigger = TriggerOnce(Event.NoEvent, "LiberationActivationTriggerForGroup" + str(group.id))
activation_trigger.add_condition(TimeAfter(seconds=flight.scheduled_in*60))
if(flight.from_cp.cptype == ControlPointType.AIRBASE):
if not flight.from_cp.captured:
activation_trigger.add_condition(CoalitionHasAirdrome(self.game.get_player_coalition_id(), flight.from_cp.id))
else:
activation_trigger.add_condition(CoalitionHasAirdrome(self.game.get_enemy_coalition_id(), flight.from_cp.id))
if flight.start_type != "In Flight":
group.late_activation = False
group.uncontrolled = True
activation_trigger = TriggerOnce(Event.NoEvent, "LiberationControlTriggerForGroup" + str(group.id))
activation_trigger.add_condition(TimeAfter(seconds=flight.scheduled_in * 60))
if (flight.from_cp.cptype == ControlPointType.AIRBASE):
if flight.from_cp.captured:
activation_trigger.add_condition(
CoalitionHasAirdrome(self.game.get_player_coalition_id(), flight.from_cp.id))
else:
activation_trigger.add_condition(
CoalitionHasAirdrome(self.game.get_enemy_coalition_id(), flight.from_cp.id))
group.add_trigger_action(StartCommand())
activation_trigger.add_action(AITaskPush(group.id, len(group.tasks)))
self.m.triggerrules.triggers.append(activation_trigger)
print("ADD TRIG CTRL")
else:
group.late_activation = True
activation_trigger = TriggerOnce(Event.NoEvent, "LiberationActivationTriggerForGroup" + str(group.id))
activation_trigger.add_condition(TimeAfter(seconds=flight.scheduled_in*60))
if(flight.from_cp.cptype == ControlPointType.AIRBASE):
if flight.from_cp.captured:
activation_trigger.add_condition(CoalitionHasAirdrome(self.game.get_player_coalition_id(), flight.from_cp.id))
else:
activation_trigger.add_condition(CoalitionHasAirdrome(self.game.get_enemy_coalition_id(), flight.from_cp.id))
activation_trigger.add_action(ActivateGroup(group.id))
self.m.triggerrules.triggers.append(activation_trigger)
activation_trigger.add_action(ActivateGroup(group.id))
self.m.triggerrules.triggers.append(activation_trigger)
def generate_planned_flight(self, cp, country, flight:Flight):
try:
if flight.start_type == "In Flight" or flight.client_count == 0:
if flight.client_count == 0:
flight.start_type = "Warm"
print(flight.start_type)
if flight.start_type == "In Flight":
group = self._generate_group(
name=namegen.next_unit_name(country, cp.id, flight.unit_type),
side=country,
@ -406,6 +431,7 @@ class AircraftConflictGenerator:
start_type=st)
except Exception:
# Generated when there is no place on Runway or on Parking Slots
flight.start_type = "In Flight"
group = self._generate_group(
name=namegen.next_unit_name(country, cp.id, flight.unit_type),
side=country,
@ -427,8 +453,27 @@ class AircraftConflictGenerator:
def setup_group_as_cap_flight(self, group, flight):
self._setup_group(group, CAP, flight.client_count)
for point in flight.points:
group.add_waypoint(Point(point.x,point.y), point.alt)
#group.points[0].tasks.clear()
#group.tasks.clear()
#group.tasks.append(EngageTargets(max_distance=40, targets=[Targets.All.Air]))
#group.tasks.append(EngageTargets(max_distance=nm_to_meter(120), targets=[Targets.All.Air]))
for i, point in enumerate(flight.points):
if not point.only_for_player or (point.only_for_player and flight.client_count > 0):
pt = group.add_waypoint(Point(point.x, point.y), point.alt)
if point.waypoint_type == FlightWaypointType.PATROL_TRACK:
action = OrbitAction(altitude=pt.alt, pattern=OrbitAction.OrbitPattern.RaceTrack)
pt.tasks.append(action)
#for tgt in point.targets:
# if hasattr(tgt, "position"):
# engagetgt = EngageTargetsInZone(tgt.position, radius=CAP_DEFAULT_ENGAGE_DISTANCE, targets=[Targets.All.Air])
# pt.tasks.append(engagetgt)
elif point.waypoint_type == FlightWaypointType.LANDING_POINT:
pt.type = "Land"
def setup_group_as_cas_flight(self, group, flight):
group.task = CAS.name

View File

@ -6,7 +6,24 @@ import random
from game import db
from gen import Conflict
from gen.flights.ai_flight_planner_db import INTERCEPT_CAPABLE, CAP_CAPABLE, CAS_CAPABLE, SEAD_CAPABLE
from gen.flights.flight import Flight, FlightType, FlightWaypoint
from gen.flights.flight import Flight, FlightType, FlightWaypoint, FlightWaypointType
def meter_to_feet(value_in_meter):
return int(3.28084 * value_in_meter)
def feet_to_meter(value_in_feet):
return int(float(value_in_feet)/3.048)
def meter_to_nm(value_in_meter):
return int(float(value_in_meter)*0.000539957)
def nm_to_meter(value_in_nm):
return int(float(value_in_nm)*1852)
# TODO : Ideally should be based on the aircraft type instead / Availability of fuel
STRIKE_MAX_RANGE = 1500000
@ -19,11 +36,15 @@ CAS_EVERY_X_MINUTES = 30
SEAD_EVERY_X_MINUTES = 40
STRIKE_EVERY_X_MINUTES = 40
INGRESS_EGRESS_DISTANCE = 45000
INGRESS_ALT = 6096 # 20k feet
EGRESS_ALT = 6096 # 20k feet
PATROL_ALT_RANGE = (3600, 9200)
INGRESS_EGRESS_DISTANCE = nm_to_meter(45)
INGRESS_ALT = feet_to_meter(20000)
EGRESS_ALT = feet_to_meter(20000)
PATROL_ALT_RANGE = (feet_to_meter(15000), feet_to_meter(33000))
NAV_ALT = 9144
PATTERN_ALTITUDE = feet_to_meter(5000)
CAP_DEFAULT_ENGAGE_DISTANCE = nm_to_meter(40)
class FlightPlanner:
@ -69,7 +90,7 @@ class FlightPlanner:
self.commision_strike()
# TODO : commision STRIKE / ANTISHIP
# TODO : commision ANTISHIP
def remove_flight(self, index):
try:
@ -135,30 +156,81 @@ class FlightPlanner:
ftype = FlightType.BARCAP if self.from_cp.is_carrier else FlightType.CAP
flight = Flight(unit, 2, self.from_cp, ftype)
# Flight path : fly over each ground object (TODO : improve)
flight.points = []
flight.scheduled_in = offset + i*random.randint(CAP_EVERY_X_MINUTES-5, CAP_EVERY_X_MINUTES+5)
patrol_alt = random.randint(PATROL_ALT_RANGE[0], PATROL_ALT_RANGE[1])
patrolled = []
for ground_object in self.from_cp.ground_objects:
if ground_object.group_id not in patrolled and not ground_object.airbase_group:
point = FlightWaypoint(ground_object.position.x, ground_object.position.y, patrol_alt)
point.name = "Patrol point"
point.description = "Patrol #" + str(len(flight.points))
point.pretty_name = "Patrol #" + str(len(flight.points))
flight.points.append(point)
patrolled.append(ground_object.group_id)
# Choose a location for CAP patrols (Either behind frontline, or to protect ground objects)
rng = random.randint(0,100)
if rng < 80 and len(self._get_cas_locations()) > 0:
loc = random.choice(self._get_cas_locations())
ingress, heading, distance = Conflict.frontline_vector(self.from_cp, loc, self.game.theater)
center = ingress.point_from_heading(heading, distance / 2)
orbit_center = center.point_from_heading(heading - 90, random.randint(nm_to_meter(6), nm_to_meter(15)))
radius = distance * 2
orbit0p = orbit_center.point_from_heading(heading, radius)
orbit1p = orbit_center.point_from_heading(heading + 180, radius)
elif len(self.from_cp.ground_objects) > 0:
loc = random.choice(self.from_cp.ground_objects)
hdg = self.from_cp.position.heading_between_point(loc.position)
radius = random.randint(nm_to_meter(5), nm_to_meter(10))
orbit0p = loc.position.point_from_heading(hdg - 90, radius)
orbit1p = loc.position.point_from_heading(hdg + 90, radius)
else:
loc = self.from_cp.position.point_from_heading(random.randint(0, 360), random.randint(nm_to_meter(5), nm_to_meter(40)))
hdg = self.from_cp.position.heading_between_point(loc.position)
radius = random.randint(nm_to_meter(40), nm_to_meter(120))
orbit0p = loc.position.point_from_heading(hdg - 90, radius)
orbit1p = loc.position.point_from_heading(hdg + 90, radius)
if len(flight.points) == 0:
for i in range(3):
pos = self.from_cp.position.point_from_heading(random.randint(0, 360), random.randint(30000, 80000))
point = FlightWaypoint(pos.x, pos.y, patrol_alt)
point.name = "Patrol point"
point.description = "Patrol #" + str(len(flight.points))
point.pretty_name = "Patrol #" + str(len(flight.points))
flight.points.append(point)
# Create points
ascend_heading = random.randint(0, 360)
pos_ascend = self.from_cp.position.point_from_heading(ascend_heading, 30000)
ascend = FlightWaypoint(pos_ascend.x, pos_ascend.y, patrol_alt)
ascend.name = "ASCEND"
ascend.description = "Ascend to alt [" + str(meter_to_feet(patrol_alt)) + " ft]"
ascend.pretty_name = "Ascend to alt [" + str(meter_to_feet(patrol_alt)) + " ft]"
ascend.waypoint_type = FlightWaypointType.ASCEND_POINT
flight.points.append(ascend)
orbit0 = FlightWaypoint(orbit0p.x, orbit0p.y, patrol_alt)
orbit0.name = "ORBIT 0"
orbit0.description = "Standby between this point and the next one"
orbit0.pretty_name = "Orbit race-track start"
orbit0.waypoint_type = FlightWaypointType.PATROL_TRACK
flight.points.append(orbit0)
orbit1 = FlightWaypoint(orbit1p.x, orbit1p.y, patrol_alt)
orbit1.name = "ORBIT 1"
orbit1.description = "Standby between this point and the previous one"
orbit1.pretty_name = "Orbit race-track end"
orbit1.waypoint_type = FlightWaypointType.PATROL
flight.points.append(orbit1)
orbit0.targets.append(self.from_cp)
obj_added = []
for ground_object in self.from_cp.ground_objects:
if ground_object.obj_name not in obj_added and not ground_object.airbase_group:
orbit0.targets.append(ground_object)
obj_added.append(ground_object.obj_name)
descend = self.from_cp.position.point_from_heading(ascend_heading-180, 30000)
descend = FlightWaypoint(descend.x, descend.y, PATTERN_ALTITUDE)
descend.name = "DESCEND"
descend.description = "Descend to pattern alt [5000ft]"
descend.pretty_name = "Descend to pattern alt [5000ft]"
descend.waypoint_type = FlightWaypointType.DESCENT_POINT
flight.points.append(descend)
rtb = self.from_cp.position.point_from_heading(ascend_heading - 180, 30000)
rtb = FlightWaypoint(rtb.x, rtb.y, PATTERN_ALTITUDE)
rtb.name = "LANDING"
rtb.description = "RTB"
rtb.pretty_name = "RTB"
rtb.waypoint_type = FlightWaypointType.LANDING_POINT
flight.points.append(rtb)
self.cap_flights.append(flight)
self.flights.append(flight)
@ -203,18 +275,21 @@ class FlightPlanner:
ingress_point.name = "INGRESS"
ingress_point.pretty_name = "INGRESS"
ingress_point.description = "Ingress into CAS area"
ingress_point.waypoint_type = FlightWaypointType.INGRESS_CAS
flight.points.append(ingress_point)
center_point = FlightWaypoint(center.x, center.y, 1000)
center_point.description = "Provide CAS"
center_point.name = "CAS"
center_point.pretty_name = "INGRESS"
center_point.waypoint_type = FlightWaypointType.CAS
flight.points.append(center_point)
egress_point = FlightWaypoint(egress.x, egress.y, 1000)
egress_point.description = "Egress from CAS area"
egress_point.name = "EGRESS"
egress_point.pretty_name = "EGRESS"
egress_point.waypoint_type = FlightWaypointType.EGRESS
flight.points.append(egress_point)
self.cas_flights.append(flight)
@ -262,23 +337,27 @@ class FlightPlanner:
ingress_point = FlightWaypoint(ingress_pos.x, ingress_pos.y, INGRESS_ALT)
ingress_point.pretty_name = "INGRESS on " + location.obj_name
ingress_point.description = "INGRESS on " + location.obj_name
ingress_point.waypoint_type = FlightWaypointType.INGRESS_SEAD
flight.points.append(ingress_point)
point = FlightWaypoint(location.position.x, location.position.y, 1000)
point = FlightWaypoint(location.position.x, location.position.y, 0)
if flight.flight_type == FlightType.DEAD:
point.description = "SEAD on " + location.obj_name
point.pretty_name = "SEAD on " + location.obj_name
point.only_for_player = True
else:
point.description = "DEAD on " + location.obj_name
point.pretty_name = "DEAD on " + location.obj_name
point.only_for_player = True
point.targets.append(location)
ingress_point.targets.append(location)
flight.points.append(point)
egress_pos = location.position.point_from_heading(egress_heading, INGRESS_EGRESS_DISTANCE)
egress_point = FlightWaypoint(egress_pos.x, egress_pos.y, EGRESS_ALT)
egress_point.pretty_name = "EGRESS on " + location.obj_name
egress_point.description = "EGRESS on " + location.obj_name
egress_point.waypoint_type = FlightWaypointType.EGRESS
flight.points.append(egress_point)
self.sead_flights.append(flight)

View File

@ -30,6 +30,24 @@ class FlightType(Enum):
EWAR = 16
class FlightWaypointType(Enum):
TAKEOFF = 0 # Take off point
ASCEND_POINT = 1 # Ascension point after take off
PATROL = 2 # Patrol point
PATROL_TRACK = 3 # Patrol race track
NAV = 4 # Nav point
INGRESS_STRIKE = 5 # Ingress strike (For generator, means that this should have bombing on next TARGET_POINT points)
INGRESS_SEAD = 6 # Ingress sead (For generator, means that this should attack groups on TARGET_GROUP_LOC points)
INGRESS_CAS = 7 # Ingress cas (should start CAS task)
CAS = 8 # Should do CAS there
EGRESS = 9 # Should stop attack
DESCENT_POINT = 10 # Should start descending to pattern alt
LANDING_POINT = 11 # Should land there
TARGET_POINT = 12 # A target building or static object, position
TARGET_GROUP_LOC = 13 # A target group approximate location
TARGET_SHIP = 14 # A target ship known location
class FlightWaypoint:
def __init__(self, x: float, y: float, alt=0):
@ -41,6 +59,8 @@ class FlightWaypoint:
self.targets = []
self.obj_name = ""
self.pretty_name = ""
self.waypoint_type = FlightWaypointType.TAKEOFF # type: FlightWaypointType
self.only_for_player = False
class Flight:

View File

@ -1,3 +1,4 @@
pydcs>=0.9.4
Pyside2>=5.13.0
pyinstaller==3.5
pyproj==2.6.1.post1

View File

@ -2,156 +2,150 @@ local unitPayloads = {
["name"] = "Su-24M",
["payloads"] = {
[1] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
["num"] = 5,
},
[4] = {
["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}",
["num"] = 7,
},
[5] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 8,
},
},
["tasks"] = {
[1] = 29,
[2] = 30,
},
},
[2] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}",
["num"] = 7,
},
[4] = {
["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}",
["num"] = 8,
},
[5] = {
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
["num"] = 6,
},
[6] = {
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
["num"] = 3,
},
[7] = {
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
["num"] = 4,
},
[8] = {
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
["num"] = 5,
},
},
["tasks"] = {
[1] = 31,
},
},
[3] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
["num"] = 3,
},
[4] = {
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
["num"] = 5,
},
[6] = {
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
["num"] = 6,
},
[7] = {
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
["num"] = 7,
},
[8] = {
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
["num"] = 8,
},
},
["tasks"] = {
[1] = 31,
},
},
[4] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
["num"] = 5,
},
[4] = {
["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}",
["num"] = 7,
},
[5] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
[2] = {
["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}",
["num"] = 8,
},
[3] = {
["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}",
["num"] = 1,
},
[4] = {
["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 29,
},
},
[5] = {
[2] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{KAB_1500LG_LOADOUT}",
["num"] = 7,
},
[2] = {
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
["num"] = 8,
},
[3] = {
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
["num"] = 1,
},
[4] = {
["CLSID"] = "{KAB_1500LG_LOADOUT}",
["num"] = 2,
},
[5] = {
["CLSID"] = "{E2C426E3-8B10-4E09-B733-9CDC26520F48}",
["num"] = 3,
},
[6] = {
["CLSID"] = "{E2C426E3-8B10-4E09-B733-9CDC26520F48}",
["num"] = 6,
},
[7] = {
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
["num"] = 4,
},
[8] = {
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
["num"] = 5,
},
},
["tasks"] = {
},
},
[3] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "{B0DBC591-0F52-4F7D-AD7B-51E67725FB81}",
["num"] = 1,
["CLSID"] = "{7D7EC917-05F6-49D4-8045-61FC587DD019}",
["num"] = 7,
},
[2] = {
["CLSID"] = "{275A2855-4A79-4B2D-B082-91EA2ADF4691}",
["num"] = 8,
},
[3] = {
["CLSID"] = "{B0DBC591-0F52-4F7D-AD7B-51E67725FB81}",
["num"] = 1,
},
[4] = {
["CLSID"] = "{7D7EC917-05F6-49D4-8045-61FC587DD019}",
["num"] = 2,
},
},
["tasks"] = {
},
},
[4] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}",
["num"] = 7,
},
[2] = {
["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}",
["num"] = 8,
},
[3] = {
["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}",
["num"] = 1,
},
[4] = {
["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}",
["num"] = 2,
},
},
["tasks"] = {
},
},
[5] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 8,
},
[2] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
["num"] = 2,
},
[4] = {
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
["num"] = 7,
},
[5] = {
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
["num"] = 6,
},
[6] = {
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
["num"] = 3,
},
[7] = {
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
["num"] = 5,
},
[8] = {
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 32,
},
},
},

View File

@ -38,6 +38,7 @@ class ControlPoint:
cptype: ControlPointType = None
ICLS_counter = 1
alt = 0
def __init__(self, id: int, name: str, position: Point, at, radials: typing.Collection[int], size: int, importance: float,
has_frontline=True, cptype=ControlPointType.AIRBASE):