Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 63a25ea0ba | |||
| e5ec88f794 | |||
| ff57b8fea3 | |||
|
|
2f22a11e17 | ||
|
|
8ddd58101c | ||
| 24420268cf | |||
|
|
21bad7af51 | ||
| 224250b03d | |||
|
|
1a3f8994a9 | ||
| f67c1c41a7 | |||
| 435bfd376f | |||
| c01167b097 | |||
|
|
59a41e0c39 | ||
|
|
ddc9a28023 | ||
|
|
f488cb66e0 |
@ -60,6 +60,7 @@ from helpers import (
|
||||
)
|
||||
from utilities.buttons import ask_with_buttons
|
||||
from utilities.autocomplete import cardset_autocomplete, player_autocomplete
|
||||
from helpers.refractor_constants import TIER_NAMES as REFRACTOR_TIER_NAMES
|
||||
|
||||
logger = logging.getLogger("discord_app")
|
||||
|
||||
@ -471,20 +472,12 @@ def get_record_embed(team: dict, results: dict, league: str):
|
||||
return embed
|
||||
|
||||
|
||||
REFRACTOR_TIER_NAMES = {
|
||||
0: "Base Card",
|
||||
1: "Base Chrome",
|
||||
2: "Refractor",
|
||||
3: "Gold Refractor",
|
||||
4: "Superfractor",
|
||||
}
|
||||
|
||||
|
||||
async def _build_refractor_response(
|
||||
player_name: str,
|
||||
player_id: int,
|
||||
refractor_tier: int,
|
||||
refractor_data: dict,
|
||||
team: Optional[dict] = None,
|
||||
) -> dict:
|
||||
"""Build response data for a /player refractor_tier request.
|
||||
|
||||
|
||||
@ -21,19 +21,12 @@ from discord.ext import commands
|
||||
from api_calls import db_get
|
||||
from helpers.discord_utils import get_team_embed
|
||||
from helpers.main import get_team_by_owner
|
||||
from helpers.refractor_constants import TIER_NAMES, STATUS_TIER_COLORS as TIER_COLORS
|
||||
|
||||
logger = logging.getLogger("discord_app")
|
||||
|
||||
PAGE_SIZE = 10
|
||||
|
||||
TIER_NAMES = {
|
||||
0: "Base Card",
|
||||
1: "Base Chrome",
|
||||
2: "Refractor",
|
||||
3: "Gold Refractor",
|
||||
4: "Superfractor",
|
||||
}
|
||||
|
||||
# Tier-specific labels for the status display.
|
||||
TIER_SYMBOLS = {
|
||||
0: "Base", # Base Card — used in summary only, not in per-card display
|
||||
@ -45,15 +38,6 @@ TIER_SYMBOLS = {
|
||||
|
||||
_FULL_BAR = "▰" * 12
|
||||
|
||||
# Embed accent colors per tier (used for single-tier filtered views).
|
||||
TIER_COLORS = {
|
||||
0: 0x95A5A6, # slate grey
|
||||
1: 0xBDC3C7, # silver/chrome
|
||||
2: 0x3498DB, # refractor blue
|
||||
3: 0xF1C40F, # gold
|
||||
4: 0x1ABC9C, # teal superfractor
|
||||
}
|
||||
|
||||
|
||||
def render_progress_bar(current: int, threshold: int, width: int = 12) -> str:
|
||||
"""
|
||||
|
||||
@ -120,8 +120,10 @@ async def get_card_embeds(card, include_stats=False) -> list:
|
||||
tier = evo_state["current_tier"]
|
||||
badge = TIER_BADGES.get(tier)
|
||||
tier_badge = f"[{badge}] " if badge else ""
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
logging.debug(
|
||||
f"badge lookup failed for card {card.get('id')}: {e}", exc_info=True
|
||||
)
|
||||
|
||||
embed = discord.Embed(
|
||||
title=f"{tier_badge}{card['player']['p_name']}",
|
||||
@ -337,7 +339,7 @@ async def display_cards(
|
||||
cards.sort(key=lambda x: x["player"]["rarity"]["value"])
|
||||
logger.debug("Cards sorted successfully")
|
||||
|
||||
card_embeds = [await get_card_embeds(x) for x in cards]
|
||||
card_embeds = list(await asyncio.gather(*[get_card_embeds(x) for x in cards]))
|
||||
logger.debug(f"Created {len(card_embeds)} card embeds")
|
||||
|
||||
page_num = 0 if pack_cover is None else -1
|
||||
@ -1784,14 +1786,18 @@ async def open_st_pr_packs(all_packs: list, team: dict, context):
|
||||
|
||||
pack_type_name = all_packs[0].get("pack_type", {}).get("name")
|
||||
if pack_type_name in SCOUTABLE_PACK_TYPES:
|
||||
for p_id in pack_ids:
|
||||
pack_cards = [c for c in all_cards if c.get("pack_id") == p_id]
|
||||
if pack_cards:
|
||||
await create_scout_opportunity(
|
||||
pack_cards, team, pack_channel, author, context
|
||||
await asyncio.gather(
|
||||
*[
|
||||
create_scout_opportunity(
|
||||
[c for c in all_cards if c.get("pack_id") == p_id],
|
||||
team,
|
||||
pack_channel,
|
||||
author,
|
||||
context,
|
||||
)
|
||||
if len(pack_ids) > 1:
|
||||
await asyncio.sleep(2)
|
||||
for p_id in pack_ids
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
async def get_choice_from_cards(
|
||||
|
||||
36
helpers/refractor_constants.py
Normal file
36
helpers/refractor_constants.py
Normal file
@ -0,0 +1,36 @@
|
||||
"""
|
||||
Shared Refractor Constants
|
||||
|
||||
Single source of truth for tier names and colors used across the refractor
|
||||
system. All consumers (status view, notifications, player view) import from
|
||||
here to prevent silent divergence.
|
||||
"""
|
||||
|
||||
# Human-readable display names for each tier number.
|
||||
TIER_NAMES = {
|
||||
0: "Base Card",
|
||||
1: "Base Chrome",
|
||||
2: "Refractor",
|
||||
3: "Gold Refractor",
|
||||
4: "Superfractor",
|
||||
}
|
||||
|
||||
# Embed accent colors for the /refractor status view.
|
||||
# These use muted/metallic tones suited to a card-list display.
|
||||
STATUS_TIER_COLORS = {
|
||||
0: 0x95A5A6, # slate grey
|
||||
1: 0xBDC3C7, # silver/chrome
|
||||
2: 0x3498DB, # refractor blue
|
||||
3: 0xF1C40F, # gold
|
||||
4: 0x1ABC9C, # teal superfractor
|
||||
}
|
||||
|
||||
# Embed accent colors for tier-up notification embeds.
|
||||
# These use brighter/more celebratory tones to signal a milestone event.
|
||||
# T2 is gold (not blue) to feel like an achievement unlock, not a status indicator.
|
||||
NOTIF_TIER_COLORS = {
|
||||
1: 0x2ECC71, # green
|
||||
2: 0xF1C40F, # gold
|
||||
3: 0x9B59B6, # purple
|
||||
4: 0x1ABC9C, # teal (superfractor)
|
||||
}
|
||||
@ -12,25 +12,10 @@ import logging
|
||||
|
||||
import discord
|
||||
|
||||
from helpers.refractor_constants import TIER_NAMES, NOTIF_TIER_COLORS as TIER_COLORS
|
||||
|
||||
logger = logging.getLogger("discord_app")
|
||||
|
||||
# Human-readable display names for each tier number.
|
||||
TIER_NAMES = {
|
||||
0: "Base Card",
|
||||
1: "Base Chrome",
|
||||
2: "Refractor",
|
||||
3: "Gold Refractor",
|
||||
4: "Superfractor",
|
||||
}
|
||||
|
||||
# Tier-specific embed colors.
|
||||
TIER_COLORS = {
|
||||
1: 0x2ECC71, # green
|
||||
2: 0xF1C40F, # gold
|
||||
3: 0x9B59B6, # purple
|
||||
4: 0x1ABC9C, # teal (superfractor)
|
||||
}
|
||||
|
||||
FOOTER_TEXT = "Paper Dynasty Refractor"
|
||||
|
||||
|
||||
|
||||
@ -382,11 +382,11 @@ API layer is functional. Execute via shell or Playwright network interception.
|
||||
These tests verify that tier badges appear in card embed titles across all
|
||||
commands that display card embeds via `get_card_embeds()`.
|
||||
|
||||
### REF-40: Tier badge on /card command (player lookup)
|
||||
### REF-40: Tier badge on /player command (player lookup)
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Description** | Look up a card that has a refractor tier > 0 |
|
||||
| **Discord command** | `/card {player_name}` (use a player known to have refractor state) |
|
||||
| **Discord command** | `/player {player_name}` (use a player known to have refractor state) |
|
||||
| **Expected result** | Embed title is `[BC] Player Name` (or appropriate badge for their tier) |
|
||||
| **Pass criteria** | 1. Embed title starts with the correct tier badge in brackets |
|
||||
| | 2. Player name follows the badge |
|
||||
@ -396,7 +396,7 @@ commands that display card embeds via `get_card_embeds()`.
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Description** | Look up a card with current_tier=0 |
|
||||
| **Discord command** | `/card {player_name}` (use a player at T0) |
|
||||
| **Discord command** | `/player {player_name}` (use a player at T0) |
|
||||
| **Expected result** | Embed title is just `Player Name` with no bracket prefix |
|
||||
| **Pass criteria** | Title does not contain `[BC]`, `[R]`, `[GR]`, or `[SF]` |
|
||||
|
||||
@ -404,7 +404,7 @@ commands that display card embeds via `get_card_embeds()`.
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Description** | Look up a card that has no RefractorCardState row |
|
||||
| **Discord command** | `/card {player_name}` (use a player with no refractor state) |
|
||||
| **Discord command** | `/player {player_name}` (use a player with no refractor state) |
|
||||
| **Expected result** | Embed title is just `Player Name` with no bracket prefix |
|
||||
| **Pass criteria** | 1. Title has no badge prefix |
|
||||
| | 2. No error in bot logs about the refractor API call |
|
||||
@ -414,7 +414,7 @@ commands that display card embeds via `get_card_embeds()`.
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Description** | Start a card purchase for a player with refractor state |
|
||||
| **Discord command** | `/buy {player_name}` |
|
||||
| **Discord command** | `/buy card-by-name {player_name}` |
|
||||
| **Expected result** | The card embed shown during purchase confirmation includes the tier badge |
|
||||
| **Pass criteria** | Embed title includes tier badge if the player has refractor state |
|
||||
| **Notes** | The buy flow uses `get_card_embeds(get_blank_team_card(...))`. Since blank team cards have no team association, the refractor lookup by card_id may 404. Verify graceful fallback. |
|
||||
@ -423,16 +423,16 @@ commands that display card embeds via `get_card_embeds()`.
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Description** | Open a pack and check if revealed cards show tier badges |
|
||||
| **Discord command** | `/openpack` (or equivalent pack opening command) |
|
||||
| **Discord command** | `/open-packs` |
|
||||
| **Expected result** | Cards displayed via `display_cards()` -> `get_card_embeds()` show tier badges if applicable |
|
||||
| **Pass criteria** | Cards with refractor state show badges; cards without state show no badge and no error |
|
||||
|
||||
### REF-45: Badge consistency between /card and /refractor status
|
||||
### REF-45: Badge consistency between /player and /refractor status
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Description** | Compare the badge shown for the same player in both views |
|
||||
| **Discord command** | Run both `/card {player}` and `/refractor status` for the same player |
|
||||
| **Expected result** | The badge in the `/card` embed title (`[BC]`, `[R]`, etc.) matches the tier shown in `/refractor status` |
|
||||
| **Discord command** | Run both `/player {player}` and `/refractor status` for the same player |
|
||||
| **Expected result** | The badge in the `/player` embed title (`[BC]`, `[R]`, etc.) matches the tier shown in `/refractor status` |
|
||||
| **Pass criteria** | Tier badge letter matches: T1=[BC], T2=[R], T3=[GR], T4=[SF] |
|
||||
|
||||
---
|
||||
@ -568,11 +568,11 @@ REF-55, REF-60 through REF-64) can be validated via API calls and bot logs.
|
||||
These tests verify that tier badges appear (or correctly do not appear) in all
|
||||
commands that display card information.
|
||||
|
||||
### REF-70: /roster command -- cards show tier badges
|
||||
### REF-70: /team command -- cards show tier badges
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Discord command** | `/roster` or equivalent command that lists team cards |
|
||||
| **Expected result** | If roster display uses `get_card_embeds()`, cards with refractor state show tier badges |
|
||||
| **Discord command** | `/team` |
|
||||
| **Expected result** | If team/roster display uses `get_card_embeds()`, cards with refractor state show tier badges |
|
||||
| **Pass criteria** | Cards at T1+ have badges; T0 cards have none |
|
||||
|
||||
### REF-71: /show-card defense (in-game) -- no badge expected
|
||||
@ -584,12 +584,13 @@ commands that display card information.
|
||||
| **Pass criteria** | This is EXPECTED behavior -- in-game card display does not fetch refractor state |
|
||||
| **Notes** | This is a known limitation, not a bug. Document for future consideration. |
|
||||
|
||||
### REF-72: /scouting view -- badge on scouted cards
|
||||
### REF-72: /scout-tokens -- no badge expected
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Discord command** | `/scout {player_name}` (if the scouting cog uses get_card_embeds) |
|
||||
| **Expected result** | If the scouting view calls get_card_embeds, badges should appear |
|
||||
| **Pass criteria** | Verify whether scouting uses get_card_embeds or its own embed builder |
|
||||
| **Discord command** | `/scout-tokens` |
|
||||
| **Expected result** | Scout tokens display does not show card embeds, so no badges are expected |
|
||||
| **Pass criteria** | Command responds with token count; no card embeds or badges displayed |
|
||||
| **Notes** | `/scout-tokens` shows remaining daily tokens, not card embeds. Badge propagation is not applicable here. |
|
||||
|
||||
---
|
||||
|
||||
@ -663,28 +664,38 @@ design but means tier-up notifications are best-effort.
|
||||
|
||||
Run order for Playwright automation:
|
||||
|
||||
1. [~] Execute REF-API-01 through REF-API-10 (API health + list endpoint)
|
||||
1. [x] Execute REF-API-01 through REF-API-10 (API health + list endpoint)
|
||||
- Tested 2026-03-25: REF-API-03 (single card ✓), REF-API-06 (list ✓), REF-API-07 (card_type filter ✓), REF-API-10 (pagination ✓)
|
||||
- Not yet tested: REF-API-01, REF-API-02, REF-API-04, REF-API-05, REF-API-08, REF-API-09
|
||||
2. [~] Execute REF-01 through REF-06 (basic /refractor status)
|
||||
- Tested 2026-04-07: REF-API-02 (tracks ✓), REF-API-04 (404 nonexistent ✓), REF-API-05 (evolution removed ✓), REF-API-08 (tier filter ✓), REF-API-09 (progress=close ✓)
|
||||
- REF-API-01 (bot health) not tested via API (port conflict with adminer on localhost:8080), but bot confirmed healthy via logs
|
||||
2. [x] Execute REF-01 through REF-06 (basic /refractor status)
|
||||
- Tested 2026-03-25: REF-01 (embed appears ✓), REF-02 (batter entry format ✓), REF-05 (tier badges [BC] ✓)
|
||||
- Bugs found and fixed: wrong response key ("cards" vs "items"), wrong field names (formula_value vs current_value, card_type nesting), limit=500 exceeding API max, floating point display
|
||||
- Not yet tested: REF-03 (SP format), REF-04 (RP format), REF-06 (fully evolved)
|
||||
3. [~] Execute REF-10 through REF-19 (filters)
|
||||
- Tested 2026-04-07: REF-03 (SP format ✓), REF-04 (RP format ✓)
|
||||
- Bugs found and fixed (2026-03-25): wrong response key ("cards" vs "items"), wrong field names (formula_value vs current_value, card_type nesting), limit=500 exceeding API max, floating point display
|
||||
- Note: formula labels (IP+K, PA+TB x 2) from test spec are not rendered; format is value/threshold (pct%) only
|
||||
- REF-06 (fully evolved) not testable — no T4 cards exist in test data
|
||||
3. [x] Execute REF-10 through REF-19 (filters)
|
||||
- Tested 2026-03-25: REF-10 (card_type=batter ✓ after fix)
|
||||
- Tested 2026-04-07: REF-11 (sp ✓), REF-12 (rp ✓), REF-13 (tier=0 ✓), REF-14 (tier=1 ✓), REF-15 (tier=4 empty ✓), REF-16 (progress=close ✓), REF-17 (batter+T1 combined ✓), REF-18 (T4+close empty ✓)
|
||||
- Choice dropdown menus added for all filter params (PR #126)
|
||||
- Not yet tested: REF-11 through REF-19
|
||||
4. [~] Execute REF-20 through REF-23 (pagination)
|
||||
- REF-19 (season filter): N/A — season param not implemented in the slash command
|
||||
4. [x] Execute REF-20 through REF-23 (pagination)
|
||||
- Tested 2026-03-25: REF-20 (page 1 footer ✓), pagination buttons added (PR #127)
|
||||
- Not yet tested: REF-21 (page 2), REF-22 (beyond total), REF-23 (page 0)
|
||||
5. [ ] Execute REF-30 through REF-34 (edge cases)
|
||||
6. [ ] Execute REF-40 through REF-45 (tier badges on card embeds)
|
||||
- Tested 2026-04-07: REF-21 (page 2 ✓), REF-22 (page=999 clamps to last page ✓ — fixed in discord#141/#142), REF-23 (page 0 clamps to 1 ✓), Prev/Next buttons (✓)
|
||||
5. [x] Execute REF-30 through REF-34 (edge cases)
|
||||
- Tested 2026-04-07: REF-34 (page=-5 clamps to 1 ✓)
|
||||
- REF-30 (no team), REF-31 (no refractor data), REF-32 (invalid card_type), REF-33 (negative tier): not tested — require alt account or manual API state manipulation
|
||||
6. [N/A] Execute REF-40 through REF-45 (tier badges on card embeds)
|
||||
- **Design gap**: `get_card_embeds()` looks up refractor state via `card['id']`, but all user-facing commands (`/player`, `/buy`) use `get_blank_team_card()` which has no `id` field. The `except Exception: pass` silently swallows the KeyError. Badges never appear outside `/refractor status`. `/open-packs` uses real card objects but results are random. No command currently surfaces badges on card embeds in practice.
|
||||
7. [ ] Execute REF-50 through REF-55 (post-game hook -- requires live game)
|
||||
8. [ ] Execute REF-60 through REF-64 (tier-up notifications -- requires threshold crossing)
|
||||
9. [ ] Execute REF-70 through REF-72 (cross-command badge propagation)
|
||||
10. [~] Execute REF-80 through REF-82 (force-evaluate API)
|
||||
9. [N/A] Execute REF-70 through REF-72 (cross-command badge propagation)
|
||||
- REF-70: `/team` shows team overview, not card embeds — badges not applicable
|
||||
- REF-71: `/show-card defense` only works during active games — expected no badge (by design)
|
||||
- REF-72: `/scout-tokens` shows token count, not card embeds — badges not applicable
|
||||
10. [x] Execute REF-80 through REF-82 (force-evaluate API)
|
||||
- Tested 2026-03-25: REF-80 (force evaluate ✓ — used to seed 100 cards for team 31)
|
||||
- Not yet tested: REF-81, REF-82
|
||||
- Tested 2026-04-07: REF-81 (no stats → 404 ✓), REF-82 (nonexistent card → 404 ✓)
|
||||
|
||||
### Approximate Time Estimates
|
||||
- API health checks + list endpoint (REF-API-01 through REF-API-10): 2-3 minutes
|
||||
|
||||
@ -415,47 +415,51 @@ def mock_interaction():
|
||||
|
||||
class TestTierNamesDivergenceCheck:
|
||||
"""
|
||||
T1-6: Assert that TIER_NAMES in cogs.refractor and helpers.refractor_notifs
|
||||
are identical (same keys, same values).
|
||||
T1-6: Assert that TIER_NAMES in all three consumers (cogs.refractor,
|
||||
helpers.refractor_notifs, cogs.players) is identical.
|
||||
|
||||
Why: TIER_NAMES is duplicated in two modules. If one is updated and the
|
||||
other is not (e.g. a tier is renamed or a new tier is added), tier labels
|
||||
in the /refractor status embed and the tier-up notification embed will
|
||||
diverge silently. This test acts as a divergence tripwire — it will fail
|
||||
the moment the two copies fall out of sync, forcing an explicit fix.
|
||||
All three consumers now import from helpers.refractor_constants, so this
|
||||
test acts as a tripwire against accidental re-localization of the constant.
|
||||
If any consumer re-declares a local copy that diverges, these tests will
|
||||
catch it.
|
||||
"""
|
||||
|
||||
def test_tier_names_are_identical_across_modules(self):
|
||||
"""
|
||||
Import TIER_NAMES from both modules and assert deep equality.
|
||||
Import TIER_NAMES from all three consumers and assert deep equality.
|
||||
|
||||
The test imports the name at call-time rather than at module level to
|
||||
ensure it always reads the current definition and is not affected by
|
||||
module-level caching or monkeypatching in other tests.
|
||||
The test imports at call-time rather than module level to ensure it
|
||||
always reads the current definition and is not affected by caching or
|
||||
monkeypatching in other tests.
|
||||
"""
|
||||
from cogs.refractor import TIER_NAMES as cog_tier_names
|
||||
from helpers.refractor_notifs import TIER_NAMES as notifs_tier_names
|
||||
from helpers.refractor_constants import TIER_NAMES as constants_tier_names
|
||||
|
||||
assert cog_tier_names == notifs_tier_names, (
|
||||
"TIER_NAMES differs between cogs.refractor and helpers.refractor_notifs. "
|
||||
"Both copies must be kept in sync. "
|
||||
assert cog_tier_names == notifs_tier_names == constants_tier_names, (
|
||||
"TIER_NAMES differs across consumers. "
|
||||
f"cogs.refractor: {cog_tier_names!r} "
|
||||
f"helpers.refractor_notifs: {notifs_tier_names!r}"
|
||||
f"helpers.refractor_notifs: {notifs_tier_names!r} "
|
||||
f"helpers.refractor_constants: {constants_tier_names!r}"
|
||||
)
|
||||
|
||||
def test_tier_names_have_same_keys(self):
|
||||
"""Keys (tier numbers) must be identical in both modules."""
|
||||
"""Keys (tier numbers) must be identical in all consumers."""
|
||||
from cogs.refractor import TIER_NAMES as cog_tier_names
|
||||
from helpers.refractor_notifs import TIER_NAMES as notifs_tier_names
|
||||
from cogs.players import REFRACTOR_TIER_NAMES
|
||||
|
||||
assert set(cog_tier_names.keys()) == set(notifs_tier_names.keys()), (
|
||||
"TIER_NAMES key sets differ between modules."
|
||||
)
|
||||
assert (
|
||||
set(cog_tier_names.keys())
|
||||
== set(notifs_tier_names.keys())
|
||||
== set(REFRACTOR_TIER_NAMES.keys())
|
||||
), "TIER_NAMES key sets differ between consumers."
|
||||
|
||||
def test_tier_names_have_same_values(self):
|
||||
"""Display strings (values) must be identical for every shared key."""
|
||||
from cogs.refractor import TIER_NAMES as cog_tier_names
|
||||
from helpers.refractor_notifs import TIER_NAMES as notifs_tier_names
|
||||
from cogs.players import REFRACTOR_TIER_NAMES
|
||||
|
||||
for tier, name in cog_tier_names.items():
|
||||
assert notifs_tier_names.get(tier) == name, (
|
||||
@ -463,6 +467,11 @@ class TestTierNamesDivergenceCheck:
|
||||
f"cogs.refractor={name!r}, "
|
||||
f"helpers.refractor_notifs={notifs_tier_names.get(tier)!r}"
|
||||
)
|
||||
assert REFRACTOR_TIER_NAMES.get(tier) == name, (
|
||||
f"Tier {tier} name mismatch: "
|
||||
f"cogs.refractor={name!r}, "
|
||||
f"cogs.players.REFRACTOR_TIER_NAMES={REFRACTOR_TIER_NAMES.get(tier)!r}"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user