1+ import numpy as np
12import pandas as pd
23
3- from core import report , ReportEnv , utils , Side , Coalition , get_translation
4+ from core import report , ReportEnv , utils , Side , Coalition , get_translation , df_to_table
45from dataclasses import dataclass
56from datetime import datetime
67from plugins .userstats .filter import StatisticsFilter
@@ -14,29 +15,37 @@ class Flight:
1415 start : datetime = None
1516 end : datetime = None
1617 plane : str = None
18+ death : bool = False
1719
1820
19- class Sorties (report .EmbedElement ):
21+ class Sorties (report .GraphElement ):
2022
21- def __init__ (self , env : ReportEnv ) -> None :
22- super ().__init__ (env )
23- self .sorties = pd .DataFrame (columns = ['plane' , 'time' ])
23+ def __init__ (self , env : ReportEnv , rows : int , cols : int , row : int | None = 0 , col : int | None = 0 ,
24+ colspan : int | None = 1 , rowspan : int | None = 1 , polar : bool | None = False ):
25+ super ().__init__ (env , rows , cols , row , col , colspan , rowspan , polar )
26+ self .sorties = pd .DataFrame (columns = ['plane' , 'time' , 'death' ])
2427
2528 def add_flight (self , flight : Flight ) -> Flight :
2629 if flight .start and flight .end and flight .plane :
27- self .sorties .loc [len (self .sorties .index )] = [flight .plane , flight .end - flight .start ]
30+ self .sorties .loc [len (self .sorties .index )] = [flight .plane , flight .end - flight .start , flight . death ]
2831 return Flight ()
2932
3033 async def render (self , ucid : str , flt : StatisticsFilter ) -> None :
31- sql = """
34+ sql = f """
3235 SELECT mission_id, init_type, init_cat, event, place, time
3336 FROM missionstats s
34- WHERE event IN ('S_EVENT_BIRTH', 'S_EVENT_TAKEOFF', 'S_EVENT_LAND', 'S_EVENT_UNIT_LOST',
35- 'S_EVENT_PLAYER_LEAVE_UNIT')
37+ WHERE event IN (
38+ 'S_EVENT_BIRTH',
39+ 'S_EVENT_TAKEOFF',
40+ 'S_EVENT_LAND',
41+ 'S_EVENT_UNIT_LOST',
42+ 'S_EVENT_PLAYER_LEAVE_UNIT'
43+ )
44+ AND { flt .filter (self .env .bot )}
45+ AND init_id = %s
46+ ORDER BY id
3647 """
3748 self .env .embed .title = flt .format (self .env .bot ) + self .env .embed .title
38- sql += ' AND ' + flt .filter (self .env .bot )
39- sql += ' AND init_id = %s ORDER BY 6'
4049
4150 async with self .apool .connection () as conn :
4251 async with conn .cursor (row_factory = dict_row ) as cursor :
@@ -66,24 +75,39 @@ async def render(self, ucid: str, flt: StatisticsFilter) -> None:
6675 flight .start = row ['time' ]
6776 elif row ['event' ] in ['S_EVENT_LAND' , 'S_EVENT_UNIT_LOST' , 'S_EVENT_PLAYER_LEAVE_UNIT' ]:
6877 flight .end = row ['time' ]
78+ if row ['event' ] == 'S_EVENT_UNIT_LOST' :
79+ flight .death = True
6980 flight = self .add_flight (flight )
7081 df = self .sorties .groupby ('plane' ).agg (
71- count = ('time' , 'size' ), total_time = ('time' , 'sum' )).sort_values (by = ['total_time' ],
72- ascending = False ).reset_index ()
73- planes = sorties = times = ''
74- for index , row in df .iterrows ():
75- planes += row ['plane' ] + '\n '
76- sorties += str (row ['count' ]) + '\n '
77- times += utils .convert_time (row ['total_time' ].total_seconds ()) + '\n '
78- if len (planes ) == 0 :
79- self .add_field (name = _ ('No sorties found for this player.' ), value = '_ _' )
80- else :
81- self .add_field (name = _ ('Module' ), value = planes )
82- self .add_field (name = _ ('Sorties' ), value = sorties )
83- self .add_field (name = _ ('Total Flighttime' ), value = times )
84- self .embed .set_footer (
85- text = _ ('Flighttime is the time you were airborne from takeoff to landing / leave or\n '
86- 'airspawn to landing / leave.' ))
82+ count = ('time' , 'size' ), total_time = ('time' , 'sum' ), avg_time = ('time' , 'mean' )
83+ ).sort_values (by = ['total_time' ], ascending = False ).reset_index ()
84+ if df .empty :
85+ self .axes .axis ('off' )
86+ self .axes .text (0.5 , 0.5 , _ ('No sorties found for this player.' ), ha = 'center' , va = 'center' ,
87+ rotation = 45 , size = 15 , transform = self .axes .transAxes )
88+ return
89+
90+ # Sum the time of those flights per plane
91+ survival_sum = self .sorties .groupby ('plane' )['time' ].sum ()
92+
93+ # Count how many deaths exist per plane
94+ death_counts = self .sorties [self .sorties .death == True ].groupby ('plane' ).size ()
95+ interval_counts = death_counts - 1 # pairs = deaths‑1
96+ interval_counts [interval_counts < 0 ] = np .nan # protect against 0 deaths
97+
98+ # Average survival time
99+ avg_survival = survival_sum / interval_counts
100+
101+ # Merge into the original dataframe
102+ df = df .merge (avg_survival .rename ('avg_survival' ), on = 'plane' , how = 'left' )
103+
104+ self .axes = df_to_table (
105+ self .axes , df [['plane' , 'count' , 'total_time' , 'avg_time' , 'avg_survival' ]],
106+ col_labels = ['Plane' , 'Sorties' , 'Total Flighttime' , 'Avg. Flighttime' , 'Avg. Survivaltime' ]
107+ )
108+ self .env .embed .set_footer (
109+ text = _ ('Flighttime is the time you were airborne from takeoff to landing / leave or\n '
110+ 'airspawn to landing / leave.' ))
87111
88112
89113class MissionStats (report .EmbedElement ):
@@ -214,15 +238,21 @@ async def render(self, ucid: str, module: str, flt: StatisticsFilter) -> None:
214238
215239class Refuelings (report .EmbedElement ):
216240 async def render (self , ucid : str , flt : StatisticsFilter ) -> None :
217- sql = "SELECT init_type, COUNT(*) FROM missionstats WHERE EVENT = 'S_EVENT_REFUELING_STOP'"
241+ sql = f"""
242+ SELECT init_type, COUNT(*)
243+ FROM missionstats
244+ WHERE EVENT = 'S_EVENT_REFUELING_STOP'
245+ AND { flt .filter (self .env .bot )}
246+ AND init_id = %s
247+ GROUP BY 1
248+ ORDER BY 2 DESC
249+ """
218250 self .env .embed .title = flt .format (self .env .bot ) + self .env .embed .title
219- sql += ' AND ' + flt .filter (self .env .bot )
220- sql += ' AND init_id = %s GROUP BY 1 ORDER BY 2 DESC'
221251
222252 modules = []
223253 numbers = []
224254 async with self .apool .connection () as conn :
225- cursor = await conn .execute (sql , (ucid , ))
255+ cursor = await conn .execute (sql , (ucid ,))
226256 async for row in cursor :
227257 modules .append (row [0 ])
228258 numbers .append (str (row [1 ]))
0 commit comments