mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
number of minor bugfixes and UI improvements
This commit is contained in:
parent
07b35f8ee1
commit
f21bd10f09
@ -343,6 +343,10 @@ PLANE_PAYLOAD_OVERRIDES = {
|
|||||||
CAP: "AIM-120*4,AIM-9*2,AIM-7*2,Fuel",
|
CAP: "AIM-120*4,AIM-9*2,AIM-7*2,Fuel",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Su_25T: {
|
||||||
|
CAS: "APU-8 Vikhr-M*2,Kh-25ML,R-73*2,SPPU-22*2,Mercury LLTV Pod,MPS-410",
|
||||||
|
},
|
||||||
|
|
||||||
Su_33: {
|
Su_33: {
|
||||||
CAP: "R-73*4,R-27R*2,R-27ER*6",
|
CAP: "R-73*4,R-27R*2,R-27ER*6",
|
||||||
},
|
},
|
||||||
|
|||||||
@ -8,7 +8,7 @@ class FrontlineAttackEvent(Event):
|
|||||||
TARGET_AMOUNT_FACTOR = 0.5
|
TARGET_AMOUNT_FACTOR = 0.5
|
||||||
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.3
|
||||||
SUCCESS_FACTOR = 1.5
|
SUCCESS_FACTOR = 1.5
|
||||||
|
|
||||||
defenders = None # type: db.ArmorDict
|
defenders = None # type: db.ArmorDict
|
||||||
|
|||||||
@ -5,7 +5,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.3
|
||||||
SUCCESS_FACTOR = 0.8
|
SUCCESS_FACTOR = 0.8
|
||||||
|
|
||||||
cas = None # type: db.PlaneDict
|
cas = None # type: db.PlaneDict
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from .event import *
|
|||||||
|
|
||||||
class StrikeEvent(Event):
|
class StrikeEvent(Event):
|
||||||
STRENGTH_INFLUENCE = 0.0
|
STRENGTH_INFLUENCE = 0.0
|
||||||
SINGLE_OBJECT_STRENGTH_INFLUENCE = 0.03
|
SINGLE_OBJECT_STRENGTH_INFLUENCE = 0.05
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Strike"
|
return "Strike"
|
||||||
@ -39,6 +39,7 @@ class StrikeEvent(Event):
|
|||||||
|
|
||||||
def commit(self, debriefing: Debriefing):
|
def commit(self, debriefing: Debriefing):
|
||||||
super(StrikeEvent, self).commit(debriefing)
|
super(StrikeEvent, self).commit(debriefing)
|
||||||
|
|
||||||
self.to_cp.base.affect_strength(-self.SINGLE_OBJECT_STRENGTH_INFLUENCE * len(debriefing.destroyed_objects))
|
self.to_cp.base.affect_strength(-self.SINGLE_OBJECT_STRENGTH_INFLUENCE * len(debriefing.destroyed_objects))
|
||||||
|
|
||||||
def player_attacking(self, flights: db.TaskForceDict):
|
def player_attacking(self, flights: db.TaskForceDict):
|
||||||
|
|||||||
44
game/game.py
44
game/game.py
@ -25,7 +25,7 @@ COMMISION_LIMITS_FACTORS = {
|
|||||||
|
|
||||||
COMMISION_AMOUNTS_SCALE = 1.5
|
COMMISION_AMOUNTS_SCALE = 1.5
|
||||||
COMMISION_AMOUNTS_FACTORS = {
|
COMMISION_AMOUNTS_FACTORS = {
|
||||||
PinpointStrike: 6,
|
PinpointStrike: 3,
|
||||||
CAS: 1,
|
CAS: 1,
|
||||||
CAP: 2,
|
CAP: 2,
|
||||||
AirDefence: 0.3,
|
AirDefence: 0.3,
|
||||||
@ -33,30 +33,39 @@ COMMISION_AMOUNTS_FACTORS = {
|
|||||||
|
|
||||||
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE = 30
|
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.4
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Various events probabilities. First key is player probabilty, second is enemy probability.
|
Various events probabilities. First key is player probabilty, second is enemy probability.
|
||||||
For the enemy events, only 1 event of each type could be generated for a turn.
|
For the enemy events, only 1 event of each type could be generated for a turn.
|
||||||
|
|
||||||
Events:
|
Events:
|
||||||
* CaptureEvent - capture base
|
* BaseAttackEvent - capture base
|
||||||
* InterceptEvent - air intercept
|
* InterceptEvent - air intercept
|
||||||
* FrontlineAttack - frontline attack
|
* FrontlineAttackEvent - frontline attack
|
||||||
* GroundAttackEvent - destroy insurgents
|
* FrontlineCAPEvent - frontline attack
|
||||||
* NavalInterceptEvent - naval intercept
|
* NavalInterceptEvent - naval intercept
|
||||||
* AntiAAStrikeEvent - anti-AA strike
|
* StrikeEvent - strike event
|
||||||
* InfantryTransportEvent - helicopter infantry transport
|
* InfantryTransportEvent - helicopter infantry transport
|
||||||
"""
|
"""
|
||||||
EVENT_PROBABILITIES = {
|
EVENT_PROBABILITIES = {
|
||||||
BaseAttackEvent: [100, 15],
|
# events always present; only for the player
|
||||||
FrontlineAttackEvent: [100, 0],
|
FrontlineAttackEvent: [100, 0],
|
||||||
FrontlinePatrolEvent: [100, 0],
|
FrontlinePatrolEvent: [100, 0],
|
||||||
StrikeEvent: [100, 0],
|
StrikeEvent: [100, 0],
|
||||||
InterceptEvent: [25, 15],
|
|
||||||
InsurgentAttackEvent: [0, 10],
|
# events randomly present; only for the player
|
||||||
NavalInterceptEvent: [25, 15],
|
|
||||||
InfantryTransportEvent: [25, 0],
|
InfantryTransportEvent: [25, 0],
|
||||||
|
|
||||||
|
# events conditionally present; for both enemy and player
|
||||||
|
BaseAttackEvent: [100, 15],
|
||||||
|
|
||||||
|
# events randomly present; for both enemy and player
|
||||||
|
InterceptEvent: [25, 15],
|
||||||
|
NavalInterceptEvent: [25, 15],
|
||||||
|
|
||||||
|
# events randomly present; only for the enemy
|
||||||
|
InsurgentAttackEvent: [0, 10],
|
||||||
}
|
}
|
||||||
|
|
||||||
# amount of strength player bases recover for the turn
|
# amount of strength player bases recover for the turn
|
||||||
@ -117,47 +126,62 @@ class Game:
|
|||||||
|
|
||||||
for event_class, (player_probability, enemy_probability) in EVENT_PROBABILITIES.items():
|
for event_class, (player_probability, enemy_probability) in EVENT_PROBABILITIES.items():
|
||||||
if event_class in [FrontlineAttackEvent, FrontlinePatrolEvent, InfantryTransportEvent]:
|
if event_class in [FrontlineAttackEvent, FrontlinePatrolEvent, InfantryTransportEvent]:
|
||||||
|
# skip events requiring frontline
|
||||||
if not Conflict.has_frontline_between(player_cp, enemy_cp):
|
if not Conflict.has_frontline_between(player_cp, enemy_cp):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if player_cp.is_global:
|
if player_cp.is_global:
|
||||||
|
# skip events requiring ground CP
|
||||||
if event_class not in [InterceptEvent, StrikeEvent, NavalInterceptEvent]:
|
if event_class not in [InterceptEvent, StrikeEvent, NavalInterceptEvent]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if player_probability == 100 or self._roll(player_probability, player_cp.base.strength):
|
if player_probability == 100 or self._roll(player_probability, player_cp.base.strength):
|
||||||
if event_class == NavalInterceptEvent and enemy_cp.radials == LAND:
|
if event_class == NavalInterceptEvent and enemy_cp.radials == LAND:
|
||||||
|
# skip naval events for non-coastal CPs
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if event_class == BaseAttackEvent and enemy_cp.base.strength > PLAYER_BASEATTACK_THRESHOLD:
|
if event_class == BaseAttackEvent and enemy_cp.base.strength > PLAYER_BASEATTACK_THRESHOLD:
|
||||||
|
# skip base attack events for CPs yet too strong
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if event_class == StrikeEvent and not enemy_cp.ground_objects:
|
if event_class == StrikeEvent and not enemy_cp.ground_objects:
|
||||||
|
# skip strikes in case of no targets
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
# finally append the event
|
||||||
self.events.append(event_class(self.player, self.enemy, player_cp, enemy_cp, self))
|
self.events.append(event_class(self.player, self.enemy, player_cp, enemy_cp, self))
|
||||||
elif enemy_probability == 100 or self._roll(enemy_probability, enemy_cp.base.strength):
|
elif enemy_probability == 100 or self._roll(enemy_probability, enemy_cp.base.strength):
|
||||||
if event_class in enemy_generated_types:
|
if event_class in enemy_generated_types:
|
||||||
|
# skip already generated event types
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if player_cp in self.ignored_cps:
|
if player_cp in self.ignored_cps:
|
||||||
|
# skip attacks against ignored CPs (for example just captured ones)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if enemy_cp.base.total_planes == 0:
|
if enemy_cp.base.total_planes == 0:
|
||||||
|
# skip event if there's no planes on the base
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if event_class == NavalInterceptEvent:
|
if event_class == NavalInterceptEvent:
|
||||||
if player_cp.radials == LAND:
|
if player_cp.radials == LAND:
|
||||||
|
# skip naval events for non-coastal CPs
|
||||||
continue
|
continue
|
||||||
elif event_class == StrikeEvent:
|
elif event_class == StrikeEvent:
|
||||||
if not player_cp.ground_objects:
|
if not player_cp.ground_objects:
|
||||||
|
# skip strikes if there's no ground objects
|
||||||
continue
|
continue
|
||||||
elif event_class == BaseAttackEvent:
|
elif event_class == BaseAttackEvent:
|
||||||
if enemy_cap_generated:
|
if enemy_cap_generated:
|
||||||
|
# skip base attack event if there's another one going on
|
||||||
continue
|
continue
|
||||||
if enemy_cp.base.total_armor == 0:
|
if enemy_cp.base.total_armor == 0:
|
||||||
|
# skip base attack if there's no armor
|
||||||
continue
|
continue
|
||||||
|
|
||||||
enemy_cap_generated = True
|
enemy_cap_generated = True
|
||||||
|
|
||||||
|
# finally append the event
|
||||||
enemy_generated_types.append(event_class)
|
enemy_generated_types.append(event_class)
|
||||||
self.events.append(event_class(self.enemy, self.player, enemy_cp, player_cp, self))
|
self.events.append(event_class(self.enemy, self.player, enemy_cp, player_cp, self))
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ REGROUP_ALT = 5000
|
|||||||
|
|
||||||
TRIGGER_WAYPOINT_OFFSET = 2
|
TRIGGER_WAYPOINT_OFFSET = 2
|
||||||
TRIGGER_MIN_DISTANCE_FROM_START = 10000
|
TRIGGER_MIN_DISTANCE_FROM_START = 10000
|
||||||
TRIGGER_RADIUS_MINIMUM = 25000
|
TRIGGER_RADIUS_MINIMUM = 20000
|
||||||
|
|
||||||
TRIGGER_RADIUS_SMALL = 30000
|
TRIGGER_RADIUS_SMALL = 30000
|
||||||
TRIGGER_RADIUS_MEDIUM = 100000
|
TRIGGER_RADIUS_MEDIUM = 100000
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
|||||||
Subproject commit e2f8478c4ed95588cea5837e62fc982decb7e133
|
Subproject commit 54eab60f228847f2d92e344e6885eca855354f41
|
||||||
@ -96,15 +96,15 @@ class EventMenu(Menu):
|
|||||||
header("Support:")
|
header("Support:")
|
||||||
# Options
|
# Options
|
||||||
awacs_enabled = self.game.budget >= AWACS_BUDGET_COST and NORMAL or DISABLED
|
awacs_enabled = self.game.budget >= AWACS_BUDGET_COST and NORMAL or DISABLED
|
||||||
Checkbutton(self.frame, var=self.awacs, state=awacs_enabled, **STYLES["radiobutton"]).grid(row=row, column=2, sticky=E)
|
|
||||||
Label(self.frame, text="AWACS ({}m)".format(AWACS_BUDGET_COST), **STYLES["widget"]).grid(row=row, column=0, sticky=W, pady=5)
|
Label(self.frame, text="AWACS ({}m)".format(AWACS_BUDGET_COST), **STYLES["widget"]).grid(row=row, column=0, sticky=W, pady=5)
|
||||||
|
Checkbutton(self.frame, var=self.awacs, state=awacs_enabled, **STYLES["radiobutton"]).grid(row=row, column=4, sticky=E)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
Label(self.frame, text="Combined Arms Slots", **STYLES["widget"]).grid(row=row, sticky=W)
|
Label(self.frame, text="Combined Arms Slots", **STYLES["widget"]).grid(row=row, sticky=W)
|
||||||
self.ca_slot_entry = Entry(self.frame, width=2)
|
self.ca_slot_entry = Entry(self.frame, width=2)
|
||||||
self.ca_slot_entry.insert(0, "0")
|
self.ca_slot_entry.insert(0, "0")
|
||||||
self.ca_slot_entry.grid(column=1, row=row, sticky=W, padx=5)
|
self.ca_slot_entry.grid(column=3, row=row, sticky=E, padx=5)
|
||||||
Button(self.frame, text="+", command=self.add_ca_slot, **STYLES["btn-primary"]).grid(column=2, row=row, padx=5, sticky=W)
|
Button(self.frame, text="+", command=self.add_ca_slot, **STYLES["btn-primary"]).grid(column=4, row=row, padx=5, sticky=W)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
header("Ready?")
|
header("Ready?")
|
||||||
|
|||||||
@ -118,7 +118,7 @@ class EventResultsMenu(Menu):
|
|||||||
|
|
||||||
def simulate_result(self, player_factor: float, enemy_factor: float):
|
def simulate_result(self, player_factor: float, enemy_factor: float):
|
||||||
def action():
|
def action():
|
||||||
debriefing = Debriefing({}, [])
|
debriefing = Debriefing({})
|
||||||
|
|
||||||
def count(country: Country) -> typing.Dict[UnitType, int]:
|
def count(country: Country) -> typing.Dict[UnitType, int]:
|
||||||
result = {}
|
result = {}
|
||||||
|
|||||||
@ -50,20 +50,21 @@ class MainMenu(Menu):
|
|||||||
nonlocal row, body
|
nonlocal row, body
|
||||||
frame = LabelFrame(body, **STYLES["label-frame"])
|
frame = LabelFrame(body, **STYLES["label-frame"])
|
||||||
frame.grid(row=row, sticky=NSEW)
|
frame.grid(row=row, sticky=NSEW)
|
||||||
Message(frame, text="{}{}".format(
|
Message(frame, text="{}".format(
|
||||||
event.defender_name == self.game.player and "Enemy attacking: " or "",
|
|
||||||
event
|
event
|
||||||
), aspect=1600, **STYLES["widget"]).grid(column=0, row=0, sticky=NSEW)
|
), aspect=1600, **STYLES["widget"]).grid(column=0, row=0, sticky=NSEW)
|
||||||
Button(body, text=">", command=self.start_event(event), **STYLES["btn-primary"]).grid(column=1, row=row, sticky=E)
|
Button(body, text=">", command=self.start_event(event), **STYLES["btn-primary"]).grid(column=1, row=row, sticky=E)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
def departure_header(text):
|
def departure_header(text, style="strong"):
|
||||||
nonlocal row, body
|
nonlocal row, body
|
||||||
Label(body, text=text, **STYLES["strong"]).grid(column=0, columnspan=2, row=row, sticky=N+EW, pady=(0, 5)); row += 1
|
Label(body, text=text, **STYLES[style]).grid(column=0, columnspan=2, row=row, sticky=N+EW, pady=(0, 5))
|
||||||
|
row += 1
|
||||||
|
|
||||||
def destination_header(text, pady=0):
|
def destination_header(text):
|
||||||
nonlocal row, body
|
nonlocal row, body
|
||||||
Label(body, text=text, **STYLES["substrong"]).grid(column=0, columnspan=2, row=row, sticky=N+EW, pady=(pady,0)); row += 1
|
Label(body, text=text, **STYLES["substrong"]).grid(column=0, columnspan=2, row=row, sticky=N+EW)
|
||||||
|
row += 1
|
||||||
|
|
||||||
events = self.game.events
|
events = self.game.events
|
||||||
events.sort(key=lambda x: x.to_cp.name)
|
events.sort(key=lambda x: x.to_cp.name)
|
||||||
@ -74,22 +75,25 @@ class MainMenu(Menu):
|
|||||||
departure = None
|
departure = None
|
||||||
|
|
||||||
for event in events:
|
for event in events:
|
||||||
new_departure = event.from_cp.name if not event.informational else "Deliveries"
|
if event.informational:
|
||||||
|
new_departure = "Deliveries"
|
||||||
|
elif not self.game.is_player_attack(event):
|
||||||
|
new_departure = "Enemy attack"
|
||||||
|
else:
|
||||||
|
new_departure = event.from_cp.name
|
||||||
|
|
||||||
if new_departure != departure:
|
if new_departure != departure:
|
||||||
body = LabelFrame(self.frame, **STYLES["body"])
|
body = LabelFrame(self.frame, **STYLES["body"])
|
||||||
body.grid(column=column, row=1, sticky=NSEW)
|
body.grid(column=column, row=1, sticky=N+EW)
|
||||||
row = 0
|
row = 0
|
||||||
column += 1
|
column += 1
|
||||||
|
|
||||||
departure = new_departure
|
departure = new_departure
|
||||||
departure_header(new_departure)
|
departure_header(new_departure, style="strong" if self.game.is_player_attack(event) else "supstrong")
|
||||||
destination = None
|
destination = None
|
||||||
|
|
||||||
if not event.informational:
|
if not event.informational:
|
||||||
if self.game.is_player_attack(event):
|
new_destination = "At {}".format(event.to_cp.name)
|
||||||
new_destination = "At {}".format(event.to_cp.name)
|
|
||||||
else:
|
|
||||||
new_destination = "Enemy attack"
|
|
||||||
if destination != new_destination:
|
if destination != new_destination:
|
||||||
destination_header(new_destination)
|
destination_header(new_destination)
|
||||||
destination = new_destination
|
destination = new_destination
|
||||||
|
|||||||
@ -29,6 +29,7 @@ STYLES["frame-wrapper"] = {"bg": BG_COLOR, "relief":"sunken"}
|
|||||||
STYLES["body"] = {"bg": BG_COLOR, "padx": 10, "pady": 10}
|
STYLES["body"] = {"bg": BG_COLOR, "padx": 10, "pady": 10}
|
||||||
STYLES["strong"] = {"font": BOLD_FONT, "bg": BG_TITLE_COLOR, "fg": FG_COLOR}
|
STYLES["strong"] = {"font": BOLD_FONT, "bg": BG_TITLE_COLOR, "fg": FG_COLOR}
|
||||||
STYLES["substrong"] = {"font": BOLD_FONT, "bg": BG_SUBTITLE_COLOR, "fg": FG_COLOR}
|
STYLES["substrong"] = {"font": BOLD_FONT, "bg": BG_SUBTITLE_COLOR, "fg": FG_COLOR}
|
||||||
|
STYLES["supstrong"] = {"font": BOLD_FONT, "bg": RED, "fg": FG_COLOR}
|
||||||
STYLES["strong-grey"] = {"font": BOLD_FONT, "bg": BG_TITLE_COLOR, "fg": FG_COLOR_LIGHT}
|
STYLES["strong-grey"] = {"font": BOLD_FONT, "bg": BG_TITLE_COLOR, "fg": FG_COLOR_LIGHT}
|
||||||
|
|
||||||
STYLES["mission-preview"] = {"font": BOLD_FONT, "bg": YELLOW, "fg": FG_COLOR}
|
STYLES["mission-preview"] = {"font": BOLD_FONT, "bg": YELLOW, "fg": FG_COLOR}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user