mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
gulf & nevada maps integration; updates to commisioning/start generation units logic; mission gen updates; carriers always on map
This commit is contained in:
207
game/db.py
207
game/db.py
@@ -8,33 +8,46 @@ from dcs.task import *
|
||||
from dcs.unittype import *
|
||||
|
||||
PRICES = {
|
||||
# planes
|
||||
|
||||
Su_25T: 11,
|
||||
Su_25: 11,
|
||||
A_10A: 18,
|
||||
A_10C: 20,
|
||||
|
||||
FA_18C_hornet: 18,
|
||||
AV8BNA: 15,
|
||||
|
||||
# fighter
|
||||
C_101CC: 10,
|
||||
AJS37: 15,
|
||||
F_5E: 12,
|
||||
MiG_23MLD: 15,
|
||||
MiG_25PD: 20,
|
||||
MiG_31: 30,
|
||||
Su_27: 30,
|
||||
Su_33: 33,
|
||||
F_15C: 30,
|
||||
M_2000C: 11,
|
||||
|
||||
MiG_15bis: 8,
|
||||
MiG_21Bis: 13,
|
||||
MiG_29A: 23,
|
||||
FA_18C_hornet: 18,
|
||||
AV8BNA: 15,
|
||||
F_15C: 30,
|
||||
M_2000C: 15,
|
||||
|
||||
# bomber
|
||||
Su_25T: 15,
|
||||
Su_24M: 18,
|
||||
Su_17M4: 13,
|
||||
L_39ZA: 10,
|
||||
MiG_29G: 18,
|
||||
Su_34: 22,
|
||||
|
||||
A_10A: 18,
|
||||
A_10C: 20,
|
||||
|
||||
# special
|
||||
IL_76MD: 13,
|
||||
An_26B: 13,
|
||||
An_30M: 13,
|
||||
Yak_40: 13,
|
||||
S_3B_Tanker: 13,
|
||||
|
||||
A_50: 8,
|
||||
E_3A: 8,
|
||||
C_130: 8,
|
||||
|
||||
# armor
|
||||
|
||||
Armor.MBT_T_55: 4,
|
||||
Armor.MBT_T_80U: 8,
|
||||
Armor.MBT_T_90: 10,
|
||||
@@ -45,49 +58,142 @@ PRICES = {
|
||||
Armor.ATGM_M1134_Stryker: 6,
|
||||
Armor.APC_BTR_80: 6,
|
||||
|
||||
AirDefence.AAA_ZU_23_on_Ural_375: 4,
|
||||
AirDefence.AAA_Vulcan_M163: 5,
|
||||
AirDefence.SAM_Avenger_M1097: 10,
|
||||
AirDefence.SAM_Patriot_ICC: 15,
|
||||
|
||||
AirDefence.AAA_ZU_23_on_Ural_375: 5,
|
||||
AirDefence.SAM_SA_18_Igla_MANPADS: 8,
|
||||
AirDefence.SAM_SA_19_Tunguska_2S6: 10,
|
||||
AirDefence.SAM_SA_8_Osa_9A33: 15,
|
||||
|
||||
# ship
|
||||
CV_1143_5_Admiral_Kuznetsov: 100,
|
||||
CVN_74_John_C__Stennis: 100,
|
||||
}
|
||||
|
||||
UNIT_BY_TASK = {
|
||||
FighterSweep: [Su_27, Su_33, FA_18C_hornet, F_15C, MiG_21Bis, MiG_29A, F_A_18C, AV8BNA, ],
|
||||
CAS: [Su_25T, A_10A, A_10C, ],
|
||||
Transport: [IL_76MD, S_3B_Tanker, ],
|
||||
FighterSweep: [
|
||||
C_101CC,
|
||||
AJS37,
|
||||
F_5E,
|
||||
MiG_23MLD,
|
||||
MiG_25PD,
|
||||
MiG_31,
|
||||
Su_27,
|
||||
Su_33,
|
||||
MiG_15bis,
|
||||
MiG_21Bis,
|
||||
MiG_29A,
|
||||
FA_18C_hornet,
|
||||
AV8BNA,
|
||||
F_15C,
|
||||
M_2000C,
|
||||
],
|
||||
CAS: [
|
||||
A_10A,
|
||||
A_10C,
|
||||
Su_25T,
|
||||
Su_24M,
|
||||
Su_17M4,
|
||||
L_39ZA,
|
||||
MiG_29G,
|
||||
Su_34,
|
||||
],
|
||||
|
||||
Transport: [
|
||||
IL_76MD,
|
||||
An_26B,
|
||||
An_30M,
|
||||
Yak_40,
|
||||
|
||||
S_3B_Tanker,
|
||||
C_130,
|
||||
],
|
||||
AWACS: [E_3A, A_50, ],
|
||||
|
||||
CAP: [Armor.MBT_T_90, Armor.MBT_T_80U, Armor.MBT_T_55, Armor.MBT_M1A2_Abrams, Armor.MBT_M60A3_Patton, Armor.ATGM_M1134_Stryker, Armor.APC_BTR_80, ],
|
||||
AirDefence: [AirDefence.AAA_ZU_23_on_Ural_375, AirDefence.SAM_Avenger_M1097 ],
|
||||
AirDefence: [
|
||||
AirDefence.AAA_Vulcan_M163,
|
||||
AirDefence.SAM_Avenger_M1097,
|
||||
AirDefence.SAM_Patriot_ICC,
|
||||
|
||||
AirDefence.AAA_ZU_23_on_Ural_375,
|
||||
AirDefence.SAM_SA_18_Igla_MANPADS,
|
||||
AirDefence.SAM_SA_19_Tunguska_2S6,
|
||||
AirDefence.SAM_SA_8_Osa_9A33,
|
||||
],
|
||||
Carriage: [CVN_74_John_C__Stennis, CV_1143_5_Admiral_Kuznetsov, ],
|
||||
}
|
||||
|
||||
UNIT_BY_COUNTRY = {
|
||||
"Russia": [
|
||||
Su_25T,
|
||||
C_101CC,
|
||||
AJS37,
|
||||
F_5E,
|
||||
MiG_23MLD,
|
||||
MiG_25PD,
|
||||
MiG_31,
|
||||
Su_27,
|
||||
Su_33,
|
||||
Su_25,
|
||||
MiG_15bis,
|
||||
MiG_21Bis,
|
||||
MiG_29A,
|
||||
M_2000C,
|
||||
|
||||
A_10A,
|
||||
A_10C,
|
||||
Su_25T,
|
||||
Su_24M,
|
||||
Su_17M4,
|
||||
L_39ZA,
|
||||
MiG_29G,
|
||||
Su_34,
|
||||
|
||||
IL_76MD,
|
||||
An_26B,
|
||||
An_30M,
|
||||
Yak_40,
|
||||
A_50,
|
||||
|
||||
AirDefence.AAA_ZU_23_on_Ural_375,
|
||||
AirDefence.SAM_SA_18_Igla_MANPADS,
|
||||
AirDefence.SAM_SA_19_Tunguska_2S6,
|
||||
AirDefence.SAM_SA_8_Osa_9A33,
|
||||
|
||||
Armor.APC_BTR_80,
|
||||
Armor.MBT_T_90,
|
||||
Armor.MBT_T_80U,
|
||||
Armor.MBT_T_55,
|
||||
IL_76MD,
|
||||
CV_1143_5_Admiral_Kuznetsov],
|
||||
|
||||
"USA": [F_15C,
|
||||
A_10C,
|
||||
FA_18C_hornet,
|
||||
AV8BNA,
|
||||
E_3A,
|
||||
Armor.MBT_M1A2_Abrams,
|
||||
Armor.MBT_M60A3_Patton,
|
||||
Armor.ATGM_M1134_Stryker,
|
||||
S_3B_Tanker,
|
||||
AirDefence.SAM_Avenger_M1097,
|
||||
CVN_74_John_C__Stennis],
|
||||
"USA": [
|
||||
F_15C,
|
||||
FA_18C_hornet,
|
||||
AV8BNA,
|
||||
AJS37,
|
||||
F_5E,
|
||||
M_2000C,
|
||||
MiG_21Bis,
|
||||
MiG_15bis,
|
||||
|
||||
A_10A,
|
||||
A_10C,
|
||||
|
||||
S_3B_Tanker,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
Armor.MBT_M1A2_Abrams,
|
||||
Armor.MBT_M60A3_Patton,
|
||||
Armor.ATGM_M1134_Stryker,
|
||||
|
||||
AirDefence.AAA_Vulcan_M163,
|
||||
AirDefence.SAM_Avenger_M1097,
|
||||
AirDefence.SAM_Patriot_ICC,
|
||||
|
||||
CVN_74_John_C__Stennis,
|
||||
],
|
||||
}
|
||||
|
||||
PLANE_PAYLOAD_OVERRIDES = {
|
||||
@@ -132,3 +238,38 @@ def task_name(task) -> str:
|
||||
return "AirDefence"
|
||||
else:
|
||||
return task.name
|
||||
|
||||
|
||||
def choose_units(for_task: Task, factor: float, count: int, country: str) -> typing.Collection[UnitType]:
|
||||
suitable_unittypes = find_unittype(for_task, country)
|
||||
suitable_unittypes.sort(key=lambda x: PRICES[x])
|
||||
|
||||
idx = int(len(suitable_unittypes) * factor)
|
||||
variety = int(count + count * factor / 2)
|
||||
|
||||
index_start = min(idx, len(suitable_unittypes) - variety)
|
||||
index_end = min(idx + variety, len(suitable_unittypes))
|
||||
return suitable_unittypes[index_start:index_end]
|
||||
|
||||
|
||||
def _validate_db():
|
||||
# check unit by task uniquity
|
||||
total_set = set()
|
||||
for t, unit_collection in UNIT_BY_TASK.items():
|
||||
for unit_type in unit_collection:
|
||||
assert unit_type not in total_set, "{} is duplicate".format(unit_type)
|
||||
total_set.add(unit_type)
|
||||
|
||||
# check country allegiance
|
||||
for unit_type in total_set:
|
||||
did_find = False
|
||||
for country_units_list in UNIT_BY_COUNTRY.values():
|
||||
if unit_type in country_units_list:
|
||||
did_find = True
|
||||
assert did_find, "{} not in country list".format(unit_type)
|
||||
|
||||
# check prices
|
||||
for unit_type in total_set:
|
||||
assert unit_type in PRICES, "{} not in prices".format(unit_type)
|
||||
|
||||
_validate_db()
|
||||
@@ -26,13 +26,13 @@ class Event:
|
||||
|
||||
def generate(self):
|
||||
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||
self.operation.prepare(is_quick=False)
|
||||
self.operation.prepare(self.game.theater.terrain, is_quick=False)
|
||||
self.operation.generate()
|
||||
self.operation.mission.save("build/nextturn.miz")
|
||||
|
||||
def generate_quick(self):
|
||||
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||
self.operation.prepare(is_quick=True)
|
||||
self.operation.prepare(self.game.theater.terrain, is_quick=True)
|
||||
self.operation.generate()
|
||||
self.operation.mission.save('build/nextturn_quick.miz')
|
||||
|
||||
@@ -88,7 +88,7 @@ class GroundInterceptEvent(Event):
|
||||
else:
|
||||
pass
|
||||
|
||||
def player_attacking(self, position: Point, strikegroup: db.PlaneDict, clients: db.PlaneDict):
|
||||
def player_attacking(self, strikegroup: db.PlaneDict, clients: db.PlaneDict):
|
||||
suitable_unittypes = db.find_unittype(CAP, self.defender_name)
|
||||
random.shuffle(suitable_unittypes)
|
||||
unittypes = suitable_unittypes[:self.TARGET_VARIETY]
|
||||
@@ -100,9 +100,9 @@ class GroundInterceptEvent(Event):
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients=clients,
|
||||
defender_clients={},
|
||||
from_cp=self.from_cp)
|
||||
op.setup(position=position,
|
||||
target=self.targets,
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp)
|
||||
op.setup(target=self.targets,
|
||||
strikegroup=strikegroup)
|
||||
|
||||
self.operation = op
|
||||
|
||||
11
game/game.py
11
game/game.py
@@ -9,6 +9,7 @@ COMMISION_LIMITS_FACTORS = {
|
||||
}
|
||||
|
||||
COMMISION_AMOUNTS_SCALE = 2
|
||||
COMMISION_UNIT_VARIETY = 4
|
||||
COMMISION_AMOUNTS_FACTORS = {
|
||||
CAP: 0.6,
|
||||
CAS: 0.3,
|
||||
@@ -85,7 +86,6 @@ class Game:
|
||||
enemy_interception = True
|
||||
break
|
||||
|
||||
|
||||
if to_cp in self.theater.conflicts(False):
|
||||
continue
|
||||
|
||||
@@ -120,8 +120,10 @@ class Game:
|
||||
break
|
||||
|
||||
def _generate_globalinterceptions(self):
|
||||
global_count = len([x for x in self.theater.player_points() if x.is_global])
|
||||
for from_cp in [x for x in self.theater.player_points() if x.is_global]:
|
||||
probability = PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE * math.log(len(self.theater.player_points()) + 1, PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG)
|
||||
probability_base = max(PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE / global_count, 1)
|
||||
probability = probability_base * math.log(len(self.theater.player_points()) + 1, PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG)
|
||||
if self._roll(probability, from_cp.base.strength):
|
||||
to_cp = random.choice([x for x in self.theater.enemy_points() if x not in self.theater.conflicts()])
|
||||
self.events.append(InterceptEvent(attacker_name=self.player,
|
||||
@@ -139,8 +141,9 @@ class Game:
|
||||
awarded_points = COMMISION_AMOUNTS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_AMOUNTS_SCALE)
|
||||
points_to_spend = cp.base.append_commision_points(for_task, awarded_points)
|
||||
if points_to_spend > 0:
|
||||
unit_type = random.choice(db.find_unittype(for_task, self.enemy))
|
||||
cp.base.commision_units({unit_type: points_to_spend})
|
||||
importance_factor = (cp.importance - IMPORTANCE_LOW) / (IMPORTANCE_HIGH - IMPORTANCE_LOW)
|
||||
unittypes = db.choose_units(for_task, importance_factor, COMMISION_UNIT_VARIETY, self.enemy)
|
||||
cp.base.commision_units({random.choice(unittypes): points_to_spend})
|
||||
|
||||
@property
|
||||
def budget_reward_amount(self):
|
||||
|
||||
@@ -58,7 +58,8 @@ class Operation:
|
||||
enemy_name = self.from_cp.captured and self.defender_name or self.attacker_name
|
||||
self.extra_aagen = ExtraAAConflictGenerator(mission, conflict, self.game, player_name, enemy_name)
|
||||
|
||||
def prepare(self, is_quick: bool):
|
||||
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||
self.mission = dcs.Mission(terrain)
|
||||
self.is_quick = is_quick
|
||||
|
||||
if is_quick:
|
||||
@@ -66,14 +67,25 @@ class Operation:
|
||||
self.defenders_starting_position = None
|
||||
else:
|
||||
self.attackers_starting_position = self.from_cp.at
|
||||
self.defenders_starting_position = self.to_cp and self.to_cp.at or None
|
||||
self.defenders_starting_position = self.to_cp.at
|
||||
|
||||
def generate(self):
|
||||
self.extra_aagen.generate()
|
||||
self.envgen.generate(self.is_quick)
|
||||
if self.is_awacs_enabled:
|
||||
self.awacsgen.generate()
|
||||
|
||||
self.extra_aagen.generate()
|
||||
self.envgen.generate(self.is_quick)
|
||||
|
||||
for global_cp in self.game.theater.controlpoints:
|
||||
if not global_cp.is_global:
|
||||
continue
|
||||
|
||||
ship = self.shipgen.generate(type=db.find_unittype(Carriage, self.attacker_name)[0],
|
||||
at=global_cp.at)
|
||||
|
||||
if global_cp == self.from_cp and not self.is_quick:
|
||||
self.attackers_starting_position = ship
|
||||
|
||||
def units_of(self, country_name: str) -> typing.Collection[UnitType]:
|
||||
return []
|
||||
|
||||
@@ -103,14 +115,12 @@ class CaptureOperation(Operation):
|
||||
self.defense = defense
|
||||
self.aa = aa
|
||||
|
||||
def prepare(self, is_quick: bool):
|
||||
super(CaptureOperation, self).prepare(is_quick)
|
||||
mission = dcs.Mission()
|
||||
|
||||
self.initialize(mission=mission,
|
||||
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||
super(CaptureOperation, self).prepare(terrain, is_quick)
|
||||
self.initialize(mission=self.mission,
|
||||
conflict=self.to_cp.conflict_attack(self.from_cp,
|
||||
mission.country(self.attacker_name),
|
||||
mission.country(self.defender_name)))
|
||||
self.mission.country(self.attacker_name),
|
||||
self.mission.country(self.defender_name)))
|
||||
|
||||
def generate(self):
|
||||
self.armorgen.generate(self.attack, self.defense)
|
||||
@@ -140,18 +150,16 @@ class InterceptOperation(Operation):
|
||||
self.airdefense = airdefense
|
||||
self.interceptors = interceptors
|
||||
|
||||
def prepare(self, is_quick: bool):
|
||||
super(InterceptOperation, self).prepare(is_quick)
|
||||
mission = dcs.Mission()
|
||||
|
||||
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||
super(InterceptOperation, self).prepare(terrain, is_quick)
|
||||
conflict = Conflict.intercept_conflict(
|
||||
attacker=mission.country(self.attacker_name),
|
||||
defender=mission.country(self.defender_name),
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp
|
||||
)
|
||||
|
||||
self.initialize(mission=mission,
|
||||
self.initialize(mission=self.mission,
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
@@ -159,40 +167,30 @@ class InterceptOperation(Operation):
|
||||
self.airgen.generate_transport_escort(self.escort, clients=self.defender_clients)
|
||||
|
||||
if self.from_cp.is_global:
|
||||
starting_ship = self.shipgen.generate(type=db.find_unittype(Carriage, self.attacker_name)[0],
|
||||
at=self.from_cp.at)
|
||||
|
||||
if self.is_quick:
|
||||
starting_ship = None
|
||||
|
||||
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=starting_ship)
|
||||
super(InterceptOperation, self).generate()
|
||||
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.attackers_starting_position)
|
||||
else:
|
||||
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.attackers_starting_position)
|
||||
|
||||
super(InterceptOperation, self).generate()
|
||||
super(InterceptOperation, self).generate()
|
||||
|
||||
|
||||
class GroundInterceptOperation(Operation):
|
||||
def setup(self,
|
||||
position: Point,
|
||||
target: db.ArmorDict,
|
||||
strikegroup: db.PlaneDict):
|
||||
self.position = position
|
||||
self.strikegroup = strikegroup
|
||||
self.target = target
|
||||
|
||||
def prepare(self, is_quick: bool):
|
||||
super(GroundInterceptOperation, self).prepare(is_quick)
|
||||
mission = dcs.Mission()
|
||||
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||
super(GroundInterceptOperation, self).prepare(terrain, is_quick)
|
||||
conflict = Conflict.ground_intercept_conflict(
|
||||
attacker=mission.country(self.attacker_name),
|
||||
defender=mission.country(self.defender_name),
|
||||
position=self.position,
|
||||
heading=randint(0, 360),
|
||||
radials=ALL_RADIALS
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
heading=self.to_cp.position.heading_between_point(self.from_cp.position),
|
||||
cp=self.to_cp
|
||||
)
|
||||
|
||||
self.initialize(mission=mission,
|
||||
self.initialize(mission=self.mission,
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
|
||||
Reference in New Issue
Block a user