diff --git a/src/mission_report/report.py b/src/mission_report/report.py index 3c3dad9..79e33bc 100644 --- a/src/mission_report/report.py +++ b/src/mission_report/report.py @@ -2,12 +2,15 @@ from itertools import count import logging import operator +from django.conf import settings from mission_report.constants import COALITION_ALIAS from mission_report.statuses import BotLifeStatus, SortieStatus, LifeStatus from mission_report.helpers import distance, point_in_polygon, is_pos_correct from mission_report import parse_mission_log_line +SORTIE_DAMAGE_DISCO_TIME = settings.SORTIE_DAMAGE_DISCO_TIME + logger = logging.getLogger('mission_report') @@ -256,7 +259,11 @@ def event_damage(self, tik, damage, attacker_id, target_id, pos): target.got_damaged(damage=damage, attacker=attacker, pos=pos) # получить время об последний урон для диско - get time of last damage done to airplane when sortie is disco if target.sortie: - target.sortie.tik_lastdamage = tik + if target.cls_base == 'aircraft': + target.sortie.tik_lastdamage = tik + if (target.cls_base == 'tank' or target.cls_base == 'vehicle' or target.cls_base == 'turret'): + if (attacker != None): + target.sortie.tik_lastdamage = tik def event_kill(self, tik, attacker_id, target_id, pos): attacker = self.get_object(object_id=attacker_id) @@ -380,8 +387,8 @@ def event_player_disconnected(self, tik, account_id, profile_id): # self.online_uuid.discard(account_id) sortie = self.sorties_accounts.get(account_id) # TODO работает только в Ил2, в РОФ нет такого события - if sortie: - # you can determine the amount of damage that is considered + if sortie and not (sortie.cls in ('tank_light', 'tank_heavy', 'tank_medium', 'tank_turret', 'truck')): + # you can determine the amount of damage that is considered for airplanes dmg_pct = 0 # the departure was completed, there was a jump, no plane was created, the plane on the ground, and the plane was damaged, # player disconection can then be changed into captured. @@ -391,10 +398,17 @@ def event_player_disconnected(self, tik, account_id, profile_id): self.logger_event({'type': 'disco', 'sortie': sortie}) sortie.aircraft.got_killed(force_by_dmg=True) # вылет был завершен, был прыжок, не был создан самолет, самолет на земле - if not (sortie.is_ended or sortie.is_bailout or (not sortie.aircraft) or sortie.aircraft.on_ground): + elif not (sortie.is_ended or sortie.is_bailout or (not sortie.aircraft) or sortie.aircraft.on_ground): sortie.is_disco = True self.logger_event({'type': 'disco', 'sortie': sortie}) + if sortie and (sortie.cls in ('tank_light', 'tank_heavy', 'tank_medium', 'tank_turret', 'truck')): + + # this is for case when tank player discnects, log will record its time and event. + if sortie.tik_lastdamage: + if (sortie.tank_is_ended_by_exit(tik=tik)) and (not sortie.is_bailout): + self.logger_event({'type': 'disco', 'sortie': sortie}) + def event_tank_travel(self, tik, tank_id, pos): pass @@ -496,6 +510,7 @@ def __init__(self, mission, object_id, object_name, country_id, coal_id, parent_ self.life_status = LifeStatus() self.is_deinitialized = False + self.is_tank_exit_damaged = False self.is_takeoff = False self.is_killed = False @@ -672,7 +687,8 @@ def got_killed(self, attacker=None, pos=None, force_by_dmg=False): attacker = None # dont give kill to attacker for tank/truck when its RTB and total damage to tank is less then 75%, if higher tank will be destroyed, no RTB, and attacker will get kill. - if (self.cls_base == 'tank' or self.cls_base == 'vehicle' or self.cls_base == 'turret') and self.is_tank_rtb(pos=pos) and (self.damage < 75): + if (self.cls_base == 'tank' or self.cls_base == 'vehicle' or self.cls_base == 'turret') and self.is_tank_rtb( + pos=pos) and (self.damage < 75): attacker = None is_friendly_fire = True if attacker and attacker.coal_id == self.coal_id else False @@ -693,12 +709,11 @@ def got_killed(self, attacker=None, pos=None, force_by_dmg=False): self.mission.logger_event({'type': 'kill', 'attacker': attacker, 'pos': pos, 'target': self, 'is_friendly_fire': is_friendly_fire}) - def killed_by_damage(self, dmg_pct=0, dmg_pct_tk=0 ): + def killed_by_damage(self, dmg_pct=0, dmg_pct_tk=0): if self.cls_base == 'tank' or self.cls_base == 'vehicle': # - by changing dmg_pct_tk value you can set up to what damage % tank or truck can be damaged to not give kill to attacker or sortie status changed to destroyed. - if not self.is_killed and (self.damage > dmg_pct_tk or self.is_captured): - if (self.on_ground and not self.is_rtb) or self.is_bailout or ( - self.bot and self.bot.life_status.is_destroyed): + if not self.is_killed and (self.damage > dmg_pct_tk): + if self.is_tank_exit_damaged: self.got_killed(force_by_dmg=True) if self.cls_base == 'aircraft': if not self.is_killed and (self.damage > dmg_pct or self.is_captured): @@ -707,6 +722,10 @@ def killed_by_damage(self, dmg_pct=0, dmg_pct_tk=0 ): if (self.on_ground and not self.is_rtb) or self.is_bailout or ( self.bot and self.bot.life_status.is_destroyed): self.got_killed(force_by_dmg=True) + # in case of disconection - the player who damaged him gets kill, when damage occurs at any time in flight + if self.sortie and not self.is_rtb: + if not self.sortie.is_ended: + self.got_killed(force_by_dmg=True) def update_by_sortie(self, sortie, is_aircraft=True): """ @@ -822,6 +841,7 @@ def __init__(self, mission, tik, aircraft_id, bot_id, account_id, profile_id, na self.is_disco = False self.is_discobailout = False self.is_damageddisco = False + self.is_tank_exit_damaged = False self.is_ended = False # логи могут баговать и идти не по порядку @@ -956,3 +976,12 @@ def is_ended_by_timeout(self, timeout, tik): return False else: return True + + # for Tanks/trucks , set True if last damage is with in specified time set in conf.ini. + # its used to give kill to attacker when sortie is turned to capture, if player bailout then dont count, bailed out game log gives kill to attacker automaticly. + def tank_is_ended_by_exit(self, tik): + if (self.cls_base == 'tank' or self.cls_base == 'vehicle' or self.cls_base == 'turret' ) and (self.tik_lastdamage is not None): + if (SORTIE_DAMAGE_DISCO_TIME > (tik - self.tik_lastdamage // 50)) and not (self.is_bailout): + return False + else: + return True \ No newline at end of file diff --git a/src/mod_rating_by_type/report.py b/src/mod_rating_by_type/report.py index 8697480..d26b4cc 100644 --- a/src/mod_rating_by_type/report.py +++ b/src/mod_rating_by_type/report.py @@ -200,7 +200,11 @@ def event_damage(self, tik, damage, attacker_id, target_id, pos): target.got_damaged(damage=damage, tik=tik, attacker=attacker, pos=pos) # получить время об последний урон для диско - get time of last damage done to airplane when sortie is disco if target.sortie: - target.sortie.tik_lastdamage = tik + if target.cls_base == 'aircraft': + target.sortie.tik_lastdamage = tik + if (target.cls_base == 'tank' or target.cls_base == 'vehicle' or target.cls_base == 'turret'): + if (attacker != None): + target.sortie.tik_lastdamage = tik # Monkey patched into Object class inside report.py diff --git a/src/mod_rating_by_type/stats_whore.py b/src/mod_rating_by_type/stats_whore.py index 22bb2a5..4daf585 100644 --- a/src/mod_rating_by_type/stats_whore.py +++ b/src/mod_rating_by_type/stats_whore.py @@ -100,7 +100,6 @@ def create_new_sortie(mission, profile, player, sortie, sortie_aircraft_id): is_ignored = True # for disco sorties, if the total departure time is less than the one set by the config, disco = bailout sortie (time is set in seconds) - if SORTIE_DISCO_MIN_TIME and sortie.is_disco: if (sortie_tik_last // 50) - (sortie.tik_takeoff // 50) < SORTIE_DISCO_MIN_TIME: sortie.is_discobailout = True @@ -108,10 +107,9 @@ def create_new_sortie(mission, profile, player, sortie, sortie_aircraft_id): # in case of disconect if time of damage to airplane happend outside of time set in conf.ini file, sortie is considered disco, # if time of damage happend inside time set, sortie will be considered captured (time is set in seconds) - if SORTIE_DAMAGE_DISCO_TIME and sortie.is_damageddisco: - - if (sortie.tik_last // 50) - (sortie.tik_lastdamage // 50) > SORTIE_DAMAGE_DISCO_TIME: + if ((sortie_tik_last // 50) - (sortie.tik_lastdamage // 50) > SORTIE_DAMAGE_DISCO_TIME) and not ( + (sortie.cls_base == 'tank' or sortie.cls_base == 'vehicle' or sortie.cls_base == 'turret')): sortie.is_disco = True sortie.is_damageddisco = False # for damaged disco sorties, if the total departure time is less than the one set by the config for disco_min_time, damageddisco = bailout sortie @@ -120,6 +118,16 @@ def create_new_sortie(mission, profile, player, sortie, sortie_aircraft_id): sortie.is_disco = False sortie.is_damageddisco = False + # in case of tank exit under fire, if time of damage to tank or truck happend outside of time set in conf.ini file, sortie is considered ok, + # if time of damage happend inside time set, sortie will be considered captured (time is set in seconds), if mission ends or crah while player is in sortie then it dont count. + if SORTIE_DAMAGE_DISCO_TIME and ( + (sortie.cls_base == 'tank' or sortie.cls_base == 'vehicle' or sortie.cls_base == 'turret')) and ( + sortie.tik_lastdamage) and (mission.date_end != sortie_date_end): + if (SORTIE_DAMAGE_DISCO_TIME > (sortie_tik_last // 50) - (sortie.tik_lastdamage // 50)) and ( + not sortie.tik_bailout): + sortie.is_tank_exit_damaged = True + sortie.aircraft.got_killed(force_by_dmg=True) + killboard_pvp = defaultdict(int) killboard_pve = defaultdict(int) @@ -203,7 +211,7 @@ def create_new_sortie(mission, profile, player, sortie, sortie_aircraft_id): bot_status=sortie.bot_status.status, is_bailout=sortie.is_bailout or sortie.is_discobailout, - is_captured=sortie.is_captured or sortie.is_damageddisco, + is_captured=sortie.is_captured or sortie.is_damageddisco or sortie.is_tank_exit_damaged, is_disco=sortie.is_disco, score=score, diff --git a/src/stats/stats_whore.py b/src/stats/stats_whore.py index 4d7b39c..815116d 100644 --- a/src/stats/stats_whore.py +++ b/src/stats/stats_whore.py @@ -41,6 +41,7 @@ SORTIE_DISCO_MIN_TIME = settings.SORTIE_DISCO_MIN_TIME SORTIE_DAMAGE_DISCO_TIME = settings.SORTIE_DAMAGE_DISCO_TIME + def main(): logger.info('IL2 stats {stats}, Python {python}, Django {django}'.format( stats=__version__, python=sys.version[0:5], django=django.get_version())) @@ -186,7 +187,8 @@ def stats_whore(m_report_file): mission.save() # собираем/создаем профили игроков и сквадов - profiles, players_pilots, players_gunners, players_tankmans, squads = create_profiles(tour=tour, sorties=m_report.sorties) + profiles, players_pilots, players_gunners, players_tankmans, squads = create_profiles(tour=tour, + sorties=m_report.sorties) players_aircraft = defaultdict(dict) players_mission = {} @@ -244,7 +246,8 @@ def stats_whore(m_report_file): player_aircraft = players_aircraft[_player_id].setdefault( new_sortie.aircraft.id, - PlayerAircraft.objects.get_or_create(profile_id=_profile_id, player_id=_player_id, aircraft_id=new_sortie.aircraft.id)[0] + PlayerAircraft.objects.get_or_create(profile_id=_profile_id, player_id=_player_id, + aircraft_id=new_sortie.aircraft.id)[0] ) vlife = VLife.objects.get_or_create(profile_id=_profile_id, player_id=_player_id, tour_id=tour.id, relive=0)[0] @@ -253,7 +256,8 @@ def stats_whore(m_report_file): if mission.win_reason == 'score': update_bonus_score(new_sortie=new_sortie) - update_sortie(new_sortie=new_sortie, player_mission=player_mission, player_aircraft=player_aircraft, vlife=vlife) + update_sortie(new_sortie=new_sortie, player_mission=player_mission, player_aircraft=player_aircraft, + vlife=vlife) reward_sortie(sortie=new_sortie) vlife.save() @@ -341,7 +345,8 @@ def stats_whore(m_report_file): else: params['type'] = 'damaged' if event['attacker']: - if ((event['attacker'].cls == 'tank_turret' or (event['attacker'].cls_base == 'tank' or (event['attacker'].cls_base == 'vehicle'))) + if ((event['attacker'].cls == 'tank_turret' or ( + event['attacker'].cls_base == 'tank' or (event['attacker'].cls_base == 'vehicle'))) and event['attacker'].parent and event['attacker'].parent.sortie): # Credit the damage to the tank driver. params['act_object_id'] = event[ @@ -366,7 +371,8 @@ def stats_whore(m_report_file): else: params['type'] = 'destroyed' if event['attacker']: - if ((event['attacker'].cls == 'tank_turret' or (event['attacker'].cls_base == 'tank' or (event['attacker'].cls_base == 'vehicle'))) + if ((event['attacker'].cls == 'tank_turret' or ( + event['attacker'].cls_base == 'tank' or (event['attacker'].cls_base == 'vehicle'))) and event['attacker'].parent and event['attacker'].parent.sortie): # Credit the kill to the tank driver. params['act_object_id'] = event[ @@ -384,8 +390,11 @@ def stats_whore(m_report_file): params['cact_object_id'] = objects[event['target'].log_name]['id'] l = LogEntry.objects.create(**params) - if l.type == 'shotdown' and l.act_sortie and l.cact_sortie and not l.act_sortie.is_disco and not l.extra_data.get('is_friendly_fire'): - update_killboard_pvp(player=l.act_sortie.player, opponent=l.cact_sortie.player, players_killboard=players_killboard) + if l.type in {'shotdown', + 'destroyed'} and l.act_sortie and l.cact_sortie and not l.act_sortie.is_disco and not l.extra_data.get( + 'is_friendly_fire'): + update_killboard_pvp(player=l.act_sortie.player, opponent=l.cact_sortie.player, + players_killboard=players_killboard) for p in players_killboard.values(): p.save() @@ -464,16 +473,17 @@ def create_new_sortie(mission, profile, player, sortie, sortie_aircraft_id): if (sortie_tik_last // 50) - (sortie.tik_spawn // 50) < SORTIE_MIN_TIME: is_ignored = True - # for disco sorties, if the total departure time is less than the one set by the config, disco = bailout sortie (time is set in seconds) + # for disco sorties, if the total departure time is less than the one set by the config, disco = bailout sortie (time is set in seconds) if SORTIE_DISCO_MIN_TIME and sortie.is_disco: if (sortie_tik_last // 50) - (sortie.tik_takeoff // 50) < SORTIE_DISCO_MIN_TIME: sortie.is_discobailout = True sortie.is_disco = False # in case of disconect if time of damage to airplane happend outside of time set in conf.ini file, sortie is considered disco, - # if time of damage happend inside time set, sortie will be considered captured (time is set in seconds) + # if time of damage happend inside time set, sortie will be considered captured (time is set in seconds) if SORTIE_DAMAGE_DISCO_TIME and sortie.is_damageddisco: - if (sortie.tik_last // 50) - (sortie.tik_lastdamage // 50) > SORTIE_DAMAGE_DISCO_TIME: + if ((sortie_tik_last // 50) - (sortie.tik_lastdamage // 50) > SORTIE_DAMAGE_DISCO_TIME) and not ( + (sortie.cls_base == 'tank' or sortie.cls_base == 'vehicle' or sortie.cls_base == 'turret')): sortie.is_disco = True sortie.is_damageddisco = False # for damaged disco sorties, if the total departure time is less than the one set by the config for disco_min_time, damageddisco = bailout sortie @@ -482,6 +492,15 @@ def create_new_sortie(mission, profile, player, sortie, sortie_aircraft_id): sortie.is_disco = False sortie.is_damageddisco = False + # in case of tank exit under fire, if time of damage to tank or truck happend outside of time set in conf.ini file, sortie is considered ok, + # if time of damage happend inside time set, sortie will be considered captured (time is set in seconds), if mission ends or crah while player is in sortie then it dont count. + if SORTIE_DAMAGE_DISCO_TIME and ( + (sortie.cls_base == 'tank' or sortie.cls_base == 'vehicle' or sortie.cls_base == 'turret')) and ( + sortie.tik_lastdamage) and (mission.date_end != sortie_date_end): + if (SORTIE_DAMAGE_DISCO_TIME > (sortie_tik_last // 50) - (sortie.tik_lastdamage // 50)) and ( + not sortie.tik_bailout): + sortie.is_tank_exit_damaged = True + sortie.aircraft.got_killed(force_by_dmg=True) killboard_pvp = defaultdict(int) killboard_pve = defaultdict(int) @@ -567,7 +586,7 @@ def create_new_sortie(mission, profile, player, sortie, sortie_aircraft_id): bot_status=sortie.bot_status.status, is_bailout=sortie.is_bailout or sortie.is_discobailout, - is_captured=sortie.is_captured or sortie.is_damageddisco, + is_captured=sortie.is_captured or sortie.is_damageddisco or sortie.is_tank_exit_damaged, is_disco=sortie.is_disco, score=score, @@ -615,7 +634,7 @@ def update_sortie(new_sortie, player_mission, player_aircraft, vlife): vlife.aircraft_status = new_sortie.aircraft_status vlife.bot_status = new_sortie.bot_status - # TODO проверить как это отработает для вылетов стрелков + # TODO проверить как это отработает для вылетов стрелков if new_sortie.aircraft.cls_base == 'aircraft' and not new_sortie.is_not_takeoff: player.sorties_coal[new_sortie.coalition] += 1 player_mission.sorties_coal[new_sortie.coalition] += 1 @@ -734,7 +753,8 @@ def update_sortie(new_sortie, player_mission, player_aircraft, vlife): def update_general(player, new_sortie): flight_time_add = 0 - if (not new_sortie.is_not_takeoff) or ( new_sortie.aircraft.cls_base == 'tank' or (new_sortie.aircraft.cls_base == 'vehicle')): + if (not new_sortie.is_not_takeoff) or ( + new_sortie.aircraft.cls_base == 'tank' or (new_sortie.aircraft.cls_base == 'vehicle')): player.sorties_total += 1 flight_time_add = new_sortie.flight_time player.flight_time += flight_time_add @@ -765,6 +785,7 @@ def update_general(player, new_sortie): except AttributeError: pass # Some player objects have no score or relive attributes for light/medium/heavy aircraft. + def update_ammo(sortie, player): # в логах есть баги, по окончание вылета у самолета может быть больше боемкомплекта чем было вначале if sortie.ammo['used_cartridges'] >= sortie.ammo['hit_bullets']: