Files
COC_API/app/game/systems/leveling.py

106 lines
4.1 KiB
Python

# utils/leveling.py
from typing import Dict, Any, Callable, Optional, List, Tuple
from app.game.generators.level_progression import LevelProgression
from app.game.models.entities import Entity
from app.game.generators.abilities_factory import newly_unlocked_abilities
def set_level(entity:Entity, target_level: int, prog: LevelProgression) -> None:
"""
Snap an entity to a *specific* level. Sets XP to that level's floor.
Optionally applies all level-up rewards from current_level+1 .. target_level (idempotent if you recompute stats from level).
"""
# ensures we never try to go above the max level in the game
target_level = max(1, min(target_level, prog.max_level))
current = entity.level
# if not changing levels, just set the xp and move along
if current == target_level:
entity.xp = prog.xp_for_level(target_level)
_recalc(entity)
# Set final level + floor XP
entity.level = target_level
entity.xp = prog.xp_for_level(target_level)
# set next level xp as xp needed for next level
entity.xp_to_next_level = prog.xp_for_level(target_level + 1)
spells_list = newly_unlocked_abilities(class_name=entity.profession.name,
path="Hellknight",
level=target_level,
per_tier=1,
primary=entity.profession.primary_stat)
_add_abilities(entity,spells_list)
_recalc(entity)
def grant_xp(entity:Entity, amount: int, prog: LevelProgression) -> Tuple[int, int]:
"""
Add XP and auto-level if thresholds crossed.
Returns (old_level, new_level).
"""
old_level = entity.level or 1
entity.xp = entity.xp + int(amount)
new_level = prog.level_for_xp(entity.xp)
if new_level > old_level:
for L in range(old_level + 1, new_level + 1):
spells_list = newly_unlocked_abilities(class_name=entity.profession.name,
path="Hellknight",
level=new_level,
per_tier=1,
primary=entity.profession.primary_stat)
_add_abilities(entity,spells_list)
if new_level > old_level:
entity.level = new_level
_recalc(entity)
# --- compute XP to next level ---
if new_level >= prog.max_level:
# Maxed out
entity.xp_to_next_level = 0
else:
next_floor = prog.xp_for_level(new_level + 1)
entity.xp_to_next_level = max(0, next_floor - entity.xp)
return old_level, new_level
# ---------- reward + recalc helpers ----------
def _add_abilities(entity:Entity, abilities_list:list) -> None:
for ability in abilities_list:
entity.abilities.append(ability)
def _recalc(entity:Entity) -> None:
"""
Recompute derived stats from entity.level + profession.
Replace with your actual formulas.
"""
L = entity.level
prof = entity.profession
# scale attack/defense by per-level gains
if prof:
base_pa = entity.profession.physical_attack_per_level or 0
base_pd = entity.profession.physical_defense_per_level or 0
base_ma = entity.profession.magic_attack_per_level or 0
base_md = entity.profession.magic_defense_per_level or 0
entity.physical_attack = round(base_pa + prof.physical_attack_per_level * (L - 1),2)
entity.physical_defense = round(base_pd + prof.physical_defense_per_level * (L - 1),2)
entity.magic_attack = round(base_ma + prof.magic_attack_per_level * (L - 1),2)
entity.magic_defense = round(base_md + prof.magic_defense_per_level * (L - 1),2)
# HP/MP growth from profession base
if prof:
entity.status.max_hp = entity.status.max_hp + int(prof.base_hp) + int((L * prof.base_hp) * 0.5)
entity.status.max_mp = entity.status.max_mp + int(prof.base_mp) + int((L * prof.base_mp) * 0.5)
# set current to max if you keep current_hp/mp
entity.status.current_hp = entity.status.max_hp
entity.status.current_mp = entity.status.max_mp