mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
updates to CAP op
This commit is contained in:
parent
3b454470f9
commit
683114f916
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
__pycache__
|
__pycache__
|
||||||
build/*
|
build/*
|
||||||
resources/payloads/*.lua
|
resources/payloads/*.lua
|
||||||
|
venv
|
||||||
logs.txt
|
logs.txt
|
||||||
.DS_Store
|
.DS_Store
|
||||||
# User-specific stuff
|
# User-specific stuff
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class FrontlineAttackEvent(Event):
|
|||||||
ATTACKER_AMOUNT_FACTOR = 0.4
|
ATTACKER_AMOUNT_FACTOR = 0.4
|
||||||
ATTACKER_DEFENDER_FACTOR = 0.7
|
ATTACKER_DEFENDER_FACTOR = 0.7
|
||||||
STRENGTH_INFLUENCE = 0.2
|
STRENGTH_INFLUENCE = 0.2
|
||||||
SUCCESS_TARGETS_HIT_PERCENTAGE = 0.25
|
SUCCESS_FACTOR = 1.5
|
||||||
|
|
||||||
defenders = None # type: db.ArmorDict
|
defenders = None # type: db.ArmorDict
|
||||||
|
|
||||||
@ -28,16 +28,13 @@ class FrontlineAttackEvent(Event):
|
|||||||
return "Frontline attack from {} at {}".format(self.from_cp, self.to_cp)
|
return "Frontline attack from {} at {}".format(self.from_cp, self.to_cp)
|
||||||
|
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
total_targets = sum(self.defenders.values())
|
alive_attackers = sum([v for k, v in debriefing.alive_units[self.attacker_name].items() if db.unit_task(k) == PinpointStrike])
|
||||||
destroyed_targets = 0
|
alive_defenders = sum([v for k, v in debriefing.alive_units[self.defender_name].items() if db.unit_task(k) == PinpointStrike])
|
||||||
for unit, count in debriefing.destroyed_units[self.defender_name].items():
|
attackers_success = (float(alive_attackers) / alive_defenders) > self.SUCCESS_FACTOR
|
||||||
if unit in self.defenders:
|
|
||||||
destroyed_targets += count
|
|
||||||
|
|
||||||
if self.from_cp.captured:
|
if self.from_cp.captured:
|
||||||
return float(destroyed_targets) / total_targets >= self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
return attackers_success
|
||||||
else:
|
else:
|
||||||
return float(destroyed_targets) / total_targets < self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
return not attackers_success
|
||||||
|
|
||||||
def commit(self, debriefing: Debriefing):
|
def commit(self, debriefing: Debriefing):
|
||||||
super(FrontlineAttackEvent, self).commit(debriefing)
|
super(FrontlineAttackEvent, self).commit(debriefing)
|
||||||
|
|||||||
@ -13,7 +13,7 @@ from userdata.debriefing import Debriefing
|
|||||||
class FrontlinePatrolEvent(Event):
|
class FrontlinePatrolEvent(Event):
|
||||||
ESCORT_FACTOR = 0.5
|
ESCORT_FACTOR = 0.5
|
||||||
STRENGTH_INFLUENCE = 0.2
|
STRENGTH_INFLUENCE = 0.2
|
||||||
SUCCESS_TARGETS_HIT_PERCENTAGE = 0.33
|
SUCCESS_FACTOR = 0.8
|
||||||
|
|
||||||
cas = None # type: db.PlaneDict
|
cas = None # type: db.PlaneDict
|
||||||
escort = None # type: db.PlaneDict
|
escort = None # type: db.PlaneDict
|
||||||
@ -25,6 +25,7 @@ class FrontlinePatrolEvent(Event):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Frontline CAP from {} at {}".format(self.from_cp, self.to_cp)
|
return "Frontline CAP from {} at {}".format(self.from_cp, self.to_cp)
|
||||||
|
|
||||||
|
"""
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
total_targets = sum(self.cas.values())
|
total_targets = sum(self.cas.values())
|
||||||
destroyed_targets = 0
|
destroyed_targets = 0
|
||||||
@ -36,6 +37,16 @@ class FrontlinePatrolEvent(Event):
|
|||||||
return float(destroyed_targets) / total_targets >= self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
return float(destroyed_targets) / total_targets >= self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
||||||
else:
|
else:
|
||||||
return float(destroyed_targets) / total_targets < self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
return float(destroyed_targets) / total_targets < self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
||||||
|
"""
|
||||||
|
|
||||||
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
|
alive_attackers = sum([v for k, v in debriefing.alive_units[self.attacker_name].items() if db.unit_task(k) == PinpointStrike])
|
||||||
|
alive_defenders = sum([v for k, v in debriefing.alive_units[self.defender_name].items() if db.unit_task(k) == PinpointStrike])
|
||||||
|
attackers_success = (float(alive_attackers) / alive_defenders) >= self.SUCCESS_FACTOR
|
||||||
|
if self.from_cp.captured:
|
||||||
|
return attackers_success
|
||||||
|
else:
|
||||||
|
return not attackers_success
|
||||||
|
|
||||||
def commit(self, debriefing: Debriefing):
|
def commit(self, debriefing: Debriefing):
|
||||||
super(FrontlinePatrolEvent, self).commit(debriefing)
|
super(FrontlinePatrolEvent, self).commit(debriefing)
|
||||||
@ -54,7 +65,7 @@ class FrontlinePatrolEvent(Event):
|
|||||||
def skip(self):
|
def skip(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def player_attacking(self, interceptors: db.PlaneDict, clients: db.PlaneDict):
|
def player_attacking(self, interceptors: db.PlaneDict, clients: db.PlaneDict, armor: db.ArmorDict):
|
||||||
self.cas = self.to_cp.base.scramble_cas(self.game.settings.multiplier)
|
self.cas = self.to_cp.base.scramble_cas(self.game.settings.multiplier)
|
||||||
self.escort = self.to_cp.base.scramble_sweep(self.game.settings.multiplier * self.ESCORT_FACTOR)
|
self.escort = self.to_cp.base.scramble_sweep(self.game.settings.multiplier * self.ESCORT_FACTOR)
|
||||||
|
|
||||||
@ -65,10 +76,12 @@ class FrontlinePatrolEvent(Event):
|
|||||||
defender_clients={},
|
defender_clients={},
|
||||||
from_cp=self.from_cp,
|
from_cp=self.from_cp,
|
||||||
to_cp=self.to_cp)
|
to_cp=self.to_cp)
|
||||||
|
|
||||||
|
defenders = self.to_cp.base.assemble_attack()
|
||||||
op.setup(cas=self.cas,
|
op.setup(cas=self.cas,
|
||||||
escort=self.escort,
|
escort=self.escort,
|
||||||
interceptors=interceptors,
|
interceptors=interceptors,
|
||||||
armor_attackers=self.from_cp.base.assemble_attack(),
|
armor_attackers=db.unitdict_restrict_count(armor, sum(defenders.values())),
|
||||||
armor_defenders=self.to_cp.base.assemble_attack())
|
armor_defenders=defenders)
|
||||||
|
|
||||||
self.operation = op
|
self.operation = op
|
||||||
|
|||||||
@ -262,11 +262,12 @@ class AircraftConflictGenerator:
|
|||||||
client_count=client_count,
|
client_count=client_count,
|
||||||
at=at and at or self._group_point(self.conflict.air_defenders_location))
|
at=at and at or self._group_point(self.conflict.air_defenders_location))
|
||||||
|
|
||||||
pos = self.conflict.air_defenders_location.point_from_heading(self.conflict.heading-90, CAP_CAS_DISTANCE)
|
location = self._group_point(self.conflict.air_defenders_location)
|
||||||
waypoint = group.add_waypoint(pos, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
insertion_point = self.conflict.find_insertion_point(location)
|
||||||
|
waypoint = group.add_waypoint(insertion_point, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||||
|
|
||||||
if self.conflict.is_vector:
|
if self.conflict.is_vector:
|
||||||
destination_tail = self.conflict.tail.distance_to_point(pos) > self.conflict.position.distance_to_point(pos)
|
destination_tail = self.conflict.tail.distance_to_point(insertion_point) > self.conflict.position.distance_to_point(insertion_point)
|
||||||
group.add_waypoint(destination_tail and self.conflict.tail or self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
group.add_waypoint(destination_tail and self.conflict.tail or self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||||
|
|
||||||
group.task = CAS.name
|
group.task = CAS.name
|
||||||
|
|||||||
@ -20,7 +20,7 @@ AIR_DISTANCE = 40000
|
|||||||
|
|
||||||
CAPTURE_AIR_ATTACKERS_DISTANCE = 25000
|
CAPTURE_AIR_ATTACKERS_DISTANCE = 25000
|
||||||
CAPTURE_AIR_DEFENDERS_DISTANCE = 60000
|
CAPTURE_AIR_DEFENDERS_DISTANCE = 60000
|
||||||
CAP_CAS_DISTANCE = 10000
|
CAP_CAS_DISTANCE = 10000, 120000
|
||||||
|
|
||||||
GROUND_INTERCEPT_SPREAD = 5000
|
GROUND_INTERCEPT_SPREAD = 5000
|
||||||
GROUND_DISTANCE_FACTOR = 1
|
GROUND_DISTANCE_FACTOR = 1
|
||||||
@ -123,6 +123,21 @@ class Conflict:
|
|||||||
def to_size(self):
|
def to_size(self):
|
||||||
return self.to_cp.size * GROUND_DISTANCE_FACTOR
|
return self.to_cp.size * GROUND_DISTANCE_FACTOR
|
||||||
|
|
||||||
|
def find_insertion_point(self, other_point: Point) -> Point:
|
||||||
|
dx = self.position.x - self.tail.x
|
||||||
|
dy = self.position.y - self.tail.y
|
||||||
|
dr2 = float(dx ** 2 + dy ** 2)
|
||||||
|
|
||||||
|
lerp = ((other_point.x - self.tail.x) * dx + (other_point.y - self.tail.y) * dy) / dr2
|
||||||
|
if lerp < 0:
|
||||||
|
lerp = 0
|
||||||
|
elif lerp > 1:
|
||||||
|
lerp = 1
|
||||||
|
|
||||||
|
x = lerp * dx + self.tail.x
|
||||||
|
y = lerp * dy + self.tail.y
|
||||||
|
return Point(x, y)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def has_frontline_between(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> bool:
|
def has_frontline_between(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> bool:
|
||||||
return from_cp.has_frontline and to_cp.has_frontline
|
return from_cp.has_frontline and to_cp.has_frontline
|
||||||
@ -138,6 +153,7 @@ class Conflict:
|
|||||||
center_position, heading = cls.frontline_position(from_cp, to_cp)
|
center_position, heading = cls.frontline_position(from_cp, to_cp)
|
||||||
|
|
||||||
left_position = center_position
|
left_position = center_position
|
||||||
|
|
||||||
for offset in range(0, int(FRONTLINE_LENGTH / 2), 1000):
|
for offset in range(0, int(FRONTLINE_LENGTH / 2), 1000):
|
||||||
pos = center_position.point_from_heading(_heading_sum(heading, -90), offset)
|
pos = center_position.point_from_heading(_heading_sum(heading, -90), offset)
|
||||||
if not theater.is_on_land(pos):
|
if not theater.is_on_land(pos):
|
||||||
@ -266,7 +282,7 @@ class Conflict:
|
|||||||
position, heading, distance = cls.frontline_vector(from_cp, to_cp, theater)
|
position, heading, distance = cls.frontline_vector(from_cp, to_cp, theater)
|
||||||
attack_position = position.point_from_heading(heading, randint(0, int(distance)))
|
attack_position = position.point_from_heading(heading, randint(0, int(distance)))
|
||||||
attackers_position = attack_position.point_from_heading(heading - 90, AIR_DISTANCE)
|
attackers_position = attack_position.point_from_heading(heading - 90, AIR_DISTANCE)
|
||||||
defenders_position = attack_position.point_from_heading(heading + 90, CAP_CAS_DISTANCE)
|
defenders_position = attack_position.point_from_heading(heading + 90, random.randint(*CAP_CAS_DISTANCE))
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
position=position,
|
position=position,
|
||||||
|
|||||||
@ -18,7 +18,7 @@ from gen import *
|
|||||||
WEATHER_CLOUD_BASE = 2000, 3000
|
WEATHER_CLOUD_BASE = 2000, 3000
|
||||||
WEATHER_CLOUD_DENSITY = 1, 8
|
WEATHER_CLOUD_DENSITY = 1, 8
|
||||||
WEATHER_CLOUD_THICKNESS = 100, 400
|
WEATHER_CLOUD_THICKNESS = 100, 400
|
||||||
WEATHER_CLOUD_BASE_MIN = 2400
|
WEATHER_CLOUD_BASE_MIN = 1600
|
||||||
|
|
||||||
RANDOM_TIME = {
|
RANDOM_TIME = {
|
||||||
"night": 5,
|
"night": 5,
|
||||||
@ -28,10 +28,10 @@ RANDOM_TIME = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RANDOM_WEATHER = {
|
RANDOM_WEATHER = {
|
||||||
1: 5, # heavy rain
|
1: 10, # heavy rain
|
||||||
2: 15, # rain
|
2: 20, # rain
|
||||||
3: 25, # dynamic
|
3: 30, # dynamic
|
||||||
4: 35, # clear
|
4: 40, # clear
|
||||||
5: 100, # random
|
5: 100, # random
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +90,13 @@ class EnviromentGenerator:
|
|||||||
self.mission.weather.wind_at_8000 = Wind(wind_direction, wind_speed * 3)
|
self.mission.weather.wind_at_8000 = Wind(wind_direction, wind_speed * 3)
|
||||||
|
|
||||||
if self.mission.weather.clouds_density > 0:
|
if self.mission.weather.clouds_density > 0:
|
||||||
|
# sometimes clouds are randomized way too low and need to be fixed
|
||||||
self.mission.weather.clouds_base = max(self.mission.weather.clouds_base, WEATHER_CLOUD_BASE_MIN)
|
self.mission.weather.clouds_base = max(self.mission.weather.clouds_base, WEATHER_CLOUD_BASE_MIN)
|
||||||
|
|
||||||
|
if self.mission.weather.wind_at_ground == 0:
|
||||||
|
# frontline smokes look silly w/o any wind
|
||||||
|
self.mission.weather.wind_at_ground = random.randint(1, 2)
|
||||||
|
|
||||||
def generate(self) -> EnvironmentSettings:
|
def generate(self) -> EnvironmentSettings:
|
||||||
self._gen_random_time()
|
self._gen_random_time()
|
||||||
self._gen_random_weather()
|
self._gen_random_weather()
|
||||||
|
|||||||
@ -8,7 +8,7 @@ from game.event import *
|
|||||||
|
|
||||||
UNITTYPES_FOR_EVENTS = {
|
UNITTYPES_FOR_EVENTS = {
|
||||||
FrontlineAttackEvent: [CAS, PinpointStrike],
|
FrontlineAttackEvent: [CAS, PinpointStrike],
|
||||||
FrontlinePatrolEvent: [CAP],
|
FrontlinePatrolEvent: [CAP, PinpointStrike],
|
||||||
InterceptEvent: [CAP],
|
InterceptEvent: [CAP],
|
||||||
InsurgentAttackEvent: [CAS],
|
InsurgentAttackEvent: [CAS],
|
||||||
NavalInterceptEvent: [CAS],
|
NavalInterceptEvent: [CAS],
|
||||||
@ -218,7 +218,7 @@ class EventMenu(Menu):
|
|||||||
e.player_attacking(armor=scrambled_armor, strikegroup=scrambled_aircraft, clients=scrambled_clients)
|
e.player_attacking(armor=scrambled_armor, strikegroup=scrambled_aircraft, clients=scrambled_clients)
|
||||||
elif type(self.event) is FrontlinePatrolEvent:
|
elif type(self.event) is FrontlinePatrolEvent:
|
||||||
e = self.event # type: FrontlinePatrolEvent
|
e = self.event # type: FrontlinePatrolEvent
|
||||||
e.player_attacking(interceptors=scrambled_aircraft, clients=scrambled_clients)
|
e.player_attacking(interceptors=scrambled_aircraft, clients=scrambled_clients, armor=scrambled_armor)
|
||||||
elif type(self.event) is NavalInterceptEvent:
|
elif type(self.event) is NavalInterceptEvent:
|
||||||
e = self.event # type: NavalInterceptEvent
|
e = self.event # type: NavalInterceptEvent
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user