mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7458181e90 | ||
|
|
ec28cdc936 | ||
|
|
9dbc9a8a56 | ||
|
|
73d4a2d414 | ||
|
|
e93ad8b800 | ||
|
|
d48985ca6d |
@@ -14,7 +14,7 @@ import ui.corruptedsavemenu
|
|||||||
|
|
||||||
from game.game import Game
|
from game.game import Game
|
||||||
from theater import start_generator
|
from theater import start_generator
|
||||||
from userdata import persistency
|
from userdata import persistency, logging
|
||||||
|
|
||||||
|
|
||||||
persistency.setup(sys.argv[1])
|
persistency.setup(sys.argv[1])
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ Following tasks are present:
|
|||||||
UNIT_BY_TASK = {
|
UNIT_BY_TASK = {
|
||||||
CAP: [
|
CAP: [
|
||||||
C_101CC,
|
C_101CC,
|
||||||
AJS37,
|
|
||||||
F_5E_3,
|
F_5E_3,
|
||||||
Su_27,
|
Su_27,
|
||||||
Su_33,
|
Su_33,
|
||||||
@@ -151,6 +150,7 @@ UNIT_BY_TASK = {
|
|||||||
MiG_15bis,
|
MiG_15bis,
|
||||||
L_39ZA,
|
L_39ZA,
|
||||||
AV8BNA,
|
AV8BNA,
|
||||||
|
AJS37,
|
||||||
A_10A,
|
A_10A,
|
||||||
A_10C,
|
A_10C,
|
||||||
Su_25,
|
Su_25,
|
||||||
@@ -347,6 +347,10 @@ PLANE_PAYLOAD_OVERRIDES = {
|
|||||||
"*": "R-73*4,R-27R*2,R-27ER*6",
|
"*": "R-73*4,R-27R*2,R-27ER*6",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
AJS37: {
|
||||||
|
CAS: "CAS (75 GUN): RB-75*2, AKAN",
|
||||||
|
},
|
||||||
|
|
||||||
AV8BNA: {
|
AV8BNA: {
|
||||||
CAS: "AS 2",
|
CAS: "AS 2",
|
||||||
},
|
},
|
||||||
@@ -459,6 +463,9 @@ def unitdict_split(unit_dict: UnitsDict, count: int):
|
|||||||
|
|
||||||
|
|
||||||
def unitdict_restrict_count(unit_dict: UnitsDict, total_count: int) -> UnitsDict:
|
def unitdict_restrict_count(unit_dict: UnitsDict, total_count: int) -> UnitsDict:
|
||||||
|
if total_count == 0:
|
||||||
|
return {}
|
||||||
|
|
||||||
groups = list(unitdict_split(unit_dict, total_count))
|
groups = list(unitdict_split(unit_dict, total_count))
|
||||||
if len(groups) > 0:
|
if len(groups) > 0:
|
||||||
return groups[0]
|
return groups[0]
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class AntiAAStrikeEvent(Event):
|
|||||||
targets = None # type: db.ArmorDict
|
targets = None # type: db.ArmorDict
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Anti-AA strike from {} at {}".format(self.from_cp, self.to_cp)
|
return "Anti-AA strike"
|
||||||
|
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
total_targets = sum(self.targets.values())
|
total_targets = sum(self.targets.values())
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class BaseAttackEvent(Event):
|
|||||||
STRENGTH_RECOVERY = 0.55
|
STRENGTH_RECOVERY = 0.55
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Base attack from {} to {}".format(self.from_cp, self.to_cp)
|
return "Base attack"
|
||||||
|
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
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_attackers = sum([v for k, v in debriefing.alive_units[self.attacker_name].items() if db.unit_task(k) == PinpointStrike])
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ class FrontlineAttackEvent(Event):
|
|||||||
return "{} vehicles".format(self.to_cp.base.assemble_count())
|
return "{} vehicles".format(self.to_cp.base.assemble_count())
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Frontline attack from {} at {}".format(self.from_cp, self.to_cp)
|
return "Frontline attack"
|
||||||
|
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
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_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])
|
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 + 0.01) > self.SUCCESS_FACTOR
|
attackers_success = (float(alive_attackers) / (alive_defenders + 0.01)) > self.SUCCESS_FACTOR
|
||||||
if self.from_cp.captured:
|
if self.from_cp.captured:
|
||||||
return attackers_success
|
return attackers_success
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class FrontlinePatrolEvent(Event):
|
|||||||
return "{} aircraft + ? CAS".format(self.to_cp.base.scramble_count(self.game.settings.multiplier * self.ESCORT_FACTOR, CAP))
|
return "{} aircraft + ? CAS".format(self.to_cp.base.scramble_count(self.game.settings.multiplier * self.ESCORT_FACTOR, CAP))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Frontline CAP from {} at {}".format(self.from_cp, self.to_cp)
|
return "Frontline CAP"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
@@ -42,7 +42,7 @@ class FrontlinePatrolEvent(Event):
|
|||||||
def is_successfull(self, debriefing: Debriefing):
|
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_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])
|
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 + 0.01) >= self.SUCCESS_FACTOR
|
attackers_success = (float(alive_attackers) / (alive_defenders + 0.01)) >= self.SUCCESS_FACTOR
|
||||||
if self.from_cp.captured:
|
if self.from_cp.captured:
|
||||||
return attackers_success
|
return attackers_success
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class InfantryTransportEvent(Event):
|
|||||||
STRENGTH_INFLUENCE = 0.3
|
STRENGTH_INFLUENCE = 0.3
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Frontline transport troops to {}".format(self.to_cp)
|
return "Frontline transport troops"
|
||||||
|
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ class InsurgentAttackEvent(Event):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Destroy insurgents at {}".format(self.to_cp)
|
return "Destroy insurgents"
|
||||||
|
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
killed_units = sum([v for k, v in debriefing.destroyed_units[self.attacker_name].items() if db.unit_task(k) == PinpointStrike])
|
killed_units = sum([v for k, v in debriefing.destroyed_units[self.attacker_name].items() if db.unit_task(k) == PinpointStrike])
|
||||||
all_units = sum(self.targets.values())
|
all_units = sum(self.targets.values())
|
||||||
attackers_success = (float(killed_units) / all_units + 0.01) > self.SUCCESS_FACTOR
|
attackers_success = (float(killed_units) / (all_units + 0.01)) > self.SUCCESS_FACTOR
|
||||||
if self.from_cp.captured:
|
if self.from_cp.captured:
|
||||||
return attackers_success
|
return attackers_success
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ class InterceptEvent(Event):
|
|||||||
transport_unit = None # type: FlyingType
|
transport_unit = None # type: FlyingType
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Intercept from {} at {}".format(self.from_cp, self.to_cp)
|
return "Intercept"
|
||||||
|
|
||||||
|
def _enemy_scramble_multiplier(self) -> float:
|
||||||
|
is_global = self.from_cp.is_global or self.to_cp.is_global
|
||||||
|
return self.game.settings.multiplier * is_global and 0.5 or 1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def threat_description(self):
|
def threat_description(self):
|
||||||
return "{} aircraft".format(self.enemy_cp.base.scramble_count(self.game.settings.multiplier, CAP))
|
return "{} aircraft".format(self.enemy_cp.base.scramble_count(self._enemy_scramble_multiplier(), CAP))
|
||||||
|
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
units_destroyed = debriefing.destroyed_units[self.defender_name].get(self.transport_unit, 0)
|
units_destroyed = debriefing.destroyed_units[self.defender_name].get(self.transport_unit, 0)
|
||||||
@@ -54,7 +58,7 @@ class InterceptEvent(Event):
|
|||||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
|
|
||||||
def player_attacking(self, interceptors: db.PlaneDict, clients: db.PlaneDict):
|
def player_attacking(self, interceptors: db.PlaneDict, clients: db.PlaneDict):
|
||||||
escort = self.to_cp.base.scramble_sweep(self.game.settings.multiplier)
|
escort = self.to_cp.base.scramble_sweep(self._enemy_scramble_multiplier())
|
||||||
|
|
||||||
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
|
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
|
||||||
assert self.transport_unit is not None
|
assert self.transport_unit is not None
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class NavalInterceptEvent(Event):
|
|||||||
return max(int(factor), 1)
|
return max(int(factor), 1)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return "Naval intercept at {}".format(self.to_cp)
|
return "Naval intercept"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def threat_description(self):
|
def threat_description(self):
|
||||||
|
|||||||
13
game/game.py
13
game/game.py
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import typing
|
import typing
|
||||||
import random
|
import random
|
||||||
import math
|
import math
|
||||||
@@ -30,7 +31,7 @@ COMMISION_AMOUNTS_FACTORS = {
|
|||||||
AirDefence: 0.3,
|
AirDefence: 0.3,
|
||||||
}
|
}
|
||||||
|
|
||||||
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE = 25
|
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE = 30
|
||||||
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG = 2
|
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG = 2
|
||||||
PLAYER_BASEATTACK_THRESHOLD = 0.2
|
PLAYER_BASEATTACK_THRESHOLD = 0.2
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ AWACS_BUDGET_COST = 4
|
|||||||
# Initial budget value
|
# Initial budget value
|
||||||
PLAYER_BUDGET_INITIAL = 170
|
PLAYER_BUDGET_INITIAL = 170
|
||||||
# Base post-turn bonus value
|
# Base post-turn bonus value
|
||||||
PLAYER_BUDGET_BASE = 10
|
PLAYER_BUDGET_BASE = 17
|
||||||
# Bonus multiplier logarithm base
|
# Bonus multiplier logarithm base
|
||||||
PLAYER_BUDGET_IMPORTANCE_LOG = 2
|
PLAYER_BUDGET_IMPORTANCE_LOG = 2
|
||||||
|
|
||||||
@@ -171,7 +172,7 @@ class Game:
|
|||||||
if points_to_spend > 0:
|
if points_to_spend > 0:
|
||||||
unittypes = self.commision_unit_types(cp, for_task)
|
unittypes = self.commision_unit_types(cp, for_task)
|
||||||
d = {random.choice(unittypes): points_to_spend}
|
d = {random.choice(unittypes): points_to_spend}
|
||||||
print("Commision {}: {}".format(cp, d))
|
logging.info("Commision {}: {}".format(cp, d))
|
||||||
cp.base.commision_units(d)
|
cp.base.commision_units(d)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -204,10 +205,13 @@ class Game:
|
|||||||
def initiate_event(self, event: Event):
|
def initiate_event(self, event: Event):
|
||||||
assert event in self.events
|
assert event in self.events
|
||||||
|
|
||||||
|
logging.info("Generating {} (regular)".format(event))
|
||||||
event.generate()
|
event.generate()
|
||||||
|
logging.info("Generating {} (quick)".format(event))
|
||||||
event.generate_quick()
|
event.generate_quick()
|
||||||
|
|
||||||
def finish_event(self, event: Event, debriefing: Debriefing):
|
def finish_event(self, event: Event, debriefing: Debriefing):
|
||||||
|
logging.info("Finishing event {}".format(event))
|
||||||
event.commit(debriefing)
|
event.commit(debriefing)
|
||||||
if event.is_successfull(debriefing):
|
if event.is_successfull(debriefing):
|
||||||
self.budget += event.bonus()
|
self.budget += event.bonus()
|
||||||
@@ -215,7 +219,7 @@ class Game:
|
|||||||
if event in self.events:
|
if event in self.events:
|
||||||
self.events.remove(event)
|
self.events.remove(event)
|
||||||
else:
|
else:
|
||||||
print("finish_event: event not in the events!")
|
logging.info("finish_event: event not in the events!")
|
||||||
|
|
||||||
def is_player_attack(self, event):
|
def is_player_attack(self, event):
|
||||||
if isinstance(event, Event):
|
if isinstance(event, Event):
|
||||||
@@ -224,6 +228,7 @@ class Game:
|
|||||||
return event.name == self.player
|
return event.name == self.player
|
||||||
|
|
||||||
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint]=None):
|
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint]=None):
|
||||||
|
logging.info("Pass turn")
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
event.skip()
|
event.skip()
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,10 @@ class Operation:
|
|||||||
else:
|
else:
|
||||||
cp = self.conflict.to_cp
|
cp = self.conflict.to_cp
|
||||||
|
|
||||||
self.triggersgen.generate(cp, self.is_quick, self.trigger_radius)
|
self.triggersgen.generate(player_cp=cp,
|
||||||
|
is_quick=self.is_quick,
|
||||||
|
activation_trigger_radius=self.trigger_radius,
|
||||||
|
awacs_enabled=self.is_awacs_enabled)
|
||||||
|
|
||||||
if self.environment_settings is None:
|
if self.environment_settings is None:
|
||||||
self.environment_settings = self.envgen.generate()
|
self.environment_settings = self.envgen.generate()
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ class Settings:
|
|||||||
night_disabled = False
|
night_disabled = False
|
||||||
multiplier = 1
|
multiplier = 1
|
||||||
sams = True
|
sams = True
|
||||||
|
cold_start = False
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
from game import db
|
from game import db
|
||||||
from game.settings import Settings
|
from game.settings import Settings
|
||||||
from .conflictgen import *
|
from .conflictgen import *
|
||||||
@@ -14,7 +16,7 @@ SPREAD_DISTANCE_FACTOR = 1, 2
|
|||||||
ESCORT_ENGAGEMENT_MAX_DIST = 100000
|
ESCORT_ENGAGEMENT_MAX_DIST = 100000
|
||||||
WORKAROUND_WAYP_DIST = 1000
|
WORKAROUND_WAYP_DIST = 1000
|
||||||
|
|
||||||
WARM_START_HELI_AIRSPEED = 200
|
WARM_START_HELI_AIRSPEED = 120
|
||||||
WARM_START_HELI_ALT = 1000
|
WARM_START_HELI_ALT = 1000
|
||||||
|
|
||||||
WARM_START_ALTITUDE = 3000
|
WARM_START_ALTITUDE = 3000
|
||||||
@@ -45,6 +47,9 @@ class AircraftConflictGenerator:
|
|||||||
self.conflict = conflict
|
self.conflict = conflict
|
||||||
self.escort_targets = []
|
self.escort_targets = []
|
||||||
|
|
||||||
|
def _start_type(self) -> StartType:
|
||||||
|
return self.settings.cold_start and StartType.Cold or StartType.Warm
|
||||||
|
|
||||||
def _group_point(self, point) -> Point:
|
def _group_point(self, point) -> Point:
|
||||||
distance = randint(
|
distance = randint(
|
||||||
int(self.conflict.size * SPREAD_DISTANCE_FACTOR[0]),
|
int(self.conflict.size * SPREAD_DISTANCE_FACTOR[0]),
|
||||||
@@ -103,13 +108,14 @@ class AircraftConflictGenerator:
|
|||||||
assert count > 0
|
assert count > 0
|
||||||
assert unit is not None
|
assert unit is not None
|
||||||
|
|
||||||
|
logging.info("airgen: {} for {} at {}".format(unit_type, side.id, airport))
|
||||||
return self.m.flight_group_from_airport(
|
return self.m.flight_group_from_airport(
|
||||||
country=side,
|
country=side,
|
||||||
name=name,
|
name=name,
|
||||||
aircraft_type=unit_type,
|
aircraft_type=unit_type,
|
||||||
airport=self.m.terrain.airport_by_id(airport.id),
|
airport=self.m.terrain.airport_by_id(airport.id),
|
||||||
maintask=None,
|
maintask=None,
|
||||||
start_type=StartType.Warm,
|
start_type=self._start_type(),
|
||||||
group_size=count,
|
group_size=count,
|
||||||
parking_slots=None)
|
parking_slots=None)
|
||||||
|
|
||||||
@@ -117,7 +123,7 @@ class AircraftConflictGenerator:
|
|||||||
assert count > 0
|
assert count > 0
|
||||||
assert unit is not None
|
assert unit is not None
|
||||||
|
|
||||||
if unit_type in helicopters.helicopter_map:
|
if unit_type in helicopters.helicopter_map.values():
|
||||||
alt = WARM_START_HELI_ALT + random.randint(50, 200)
|
alt = WARM_START_HELI_ALT + random.randint(50, 200)
|
||||||
speed = WARM_START_HELI_AIRSPEED
|
speed = WARM_START_HELI_AIRSPEED
|
||||||
else:
|
else:
|
||||||
@@ -126,6 +132,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
pos = Point(at.x + random.randint(100, 200), at.y + random.randint(100, 200))
|
pos = Point(at.x + random.randint(100, 200), at.y + random.randint(100, 200))
|
||||||
|
|
||||||
|
logging.info("airgen: {} for {} at {} at {}".format(unit_type, side.id, alt, speed))
|
||||||
return self.m.flight_group(
|
return self.m.flight_group(
|
||||||
country=side,
|
country=side,
|
||||||
name=name,
|
name=name,
|
||||||
@@ -135,20 +142,21 @@ class AircraftConflictGenerator:
|
|||||||
altitude=alt,
|
altitude=alt,
|
||||||
speed=speed,
|
speed=speed,
|
||||||
maintask=None,
|
maintask=None,
|
||||||
start_type=StartType.Warm,
|
start_type=self._start_type(),
|
||||||
group_size=count)
|
group_size=count)
|
||||||
|
|
||||||
def _generate_at_carrier(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: ShipGroup) -> FlyingGroup:
|
def _generate_at_carrier(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: ShipGroup) -> FlyingGroup:
|
||||||
assert count > 0
|
assert count > 0
|
||||||
assert unit is not None
|
assert unit is not None
|
||||||
|
|
||||||
|
logging.info("airgen: {} for {} at carrier {}".format(unit_type, side.id, at))
|
||||||
return self.m.flight_group_from_unit(
|
return self.m.flight_group_from_unit(
|
||||||
country=side,
|
country=side,
|
||||||
name=name,
|
name=name,
|
||||||
aircraft_type=unit_type,
|
aircraft_type=unit_type,
|
||||||
pad_group=at,
|
pad_group=at,
|
||||||
maintask=None,
|
maintask=None,
|
||||||
start_type=StartType.Warm,
|
start_type=self._start_type(),
|
||||||
group_size=count)
|
group_size=count)
|
||||||
|
|
||||||
def _generate_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: db.StartingPosition):
|
def _generate_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: db.StartingPosition):
|
||||||
@@ -206,9 +214,11 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
group.task = Escort.name
|
group.task = Escort.name
|
||||||
|
|
||||||
|
"""
|
||||||
heading = group.position.heading_between_point(self.conflict.position)
|
heading = group.position.heading_between_point(self.conflict.position)
|
||||||
position = group.position # type: Point
|
position = group.position # type: Point
|
||||||
wayp = group.add_waypoint(position.point_from_heading(heading, WORKAROUND_WAYP_DIST), CAS_ALTITUDE, WARM_START_AIRSPEED)
|
wayp = group.add_waypoint(position.point_from_heading(heading, WORKAROUND_WAYP_DIST), CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||||
|
"""
|
||||||
self._setup_group(group, CAP, client_count)
|
self._setup_group(group, CAP, client_count)
|
||||||
|
|
||||||
for escorted_group, waypoint_index in self.escort_targets:
|
for escorted_group, waypoint_index in self.escort_targets:
|
||||||
@@ -216,7 +226,7 @@ class AircraftConflictGenerator:
|
|||||||
if not is_quick:
|
if not is_quick:
|
||||||
waypoint_index += TRIGGER_WAYPOINT_OFFSET
|
waypoint_index += TRIGGER_WAYPOINT_OFFSET
|
||||||
|
|
||||||
wayp.tasks.append(EscortTaskAction(escorted_group.id, engagement_max_dist=ESCORT_ENGAGEMENT_MAX_DIST, lastwpt=waypoint_index))
|
group.points[0].tasks.append(EscortTaskAction(escorted_group.id, engagement_max_dist=ESCORT_ENGAGEMENT_MAX_DIST, lastwpt=waypoint_index))
|
||||||
|
|
||||||
if should_orbit:
|
if should_orbit:
|
||||||
orbit_task = ControlledTask(OrbitAction(ATTACK_CIRCLE_ALT, pattern=OrbitAction.OrbitPattern.Circle))
|
orbit_task = ControlledTask(OrbitAction(ATTACK_CIRCLE_ALT, pattern=OrbitAction.OrbitPattern.Circle))
|
||||||
|
|||||||
@@ -22,10 +22,11 @@ class AirSupportConflictGenerator:
|
|||||||
self.game = game
|
self.game = game
|
||||||
|
|
||||||
def generate(self, is_awacs_enabled):
|
def generate(self, is_awacs_enabled):
|
||||||
|
player_cp = self.conflict.from_cp if self.conflict.from_cp.captured else self.conflict.to_cp
|
||||||
tanker_unit = db.find_unittype(Refueling, self.conflict.attackers_side.name)[0]
|
tanker_unit = db.find_unittype(Refueling, self.conflict.attackers_side.name)[0]
|
||||||
tanker_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position)
|
tanker_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position)
|
||||||
tanker_position = self.conflict.from_cp.position.point_from_heading(tanker_heading, TANKER_DISTANCE)
|
tanker_position = player_cp.position.point_from_heading(tanker_heading, TANKER_DISTANCE)
|
||||||
self.mission.refuel_flight(
|
tanker_group = self.mission.refuel_flight(
|
||||||
country=self.mission.country(self.game.player),
|
country=self.mission.country(self.game.player),
|
||||||
name=namegen.next_tanker_name(self.mission.country(self.game.player)),
|
name=namegen.next_tanker_name(self.mission.country(self.game.player)),
|
||||||
airport=None,
|
airport=None,
|
||||||
@@ -34,8 +35,11 @@ class AirSupportConflictGenerator:
|
|||||||
altitude=TANKER_ALT,
|
altitude=TANKER_ALT,
|
||||||
frequency=140,
|
frequency=140,
|
||||||
start_type=StartType.Warm,
|
start_type=StartType.Warm,
|
||||||
|
tacanchannel="99X",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tanker_group.points[0].tasks.append(ActivateBeaconCommand(channel=10, unit_id=tanker_group.id, aa=False))
|
||||||
|
|
||||||
if is_awacs_enabled:
|
if is_awacs_enabled:
|
||||||
awacs_unit = db.find_unittype(AWACS, self.conflict.attackers_side.name)[0]
|
awacs_unit = db.find_unittype(AWACS, self.conflict.attackers_side.name)[0]
|
||||||
self.mission.awacs_flight(
|
self.mission.awacs_flight(
|
||||||
@@ -45,6 +49,6 @@ class AirSupportConflictGenerator:
|
|||||||
altitude=AWACS_ALT,
|
altitude=AWACS_ALT,
|
||||||
airport=None,
|
airport=None,
|
||||||
position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE),
|
position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE),
|
||||||
frequency=251,
|
frequency=180,
|
||||||
start_type=StartType.Warm,
|
start_type=StartType.Warm,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
from random import randint
|
from random import randint
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
|
|
||||||
@@ -34,6 +36,7 @@ class ArmorConflictGenerator:
|
|||||||
|
|
||||||
def _generate_group(self, side: Country, unit: VehicleType, count: int, at: Point, to: Point = None):
|
def _generate_group(self, side: Country, unit: VehicleType, count: int, at: Point, to: Point = None):
|
||||||
for c in range(count):
|
for c in range(count):
|
||||||
|
logging.info("armorgen: {} for {}".format(unit, side.id))
|
||||||
group = self.m.vehicle_group(
|
group = self.m.vehicle_group(
|
||||||
side,
|
side,
|
||||||
namegen.next_unit_name(side, unit),
|
namegen.next_unit_name(side, unit),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import typing
|
import typing
|
||||||
import pdb
|
import pdb
|
||||||
import dcs
|
import dcs
|
||||||
@@ -182,7 +183,7 @@ class Conflict:
|
|||||||
|
|
||||||
initial = initial.point_from_heading(heading, 800)
|
initial = initial.point_from_heading(heading, 800)
|
||||||
|
|
||||||
print("Didn't find ground position!")
|
logging.info("Didn't find ground position!")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import typing
|
import typing
|
||||||
import random
|
import random
|
||||||
from datetime import datetime, timedelta, time
|
from datetime import datetime, timedelta, time
|
||||||
@@ -68,7 +69,7 @@ class EnviromentGenerator:
|
|||||||
weather_type = k
|
weather_type = k
|
||||||
break
|
break
|
||||||
|
|
||||||
print("generated weather {}".format(weather_type))
|
logging.info("generated weather {}".format(weather_type))
|
||||||
if weather_type == 1:
|
if weather_type == 1:
|
||||||
self.mission.weather.heavy_rain()
|
self.mission.weather.heavy_rain()
|
||||||
elif weather_type == 2:
|
elif weather_type == 2:
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
from game import db
|
from game import db
|
||||||
from .conflictgen import *
|
from .conflictgen import *
|
||||||
from .naming import *
|
from .naming import *
|
||||||
@@ -15,15 +17,20 @@ class ShipGenerator:
|
|||||||
self.conflict = conflict
|
self.conflict = conflict
|
||||||
|
|
||||||
def generate_carrier(self, type: ShipType, country: str, at: Point) -> ShipGroup:
|
def generate_carrier(self, type: ShipType, country: str, at: Point) -> ShipGroup:
|
||||||
return self.m.ship_group(
|
group = self.m.ship_group(
|
||||||
country=self.m.country(country),
|
country=self.m.country(country),
|
||||||
name=namegen.next_carrier_name(self.m.country(country)),
|
name=namegen.next_carrier_name(self.m.country(country)),
|
||||||
_type=type,
|
_type=type,
|
||||||
position=at)
|
position=at)
|
||||||
|
|
||||||
|
group.points[0].tasks.append(ActivateBeaconCommand(unit_id=group.id, channel=20, callsign="SHDW", aa=False))
|
||||||
|
group.points[0].tasks.append(ActivateICLSCommand(unit_id=group.id, channel=1))
|
||||||
|
return group
|
||||||
|
|
||||||
def generate_cargo(self, units: db.ShipDict) -> typing.Collection[ShipGroup]:
|
def generate_cargo(self, units: db.ShipDict) -> typing.Collection[ShipGroup]:
|
||||||
groups = []
|
groups = []
|
||||||
for unit_type, unit_count in units.items():
|
for unit_type, unit_count in units.items():
|
||||||
|
logging.info("shipgen: {} ({}) for {}".format(unit_type, unit_count, self.conflict.defenders_side))
|
||||||
group = self.m.ship_group(
|
group = self.m.ship_group(
|
||||||
country=self.conflict.defenders_side,
|
country=self.conflict.defenders_side,
|
||||||
name=namegen.next_unit_name(self.conflict.defenders_side, unit_type),
|
name=namegen.next_unit_name(self.conflict.defenders_side, unit_type),
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ class TriggersGenerator:
|
|||||||
for vehicle_group in country.vehicle_group:
|
for vehicle_group in country.vehicle_group:
|
||||||
vehicle_group.set_skill(Skill(skill_level))
|
vehicle_group.set_skill(Skill(skill_level))
|
||||||
|
|
||||||
def generate(self, player_cp: ControlPoint, is_quick: bool, activation_trigger_radius: int):
|
def generate(self, player_cp: ControlPoint, is_quick: bool, activation_trigger_radius: int, awacs_enabled: bool):
|
||||||
player_coalition = self.game.player == "USA" and "blue" or "red"
|
player_coalition = self.game.player == "USA" and "blue" or "red"
|
||||||
enemy_coalition = player_coalition == "blue" and "red" or "blue"
|
enemy_coalition = player_coalition == "blue" and "red" or "blue"
|
||||||
|
|
||||||
@@ -146,6 +146,19 @@ class TriggersGenerator:
|
|||||||
self._set_skill(player_coalition, enemy_coalition)
|
self._set_skill(player_coalition, enemy_coalition)
|
||||||
self._set_allegiances(player_coalition, enemy_coalition)
|
self._set_allegiances(player_coalition, enemy_coalition)
|
||||||
|
|
||||||
|
description = ""
|
||||||
|
description += "FREQUENCIES:"
|
||||||
|
description += "\nFlight: 251 MHz AM"
|
||||||
|
description += "\nTanker: 10X/140 MHz"
|
||||||
|
|
||||||
|
if awacs_enabled:
|
||||||
|
description += "\nAWACS: 180 MHz"
|
||||||
|
|
||||||
|
if self.conflict.from_cp.is_global or self.conflict.to_cp.is_global:
|
||||||
|
description += "\nCarrier: 20X/ICLS CHAN1"
|
||||||
|
|
||||||
|
self.mission.set_description_text(description)
|
||||||
|
|
||||||
if not is_quick:
|
if not is_quick:
|
||||||
# TODO: waypoint parts of this should not be post-hacked but added in airgen
|
# TODO: waypoint parts of this should not be post-hacked but added in airgen
|
||||||
self._gen_activation_trigger(activation_trigger_radius, player_cp, player_coalition, enemy_coalition)
|
self._gen_activation_trigger(activation_trigger_radius, player_cp, player_coalition, enemy_coalition)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 62 KiB |
@@ -1 +1 @@
|
|||||||
py.exe __init__.py "%UserProfile%" > logs.txt 2>&1
|
py.exe __init__.py "%UserProfile%"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import typing
|
import typing
|
||||||
import math
|
import math
|
||||||
import itertools
|
import itertools
|
||||||
@@ -53,7 +54,7 @@ class Base:
|
|||||||
|
|
||||||
def _find_best_unit(self, dict, for_type: Task, count: int) -> typing.Dict:
|
def _find_best_unit(self, dict, for_type: Task, count: int) -> typing.Dict:
|
||||||
if count <= 0:
|
if count <= 0:
|
||||||
print("{}: no units for {}".format(self, for_type))
|
logging.info("{}: no units for {}".format(self, for_type))
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
sorted_units = [key for key in dict.keys() if key in db.UNIT_BY_TASK[for_type]]
|
sorted_units = [key for key in dict.keys() if key in db.UNIT_BY_TASK[for_type]]
|
||||||
@@ -74,7 +75,7 @@ class Base:
|
|||||||
assert result_unit_count > 0
|
assert result_unit_count > 0
|
||||||
result[unit_type] = result.get(unit_type, 0) + result_unit_count
|
result[unit_type] = result.get(unit_type, 0) + result_unit_count
|
||||||
|
|
||||||
print("{} for {} ({}): {}".format(self, for_type, count, result))
|
logging.info("{} for {} ({}): {}".format(self, for_type, count, result))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _find_best_planes(self, for_type: Task, count: int) -> typing.Dict[PlaneType, int]:
|
def _find_best_planes(self, for_type: Task, count: int) -> typing.Dict[PlaneType, int]:
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ from .landmap import load_poly
|
|||||||
class PersianGulfTheater(ConflictTheater):
|
class PersianGulfTheater(ConflictTheater):
|
||||||
terrain = dcs.terrain.PersianGulf()
|
terrain = dcs.terrain.PersianGulf()
|
||||||
overview_image = "persiangulf.gif"
|
overview_image = "persiangulf.gif"
|
||||||
reference_points = {(persiangulf.Sir_Abu_Nuayr.position.x, persiangulf.Sir_Abu_Nuayr.position.y): (351, 115),
|
reference_points = {(persiangulf.Sir_Abu_Nuayr.position.x, persiangulf.Sir_Abu_Nuayr.position.y): (321, 145),
|
||||||
(persiangulf.Sirri_Island.position.x, persiangulf.Sirri_Island.position.y): (389, 22), }
|
(persiangulf.Sirri_Island.position.x, persiangulf.Sirri_Island.position.y): (347, 82), }
|
||||||
landmap_poly = load_poly("resources\\gulflandmap.p")
|
landmap_poly = load_poly("resources\\gulflandmap.p")
|
||||||
daytime_map = {
|
daytime_map = {
|
||||||
"dawn": (6, 8),
|
"dawn": (6, 8),
|
||||||
@@ -35,11 +35,13 @@ class PersianGulfTheater(ConflictTheater):
|
|||||||
tunb_kochak = ControlPoint.from_airport(persiangulf.Tunb_Kochak, [135, 180], SIZE_SMALL, 1.2, has_frontline=False)
|
tunb_kochak = ControlPoint.from_airport(persiangulf.Tunb_Kochak, [135, 180], SIZE_SMALL, 1.2, has_frontline=False)
|
||||||
|
|
||||||
bandar_lengeh = ControlPoint.from_airport(persiangulf.Bandar_Lengeh, [270, 315, 0, 45], SIZE_SMALL, 1.1)
|
bandar_lengeh = ControlPoint.from_airport(persiangulf.Bandar_Lengeh, [270, 315, 0, 45], SIZE_SMALL, 1.1)
|
||||||
qeshm = ControlPoint.from_airport(persiangulf.Qeshm_Island, [270, 315, 0, 45, 90, 135, 180], SIZE_SMALL, 1.1, has_frontline=False)
|
qeshm = ControlPoint.from_airport(persiangulf.Qeshm_Island, [270, 315, 0, 45, 90, 135, 180], SIZE_SMALL, 1.3, has_frontline=False)
|
||||||
|
|
||||||
havadarya = ControlPoint.from_airport(persiangulf.Havadarya, COAST_DL_W, SIZE_REGULAR, IMPORTANCE_LOW)
|
havadarya = ControlPoint.from_airport(persiangulf.Havadarya, COAST_DL_W, SIZE_REGULAR, 1.2)
|
||||||
bandar_abbas = ControlPoint.from_airport(persiangulf.Bandar_Abbas_Intl, LAND, SIZE_BIG, 1.3)
|
bandar_abbas = ControlPoint.from_airport(persiangulf.Bandar_Abbas_Intl, LAND, SIZE_BIG, 1.3)
|
||||||
lar = ControlPoint.from_airport(persiangulf.Lar_Airbase, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
|
lar = ControlPoint.from_airport(persiangulf.Lar_Airbase, LAND, SIZE_REGULAR, 1.1)
|
||||||
|
shiraz = ControlPoint.from_airport(persiangulf.Shiraz_International_Airport, LAND, SIZE_BIG, IMPORTANCE_LOW)
|
||||||
|
kerman = ControlPoint.from_airport(persiangulf.Kerman_Airport, LAND, SIZE_BIG, IMPORTANCE_LOW)
|
||||||
|
|
||||||
west_carrier = ControlPoint.carrier("East carrier", Point(-100531.972946, 60939.275818))
|
west_carrier = ControlPoint.carrier("East carrier", Point(-100531.972946, 60939.275818))
|
||||||
|
|
||||||
@@ -64,12 +66,14 @@ class PersianGulfTheater(ConflictTheater):
|
|||||||
self.add_controlpoint(self.qeshm, connected_to=[self.bandar_lengeh, self.havadarya, self.tunb_island, self.lar])
|
self.add_controlpoint(self.qeshm, connected_to=[self.bandar_lengeh, self.havadarya, self.tunb_island, self.lar])
|
||||||
self.add_controlpoint(self.havadarya, connected_to=[self.lar, self.qeshm, self.bandar_abbas])
|
self.add_controlpoint(self.havadarya, connected_to=[self.lar, self.qeshm, self.bandar_abbas])
|
||||||
self.add_controlpoint(self.bandar_abbas, connected_to=[self.havadarya])
|
self.add_controlpoint(self.bandar_abbas, connected_to=[self.havadarya])
|
||||||
self.add_controlpoint(self.lar, connected_to=[self.bandar_lengeh, self.qeshm, self.havadarya])
|
self.add_controlpoint(self.lar, connected_to=[self.bandar_lengeh, self.qeshm, self.havadarya, self.shiraz, self.kerman])
|
||||||
|
self.add_controlpoint(self.shiraz, connected_to=[self.lar, self.kerman])
|
||||||
|
self.add_controlpoint(self.kerman, connected_to=[self.lar, self.shiraz])
|
||||||
|
|
||||||
self.add_controlpoint(self.west_carrier)
|
self.add_controlpoint(self.west_carrier)
|
||||||
|
|
||||||
self.west_carrier.captured = True
|
self.west_carrier.captured = True
|
||||||
self.lar.captured = True
|
self.kerman.captured = True
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Mid game:
|
Mid game:
|
||||||
|
|||||||
@@ -35,5 +35,5 @@ def generate_initial(theater: ConflictTheater, enemy: str, sams: bool, multiplie
|
|||||||
count = max(COUNT_BY_TASK[task] * multiplier * (1+count_log), 1)
|
count = max(COUNT_BY_TASK[task] * multiplier * (1+count_log), 1)
|
||||||
count_per_type = max(int(float(count) / len(unittypes)), 1)
|
count_per_type = max(int(float(count) / len(unittypes)), 1)
|
||||||
for unit_type in unittypes:
|
for unit_type in unittypes:
|
||||||
print("{} - {} {}".format(cp.name, db.unit_type_name(unit_type), count_per_type))
|
logging.info("{} - {} {}".format(cp.name, db.unit_type_name(unit_type), count_per_type))
|
||||||
cp.base.commision_units({unit_type: count_per_type})
|
cp.base.commision_units({unit_type: count_per_type})
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ class ConfigurationMenu(Menu):
|
|||||||
self.night_var = BooleanVar()
|
self.night_var = BooleanVar()
|
||||||
self.night_var.set(self.game.settings.night_disabled)
|
self.night_var.set(self.game.settings.night_disabled)
|
||||||
|
|
||||||
|
self.cold_start_var = BooleanVar()
|
||||||
|
self.cold_start_var.set(self.game.settings.cold_start)
|
||||||
|
|
||||||
def dismiss(self):
|
def dismiss(self):
|
||||||
self.game.settings.player_skill = self.player_skill_var.get()
|
self.game.settings.player_skill = self.player_skill_var.get()
|
||||||
self.game.settings.enemy_skill = self.enemy_skill_var.get()
|
self.game.settings.enemy_skill = self.enemy_skill_var.get()
|
||||||
self.game.settings.only_player_takeoff = self.takeoff_var.get()
|
self.game.settings.only_player_takeoff = self.takeoff_var.get()
|
||||||
self.game.settings.night_disabled = self.night_var.get()
|
self.game.settings.night_disabled = self.night_var.get()
|
||||||
|
self.game.settings.cold_start = self.cold_start_var.get()
|
||||||
super(ConfigurationMenu, self).dismiss()
|
super(ConfigurationMenu, self).dismiss()
|
||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
@@ -36,11 +40,16 @@ class ConfigurationMenu(Menu):
|
|||||||
OptionMenu(self.frame, self.player_skill_var, "Average", "Good", "High", "Excellent").grid(row=0, column=1)
|
OptionMenu(self.frame, self.player_skill_var, "Average", "Good", "High", "Excellent").grid(row=0, column=1)
|
||||||
OptionMenu(self.frame, self.enemy_skill_var, "Average", "Good", "High", "Excellent").grid(row=1, column=1)
|
OptionMenu(self.frame, self.enemy_skill_var, "Average", "Good", "High", "Excellent").grid(row=1, column=1)
|
||||||
|
|
||||||
Checkbutton(self.frame, text="Takeoff only for player group", variable=self.takeoff_var).grid(row=2, column=0, columnspan=2)
|
Label(self.frame, text="Aircraft cold start").grid(row=2, column=0)
|
||||||
Checkbutton(self.frame, text="Disable night missions", variable=self.night_var).grid(row=3, column=0, columnspan=2)
|
Label(self.frame, text="Takeoff only for player group").grid(row=3, column=0)
|
||||||
|
Label(self.frame, text="Disable night missions").grid(row=4, column=0)
|
||||||
|
|
||||||
Button(self.frame, text="Back", command=self.dismiss).grid(row=4, column=0, columnspan=1)
|
Checkbutton(self.frame, variable=self.cold_start_var).grid(row=2, column=1)
|
||||||
Button(self.frame, text="Cheat +200m", command=self.cheat_money).grid(row=5, column=0)
|
Checkbutton(self.frame, variable=self.takeoff_var).grid(row=3, column=1)
|
||||||
|
Checkbutton(self.frame, variable=self.night_var).grid(row=4, column=1)
|
||||||
|
|
||||||
|
Button(self.frame, text="Back", command=self.dismiss).grid(row=5, column=0, columnspan=1)
|
||||||
|
Button(self.frame, text="Cheat +200m", command=self.cheat_money).grid(row=6, column=1)
|
||||||
|
|
||||||
def cheat_money(self):
|
def cheat_money(self):
|
||||||
self.game.budget += 200
|
self.game.budget += 200
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from game.event import *
|
|||||||
UNITTYPES_FOR_EVENTS = {
|
UNITTYPES_FOR_EVENTS = {
|
||||||
FrontlineAttackEvent: [CAS, PinpointStrike],
|
FrontlineAttackEvent: [CAS, PinpointStrike],
|
||||||
FrontlinePatrolEvent: [CAP, PinpointStrike],
|
FrontlinePatrolEvent: [CAP, PinpointStrike],
|
||||||
|
BaseAttackEvent: [CAP, CAS, PinpointStrike],
|
||||||
InterceptEvent: [CAP],
|
InterceptEvent: [CAP],
|
||||||
InsurgentAttackEvent: [CAS],
|
InsurgentAttackEvent: [CAS],
|
||||||
NavalInterceptEvent: [CAS],
|
NavalInterceptEvent: [CAS],
|
||||||
|
|||||||
@@ -22,21 +22,20 @@ class EventResultsMenu(Menu):
|
|||||||
self.window.clear_right_pane()
|
self.window.clear_right_pane()
|
||||||
|
|
||||||
if not self.finished:
|
if not self.finished:
|
||||||
"""
|
|
||||||
For debugging purposes
|
|
||||||
|
|
||||||
Button(self.frame, text="no losses, succ", command=self.simulate_result(0, 1)).grid()
|
|
||||||
Button(self.frame, text="no losses, fail", command=self.simulate_result(0, 1)).grid(row=1, column=1)
|
|
||||||
|
|
||||||
Button(self.frame, text="half losses, succ", command=self.simulate_result(0.5, 0.5)).grid(row=2, )
|
|
||||||
Button(self.frame, text="half losses, fail", command=self.simulate_result(0.5, 0.5)).grid(row=2, column=1)
|
|
||||||
|
|
||||||
Button(self.frame, text="full losses, succ", command=self.simulate_result(1, 0)).grid(row=3, )
|
|
||||||
Button(self.frame, text="full losses, fail", command=self.simulate_result(1, 0)).grid(row=3, column=1)
|
|
||||||
"""
|
|
||||||
|
|
||||||
Label(self.frame, text="Play the mission and save debriefing to").grid(row=0, column=0)
|
Label(self.frame, text="Play the mission and save debriefing to").grid(row=0, column=0)
|
||||||
Label(self.frame, text=debriefing_directory_location()).grid(row=1, column=0)
|
Label(self.frame, text=debriefing_directory_location()).grid(row=1, column=0)
|
||||||
|
|
||||||
|
"""
|
||||||
|
For debugging purposes
|
||||||
|
"""
|
||||||
|
|
||||||
|
row = 3
|
||||||
|
Separator(self.frame, orient=HORIZONTAL).grid(row=row, sticky=EW); row += 1
|
||||||
|
Label(self.frame, text="Cheat operation results: ").grid(row=row); row += 1
|
||||||
|
Button(self.frame, text="full enemy losses", command=self.simulate_result(0, 1)).grid(row=row); row += 1
|
||||||
|
Button(self.frame, text="full player losses", command=self.simulate_result(1, 0)).grid(row=row); row += 1
|
||||||
|
Button(self.frame, text="some enemy losses", command=self.simulate_result(0, 0.8)).grid(row=row); row += 1
|
||||||
|
Button(self.frame, text="some player losses", command=self.simulate_result(0.8, 0)).grid(row=row); row += 1
|
||||||
else:
|
else:
|
||||||
row = 0
|
row = 0
|
||||||
if self.event.is_successfull(self.debriefing):
|
if self.event.is_successfull(self.debriefing):
|
||||||
@@ -81,27 +80,53 @@ class EventResultsMenu(Menu):
|
|||||||
def action():
|
def action():
|
||||||
debriefing = Debriefing({})
|
debriefing = Debriefing({})
|
||||||
|
|
||||||
def count_planes(groups: typing.List[FlyingGroup], mult: float) -> typing.Dict[UnitType, int]:
|
def count(country: Country) -> typing.Dict[UnitType, int]:
|
||||||
result = {}
|
result = {}
|
||||||
for group in groups:
|
for g in country.plane_group + country.vehicle_group + country.helicopter_group + country.ship_group:
|
||||||
|
group = g # type: Group
|
||||||
for unit in group.units:
|
for unit in group.units:
|
||||||
result[unit.unit_type] = result.get(unit.unit_type, 0) + 1 * mult
|
unit_type = None
|
||||||
|
if isinstance(unit, Vehicle):
|
||||||
|
unit_type = vehicle_map[unit.type]
|
||||||
|
elif isinstance(unit, Ship):
|
||||||
|
unit_type = ship_map[unit.type]
|
||||||
|
else:
|
||||||
|
unit_type = unit.unit_type
|
||||||
|
|
||||||
return {x: math.ceil(y) for x, y in result.items() if y >= 1}
|
if unit_type in db.EXTRA_AA.values():
|
||||||
|
continue
|
||||||
|
|
||||||
player_planes = self.event.operation.mission.country(self.game.player).plane_group
|
result[unit_type] = result.get(unit_type, 0) + 1
|
||||||
enemy_planes = self.event.operation.mission.country(self.game.enemy).plane_group
|
|
||||||
|
|
||||||
self.player_losses = count_planes(player_planes, player_factor)
|
return result
|
||||||
self.enemy_losses = count_planes(enemy_planes, enemy_factor)
|
|
||||||
|
player = self.event.operation.mission.country(self.game.player)
|
||||||
|
enemy = self.event.operation.mission.country(self.game.enemy)
|
||||||
|
|
||||||
|
alive_player_units = count(player)
|
||||||
|
alive_enemy_units = count(enemy)
|
||||||
|
|
||||||
|
destroyed_player_units = db.unitdict_restrict_count(alive_player_units, math.ceil(sum(alive_player_units.values()) * player_factor))
|
||||||
|
destroyed_enemy_units = db.unitdict_restrict_count(alive_enemy_units, math.ceil(sum(alive_enemy_units.values()) * enemy_factor))
|
||||||
|
|
||||||
|
alive_player_units = {k: v - destroyed_player_units.get(k, 0) for k, v in alive_player_units.items()}
|
||||||
|
alive_enemy_units = {k: v - destroyed_enemy_units.get(k, 0) for k, v in alive_enemy_units.items()}
|
||||||
|
|
||||||
|
debriefing.alive_units = {
|
||||||
|
enemy.name: alive_enemy_units,
|
||||||
|
player.name: alive_player_units,
|
||||||
|
}
|
||||||
|
|
||||||
debriefing.destroyed_units = {
|
debriefing.destroyed_units = {
|
||||||
self.game.player: self.player_losses,
|
player.name: destroyed_player_units,
|
||||||
self.game.enemy: self.enemy_losses,
|
enemy.name: destroyed_enemy_units,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finished = True
|
self.finished = True
|
||||||
self.debriefing = debriefing
|
self.debriefing = debriefing
|
||||||
|
self.player_losses = debriefing.destroyed_units.get(self.game.player, {})
|
||||||
|
self.enemy_losses = debriefing.destroyed_units.get(self.game.enemy, {})
|
||||||
|
|
||||||
self.game.finish_event(self.event, debriefing)
|
self.game.finish_event(self.event, debriefing)
|
||||||
self.display()
|
self.display()
|
||||||
self.game.pass_turn()
|
self.game.pass_turn()
|
||||||
|
|||||||
@@ -34,13 +34,18 @@ class MainMenu(Menu):
|
|||||||
|
|
||||||
def event_button(event):
|
def event_button(event):
|
||||||
nonlocal row
|
nonlocal row
|
||||||
Message(self.frame, text="{}{}".format(
|
Message(self.frame, text="{}{} at {}".format(
|
||||||
event.defender_name == self.game.player and "Enemy attacking: " or "",
|
event.defender_name == self.game.player and "Enemy attacking: " or "",
|
||||||
event
|
event,
|
||||||
|
event.to_cp,
|
||||||
), aspect=1600).grid(column=0, row=row, sticky=NW)
|
), aspect=1600).grid(column=0, row=row, sticky=NW)
|
||||||
Button(self.frame, text=">", command=self.start_event(event)).grid(column=0, row=row, sticky=NE+S)
|
Button(self.frame, text=">", command=self.start_event(event)).grid(column=0, row=row, sticky=NE+S); row += 1
|
||||||
row += 1
|
|
||||||
Separator(self.frame, orient='horizontal').grid(row=row, sticky=EW); row += 1
|
def destination_header(text, separator=True):
|
||||||
|
nonlocal row
|
||||||
|
if separator:
|
||||||
|
Separator(self.frame, orient=HORIZONTAL).grid(row=row, sticky=EW); row += 1
|
||||||
|
Label(self.frame, text=text).grid(column=0, row=row, sticky=N); row += 1
|
||||||
|
|
||||||
Button(self.frame, text="Configuration", command=self.configuration_menu).grid(column=0, row=0, sticky=NE)
|
Button(self.frame, text="Configuration", command=self.configuration_menu).grid(column=0, row=0, sticky=NE)
|
||||||
Button(self.frame, text="Pass turn", command=self.pass_turn).grid(column=0, row=0, sticky=NW)
|
Button(self.frame, text="Pass turn", command=self.pass_turn).grid(column=0, row=0, sticky=NW)
|
||||||
@@ -48,9 +53,20 @@ class MainMenu(Menu):
|
|||||||
Separator(self.frame, orient='horizontal').grid(row=row, sticky=EW); row += 1
|
Separator(self.frame, orient='horizontal').grid(row=row, sticky=EW); row += 1
|
||||||
|
|
||||||
events = self.game.events
|
events = self.game.events
|
||||||
|
events.sort(key=lambda x: x.from_cp.name)
|
||||||
events.sort(key=lambda x: x.informational and 2 or (self.game.is_player_attack(x) and 1 or 0))
|
events.sort(key=lambda x: x.informational and 2 or (self.game.is_player_attack(x) and 1 or 0))
|
||||||
|
|
||||||
|
destination = None
|
||||||
for event in events:
|
for event in events:
|
||||||
|
if not event.informational:
|
||||||
|
if self.game.is_player_attack(event):
|
||||||
|
new_destination = event.from_cp.name
|
||||||
|
else:
|
||||||
|
new_destination = "Enemy attack"
|
||||||
|
if destination != new_destination:
|
||||||
|
destination_header(new_destination, destination is not None)
|
||||||
|
destination = new_destination
|
||||||
|
|
||||||
if event.informational:
|
if event.informational:
|
||||||
label(str(event))
|
label(str(event))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -28,20 +28,24 @@ class OverviewCanvas:
|
|||||||
point_b = list(self.game.theater.reference_points.keys())[1]
|
point_b = list(self.game.theater.reference_points.keys())[1]
|
||||||
point_b_img = self.game.theater.reference_points[point_b]
|
point_b_img = self.game.theater.reference_points[point_b]
|
||||||
|
|
||||||
x_dist = point_a_img[0] - point_b_img[0]
|
Y_dist = point_a_img[0] - point_b_img[0]
|
||||||
lon_dist = point_a[1] - point_b[1]
|
lon_dist = point_a[1] - point_b[1]
|
||||||
|
|
||||||
y_dist = point_a_img[1] - point_b_img[1]
|
X_dist = point_a_img[1] - point_b_img[1]
|
||||||
lat_dist = point_b[0] - point_a[0]
|
lat_dist = point_b[0] - point_a[0]
|
||||||
|
|
||||||
x_scale = float(x_dist) / float(lon_dist)
|
Y_scale = float(Y_dist) / float(lon_dist)
|
||||||
y_scale = float(y_dist) / float(lat_dist)
|
X_scale = float(X_dist) / float(lat_dist)
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
x_offset = p.x - point_a[0]
|
Y_offset = p.x - point_a[0]
|
||||||
y_offset = p.y - point_a[1]
|
X_offset = p.y - point_a[1]
|
||||||
|
|
||||||
return point_b_img[1] + y_offset * y_scale, point_a_img[0] - x_offset * x_scale
|
X = point_b_img[1] + X_offset * X_scale
|
||||||
|
Y = point_a_img[0] - Y_offset * Y_scale
|
||||||
|
|
||||||
|
treshold = 30
|
||||||
|
return X > treshold and X or treshold, Y > treshold and Y or treshold
|
||||||
|
|
||||||
def create_cp_title(self, coords, cp: ControlPoint):
|
def create_cp_title(self, coords, cp: ControlPoint):
|
||||||
title = cp.name
|
title = cp.name
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import typing
|
import typing
|
||||||
import re
|
import re
|
||||||
import threading
|
import threading
|
||||||
@@ -83,17 +84,16 @@ class Debriefing:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
components = event["initiator"].split("|")
|
components = event["initiator"].split("|")
|
||||||
print(components)
|
|
||||||
category, country_id, group_id, unit_type = components[0], int(components[1]), int(components[2]), db.unit_type_from_name(components[3])
|
category, country_id, group_id, unit_type = components[0], int(components[1]), int(components[2]), db.unit_type_from_name(components[3])
|
||||||
if unit_type is None:
|
if unit_type is None:
|
||||||
print("Skipped due to no unit type")
|
logging.info("Skipped due to no unit type")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if category != "unit":
|
if category != "unit":
|
||||||
print("Skipped due to category")
|
logging.info("Skipped due to category")
|
||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logging.error(e)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if country_id not in dead_units:
|
if country_id not in dead_units:
|
||||||
|
|||||||
29
userdata/logging.py
Normal file
29
userdata/logging.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from io import StringIO
|
||||||
|
from tkinter import *
|
||||||
|
from tkinter.scrolledtext import *
|
||||||
|
|
||||||
|
log_stream = StringIO()
|
||||||
|
logging.basicConfig(stream=log_stream, level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
|
def _error_prompt():
|
||||||
|
tk = Tk()
|
||||||
|
Label(tk, text="Oops, something went wrong.").grid(row=0)
|
||||||
|
Label(tk, text="Please send following text to the developer:").grid(row=1)
|
||||||
|
|
||||||
|
text = ScrolledText(tk)
|
||||||
|
text.insert("0.0", log_stream.getvalue())
|
||||||
|
text.grid(row=2, sticky=NSEW)
|
||||||
|
tk.focus()
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_exception(self, exception: BaseException, *args):
|
||||||
|
logging.exception(exception)
|
||||||
|
_error_prompt()
|
||||||
|
|
||||||
|
|
||||||
|
Tk.report_callback_exception = _handle_exception
|
||||||
|
logging.info("DCS Libration 1.3 RC2")
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import typing
|
import typing
|
||||||
import pickle
|
import pickle
|
||||||
import os
|
import os
|
||||||
@@ -56,5 +57,5 @@ def save_game(game) -> bool:
|
|||||||
shutil.copy(_temporary_save_file(), _save_file())
|
shutil.copy(_temporary_save_file(), _save_file())
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logging.error(e)
|
||||||
return False
|
return False
|
||||||
|
|||||||
Reference in New Issue
Block a user