Untitled

 avatar
unknown
python
3 months ago
12 kB
8
Indexable
ATTEMPT_VALUES  = [1, 2, 3, 4, 5, 6]
ATTEMPT_WEIGHTS = [2, 12, 15, 12, 8, 7]

MAX_PASSES = 10
MAX_BALLS  = 10

FAIL_TEXT = [
"Le Pokémon se débat !",
"La Pokéball a rebondit !",
"Il esquive la balle !",
"La Pokéball s'ouvre !",
"Ça y était presque !",
"Il veut te résister !",
"La cible a ésquiver !"
]

UI = {
"caught":   "<:caught:1379044694922760282>",
"uncaught": "<:uncaught:1379044710437617674>",
"waiting":  "<a:waiting:1379500515343470613>",
"success":  "<a:success:1379500529171955722>",
"random":   "<a:random:1379500466945130597>",
"fled":     "<a:fled:1379500541037514833>",
"shiny":    "<a:shiny:1377962995552096388>"
}

db = lambda c: SlashMongo("inventory", c)
items   = db("items")
daycare = db("daycare")
pokedex = db("emojis")
daily   = db("daily")
icons   = db("ressource")

class PokeCatch(View):
    def __init__(self, user_id):
        self.user_id = user_id
        self.filter = {"user_id": str(user_id)}

        self.passes = MAX_PASSES
        self.balls = MAX_BALLS

        self.captured = 0
        self.tries = 0
        self.ended = False
        self.evo_rdy = False

    # -- INIT --

    async def initialize(self):
        data = await icons.find({})
        self.icon = dict((e["type"], e["icon"]) for e in data)
        self.anim = dict((e["type"], e["animated"]) for e in data)

        self.choices = await pokedex.find({})
        self.weights = await self.get_rarity_weights()

    async def get_rarity_weights(self):
        data = await daily.find_one(self.filter) or {}
        badges = data.get("user_badges", [])
        boost = min(1 + 0.02 * len(badges), 1.3)

        return list(
            p["weight"] * boost
            if p["weight"] <= 0.3 else p["weight"]
            for p in self.choices
        )

    # -- ENCOUNTER --

    def get_catch_rate(self):
        chance = (self.pkmn["weight"] ** 1.2) * 0.5
        chance += min((self.tries - 1) * 0.03, 0.1)
        return max(0.05, min(chance, 0.35))

    async def pick_pokemon(self):
        self.pkmn, = pyrandom.choices(
            self.choices, weights=self.weights, k=1
        )
        self.max_tries, = pyrandom.choices(
            ATTEMPT_VALUES, weights=ATTEMPT_WEIGHTS, k=1
        )
        self.tries = 0
        self.p_id = self.pkmn["item_numb"]
        self.p_name = self.pkmn["emoji_name"]
        self.p_emoji = f"<a:{self.p_name}:{self.pkmn['emoji_id']}>"

    async def start_encounter(self, i):
        await self.respond(i, UI["random"], components=False)
        await sleep(0.4)
        await self.pick_pokemon()
        embed = await self.encounter_embed()
        await self.respond(i, self.render_pkmn(), embed)

    # -- UI HELPERS --

    async def respond(self, i, content, embed=None, components=True):
        respond_interaction(
            i, 
            content,
            embed=embed,
            components=self if components else None
        )

    def try_bonus(self):
        if self.ended:
            return ""

        r = pyrandom.random()
        if r < 0.04:
            self.balls += 1
            return "\n\n🎁 Cadeau Bonus : **+1 Pokéball** !"

        if r < 0.08:
            self.passes += 1
            return "\n\n🎁 Cadeau Bonus : **+1 Passe** !"

        return ""

    def embed(self, text, color=0x248046):
        return Message(description=text, color=color)

    def render_pkmn(self):
        emoji = self.anim.get(self.pkmn["types"][0], "🌲")
        return f"{emoji} {self.p_emoji} {emoji}"

    def get_types(self, types):
        return " ".join(
            f"{self.icon.get(t,'')} {t}" 
            for t in types
        )

    def xp_bar(self, current, total, size=10):
        if not total:
            return "▱" * size
        filled = round(current / total * size)
        return "▰" * filled + "▱" * (size - filled)

    def get_rarity(self):
        w = self.pkmn["weight"]
        if w >= 0.5: return "Commun"
        if w >= 0.4: return "Peu commun"
        if w >= 0.2: return "Rare"
        if w >= 0.1: return "Très Rare"
        return "Légendaire"

    async def is_caught(self):
        item = await items.find_one({
            "item_numb": self.p_id,
            **self.filter
        })
        return UI["caught"] if item else UI["uncaught"]

    def check_end_of_hunt(self):
        if self.passes <= 0 or self.balls <= 0:
            self.ended = True

    # -- EMBEDS --

    async def encounter_embed(self):
        status = await self.is_caught()
        types = self.get_types(self.pkmn['types'])
        
        return self.embed(
            "-# 🌿 Nouveau Pokémon sauvage !\n\n"
            f"🔹*N°{self.p_id} :* {status} **{self.p_name}**\n"
            f"🔹*Types :* {types}\n"
            f"🔹*Rareté :* {self.get_rarity()}"
        )

    async def result_embed(self):
        name = f"**{self.p_name}** {self.p_emoji}"

        if self.caught:
            text = f"Et Hop !\n{name} a été capturé ✨"
            text += await self.update_challenge()
            text += await self.add_daycare_xp()
            content, color = UI["success"], 0xFFAC32
        else:
            text = f"Oh Non...\nLe {name} s'enfuit ! 😔"
            content, color = UI["fled"], 0xFF0000

        text += self.bonus

        if self.ended:
            text += (
                f"\n\n⏰ Fin de la chasse.\n"
                f"🏆 Pokémon capturés : **{self.captured}**"
            )

        return self.embed(text, color), content

    # -- CAPTURE FLOW --

    async def throw_ball(self, i):
        roll = pyrandom.random()
        chance = self.get_catch_rate()
        self.caught = roll < chance
        delta = chance - roll

        delay = (
            3.5 if self.caught
            else 2.6 if delta > -0.06 
            else 1.6
        )

        embed = self.embed(
            f"{i.user.mention}\n"
            "lance une **Poké Ball** !",
            0x0094FF
        )
        await self.respond(i, UI["waiting"], embed, False)
        await sleep(delay)

    async def failed_try(self, i):
        embed = self.embed(
            f"❌ **Échec** de la capture...\n"
            f"{pyrandom.choice(FAIL_TEXT)}",
            0xFF0000
        )
        await self.respond(i, self.render_pkmn(), embed)

    async def end_capture(self, i):
        if self.caught:
            await items.update_one(
                {"item_numb": self.p_id, **self.filter},
                {"$inc": {"count": 1}}, 
                upsert=True
            )

        self.check_end_of_hunt()
        self.bonus = self.try_bonus()

        embed, content = await self.result_embed()
        self.update_btns(lock_capture=True)
        await self.respond(i, content, embed)

        if self.ended and not self.evo_rdy:
            self.stop()

    # -- BUTTONS --

    async def verify(self, i):
        if i.user.id != self.user_id:
            return False
        await defer(i, action="update")
        return True

    def update_btns(self, lock_capture=False):
        show_evo = self.ended and self.evo_rdy

        self.update_component(
            "ball",
            label=f"Poké Balls ({self.balls})",
            hidden=show_evo,
            is_disabled=lock_capture
        )

        self.update_component(
            "skip",
            label=f"Passes ({self.passes})",
            hidden=show_evo,
            is_disabled=self.passes <= 0 or self.ended
        )

        self.update_component(
            "evo",
            hidden=not show_evo
        )

    @button(label=f"Poké Balls ({MAX_BALLS})", style="success", custom_id="ball")
    async def capture(self, i, b):
        if not await self.verify(i):
            return

        self.tries += 1
        self.balls -= 1
        self.update_btns()

        await self.throw_ball(i)

        if self.caught:
            self.captured += 1
            return await self.end_capture(i)

        if self.tries >= self.max_tries or self.balls <= 0:
            return await self.end_capture(i)
        
        await self.failed_try(i)

    @button(label=f"Passes ({MAX_PASSES})", style="primary", custom_id="skip")
    async def skip(self, i, b):
        if not await self.verify(i):
            return

        self.passes -= 1
        self.update_btns()

        await self.start_encounter(i)

    @button(label="✨ Évolution", style="success", hidden=True, custom_id="evo")
    async def evolve(self, i, b):
        if not await self.verify(i):
            return
        
        await self.animate_evolution(i, self.evo_data, self.evo)
        self.stop()

    # -- DAYCARE --

    async def add_daycare_xp(self):
        data = await daycare.find_one(self.filter)
        if not data:
            return ""

        gain = pyrandom.randint(10, 20)
        total = data["xp"] + gain
        required = data["xp_required"]

        await daycare.update_one(
            self.filter, {"$inc": {"xp": gain}}
        )

        if total >= required:
            self.evo_rdy = True
            self.evo_data = data
            await self.pick_evolved(data)

        return (
            "\n\n🆙 Ton "
            f"**{data['emoji_name']}** gagne **{gain} XP**\n"
            f"{self.xp_bar(total, required)} "
            f"({min(total, required)}/{required})"
        )
        
    async def pick_evolved(self, data):
        await daycare.delete_one(self.filter)

        self.evo = await pokedex.find_one({
            "item_numb": pyrandom.choice(data["evolution_numb"])
        })

        await items.update_one(
            {"item_numb": self.evo["item_numb"], **self.filter},
            {"$inc": {"count": 1}},
            upsert=True
        )

    async def animate_evolution(self, i, data, evo):
        old = data['emoji_name']
        new = evo['emoji_name']
        glow = UI["shiny"]

        frames = [
            f"{glow}<a:{old}:{data['emoji_id']}>{glow}",
            f"{glow}<a:{new}:{evo['emoji_id']}>{glow}"
        ]

        async def animate(index, _):
            is_final = index == 5
            desc = (
                f"Ton **{old}** évolue en...\n# {new} ! 🎉"
                if is_final else
                f"Quoi ??\nTon **{old}** évolue !"
            )

            content = frames[index % 2]
            embed = self.embed(desc, color=0xFFAC32)

            await self.respond(i, content, embed, False)
            await sleep(0.35)

        loop(6, animate)

    # -- CHALLENGE --

    async def update_challenge(self):
        data = await daily.find_one(self.filter) or {}
        ch = data.get("challenge")

        if not ch:
            return ""

        badge = ch["current_badge"]
        goal  = ch["capture_goal"]
        count = ch["count"]

        if badge not in self.pkmn["types"] or count >= goal:
            return ""

        await daily.update_one(
            self.filter, {"$inc": {"challenge.count": 1}}
        )

        count += 1
        badge_str = self.get_types([badge])

        if count >= goal:
            return f"\n\n🎯 Défi **{badge_str}** terminé !"

        return f"\n\n🎯 Défi **{badge_str}** : {count}/{goal}"


view = PokeCatch(user.id)
await view.initialize()
await view.start_encounter(interaction)

if await view.wait(scope=scope, timeout=60) == "timeout":
    await view.respond(interaction, "⏳ Timeout...", components=False)
    view.stop()
Editor is loading...
Leave a Comment