22import discord
33
44from core import EventListener , Server , Status , utils , event , chat_command , get_translation , DataObjectFactory
5- from typing import cast , TYPE_CHECKING
5+ from typing import cast , TYPE_CHECKING , Literal
66
77from .player import CreditPlayer
88from .squadron import Squadron
@@ -115,17 +115,17 @@ async def get_flighttime(self, ucid: str, campaign_id: int) -> int:
115115 cursor = await conn .execute ("""
116116 SELECT COALESCE(ROUND(SUM(EXTRACT(EPOCH FROM (s.hop_off - s.hop_on)))), 0) AS playtime
117117 FROM statistics s JOIN missions m ON m.id = s.mission_id
118- JOIN campaigns c ON c.id = %s
118+ JOIN campaigns c ON c.id = %(campaign_id) s
119119 JOIN campaigns_servers cs ON cs.campaign_id = c.id
120- WHERE s.player_ucid = %s
120+ WHERE s.player_ucid = %(ucid) s
121121 AND m.server_name = cs.server_name
122122 AND tsrange(s.hop_on, s.hop_off) && tsrange(c.start, c.stop)
123- """ , ( ucid , campaign_id ) )
123+ """ , { "campaign_id" : campaign_id , "ucid" : ucid } )
124124 return int ((await cursor .fetchone ())[0 ])
125125
126126 async def process_achievements (self , server : Server , player : CreditPlayer ):
127127
128- async def manage_role (member : discord . Member , role : str | int , action : str ):
128+ async def manage_role (role : str | int , action : Literal [ 'add' , 'remove' ] ):
129129 _role = self .bot .get_role (role )
130130 if not _role :
131131 self .log .error (f"Role { role } not found in your Discord!" )
@@ -141,46 +141,79 @@ async def manage_role(member: discord.Member, role: str | int, action: str):
141141 self .log .error (
142142 f'The bot needs the "Manage Roles" permission or needs to be placed higher than role { _role .name } !' )
143143
144- # only linked player can achieve roles
145- member = player .member
146- if not member :
147- return
144+ async def manage_badge (badge : dict , action : Literal ['add' , 'remove' ]):
145+ if action == "add" :
146+ async with self .apool .connection () as conn :
147+ async with conn .transaction ():
148+ await conn .execute ("""
149+ INSERT INTO players_badges (campaign_id, player_ucid, badge_name, badge_url)
150+ VALUES (%s, %s, %s, %s)
151+ ON CONFLICT (campaign_id, player_ucid) DO NOTHING
152+ """ , (campaign_id , player .ucid , badge ['name' ], badge ['img' ]))
153+ await self .bot .audit (f"achieved the badge { badge ['name' ]} " , user = player .ucid )
154+ elif action == "remove" :
155+ async with self .apool .connection () as conn :
156+ async with conn .transaction ():
157+ await conn .execute ("""
158+ DELETE FROM players_badges WHERE campaign_id = %s AND player_ucid = %s
159+ """ , (campaign_id , player .ucid ))
160+ await self .bot .audit (f"lost the badge { badge ['name' ]} " , user = player .ucid )
161+
148162 config : dict = self .plugin .get_config (server )
149163 if 'achievements' not in config :
150164 return
151165
152166 campaign_id , _ = utils .get_running_campaign (self .node , server )
167+ # only members can get roles
168+ member = player .member
153169 playtime = (await self .get_flighttime (player .ucid , campaign_id )) / 3600.0
154170 sorted_achievements = sorted (config ['achievements' ],
155171 key = lambda x : x ['credits' ] if 'credits' in x else x ['playtime' ],
156172 reverse = True )
157- given = False
173+ role_given = badge_given = False
158174 for achievement in sorted_achievements :
159- if given :
160- await manage_role (member , achievement ['role' ], 'remove' )
175+ if role_given or badge_given :
176+ if role_given :
177+ await manage_role (achievement ['role' ], 'remove' )
178+ if badge_given :
179+ await manage_badge (achievement ['badge' ], 'remove' )
161180 continue
162181 if achievement .get ('combined' ):
163182 if ('credits' in achievement and player .points >= achievement ['credits' ]) and \
164183 ('playtime' in achievement and playtime >= achievement ['playtime' ]):
165- await manage_role (member , achievement ['role' ], 'add' )
166- given = True
184+ if 'role' in achievement and member :
185+ await manage_role (achievement ['role' ], 'add' )
186+ role_given = True
187+ if 'badge' in achievement :
188+ await manage_badge (achievement ['badge' ], 'add' )
189+ badge_given = True
167190 else :
168- await manage_role (member , achievement ['role' ], 'remove' )
191+ if 'role' in achievement and member :
192+ await manage_role (achievement ['role' ], 'remove' )
193+ if 'badge' in achievement :
194+ await manage_badge (achievement ['badge' ], 'remove' )
169195 else :
170196 if ('credits' in achievement and player .points >= achievement ['credits' ]) or \
171197 ('playtime' in achievement and playtime >= achievement ['playtime' ]):
172- await manage_role (member , achievement ['role' ], 'add' )
173- given = True
198+ if 'role' in achievement and member :
199+ await manage_role (achievement ['role' ], 'add' )
200+ role_given = True
201+ if 'badge' in achievement :
202+ await manage_badge (achievement ['badge' ], 'add' )
203+ badge_given = True
174204 else :
175- await manage_role (member , achievement ['role' ], 'remove' )
205+ if 'role' in achievement and member :
206+ await manage_role (achievement ['role' ], 'remove' )
207+ if 'badge' in achievement :
208+ await manage_badge (achievement ['badge' ], 'remove' )
176209
177210 @event (name = "onGameEvent" )
178211 async def onGameEvent (self , server : Server , data : dict ) -> None :
179212 config = self .plugin .get_config (server )
180213 if not config or server .status != Status .RUNNING :
181214 return
182215 if data ['eventName' ] == 'kill' :
183- # players gain points only, if they don't kill themselves and no teamkills
216+ # players gain points only if they don't kill themselves and no teamkills
184217 if data ['arg1' ] != - 1 and data ['arg1' ] != data ['arg4' ] and data ['arg3' ] != data ['arg6' ]:
185218 # Multicrew - pilot and all crew members gain points
186219 for player in server .get_crew_members (server .get_player (id = data ['arg1' ])): # type: CreditPlayer
0 commit comments