Changed status lookup to only queue okay enemies for attack

This commit is contained in:
2026-01-26 15:51:44 -05:00
parent 7ea6f146e1
commit f45f02501a
4 changed files with 69 additions and 26 deletions

View File

@@ -9,13 +9,8 @@ Features:
ToDo: ToDo:
- API Key section
- Have user enter their own API key, pass along to the functions that call APIs
- server side config storage
- have multiple managers logged in to make changes
- basic auth - basic auth
- since control of the Discord bot would also be through there technically - since control of the Discord bot would also be through there technically
- add status description to member cards - Log output section on webpage, to see who is being assigned to who, when the hit is complete, if it is missed, how many hits a person has done
- Hit Leaderboard?
For now let's pivot to the Discord Bot functionality. What the bot is going to do is for each battle group it needs to assign a friendly member to an enemy member. That friendly will then get a ping in Discord by pulling the list of Discord users and matching the player id to the user in the Discord server. It will ping them and say "New target for @user , attack (link to enemy profile) in the next 30 seconds!" If the enemies status does not change to "In Hospital" in the next 30 seconds that enemy will be assigned to the next player in the group that has not received a hit yet. We will also need to keep track of how many hits a friendly has completed. That way if a new friendly enters a pool they will get a chance to attack before the ones that have not had a chance. We also need a button on the webpage to start and stop the bot

Binary file not shown.

View File

