From 6dbd8f09ca5d0b646b8e6f3b5466c47a19dacbe7 Mon Sep 17 00:00:00 2001 From: esefxdz Date: Sat, 11 Jul 2026 18:06:12 +0300 Subject: [PATCH] fix pool filtering exclude welfare and limited from regular, remove pull embed, single process --- blue_archive/data.py | 28 +++++++++++++++++----------- blue_archive/gacha.py | 39 ++++++--------------------------------- 2 files changed, 23 insertions(+), 44 deletions(-) diff --git a/blue_archive/data.py b/blue_archive/data.py index f3f95ab..9fe3d96 100644 --- a/blue_archive/data.py +++ b/blue_archive/data.py @@ -63,8 +63,6 @@ def wiki_portrait_url(student: dict) -> str: def schale_portrait_url(student_id: int) -> str: """Full-body sprite URL (fallback if wiki portrait is unavailable).""" return f"{SCHALE_PORTRAIT}/{student_id}.webp" -PORTRAIT_BASE = "https://raw.githubusercontent.com/SchaleDB/SchaleDB/main/images/student/portrait" -ICON_BASE = "https://raw.githubusercontent.com/SchaleDB/SchaleDB/main/images/student/icon" class StudentDB: @@ -83,36 +81,44 @@ class StudentDB: with open(BUNDLED_DB, "r", encoding="utf-8") as f: self.students = json.load(f) + excluded = 0 for s in self.students: sid = s["Id"] name = s["Name"].lower() rarity = s["StarGrade"] + limit = s.get("IsLimited") or 0 self.by_id[sid] = s self.by_name[name] = s + + # Exclude welfare/event characters (IsLimited >= 2) from pullable pool + if limit >= 2: + excluded += 1 + continue + if rarity in self.by_rarity: self.by_rarity[rarity].append(s) self._loaded = True log.info( - "Loaded %d students (1*: %d, 2*: %d, 3*: %d)", + "Loaded %d students (1*: %d, 2*: %d, 3*: %d) — %d welfare excluded", len(self.students), len(self.by_rarity[1]), len(self.by_rarity[2]), len(self.by_rarity[3]), + excluded, ) - def get(self, student_id: int) -> Optional[dict]: - return self.by_id.get(student_id) + def random_by_rarity(self, rarity: int, exclude_limited: bool = False) -> dict: + """Pick a random student of the given base rarity. - def get_by_name(self, name: str) -> Optional[dict]: - return self.by_name.get(name.lower()) - - def random_by_rarity(self, rarity: int) -> dict: - """Pick a random student of the given base rarity (1, 2, or 3).""" + If exclude_limited is True, only returns standard-pool characters + (IsLimited == 0). Used by Regular Recruitment to exclude banner-only units. + """ pool = self.by_rarity.get(rarity, []) + if exclude_limited: + pool = [s for s in pool if (s.get("IsLimited") or 0) == 0] if not pool: - # Fallback: any student pool = self.students return random.choice(pool) diff --git a/blue_archive/gacha.py b/blue_archive/gacha.py index c4ffe2b..d647fdc 100644 --- a/blue_archive/gacha.py +++ b/blue_archive/gacha.py @@ -230,6 +230,9 @@ class BlueArchiveGacha(commands.Cog): # "Opening envelope" teaser teaser = await ctx.reply("Opening recruitment envelope" + ("s..." if count > 1 else "...")) + # Determine pool scope: regular banner excludes limiteds + is_regular = (banner_id is None or banner_id == "regular") + # Perform pulls pulls = [] for i in range(count): @@ -239,7 +242,7 @@ class BlueArchiveGacha(commands.Cog): r = PULL10_RATES rarity = roll_rarity(r) - student = db.random_by_rarity(rarity) + student = db.random_by_rarity(rarity, exclude_limited=is_regular) # Check for rate-up weighting (simplified: 30% chance to hit rate-up if 3★) if banner and rarity == 3 and banner.get("rateups"): @@ -267,43 +270,13 @@ class BlueArchiveGacha(commands.Cog): async with ctx.typing(): img_bytes = await render_pull(pulls, banner_name, spark) - # Build summary embed - rarity_counts = {3: 0, 2: 0, 1: 0} - for p in pulls: - rarity_counts[p["StarGrade"]] += 1 - - summary_lines = [f"{p['StarGrade']}★ {p['Name']}" for p in pulls] - summary_text = "\n".join(summary_lines) - - best = max(pulls, key=lambda p: p["StarGrade"]) - embed = discord.Embed( - title=f"{count}x Recruitment Result", - description=summary_text, - color={ - 3: 0xF0C040, - 2: 0xB478DC, - 1: 0x64A0DC, - }.get(best["StarGrade"], 0x5BA0D0), - ) - embed.add_field( - name="Summary", - value=f"3★: {rarity_counts[3]} | 2★: {rarity_counts[2]} | 1★: {rarity_counts[1]}", - ) - embed.add_field(name="Banner", value=banner_name, inline=False) - embed.add_field( - name="Recruitment Points", - value=f"{spark}/{SPARK_TARGET} {'-- Spark Ready!' if spark >= SPARK_TARGET else ''}", - ) - embed.set_footer(text=f"Top pull: {best['StarGrade']}★ {best['Name']} ({best.get('School', '')})") - - # Send image and embed + # Send image only — the picture says it all file = discord.File(img_bytes, filename="gacha_result.png") - embed.set_image(url="attachment://gacha_result.png") try: await teaser.delete() except (discord.NotFound, discord.Forbidden): pass - await ctx.reply(file=file, embed=embed) + await ctx.reply(file=file) @commands.command(name="spark") async def spark(self, ctx: commands.Context, *, character_name: str = "") -> None: