This commit is contained in:
Simon Junod
2025-08-08 17:59:27 +02:00
parent e27b4af4ec
commit 828c4dc70e
2 changed files with 27 additions and 15 deletions

11
run.py
View File

@@ -15,8 +15,11 @@ from emojis import *
from settings import * from settings import *
intents = nextcord.Intents.default() intents = nextcord.Intents.default()
# noinspection PyDunderSlots,PyUnresolvedReferences
intents.typing = False intents.typing = False
# noinspection PyDunderSlots,PyUnresolvedReferences
intents.presences = False intents.presences = False
# noinspection PyDunderSlots,PyUnresolvedReferences
intents.message_content = True intents.message_content = True
bot = nextcord.Client(intents=intents) bot = nextcord.Client(intents=intents)
@@ -45,6 +48,7 @@ async def on_ready():
print(f"Écoute pour Spoutnik sur {channel.guild} > {channel.name}") print(f"Écoute pour Spoutnik sur {channel.guild} > {channel.name}")
current_date = None current_date = None
events_done = []
while True: while True:
await asyncio.sleep(HEARTBEAT) await asyncio.sleep(HEARTBEAT)
now = datetime.now() now = datetime.now()
@@ -63,7 +67,7 @@ async def on_ready():
await wordle_game.reset() await wordle_game.reset()
elif event[0] == SPOUTNIK: elif event[0] == SPOUTNIK:
for spoutnik_game in spoutnik_games.values(): for spoutnik_game in spoutnik_games.values():
await spoutnik_game.reset() await spoutnik_game.reset(preset=SPOUTNIK_PRESETS[event[2]], force=False)
# Receiving a message # Receiving a message
@@ -104,9 +108,9 @@ async def on_message(message):
output += f"{spoutnik_game.channel.guild} > {spoutnik_game.channel.name} : {spoutnik_game.target}\n" output += f"{spoutnik_game.channel.guild} > {spoutnik_game.channel.name} : {spoutnik_game.target}\n"
await message.author.send(output) await message.author.send(output)
if regex := re.search(r"^[sS]poutnik reset ([0-9]+)$", content_lowercase): if regex := re.search(r"^[sS]poutnik reset ([0-9]+) (.+)$", content_lowercase):
channel_id = int(regex.group(1)) channel_id = int(regex.group(1))
await spoutnik_games[channel_id].reset() await spoutnik_games[channel_id].reset(preset=SPOUTNIK_PRESETS[regex.group(2).strip()], force=True)
if re.search(r"^[eE]phemeris$", content_lowercase): if re.search(r"^[eE]phemeris$", content_lowercase):
embed = ephemeris.digest() embed = ephemeris.digest()
@@ -244,6 +248,7 @@ async def on_message(message):
poll = polls.Poll() poll = polls.Poll()
poll.owner = message.author poll.owner = message.author
poll.intro = intro poll.intro = intro
letter = None
for part in parts: for part in parts:
if re.fullmatch(bullet, part): # the part is a bullet if re.fullmatch(bullet, part): # the part is a bullet
letter = part[0].lower() letter = part[0].lower()

View File

