Auto merge dev → main (#1341)
* chore(tally): remove /dev-tally testing command Feature is verified working; drop the dev-only manual win/loss command and its now-unused apply_manual_result helper and test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(tally): rename /tally-wipe to /tally-clear Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+3
-79
@@ -4242,7 +4242,7 @@ async def set_player_perm_error(interaction, error):
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
# /tally-claim · /tally-transfer · /tally-wipe — live VC scoreline tracking
|
||||
# /tally-claim · /tally-transfer · /tally-clear — live VC scoreline tracking
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
def _invoker_voice_channel(interaction: discord.Interaction):
|
||||
@@ -4339,13 +4339,13 @@ async def tally_transfer(interaction: discord.Interaction, username: str):
|
||||
|
||||
|
||||
@bot.tree.command(
|
||||
name="tally-wipe",
|
||||
name="tally-clear",
|
||||
description=command_locale(
|
||||
"Clear the active tally on your current voice channel",
|
||||
"commands.tally.description_wipe",
|
||||
),
|
||||
)
|
||||
async def tally_wipe(interaction: discord.Interaction):
|
||||
async def tally_clear(interaction: discord.Interaction):
|
||||
lang = await guild_lang(interaction.guild.id) if interaction.guild else "en"
|
||||
vc = _invoker_voice_channel(interaction)
|
||||
if vc is None:
|
||||
@@ -4362,82 +4362,6 @@ async def tally_wipe(interaction: discord.Interaction):
|
||||
)
|
||||
|
||||
|
||||
@bot.tree.command(
|
||||
name="dev-tally",
|
||||
description="[DEV] Manually attribute a win or loss to the tally in your voice channel",
|
||||
)
|
||||
@app_commands.describe(
|
||||
result="Whether to record a win or a loss",
|
||||
username="The player to attribute it to (use alone, not with squadron)",
|
||||
squadron="The squadron to attribute it to (use alone, not with username)",
|
||||
)
|
||||
@app_commands.choices(result=[
|
||||
app_commands.Choice(name="Win", value="win"),
|
||||
app_commands.Choice(name="Loss", value="loss"),
|
||||
])
|
||||
@discord.app_commands.autocomplete(username=player_autocomplete, squadron=squadron_autocomplete)
|
||||
async def dev_tally(interaction: discord.Interaction, result: app_commands.Choice[str],
|
||||
username: str = "", squadron: str = ""):
|
||||
await collect_command_stats(interaction)
|
||||
if not await is_dev_team(interaction):
|
||||
await interaction.response.send_message(t("en", "dev.restricted_dev_team"), ephemeral=True)
|
||||
return
|
||||
lang = await guild_lang(interaction.guild.id) if interaction.guild else "en"
|
||||
vc = _invoker_voice_channel(interaction)
|
||||
if vc is None:
|
||||
await interaction.response.send_message(t(lang, "commands.tally.not_in_vc"), ephemeral=True)
|
||||
return
|
||||
username = username.strip()
|
||||
squadron = squadron.strip()
|
||||
if username and squadron:
|
||||
await interaction.response.send_message(
|
||||
"Use `username` or `squadron` separately — don't pass both.", ephemeral=True
|
||||
)
|
||||
return
|
||||
if not username and not squadron:
|
||||
await interaction.response.send_message(
|
||||
"Provide a `username` or a `squadron` to attribute the result to.", ephemeral=True
|
||||
)
|
||||
return
|
||||
if not interaction.guild_id:
|
||||
await interaction.response.send_message(t(lang, "commands.tally.not_in_vc"), ephemeral=True)
|
||||
return
|
||||
active = tally.get(interaction.guild_id, vc.id)
|
||||
if active is None:
|
||||
await interaction.response.send_message(
|
||||
t(lang, "commands.tally.no_active", channel=vc.name), ephemeral=True
|
||||
)
|
||||
return
|
||||
# Only attribute the result if the argument matches what this VC tracks —
|
||||
# a player arg must match a player-mode tally's target; a squadron arg must
|
||||
# match a squadron-mode tally's target (tag-insensitive). Mirrors how a real
|
||||
# finished game only counts when the tracked entity actually played.
|
||||
if username:
|
||||
matches = active.mode == "player" and active.target.strip().lower() == username.lower()
|
||||
else:
|
||||
matches = active.mode == "squadron" and \
|
||||
tally.strip_tag(active.target).lower() == tally.strip_tag(squadron).lower()
|
||||
if not matches:
|
||||
await interaction.response.send_message(
|
||||
f"This VC is tracking the {active.mode} **{active.display_target}** — "
|
||||
f"**{username or squadron}** doesn't match it, so nothing was recorded.",
|
||||
ephemeral=True,
|
||||
)
|
||||
return
|
||||
tly = tally.apply_manual_result(interaction.guild_id, vc.id, result.value)
|
||||
if tly is None:
|
||||
await interaction.response.send_message(
|
||||
t(lang, "commands.tally.no_active", channel=vc.name), ephemeral=True
|
||||
)
|
||||
return
|
||||
await tally.push_status(tly)
|
||||
await interaction.response.send_message(
|
||||
f"Recorded a **{result.name}** for **{username or squadron}** in **{vc.name}** "
|
||||
f"(`{tly.wins}W-{tly.losses}L`).",
|
||||
ephemeral=True,
|
||||
)
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
# /view-player-games — Last 20 games for a player
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
+1
-1
@@ -861,7 +861,7 @@
|
||||
"not_in_vc": "You must be connected to a voice channel to use this.",
|
||||
"premium_required": "This is a premium feature. Use /unlock to enable it for this server.",
|
||||
"need_one_input": "Provide exactly one of `ign` or `squadron_short`.",
|
||||
"already_active": "A tally is already active in **{channel}** tracking **{target}**. Use /tally-transfer or /tally-wipe first.",
|
||||
"already_active": "A tally is already active in **{channel}** tracking **{target}**. Use /tally-transfer or /tally-clear first.",
|
||||
"claimed": "Now tracking **{target}** in **{channel}**. Status set to `0W-0L`.",
|
||||
"no_active": "There is no active tally in **{channel}**.",
|
||||
"transferred": "Tally in **{channel}** now tracking **{target}** (count carried over: `{base}`).",
|
||||
|
||||
@@ -217,28 +217,6 @@ def wipe(guild_id: int, channel_id: int) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def apply_manual_result(guild_id: int, channel_id: int, kind: str,
|
||||
opponent: str = "DEV") -> Optional["Tally"]:
|
||||
"""Manually bump a VC's active tally by a win or loss (dev/testing).
|
||||
|
||||
``kind`` is "win" or "loss". Mirrors what a finished game would do but with
|
||||
no real opponent, so ``last_opponent`` is set to a fixed label. Returns the
|
||||
updated tally, or None if the VC has no active tally.
|
||||
"""
|
||||
tly = _REGISTRY.get((guild_id, channel_id))
|
||||
if tly is None:
|
||||
return None
|
||||
if kind == "win":
|
||||
tly.wins += 1
|
||||
else:
|
||||
tly.losses += 1
|
||||
tly.last_result_kind = kind
|
||||
tly.last_opponent = opponent
|
||||
tly.last_update_ts = time.time()
|
||||
_save()
|
||||
return tly
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Voice-status HTTP helper
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -133,25 +133,6 @@ def test_squadron_mode_matches_bare_name_despite_resolved_short():
|
||||
assert team_index_for(t, _teams_resolved_mismatch()) == 0
|
||||
|
||||
|
||||
def test_apply_manual_result_win_and_loss():
|
||||
import tempfile
|
||||
import BOT.tally as tal
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
tal.TALLY_PATH = Path(d) / "TALLY.json"
|
||||
tal._REGISTRY.clear()
|
||||
tal.claim(1, 2, "player", "bravo", "Bravo", user_id=7)
|
||||
win = tal.apply_manual_result(1, 2, "win")
|
||||
assert win is not None
|
||||
assert (win.wins, win.losses) == (1, 0)
|
||||
assert win.last_result_kind == "win" and win.last_opponent == "DEV"
|
||||
loss = tal.apply_manual_result(1, 2, "loss")
|
||||
assert loss is not None
|
||||
assert (loss.wins, loss.losses) == (1, 1)
|
||||
assert loss.last_result_kind == "loss" and loss.last_opponent == "DEV"
|
||||
# No active tally in a different VC → None
|
||||
assert tal.apply_manual_result(1, 999, "win") is None
|
||||
|
||||
|
||||
def _run():
|
||||
fns = [v for k, v in sorted(globals().items()) if k.startswith("test_")]
|
||||
for fn in fns:
|
||||
|
||||
Reference in New Issue
Block a user