🚚 mv scripts into src folder
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import os
|
||||
import sys
|
||||
from enum import Enum
|
||||
|
||||
from base_mob import BaseMob
|
||||
from character_builder import CharacterBuilder
|
||||
from level import Level
|
||||
|
||||
|
||||
class Action(Enum):
|
||||
PIECE_SUIVANTE = (1, "Pièce suivante")
|
||||
COMBAT = (2, "Combat")
|
||||
FUIR = (3, "Fuir")
|
||||
QUITTER = (4, "Quitter")
|
||||
|
||||
@property
|
||||
def code(self):
|
||||
return self.value[0]
|
||||
|
||||
@property
|
||||
def libelle(self):
|
||||
return self.value[1]
|
||||
|
||||
|
||||
def clear_console() -> None:
|
||||
os.system('cls' if os.name == 'nt' else 'clear')
|
||||
|
||||
|
||||
def action_menu(actions_autorisees: list[Action] = None) -> Action:
|
||||
"""Affiche le menu et retourne une action valide."""
|
||||
|
||||
actions_autorisees = list(Action) if actions_autorisees is None else actions_autorisees
|
||||
|
||||
while True:
|
||||
print("\n------ Menu Action ------\n")
|
||||
|
||||
for action in actions_autorisees:
|
||||
print(f"{action.libelle:<20} : {action.code}")
|
||||
|
||||
try:
|
||||
choix = int(input("\nChoix : "))
|
||||
clear_console()
|
||||
for action in actions_autorisees:
|
||||
if action.code == choix:
|
||||
return action
|
||||
|
||||
print("Mauvais choix")
|
||||
except ValueError:
|
||||
clear_console()
|
||||
print("Veuillez saisir un nombre.")
|
||||
|
||||
|
||||
def play_room(room: list[BaseMob], level: Level) -> int:
|
||||
if room is None:
|
||||
print("\n ------ Pièce vide ------ \n")
|
||||
return 1
|
||||
|
||||
for mob in room:
|
||||
print(f"Un {mob.name} est devant toi !")
|
||||
match action_menu([Action.COMBAT, Action.FUIR]):
|
||||
case Action.COMBAT:
|
||||
level.combat(mob, level.player)
|
||||
if level.player.current_pv <= 0:
|
||||
print("!!!!!!!!! Joueur mort !!!!!!!!!!")
|
||||
sys.exit(0)
|
||||
if mob.current_pv == 0:
|
||||
print(f"Le {mob.name} est mort !!")
|
||||
case Action.FUIR:
|
||||
print("Tu fuis la pièce")
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
def play_donjon(level: Level) -> None:
|
||||
while level.exit_level:
|
||||
print(f"Pièce actuelle : {level.current_room_index}")
|
||||
match action_menu([Action.PIECE_SUIVANTE, Action.QUITTER]):
|
||||
case Action.PIECE_SUIVANTE:
|
||||
if level.current_room_index >= len(level.rooms):
|
||||
print("fin du donjon !")
|
||||
break
|
||||
level.current_room_index += play_room(level.rooms[level.current_room_index], level)
|
||||
level.player.current_pv = level.player.max_pv
|
||||
case Action.QUITTER:
|
||||
level.exit_level = False
|
||||
print(f"Au revoir {level.player.name} !")
|
||||
|
||||
|
||||
def app() -> None:
|
||||
loaded_character = CharacterBuilder.load_character(sys.argv[1] if len(sys.argv) > 1 else "Jamin")
|
||||
if not loaded_character:
|
||||
sys.exit(-1)
|
||||
|
||||
print(loaded_character)
|
||||
|
||||
level = Level(2, loaded_character)
|
||||
print(f"Nombre de pièce dans le donjon : {len(level.rooms)}")
|
||||
|
||||
play_donjon(level)
|
||||
|
||||
|
||||
# Exemple d'utilisation
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
@@ -0,0 +1,65 @@
|
||||
class BaseMob:
|
||||
"""Classe de base représentant un mob avec différentes caractéristiques."""
|
||||
|
||||
# Types possibles
|
||||
FRIEND = 0
|
||||
NEUTRAL = 1
|
||||
ENEMY = 2
|
||||
|
||||
def __init__(self, name, max_pv, strength, protection, speed, mob_type):
|
||||
"""
|
||||
Initialisation d'un nouveau mob.
|
||||
|
||||
:param name: Nom du mob
|
||||
:param max_pv: Points de vie maximum
|
||||
:param strength: Force d'attaque
|
||||
:param protection: Protection contre les dommages
|
||||
:param speed: Vitesse d'attaque (nombre d'attaques par tour)
|
||||
:param mob_type: Type de mob (0 = Ami, 1 = Neutre, 2 = Ennemi)
|
||||
"""
|
||||
self.name = name
|
||||
self.max_pv = max_pv
|
||||
self.current_pv = max_pv
|
||||
self.strength = strength
|
||||
self.protection = protection
|
||||
self.speed = speed
|
||||
self.mob_type = mob_type
|
||||
|
||||
def change_type(self, new_type):
|
||||
"""
|
||||
Change le type du mob.
|
||||
|
||||
:param new_type: Nouveau type (0 = Ami, 1 = Neutre, 2 = Ennemi)
|
||||
"""
|
||||
self.mob_type = new_type
|
||||
|
||||
def change_pv(self, pv_modifier):
|
||||
"""
|
||||
Modifie les points de vie actuels du mob.
|
||||
|
||||
:param pv_modifier: Valeur par laquelle modifier les PV (positive pour guérir, négative pour infliger des dégâts)
|
||||
"""
|
||||
if pv_modifier > 0:
|
||||
# Ajout de PV (guérison)
|
||||
self.current_pv = min(self.max_pv, self.current_pv + pv_modifier)
|
||||
else:
|
||||
# Retrait de PV (dommages)
|
||||
damage = pv_modifier + self.protection
|
||||
self.current_pv = max(0, self.current_pv + damage)
|
||||
|
||||
def perform_attack(self, target):
|
||||
"""
|
||||
Le mob attaque une cible.
|
||||
|
||||
:param target: Le mob cible de l'attaque
|
||||
"""
|
||||
for _ in range(self.speed):
|
||||
if target.current_pv <= 0:
|
||||
break
|
||||
target.change_pv(-self.strength)
|
||||
|
||||
def __str__(self):
|
||||
"""Retourne une représentation sous forme de chaîne du mob."""
|
||||
return (f"{self.name} - PV: {self.current_pv}/{self.max_pv}, "
|
||||
f"Force: {self.strength}, Protection: {self.protection}, "
|
||||
f"Vitesse: {self.speed}")
|
||||
@@ -0,0 +1,105 @@
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from typing import Callable
|
||||
|
||||
from base_mob import BaseMob
|
||||
|
||||
|
||||
class CharacterBuilder:
|
||||
save_character_impl: Callable[[BaseMob], str]
|
||||
load_character_impl: Callable[[str], None]
|
||||
|
||||
@classmethod
|
||||
def build_character(cls):
|
||||
"""Demande à l'utilisateur de saisir les attributs du personnage."""
|
||||
print("Création d'un nouveau personnage :")
|
||||
name = input("Nom du personnage : ")
|
||||
max_pv = int(input("Points de vie maximum : "))
|
||||
strength = int(input("Force : "))
|
||||
protection = int(input("Protection : "))
|
||||
speed = int(input("Vitesse : "))
|
||||
mob_type = 0
|
||||
return BaseMob(name, max_pv, strength, protection, speed, mob_type)
|
||||
|
||||
@classmethod
|
||||
def save_character(cls, character: BaseMob) -> None:
|
||||
"""Enregistre un personnage dans un fichier JSON."""
|
||||
filename = cls.save_character_impl(character)
|
||||
print(f"Personnage enregistré dans {filename}.")
|
||||
|
||||
@classmethod
|
||||
def load_character(cls, name: str) -> BaseMob | None:
|
||||
"""Charge un personnage à partir d'un fichier JSON."""
|
||||
try:
|
||||
return cls.load_character_impl(name)
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
|
||||
def save_character(character: BaseMob) -> str:
|
||||
"""Enregistre un personnage dans un fichier JSON."""
|
||||
character_data = {
|
||||
"name": character.name,
|
||||
"max_pv": character.max_pv,
|
||||
"current_pv": character.current_pv,
|
||||
"strength": character.strength,
|
||||
"protection": character.protection,
|
||||
"speed": character.speed,
|
||||
"mob_type": character.mob_type
|
||||
}
|
||||
filename = character.name + ".json"
|
||||
with open(filename, "w", encoding='UTF-8') as file:
|
||||
json.dump(character_data, file, indent=4)
|
||||
return filename
|
||||
|
||||
|
||||
def load_character(name: str) -> BaseMob | None:
|
||||
"""Charge un personnage à partir d'un fichier JSON."""
|
||||
filename = name + ".json"
|
||||
if not os.path.exists(filename):
|
||||
print(f"Erreur : Le fichier {filename} n'existe pas.")
|
||||
return None
|
||||
|
||||
try:
|
||||
with open(filename, "r", encoding='UTF-8') as file:
|
||||
character_data = json.load(file)
|
||||
|
||||
# Vérification des clés essentielles dans le JSON pour éviter les erreurs
|
||||
required_keys = ["name", "max_pv", "current_pv",
|
||||
"strength", "protection", "speed", "mob_type"]
|
||||
if not all(key in character_data for key in required_keys):
|
||||
print(f"Erreur : Le fichier {filename} ne contient pas toutes les clés nécessaires.")
|
||||
return None
|
||||
|
||||
# Construction du personnage
|
||||
return BaseMob(
|
||||
name=character_data["name"],
|
||||
max_pv=character_data["max_pv"],
|
||||
strength=character_data["strength"],
|
||||
protection=character_data["protection"],
|
||||
speed=character_data["speed"],
|
||||
mob_type=character_data["mob_type"]
|
||||
)
|
||||
except json.JSONDecodeError:
|
||||
print(f"Erreur : Le fichier {filename} n'est pas un JSON valide.")
|
||||
return None
|
||||
|
||||
|
||||
pydantic = None
|
||||
name = 'pydantic'
|
||||
if name in sys.modules:
|
||||
pydantic = sys.modules[name]
|
||||
elif (spec := importlib.util.find_spec(name)) is not None:
|
||||
pydantic = importlib.util.module_from_spec(spec)
|
||||
sys.modules[name] = pydantic
|
||||
spec.loader.exec_module(pydantic)
|
||||
|
||||
if pydantic and os.environ.get('ELIRON_BUILDER') == 'pydantic':
|
||||
pydantic_character_builder = importlib.import_module('pydantic_character_builder')
|
||||
CharacterBuilder.save_character_impl = pydantic_character_builder.save_character
|
||||
CharacterBuilder.load_character_impl = pydantic_character_builder.load_character
|
||||
else:
|
||||
CharacterBuilder.save_character_impl = save_character
|
||||
CharacterBuilder.load_character_impl = load_character
|
||||
@@ -0,0 +1,30 @@
|
||||
""" Class Level """
|
||||
import random
|
||||
|
||||
import mobs_utils
|
||||
|
||||
|
||||
class Level:
|
||||
""" Class Level """
|
||||
|
||||
def __init__(self, difficulty, player):
|
||||
""" Chargement du niveau """
|
||||
print("Loading Level")
|
||||
self.mobs_in_level = mobs_utils.generate_random_mob_list(random.randint(2, difficulty))
|
||||
self.exit_level = True
|
||||
self.player = player
|
||||
self.rooms = mobs_utils.generate_random_rooms(self.mobs_in_level, difficulty) # Liste des pièces du niveau
|
||||
self.current_room_index = 0 # Index de la pièce actuelle
|
||||
|
||||
print("Level Loaded")
|
||||
|
||||
def combat(self, mob, player):
|
||||
while mob.current_pv > 0 and player.current_pv > 0:
|
||||
if mob.speed > player.speed:
|
||||
mob.perform_attack(player)
|
||||
player.perform_attack(mob)
|
||||
else:
|
||||
player.perform_attack(mob)
|
||||
mob.perform_attack(player)
|
||||
print(f"{player.name} - {player.current_pv} PV")
|
||||
print(f"{mob.name} - {mob.current_pv} PV")
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
# def main_loop(breaker:bool):
|
||||
# pass
|
||||
|
||||
# def menu ():
|
||||
# print("Nouvelle partie :\t1")
|
||||
# print("Charger :\t\t2")
|
||||
# print("Option :\t\t3")
|
||||
# print("Quitter :\t\t4")
|
||||
# return int(input("Choix : "))
|
||||
|
||||
|
||||
# choix = menu()
|
||||
|
||||
# match choix:
|
||||
# case 1:
|
||||
# print("Nouvelle partie")
|
||||
# case 2:
|
||||
# print("Charger")
|
||||
# case 3:
|
||||
# print("Option")
|
||||
# case 4:
|
||||
# print("Quitter")
|
||||
# case _:
|
||||
# print("Mauvais choix")
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import random
|
||||
from base_mob import BaseMob
|
||||
|
||||
# Créer des instances de BaseMob
|
||||
yanaar = BaseMob("Yanaar", 15, 2, 1, 3, 2)
|
||||
ulnarain = BaseMob("Ulnarain", 20, 3, 3, 2, 2)
|
||||
skroll = BaseMob("Skroll", 25, 5, 3, 1, 2)
|
||||
|
||||
# Liste d'instances de BaseMob (au lieu d'un ensemble pour autoriser des doublons)
|
||||
mobs_list = [yanaar, skroll, ulnarain]
|
||||
|
||||
|
||||
def generate_random_mob_list(max_mobs):
|
||||
"""
|
||||
Génère une liste aléatoire de mobs à partir de la liste des instances disponibles.
|
||||
|
||||
:param max_mobs: Le nombre maximum de mobs dans la liste générée.
|
||||
:return: Une liste de mobs sélectionnés aléatoirement.
|
||||
"""
|
||||
if max_mobs <= 0:
|
||||
return []
|
||||
|
||||
num_mobs = random.randint(2, max_mobs)
|
||||
selected_mobs = [random.choice(mobs_list) for _ in range(num_mobs)]
|
||||
return selected_mobs
|
||||
|
||||
|
||||
def generate_random_rooms(mobs_in_level, num_rooms):
|
||||
"""
|
||||
Génère un nombre spécifié de pièces et y distribue les mobs disponibles.
|
||||
|
||||
:param mobs_in_level: Liste des mobs disponibles pour le niveau.
|
||||
:param num_rooms: Nombre total de pièces à générer.
|
||||
:return: Une liste de pièces, chaque pièce contenant un ou plusieurs mobs, ou étant vide si aucun mob n'est disponible.
|
||||
"""
|
||||
rooms = []
|
||||
|
||||
for _ in range(num_rooms):
|
||||
if len(mobs_in_level) > 0:
|
||||
# Si des mobs sont disponibles, ajouter le premier mob à la pièce
|
||||
new_room = []
|
||||
for x in range(random.randint(1, len(mobs_in_level))):
|
||||
new_room.append(mobs_in_level.pop(0))
|
||||
rooms.append(new_room)
|
||||
else:
|
||||
# Ajouter une pièce vide si aucun mob n'est disponible
|
||||
rooms.append(None)
|
||||
|
||||
return rooms
|
||||
@@ -0,0 +1,46 @@
|
||||
import pathlib
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from base_mob import BaseMob
|
||||
|
||||
|
||||
class CharacterModel(BaseModel):
|
||||
name: str
|
||||
max_pv: int
|
||||
current_pv: int
|
||||
strength: int
|
||||
protection: int
|
||||
speed: int
|
||||
mob_type: int
|
||||
|
||||
|
||||
def save_character(character: BaseMob) -> str:
|
||||
filename = f'{character.name}.json'
|
||||
character_model = CharacterModel(
|
||||
name=character.name,
|
||||
max_pv=character.max_pv,
|
||||
current_pv=character.current_pv,
|
||||
strength=character.strength,
|
||||
protection=character.protection,
|
||||
speed=character.speed,
|
||||
mob_type=character.mob_type
|
||||
)
|
||||
pathlib.Path(filename).write_text(
|
||||
data=character_model.model_dump_json(indent=4),
|
||||
encoding='utf-8'
|
||||
)
|
||||
return filename
|
||||
|
||||
|
||||
def load_character(name: str) -> BaseMob | None:
|
||||
json_data = pathlib.Path(f'{name}.json').read_text(encoding='utf-8')
|
||||
character_model = CharacterModel.model_validate_json(json_data)
|
||||
return BaseMob(
|
||||
name=character_model.name,
|
||||
max_pv=character_model.max_pv,
|
||||
strength=character_model.strength,
|
||||
protection=character_model.protection,
|
||||
speed=character_model.speed,
|
||||
mob_type=character_model.mob_type,
|
||||
)
|
||||
Reference in New Issue
Block a user