@@ -43,6 +43,7 @@ class Game:
def __init__(self, channel): def __init__(self, channel):
self.channel = channel self.channel = channel
self.target = None self.target = None
self.preset = None
self.file = f"/tmp/spoutnik_{channel}.jpg" self.file = f"/tmp/spoutnik_{channel}.jpg"
self.winner = None self.winner = None
self.last_player = None self.last_player = None
@@ -50,22 +51,27 @@ class Game:
self.resetters = set() self.resetters = set()
self.jump_url = None self.jump_url = None
async def reset(self): async def reset(self, preset, force=False):
if not force and not self.winner and self.last_datetime and (datetime.now() - self.last_datetime).total_seconds() < SPOUTNIK_EXPIRY_TIMEOUT:
return
output = "" output = ""
self.preset = preset
zoom = self.preset["zoom"]
if self.target and not self.winner: if self.target and not self.winner:
output = f":expressionless: Le lieu précédent était [ici](<https://www.google.ch/maps/@{self.target[0]},{self.target[1]},{SPOUTNIK_ZOOM}z>).\n\n" output = f":expressionless: Le lieu précédent était [ici](<https://www.google.ch/maps/@{self.target[0]},{self.target[1]},{zoom}z>).\n\n"
random_lat, random_lon = random_point(SPOUTNIK_FILE) random_lat, random_lon = random_point(self.preset["geojson_file"])
tile_x, tile_y = wgs84_to_tile(random_lat, random_lon, SPOUTNIK_ZOOM) tile_x, tile_y = wgs84_to_tile(random_lat, random_lon, zoom)
req = requests.get(f"https://khms2.google.com/kh/v=1000?x={tile_x}&y={tile_y}&z={SPOUTNIK_ZOOM}") req = requests.get(f"https://khms2.google.com/kh/v=1000?x={tile_x}&y={tile_y}&z={zoom}")
with open(self.file, "wb") as f: with open(self.file, "wb") as f:
f.write(req.content) f.write(req.content)
self.target = tile_to_wgs84(tile_x + 0.5, tile_y + 0.5, SPOUTNIK_ZOOM) self.target = tile_to_wgs84(tile_x + 0.5, tile_y + 0.5, zoom)
self.winner = None self.winner = None
self.last_player = None self.last_player = None
self.last_datetime = None self.last_datetime = None
self.resetters = set() self.resetters = set()
output += f":satellite_orbital: Il y a un nouveau lieu à trouver !" output += f":satellite_orbital: Il y a un nouveau lieu à trouver ! Le terrain de jeu est {self.preset["label"]}."
output += f"\n\nDonnez-moi les coordonnées GPS du centre de l'image, à {SPOUTNIK_MAX_DISTANCE} m près." output += f"\n\nDonnez-moi les coordonnées GPS du centre de l'image, à {self.preset["max_distance"]} m près."
output += f"\n\n*Sur le site Google Maps, clic droit puis clic sur les coordonnées.*" output += f"\n\n*Sur le site Google Maps, clic droit puis clic sur les coordonnées.*"
output += f"\n*Sur l'app Google Maps, appui long puis appui sur les coordonnées.*" output += f"\n*Sur l'app Google Maps, appui long puis appui sur les coordonnées.*"
self.jump_url = (await self.channel.send(output, file=File(self.file))).jump_url self.jump_url = (await self.channel.send(output, file=File(self.file))).jump_url
@@ -80,7 +86,7 @@ class Game:
self.resetters.add(message.author) self.resetters.add(message.author)
await self.channel.send(f"Réinitialisation : {len(self.resetters)}/{SPOUTNIK_RESETTERS_NEEDED}") await self.channel.send(f"Réinitialisation : {len(self.resetters)}/{SPOUTNIK_RESETTERS_NEEDED}")
if len(self.resetters) >= SPOUTNIK_RESETTERS_NEEDED: if len(self.resetters) >= SPOUTNIK_RESETTERS_NEEDED:
await self.reset() await self.reset(preset=self.preset, force=True)
return return
# if somebody has already won, return silently # if somebody has already won, return silently
@@ -114,17 +120,18 @@ class Game:
distance = geodesic((lat, lon), self.target).meters distance = geodesic((lat, lon), self.target).meters
blurred_distance = f"{ceil(distance / 1000)} km" if distance > 1000 else f"{ceil(distance / 100) * 100} m" blurred_distance = f"{ceil(distance / 1000)} km" if distance > 1000 else f"{ceil(distance / 100) * 100} m"
if distance <= SPOUTNIK_MAX_DISTANCE: zoom = self.preset["zoom"]
if distance <= self.preset["max_distance"]:
self.winner = message.author self.winner = message.author
self.resetters = set() self.resetters = set()
output = f":trophy: YOUPI ! {message.author.mention} a trouvé le lieu ! :trophy:" output = f":trophy: YOUPI ! {message.author.mention} a trouvé le lieu ! :trophy:"
output += f"\n\n[Lieu exact](<https://www.google.ch/maps/@{self.target[0]},{self.target[1]},{SPOUTNIK_ZOOM}z>)" output += f"\n\n[Lieu exact](<https://www.google.ch/maps/@{self.target[0]},{self.target[1]},{zoom}z>)"
await self.channel.send(output) await self.channel.send(output)
else: else:
try: try:
address = clean_address(geolocator.reverse((lat, lon), language="fr").address) address = clean_address(geolocator.reverse((lat, lon), language="fr").address)
except ValueError: except ValueError:
address = "un lieu apparemment invalide" address = "un lieu apparemment invalide"
output = f"{message.author.mention} propose [un point](<https://www.google.ch/maps/@{lat},{lon},{SPOUTNIK_ZOOM}z>) proche de {address}." output = f"{message.author.mention} propose [un point](<https://www.google.ch/maps/@{lat},{lon},{zoom}z>) proche de {address}."
output += f"\n\nC'est pas ça chef, mais tu es à moins de {blurred_distance} de [la cible](<{self.jump_url}>) !" output += f"\n\nC'est pas ça chef, mais tu es à moins de {blurred_distance} de [la cible](<{self.jump_url}>) !"
await self.channel.send(output) await self.channel.send(output)