chore(release): v2.2.3 - fixed bug causing basic lands to not be added; updated removal tagging logic causing non-removal cards to be tagged due to wording

This commit is contained in:
mwisnowski 2025-09-01 20:20:04 -07:00
parent a0a12baa9b
commit fe9aabbce9
9 changed files with 48 additions and 16 deletions

View file

@ -1030,15 +1030,25 @@ class DeckBuilder(
# Allow the commander to bypass this check.
try:
if not is_commander:
df_src = self._full_cards_df if self._full_cards_df is not None else self._combined_cards_df
if df_src is not None and not df_src.empty and 'name' in df_src.columns:
if df_src[df_src['name'].astype(str).str.lower() == str(card_name).lower()].empty:
# Not in the legal pool (likely off-color or unavailable)
try:
self.output_func(f"Skipped illegal/off-pool card: {card_name}")
except Exception:
pass
return
# Permit basic lands even if they aren't present in the current CSV pool.
# Some distributions may omit basics from the per-color card CSVs, but they are
# always legal within color identity. We therefore bypass pool filtering for
# basic/snow basic lands and Wastes.
try:
basic_names = bu.basic_land_names()
except Exception:
basic_names = set()
if str(card_name) not in basic_names:
df_src = self._full_cards_df if self._full_cards_df is not None else self._combined_cards_df
if df_src is not None and not df_src.empty and 'name' in df_src.columns:
if df_src[df_src['name'].astype(str).str.lower() == str(card_name).lower()].empty:
# Not in the legal pool (likely off-color or unavailable)
try:
self.output_func(f"Skipped illegal/off-pool card: {card_name}")
except Exception:
pass
return
except Exception:
# If any unexpected error occurs, fall through (do not block legitimate adds)
pass

View file

@ -496,7 +496,18 @@ REMOVAL_TEXT_PATTERNS: List[str] = [
REMOVAL_SPECIFIC_CARDS: List[str] = ['from.*graveyard.*hand']
REMOVAL_EXCLUSION_PATTERNS: List[str] = []
REMOVAL_EXCLUSION_PATTERNS: List[str] = [
# Ignore self-targeting effects so they aren't tagged as spot removal
# Exile self
r'exile target.*you control',
r'exiles target.*you control',
# Destroy self
r'destroy target.*you control',
r'destroys target.*you control',
# Bounce self to hand
r'return target.*you control.*to.*hand',
r'returns target.*you control.*to.*hand',
]
REMOVAL_KEYWORDS: List[str] = []

View file

@ -6775,9 +6775,10 @@ def tag_for_removal(df: pd.DataFrame, color: str) -> None:
# Create masks for different removal patterns
text_mask = create_removal_text_mask(df)
exclude_mask = create_removal_exclusion_mask(df)
# Combine masks
final_mask = text_mask
# Combine masks (and exclude self-targeting effects like 'target permanent you control')
final_mask = text_mask & (~exclude_mask)
# Apply tags via rules engine
tag_utils.apply_rules(df, rules=[