Skip to content

Commit d63b666

Browse files
author
NozZy
committed
equilibrage (tentative)
1 parent 78ddc20 commit d63b666

1 file changed

Lines changed: 77 additions & 42 deletions

File tree

cogs/pokemon_starter.py

Lines changed: 77 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@ def _to_poke_tuple(entry: list) -> tuple[str | int | None, ...]:
8383
POKEMON_TYPES = ["🌿", "🔥", "💧"]
8484

8585
TYPE_MULTIPLIER = {
86-
("🔥", "🌿"): 1.4,
87-
("🌿", "💧"): 1.4,
88-
("💧", "🔥"): 1.4,
86+
("🔥", "🌿"): 1.25,
87+
("🌿", "💧"): 1.25,
88+
("💧", "🔥"): 1.25,
8989

90-
("🌿", "🔥"): 0.6,
91-
("💧", "🌿"): 0.6,
92-
("🔥", "💧"): 0.6,
90+
("🌿", "🔥"): 0.8,
91+
("💧", "🌿"): 0.8,
92+
("🔥", "💧"): 0.8,
9393
}
9494

9595
COLORS = {
@@ -101,20 +101,48 @@ def _to_poke_tuple(entry: list) -> tuple[str | int | None, ...]:
101101
COMBAT_COOLDOWN = 60 * 5
102102
XP_COOLDOWN = 60
103103

104-
CRIT_CHANCE = 0.07
104+
BASE_HP = 15
105+
HP_PER_LEVEL = 1.8
106+
107+
CRIT_CHANCE = 0.06
105108
CRIT_MULTIPLIER = 1.5
106109

107110
XP_MIN, XP_MAX = 15, 55
108111

109-
DEFAULT = {
110-
"HP": 15,
112+
POKEMON_ENTRY_DEFAULTS = {
113+
"starter": None,
114+
"pokemon": None,
115+
"level": 1,
116+
"xp": 0,
117+
"last_time": None,
118+
"HP": BASE_HP,
119+
"type": None,
111120
"wins": 0,
112121
"losses": 0,
113-
"last_combat": 0
122+
"begin_date": None,
114123
}
115124

116-
POKEMON_DATA_FILE = "data/pokemon_starters.json"
125+
import logging
126+
127+
log = logging.getLogger(__name__)
128+
129+
130+
def normalize_pokemon_entry(entry):
131+
if not isinstance(entry, dict):
132+
log.warning(
133+
"Entrée Pokémon ignorée (type invalide): %r (%s)",
134+
entry, type(entry).__name__
135+
)
136+
return None
137+
138+
for key, default in POKEMON_ENTRY_DEFAULTS.items():
139+
if key not in entry or entry[key] is None:
140+
if key == "begin_date":
141+
entry[key] = datetime.datetime.now().replace(microsecond=0).isoformat()
142+
else:
143+
entry[key] = default
117144

145+
return entry
118146

119147
def pokepedia_url(name: str) -> str:
120148
# remplace espaces par underscore + encode safe URL
@@ -125,7 +153,23 @@ def load_pokemon_data() -> dict:
125153
os.makedirs("data", exist_ok=True)
126154
try:
127155
with open(POKEMON_DATA_FILE, "r", encoding="utf-8") as f:
128-
return json.load(f)
156+
data = json.load(f)
157+
for guild_id, users in list(data.items()):
158+
if not isinstance(users, dict):
159+
log.error("Guild %s a une structure invalide: %r", guild_id, users)
160+
data[guild_id] = {}
161+
continue
162+
163+
for user_id, entry in list(users.items()):
164+
fixed = normalize_pokemon_entry(entry)
165+
if fixed is None:
166+
log.warning(
167+
"Suppression entrée Pokémon invalide | guild=%s user=%s",
168+
guild_id, user_id
169+
)
170+
del users[user_id]
171+
save_pokemon_data(data)
172+
return data
129173
except (FileNotFoundError, json.JSONDecodeError) as e:
130174
logger.error(f"Error reading file: {e}")
131175
return {}
@@ -275,8 +319,14 @@ def power_emoji_for_level(level: int) -> str:
275319
return emoji
276320
return POWER_EMOJIS[-1][1]
277321

322+
323+
def ensure_hp_field(entry: dict) -> None:
324+
if "HP" not in entry or not isinstance(entry["HP"], int):
325+
entry["HP"] = 0
326+
278327
def compute_damage(attacker: dict, defender: dict) -> tuple[int, bool]:
279-
damage_base = attacker["level"] * 0.55 * random.uniform(0.85, 1.35)
328+
damage_base = attacker["level"] * 0.78
329+
rng = random.uniform(0.9, 1.3)
280330

281331
multiplier = TYPE_MULTIPLIER.get(
282332
(attacker["type"], defender["type"]),
@@ -287,8 +337,14 @@ def compute_damage(attacker: dict, defender: dict) -> tuple[int, bool]:
287337
if crit:
288338
multiplier *= CRIT_MULTIPLIER
289339

290-
dmg = round(damage_base * multiplier)
291-
return max(1, dmg), crit
340+
damage = round(damage_base * rng * multiplier)
341+
342+
return max(1, damage), crit
343+
344+
345+
def compute_max_hp(entry: dict) -> int:
346+
ensure_hp_field(entry)
347+
return BASE_HP + int(entry["level"] * HP_PER_LEVEL) + entry["HP"]
292348

293349
def health_bar(current: int, max_hp: int, size: int = 10) -> str:
294350
ratio = current / max_hp if max_hp > 0 else 0
@@ -406,7 +462,6 @@ async def on_message(self, message: discord.Message):
406462
if not entry:
407463
return
408464

409-
entry.setdefault("last_time", DEFAULT.get("last_time"))
410465
now = time.time()
411466
if entry.get("last_time", 0) + XP_COOLDOWN > now:
412467
return
@@ -443,8 +498,6 @@ async def level_up(self, entry: dict, user: discord.Member) -> str | None:
443498
message = None
444499
leveled_up = False
445500

446-
entry.setdefault("HP", DEFAULT.get("HP") + round(1.5 * entry["level"]))
447-
448501
while entry["xp"] >= xp_to_next_level(entry["level"]) and entry["level"] < 100:
449502
entry["xp"] -= xp_to_next_level(entry["level"])
450503
entry["level"] += 1
@@ -507,8 +560,7 @@ async def evolve(self, entry: dict, user: discord.Member, channel: discord.TextC
507560
old_name = entry["pokemon"]
508561
next_name = chain[i + 1][0]
509562
entry["pokemon"] = next_name
510-
entry.setdefault("HP", DEFAULT.get("HP") + round(1.5 * entry["level"]))
511-
entry["HP"] += random.randint(5, 10)
563+
compute_max_hp(entry)
512564

513565
old_id = chain[i][2] if len(chain[i]) > 2 else None
514566
new_id = chain[i + 1][2] if len(chain[i + 1]) > 2 else None
@@ -678,18 +730,7 @@ async def choose_starter(self, interaction: discord.Interaction, choix: str | No
678730
)
679731
return
680732

681-
self.pokemon_data.setdefault(guild_id, {})[user_id] = {
682-
"starter": found_chain[0][0],
683-
"pokemon": found_chain[0][0],
684-
"level": 1,
685-
"xp": 0,
686-
"last_time": DEFAULT.get("last_time"),
687-
"HP": DEFAULT.get("HP"),
688-
"type": starter_type,
689-
"wins": DEFAULT.get("wins"),
690-
"losses": DEFAULT.get("wins"),
691-
"begin_date": datetime.datetime.now().replace(microsecond=0).isoformat()
692-
}
733+
self.pokemon_data.setdefault(guild_id, {})[user_id] = POKEMON_ENTRY_DEFAULTS
693734

694735
save_pokemon_data(self.pokemon_data)
695736

@@ -765,7 +806,7 @@ async def starter(
765806
)
766807
return
767808

768-
entry.setdefault("HP", DEFAULT.get("HP") + round(1.5 * entry["level"]))
809+
compute_max_hp(entry)
769810

770811
chain = STARTER_CHAINS.get(entry["pokemon"].lower(), [])
771812
xp_needed = xp_to_next_level(entry["level"])
@@ -857,9 +898,6 @@ async def combat(self, interaction: discord.Interaction, adversaire: discord.Mem
857898
await interaction.followup.send("Combat annulé !")
858899
return
859900

860-
p1.setdefault("last_combat", now)
861-
p2.setdefault("last_combat", now)
862-
863901
p1["last_combat"] = now
864902
p2["last_combat"] = now
865903

@@ -894,13 +932,10 @@ async def start_combat(
894932
p2: dict,
895933
thread: discord.Thread
896934
):
935+
897936
max_hp1 = hp1 = p1["HP"]
898937
max_hp2 = hp2 = p2["HP"]
899938

900-
for p in (p1, p2):
901-
p.setdefault("wins", DEFAULT.get("wins"))
902-
p.setdefault("losses", DEFAULT.get("losses"))
903-
904939
# Qui commence
905940
if p1["level"] > p2["level"]:
906941
turn = 1
@@ -961,8 +996,8 @@ def format_pokemon_label(pokemon_name: str, trainer: discord.Member) -> str:
961996
msg += "\n# ⚡ **COUP CRITIQUE !**"
962997

963998
msg += (
964-
f"\n\n❤️ **{def_label_1}** : {hp1}/{max_hp1}HP HP\n{bar1}"
965-
f"\n\n❤️ **{def_label_2}** : {hp2}/{max_hp2}HP HP\n{bar2}"
999+
f"\n\n❤️ **{def_label_1}** : {hp1}/{max_hp1}HP\n{bar1}"
1000+
f"\n\n❤️ **{def_label_2}** : {hp2}/{max_hp2}HP\n{bar2}"
9661001
)
9671002

9681003
await thread.send(msg)

0 commit comments

Comments
 (0)