@@ -102,13 +102,21 @@ class BotAssignmentManager:
def get_next_enemy_in_group(self, group_id: str, enemy_ids: list) -> Optional[int]: def get_next_enemy_in_group(self, group_id: str, enemy_ids: list) -> Optional[int]:
""" """
Get the next enemy in the group who needs to be assigned. Get the next enemy in the group who needs to be assigned.
Returns None if all enemies are already assigned. Returns None if all enemies are already assigned or not attackable.
""" """
for eid in enemy_ids: for eid in enemy_ids:
key = f"{group_id}:{eid}" key = f"{group_id}:{eid}"
# If enemy is not currently assigned, return it # If enemy is already assigned, skip them
if key not in self.active_targets: if key in self.active_targets:
return eid continue
# Check if enemy is attackable (status must be "Okay")
enemy = STATE.enemy.get(eid)
if not enemy or enemy.status.lower() != "okay":
continue
# This enemy is available for assignment
return eid
return None return None
async def assignment_loop(self): async def assignment_loop(self):
@@ -176,18 +184,30 @@ class BotAssignmentManager:
print(f"Cannot assign: friendly {friendly_id} or enemy {enemy_id} not found") print(f"Cannot assign: friendly {friendly_id} or enemy {enemy_id} not found")
return return
# Only assign if enemy status is "Okay" (not traveling, hospitalized, etc.)
if enemy.status.lower() != "okay":
print(f"Skipping assignment: {enemy.name} status is '{enemy.status}' (must be 'Okay')")
return
# Get Discord user # Get Discord user
discord_id = self.get_discord_id(friendly_id) discord_id = self.get_discord_id(friendly_id)
if not discord_id: if not discord_id:
print(f"No Discord mapping for Torn ID {friendly_id}") print(f"No Discord mapping for Torn ID {friendly_id} - skipping assignment")
# Record assignment to prevent infinite retries
key = f"{group_id}:{enemy_id}"
self.active_targets[key] = {
"group_id": group_id,
"friendly_id": friendly_id,
"enemy_id": enemy_id,
"discord_id": None,
"assigned_at": datetime.now(),
"reminded": False,
"failed": True
}
return return
discord_user = await self.bot.fetch_user(discord_id) # Record assignment BEFORE attempting to send message
if not discord_user: # This prevents infinite retries if message sending fails
print(f"Discord user {discord_id} not found")
return
# Record assignment
key = f"{group_id}:{enemy_id}" key = f"{group_id}:{enemy_id}"
self.active_targets[key] = { self.active_targets[key] = {
"group_id": group_id, "group_id": group_id,
@@ -195,22 +215,32 @@ class BotAssignmentManager:
"enemy_id": enemy_id, "enemy_id": enemy_id,
"discord_id": discord_id, "discord_id": discord_id,
"assigned_at": datetime.now(), "assigned_at": datetime.now(),
"reminded": False "reminded": False,
"failed": False
} }
# Send Discord message to channel # Fetch Discord user and send message
attack_link = f"https://www.torn.com/loader.php?sid=attack&user2ID={enemy_id}"
message = f"**New target for {discord_user.mention}!**\n\n[**{enemy.name}** (Level {enemy.level})]({attack_link})\n\nYou have {ASSIGNMENT_TIMEOUT} seconds!"
try: try:
discord_user = await self.bot.fetch_user(discord_id)
if not discord_user:
print(f"Discord user {discord_id} not found")
self.active_targets[key]["failed"] = True
return
# Send Discord message to channel
attack_link = f"https://www.torn.com/loader.php?sid=attack&user2ID={enemy_id}"
message = f"**New target for {discord_user.mention}!**\n\n[**{enemy.name}** (Level {enemy.level})]({attack_link})\n\nYou have {ASSIGNMENT_TIMEOUT} seconds!"
channel = self.bot.get_channel(ALLOWED_CHANNEL_ID) channel = self.bot.get_channel(ALLOWED_CHANNEL_ID)
if channel: if channel:
await channel.send(message) await channel.send(message)
print(f"Assigned {enemy.name} to {friendly.name} (Discord: {discord_user.name})") print(f"Assigned {enemy.name} to {friendly.name} (Discord: {discord_user.name})")
else: else:
print(f"Assignment channel {ALLOWED_CHANNEL_ID} not found") print(f"Assignment channel {ALLOWED_CHANNEL_ID} not found")
self.active_targets[key]["failed"] = True
except Exception as e: except Exception as e:
print(f"Failed to send Discord message to channel: {e}") print(f"Failed to send Discord message to channel: {e}")
self.active_targets[key]["failed"] = True
async def monitor_active_targets(self): async def monitor_active_targets(self):
"""Monitor active targets for status changes or timeouts""" """Monitor active targets for status changes or timeouts"""
@@ -220,12 +250,24 @@ class BotAssignmentManager:
for key, data in list(self.active_targets.items()): for key, data in list(self.active_targets.items()):
elapsed = (now - data["assigned_at"]).total_seconds() elapsed = (now - data["assigned_at"]).total_seconds()
# Remove failed assignments after a short delay (don't reassign them)
if data.get("failed", False):
if elapsed >= 30: # Clean up after 30 seconds
print(f"Removing failed assignment: {key}")
del self.active_targets[key]
continue
# Check enemy status # Check enemy status
enemy_id = data["enemy_id"] enemy_id = data["enemy_id"]
enemy = STATE.enemy.get(enemy_id) enemy = STATE.enemy.get(enemy_id)
if enemy and "hospital" in enemy.status.lower(): if not enemy:
# Enemy is hospitalized - success! # Enemy no longer exists, remove assignment
del self.active_targets[key]
continue
# Check if enemy is hospitalized (success!)
if "hospital" in enemy.status.lower():
friendly_id = data["friendly_id"] friendly_id = data["friendly_id"]
if friendly_id in STATE.friendly: if friendly_id in STATE.friendly:
# Increment hit count # Increment hit count
@@ -236,7 +278,13 @@ class BotAssignmentManager:
del self.active_targets[key] del self.active_targets[key]
continue continue
# Send reminder # Check if enemy is no longer attackable (traveling, etc.)
if enemy.status.lower() != "okay":
print(f"Target {enemy.name} is now '{enemy.status}' - removing assignment")
del self.active_targets[key]
continue
# Send reminder (only for successful assignments)
if elapsed >= ASSIGNMENT_REMINDER and not data["reminded"]: if elapsed >= ASSIGNMENT_REMINDER and not data["reminded"]:
discord_id = data["discord_id"] discord_id = data["discord_id"]
try: try: