Untitled
Melon
python
2 months ago
12 kB
6
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 esquivé !"
]
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")
# -------------------- VIEW --------------------
class PokeCatch(View):
def __init__(self, user_id):
self.user_id = user_id
self.query = {"user_id": str(user_id)}
self.passes = MAX_PASSES
self.balls = MAX_BALLS
self.tries = 0
self.captures = 0
self.ended = False
self.evo_rdy = False
self.crit = False
# ---------------- INIT ----------------
async def initialize(self):
await self._load_icons()
await self._load_pokedex()
await self._load_user()
async def _load_icons(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)
async def _load_pokedex(self):
self.choices = await pokedex.find({})
self.weights = list(p["weight"] for p in self.choices)
async def _load_user(self):
data = await daily.find_one(self.query) or {}
self.badges = len(data.get("user_badges", []))
# ---------------- ENCOUNTER ----------------
async def start_encounter(self, i):
await self.reply(i, UI["random"], btns=False)
await sleep(0.4)
await self.pick_pokemon()
embed = await self.encounter_embed()
await self.reply(i, self.render_pkmn(), embed)
def _reset_state(self):
self.tries = 0
self.caught = False
self.crit = False
self.bonus = ""
def _set_current(self):
p = self.pkmn
self.p_id = p["item_numb"]
self.p_name = p["emoji_name"]
self.p_emoji = f"<a:{self.p_name}:{p['emoji_id']}>"
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._set_current()
self._reset_state()
# ---------------- HELPERS ----------------
async def reply(self, i, content, embed=None, btns=True):
respond_interaction(
i,
content,
embed=embed,
components=self if btns else None
)
def embed(self, text, color=0x248046):
return Message(description=text, color=color)
def render_pkmn(self):
e = self.anim.get(self.pkmn["types"][0], "🌲")
return f"{e} {self.p_emoji} {e}"
def xp_bar(self, cur, total, size=10):
if not total:
return "▱" * size
fill = round(cur / total * size)
return "▰" * fill + "▱" * (size - fill)
def get_types(self, types):
return " ".join(
f"{self.icon.get(t,'')} {t}" for t in types
)
def get_rarity(self):
w = self.pkmn["weight"]
if w >= 0.6: return "Très Commun"
if w >= 0.5: return "Commun"
if w >= 0.4: return "Peu commun"
if w >= 0.3: return "Rare"
if w >= 0.2: return "Très Rare"
if w >= 0.1: return "Mythique ✨"
return "Légendaire 👑"
# ---------------- CATCH RATE ----------------
def get_catch_rate(self):
w = self.pkmn["weight"]
chance = (w ** 1.2) * 0.5
chance += min((self.tries - 1) * 0.03, 0.1)
return max(0.06, min(chance, 0.4))
def resolve(self, roll, chance):
crit_ch = min(0.15, 0.003 * self.badges)
crit = pyrandom.random() < crit_ch
return (roll < chance) or crit, crit
# ---------------- 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 is_caught(self):
item = await items.find_one({
"item_numb": self.p_id,
**self.query
})
return UI["caught"] if item else UI["uncaught"]
async def win_text(self, name):
intro = "💥 Capture Critique !\n" if self.crit else ""
txt = f"{intro}Et Hop !\n{name} a été capturé ✨"
txt += await self.update_challenge()
txt += await self.add_daycare_xp()
return txt
async def result_embed(self):
name = f"**{self.p_name}** {self.p_emoji}"
if self.caught:
txt = await self.win_text(name)
content, color = UI["success"], 0xFFAC32
else:
txt = f"Oh Non...\nLe {name} s'enfuit ! 😔"
content, color = UI["fled"], 0xFF0000
if self.bonus:
txt += f"\n\n🎁 Cadeau Bonus : {self.bonus}"
if self.ended:
txt += (
"\n\n⏰ Fin de la chasse.\n"
f"🏆 Pokémon capturés : **{self.captures}**"
)
return self.embed(txt, color), content
# ---------------- BALL FLOW ----------------
async def throw_ball(self, i):
roll = pyrandom.random()
chance = self.get_catch_rate()
caught, crit = self.resolve(roll, chance)
self.caught, self.crit = caught, crit
delay = self.calc_delay(roll, chance)
emb = self.embed(
f"{i.user.mention}\n"
"lance une **Poké Ball** !",
0x0094FF
)
await self.reply(i, UI["waiting"], emb, False)
await sleep(delay)
def calc_delay(self, roll, chance):
delta = chance - roll
if self.crit: return 1.2
if self.caught: return 3.5
if delta > -0.06: return 2.6
return 1.6
async def failed_try(self, i):
txt = pyrandom.choice(FAIL_TEXT)
emb = self.embed(f"❌ **Échec**\n{txt}", 0xFF0000)
await self.reply(i, self.render_pkmn(), emb)
# ---------------- END FLOW ----------------
async def end_capture(self, i):
if self.caught:
await self.save_item()
if self.passes <= 0 or self.balls <= 0:
self.ended = True
self.bonus = self.try_bonus()
emb, content = await self.result_embed()
self.update_btns(lock_capture=True)
await self.reply(i, content, emb)
if self.ended and not self.evo_rdy:
self.stop()
async def save_item(self):
await items.update_one(
{"item_numb": self.p_id, **self.query},
{"$inc": {"count": 1}},
upsert=True
)
def try_bonus(self):
if self.ended:
return ""
r = pyrandom.random()
if r < 0.04:
self.balls += 1
return "**+1 Pokéball**"
if r < 0.08:
self.passes += 1
return "**+1 Passe**"
return ""
# ---------------- 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):
self.update_component(
"ball",
label=f"Poké Balls ({self.balls})",
hidden=self.evo_rdy,
is_disabled=lock_capture
)
self.update_component(
"skip",
label=f"Passes ({self.passes})",
hidden=self.evo_rdy,
is_disabled=self.passes <= 0 or self.ended
)
self.update_component(
"evo",
hidden=not self.evo_rdy
)
# ---------------- BUTTON ACTIONS ----------------
@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.captures += 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
self.evo_rdy = False
self.update_btns(lock_capture=True)
await self.evolve_anim(i, self.evo_data, self.evo)
if self.ended:
self.stop()
# ---------------- DAYCARE ----------------
async def add_daycare_xp(self):
data = await daycare.find_one(self.query)
if not data:
return ""
gain = pyrandom.randint(10, 20)
total = data["xp"] + gain
req = data["xp_required"]
await daycare.update_one(
self.query, {"$inc": {"xp": gain}}
)
if total >= req:
self.evo_rdy = True
self.evo_data = data
await self.pick_evolved(data)
bar = self.xp_bar(total, req)
txt = (
f"\n\n🆙 **{data['emoji_name']}** gagne **{gain} XP**\n"
f"{bar} ({min(total, req)}/{req})"
)
if self.evo_rdy:
txt += "\n-# 🚀 Prêt à évoluer !"
return txt
async def pick_evolved(self, data):
await daycare.delete_one(self.query)
self.evo = await pokedex.find_one({
"item_numb": pyrandom.choice(data["evolution_numb"])
})
await items.update_one(
{"item_numb": self.evo["item_numb"], **self.query},
{"$inc": {"count": 1}},
upsert=True
)
# ---------------- EVOLUTION ----------------
async def evolve_anim(self, i, data, evo):
old = data["emoji_name"]
new = evo["emoji_name"]
glow = UI["shiny"]
frames = [
f"<a:{old}:{data['emoji_id']}>",
f"<a:{new}:{evo['emoji_id']}>"
]
async def animate(idx, _):
final = idx == 5
desc = (
f"Ton **{old}** évolue en...\n# {new} ! 🎉"
if final else
f"Quoi ?? {old} évolue !"
)
content = f"{glow}{frames[idx & 1]}{glow}"
embed = self.embed(desc, 0xFFAC32)
btns = self if final else False
await self.reply(i, content, embed, btns)
await sleep(0.35)
loop(6, animate)
view = PokeCatch(user.id)
await view.initialize()
await view.start_encounter(interaction)
exit_code = await view.wait(scope=scope, timeout=600)
if exit_code == "timeout":
await view.reply(interaction, "⏳ Timeout...", btns=False)
view.stop()Editor is loading...
Leave a Comment