From fcf9e44434038f3668e9d36817ef9ed9d185998f Mon Sep 17 00:00:00 2001 From: Shadow15510 Date: Sat, 14 Aug 2021 22:27:07 +0200 Subject: [PATCH] Add an advanced exemple --- README.md | 201 +++++++++++++++++++++++++++++++++++++++++- rpg_maker/asci_lib.py | 17 ++-- rpg_maker/sample_2.py | 4 +- rpg_maker/sample_3.py | 133 ++++++++++++++++------------ 4 files changed, 283 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 4417ffa..61d5544 100644 --- a/README.md +++ b/README.md @@ -299,4 +299,203 @@ La limite est à 13 xp comme on peut le voir sur l'arbre : -0--+ +--5--7--+ +--2--3--+ +--9-X ``` -les `X` symbolise les impasses. \ No newline at end of file +les `X` symbolise les impasses. + +Le fichier complet est disponible sous le nom `rpg_maker/sample_2.py` + +#### Exemple de manipulation avancées + +Maintenant que vous êtes bien chaud, on va commencer les choses sérieuses. Enfin "sérieuses" je vous propose de faire pas à pas un petit jeu avec disons une quête et quelques mécaniques un peu bidon (ça reste un exemple). On peut déjà poser quelques petits trucs : + - le joueur a des points de vie, d'attaque et de défense + - le scénario se résumera à une seule quête : tuer un adversaire. La quête peut être refusée. + +On peut déjà rapidement voir à quoi va ressembler l'arbre d'XP (j'en fait pas mal et je vous invite à en faire aussi, ça aide vraiment à voir le déroulement de l'histoire) : +``` + +--1--3--4--5- +-0--+ + +--2-X +``` +Pour expliquer rapidement : + - 0 : début de l'histoire, énoncé de la quête + - 1 : quête acceptée + - 2 : quête refusée + - 3 : combat avec le bandit + - 4 : debrief avec le PnJ + - 5 : fin de la partie (limite de l'XP pour le jeu) + +Comme on est vraiment chaud, on va essayer de faire une map un peu plus joli que d'habitude avec des PnJ qui vont avoir des dialogues sans forcément avoir un rôle dans l'histoire, ça va être l'occasion de sortir un peu du modèle "1 PnJ = 1 dictionnaire d'évènements" et de vous rappeller que vous pouvez renvoyer un évènement seul. + +Allez ! On est parti avec une map et deux maisons : +``` +cartes = ( +r""" + __ +/ \___ ### * +|<> \ ##### _ +|^|____| ### / \ + /_\ |^| * + + __ __ + $ ## / \___/ \ ## + #### |<> <>| #### + ## |___|^|___| ## + || ||""", + +(r""" ++--+--+--------+--+--+ +| | | | | | +| + + + + | +| | +| + + + + | ++--/ *\--------/ \--+ +| | ++---|^|--------------+""", +(1, 3), (5, 7)), + +(r""" ++-------+ +| | +| | +| | ++--|^|--+ +""", +(19, 4), (4, 4)) +) +``` + +On va commencer par faire le PnJ qui n'a pas un rôle énorme dans le scénario. On va faire un médecin (comme y a du combat, c'est pratique de mettre un medecin dans la place). L'idée est simple : si le joueur a moins de 100 points de vie, il est blessé, donc on lui rajoute des points de vie avec un texte. Si il est en pleine forme, on le lui signale et on ne touche pas aux points de vie. + +On a donc la fonction qui ressemble à ça (je met des `...` au niveau des trucs pas encore définis): +``` +def evenements(xp, carte_actuelle, x, y, stat): + coords = (x, y) + + if carte_actuelle == 0: + if coords == (...): + # Joueur blessé + if stat[0] < 100: return [0, "Oh, mais tu es blesse !", 0, 50] + else: return [0, "Reviens me voir quand tu seras blesse."] + + return [0, "Hmm ?"] +``` + +Comme il s'agit d'un personnage très secondaire (voir inutile) on peut prendre pour médecin le PnJ tout à l'est, aux coordonnées `(24, 4)`. On prend alors l'autre PnJ pour le personnage qui donne la quête au joueur (aux coordonnées `(16, 1)`) + +On peut compléter notre fonction avec la proposition de la quête : +``` +def evenements(xp, carte_actuelle, x, y, stat): + coords = (x, y) + + if carte_actuelle == 0: + if coords == (24, 4): + if stat[0] < 100: return [0, "Oh, mais tu es blesse !", 0, 50] + else: return [0, "Reviens me voir quand tu seras blesse."] + + elif coords == (16, 1): return { + "base": [0, "Alors ? T'en sorts-tu ?"], + + 0: [0, "J'ai une quete pour toi ! Un ami a moi a des problemes : un personnage louche traine autour de sa maison... Si tu pouvais l'en debarasser, il t'en serai reconnaissant. 1. Je m'en charge ! 2. Trouve quelqu'un d'autre.", 2], + 1: [2, "J'etais sur que je pouvais compter sur toi ! Tiens, voila une dague et une petit bouclier.", 0, 0, 10, 10], + 2: [2, "Si un jour tu as besoin de moi, tu seras sympa de m'oublier."], + + 3: [0, "Alors ? Il est mort ce bandit ?"], + 4: [1, "Merci, tu as rendu un grand service a mon ami !"] + } + + return [0, "Hmm ?"] +``` + +Maintenant il reste à programmer la fin du combat, en d'autre terme, si le joueur gagne le combat, la fonction `evenements` va être appelée, il faut donc renvoyer un petit texte qui signale que le combat est gagné et qui incrémente les points d'XP de 2 points (pour passer de 1 à 3). Le bandit est sur les coordonnées `(4, 7)`. +``` +def evenements(xp, carte_actuelle, x, y, stat): + coords = (x, y) + + if carte_actuelle == 0: + if coords == (24, 4): + if stat[0] < 100: return [0, "Oh, mais tu es blesse !", 0, 50] + else: return [0, "Reviens me voir quand tu seras blesse."] + + elif coords == (16, 1): return { + "base": [0, "Alors ? T'en sorts-tu ?"], + + 0: [0, "J'ai une quete pour toi ! Un ami a moi a des problemes : un personnage louche traine autour de sa maison... Si tu pouvais l'en debarasser, il t'en serai reconnaissant. 1. Je m'en charge ! 2. Trouve quelqu'un d'autre.", 2], + 1: [2, "J'etais sur que je pouvais compter sur toi ! Tiens, voila une dague et une petit bouclier.", 0, 0, 10, 10], + 2: [2, "Si un jour tu as besoin de moi, tu seras sympa de m'oublier."], + + 3: [0, "Alors ? Il est mort ce bandit ?"], + 4: [1, "Merci, tu as rendu un grand service a mon ami !"] + } + + elif coords == (4, 7): + # Si le bandit vient d'être tué + if xp == 3: return [1, "Vous avez reussi la quete !"] + + # Si le bandit est encore vivant + elif xp < 3: return [0, "Qu'est-ce que tu regardes toi ? Casses-toi !"] + + # Si le bandit est déjà mort + else: return [0, "Vous regardez le cadavre froid du bandit."] + + return [0, "Hmm ?"] +``` + +Il reste à faire une fonction pour les combats ! +Le principe est simple, la fonction va regarder de quel bandit il s'agit, si c'est le moment du combat, la fonction va lancer le combat, sinon elle déclare le combat gagnée ce qui va déclencher la fonction `evenements` (donc afficher le texte prévu juste avant) +``` +def combats(xp, carte_actuelle, x, y, stat): + coords = (x, y) + + if carte_actuelle == 0: + if coords == (4, 7): + if xp == 3: ennemi_stat = [75, randint(5, 10), randint(5, 10)] + else: return True + + defense_temporaire = defense_temporaire_ennemi = 0 + while stat[0] > 0 and ennemi_stat[0] > 0: + + print("Vos PV : {0}\nPV ennemi : {1}".format(stat[0], ennemi_stat[0])) + print("<*> Actions <*>") + print("1. Attaquer") + print("2. Defendre") + + action = int(input(">")) + + defense_temporaire = 0 + if action == 1: + pv = (stat[1] - ennemi_stat[2] - defense_temporaire_ennemi) + randint(-5, 10) + if pv < 0: pv = 0 + ennemi_stat[0] -= pv + elif action == 2: + defense_temporaire = randint(1, 5) + + defense_temporaire_ennemi = 0 + if randint(1, 2) == 1: + pv = (ennemi_stat[1] - stat[2] - defense_temporaire) + randint(-5, 10) + if pv < 0: pv = 0 + stat[0] -= pv + else: + defense_temporaire_ennemi = randint(1, 5) + + return stat[0] > 0 +``` + +Il reste à faire la fonction d'affichage des statistiques et la petite fonction d'appel : +``` +def affichage_stat(stat): + pv, pa, pd = stat + + print("<*> Statistiques <*>") + print("Points de vie .: {}".format(pv)) + print("Points attaque : {}".format(pa)) + print("Points defense : {}".format(pd)) +``` +et : +``` +def mon_jeu(): + rpg_python = Asci(cartes, evenements, combats, affichage_stat, 5, [100, 0, 0]) + rpg_python.mainloop() +``` +Vous pouvez retrouver le fichier complet dans `rpg_maker/sample_3.py` + + + diff --git a/rpg_maker/asci_lib.py b/rpg_maker/asci_lib.py index 3b8fef3..603ce16 100644 --- a/rpg_maker/asci_lib.py +++ b/rpg_maker/asci_lib.py @@ -1,17 +1,10 @@ class Screen: - def __init__(self, world, screen_width=21, screen_height=6): + def __init__(self, screen_width=21, screen_height=6): # Screen configuration self.screen_width = screen_width self.screen_height = screen_height self._data = [[" " for _ in range(screen_width)] for _ in range(screen_height)] - # Load map data - self.set_world(world) - - - def clear_data(self): - self._data = [[" " for _ in range(self.screen_width)] for _ in range(self.screen_height)] - def clear(self): print("\n" * self.screen_height) @@ -43,7 +36,8 @@ class Screen: if paragraph: self.clear() print(paragraph) - return input(">") + last_input = input(">") + return last_input def get_cell(self, x, y): return self._data[y][x] @@ -71,7 +65,8 @@ class Asci: self._game_stat = fn_stat # Screen configuration - self.screen = Screen(maps[data[2]], screen_width, screen_height) + self.screen = Screen(screen_width, screen_height) + self.screen.set_world(maps[data[2]]) self.map_width, self.map_height = self.screen.get_map_size() def _looked_case(self, direction): @@ -205,7 +200,7 @@ class Asci: def mainloop(self): key = key_buffer = 0 while key != 9 and self.stat[0] > 0 and self.data[0] < self.end_game: - self.screen.clear_data() + # self.screen.clear_data() self.screen.set_data(self.data[-2:]) self.screen.set_cell(10, 3, "@") diff --git a/rpg_maker/sample_2.py b/rpg_maker/sample_2.py index 046c2d0..16c0f62 100644 --- a/rpg_maker/sample_2.py +++ b/rpg_maker/sample_2.py @@ -22,8 +22,8 @@ r""" +--/ \--------/ \--+ | | +---|^|--------------+""", -(1, 3), (5, 7) -)) +(1, 3), (5, 7)) +) def evenements(xp, carte_actuelle, x, y, stat): diff --git a/rpg_maker/sample_3.py b/rpg_maker/sample_3.py index 8434e53..da869da 100644 --- a/rpg_maker/sample_3.py +++ b/rpg_maker/sample_3.py @@ -1,7 +1,8 @@ from asci_lib import * from random import randint -maps = ( + +cartes = ( r""" __ / \___ ### * @@ -16,89 +17,105 @@ r""" || ||""", (r""" -+------------------------------+ -| | -| | -| * | -| | -| | -+--|^|-------------------------+ -""", (1, 3), (4, 6)) ++--+--+--------+--+--+ +| | | | | | +| + + + + | +| | +| + + + + | ++--/ *\--------/ \--+ +| | ++---|^|--------------+""", +(1, 3), (5, 7)), + +(r""" ++-------+ +| | +| | +| | ++--|^|--+ +""", +(19, 4), (4, 4)) ) -def get_dialogue(xp, current_map, x, y, stat): +def evenements(xp, carte_actuelle, x, y, stat): coords = (x, y) - if current_map == 0: - if coords == (16, 1): return { - 0: [1, "Hey, bienvenue dans la map de test d'Asci !", 0], - 1: [0, "Comment vas-tu aujourd'hui ? 1. Tres bien, merci ! Et vous-meme ? 2. La ferme le vieux ! ", 2], - 2: [4, "Je vais bien, merci ! Voici une epee et une cote de maille.", 0, 0, 10, 10], - 3: [0, "Oh, insultant personnage ! Pour la peine tu n'auras rien !", 0], + if carte_actuelle == 0: + if coords == (24, 4): + if stat[0] < 100: return [0, "Oh, mais tu es blesse !", 0, 50] + else: return [0, "Reviens me voir quand tu seras blesse."] - 6: [1, "Belle journée, n'est-ce pas ? Dommage que ce brigand un peu au sud soit la...", 0], + elif coords == (16, 1): return { + "base": [0, "Alors ? T'en sorts-tu ?"], - 8: [0, "Et bien je crois que c'est un test concluant !", 0], - - "base": [0, "Bonjour, besoin d'aide ?", 0], - } + 0: [0, "J'ai une quete pour toi ! Un ami a moi a des problemes : un personnage louche traine autour de sa maison... Si tu pouvais l'en debarasser, il t'en serai reconnaissant. 1. Je m'en charge ! 2. Trouve quelqu'un d'autre.", 2], + 1: [2, "J'etais sur que je pouvais compter sur toi ! Tiens, voila une dague et une petit bouclier.", 0, 0, 10, 10], + 2: [2, "Si un jour tu as besoin de moi, tu seras sympa de m'oublier."], - elif coords == (24, 4): - if stat[0] < 100: return [0, "Tsst, est-ce que je tape sur des gens moi ? Bah alors ? J'ai panse tes plaies, mais fait gaffe a toi...", 0, 50] - else: return [0, "Tu es en pleine forme !", 0] - - # - elif coords == (4, 7): return { - 6: [2, "Tu as tue le brigand !", 0], - "base": [0, "Il n'y a rien a faire par ici..."] + 3: [0, "Alors ? Il est mort ce bandit ?"], + 4: [1, "Merci, tu as rendu un grand service a mon ami !"] } + elif coords == (4, 7): + # Si le bandit vient d'être tué + if xp == 3: return [1, "Vous avez reussi la quete !"] - elif current_map == 1: - if coords == (4, 3): return { - 3: [0, "Tsst, tu as encore insulte quelqu'un ? 1. Oui... 2. Hein ? Quoi ?", 2], - 4: [0, "C'est pas tres malin, tu sais ?", 0], - 5: [0, "Je n'aime pas les menteurs. Sort de chez moi.", 0], + # Si le bandit est encore vivant + elif xp < 3: return [0, "Qu'est-ce que tu regardes toi ? Casses-toi !"] - "base": [0, "Oui ?", False] - } + # Si le bandit est déjà mort + else: return [0, "Vous regardez le cadavre froid du bandit."] - return [0, "Hmmm ?", False] + return [0, "Hmm ?"] -def fight(xp, current_map, x, y, stat): +def combats(xp, carte_actuelle, x, y, stat): coords = (x, y) - if current_map == 0: + if carte_actuelle == 0: if coords == (4, 7): - if xp == 6: - enemy = [75, randint(0, 10), 0] - else: - return True + if xp == 3: ennemi_stat = [75, randint(5, 10), randint(5, 10)] + else: return True - end = 1 - - while stat[0] > 0 and enemy[0] > 0: - player = stat[1] + randint(1, 5) - adv = enemy[1] + randint(1, 5) + defense_temporaire = defense_temporaire_ennemi = 0 + while stat[0] > 0 and ennemi_stat[0] > 0: - if player > adv: - enemy[0] -= (player - enemy[2]) + print("Vos PV : {0}\nPV ennemi : {1}".format(stat[0], ennemi_stat[0])) + print("<*> Actions <*>") + print("1. Attaquer") + print("2. Defendre") + + action = int(input(">")) + + defense_temporaire = 0 + if action == 1: + pv = (stat[1] - ennemi_stat[2] - defense_temporaire_ennemi) + randint(-5, 10) + if pv < 0: pv = 0 + ennemi_stat[0] -= pv + elif action == 2: + defense_temporaire = randint(1, 5) + + defense_temporaire_ennemi = 0 + if randint(1, 2) == 1: + pv = (ennemi_stat[1] - stat[2] - defense_temporaire) + randint(-5, 10) + if pv < 0: pv = 0 + stat[0] -= pv else: - stat[0] -= (adv - stat[2]) + defense_temporaire_ennemi = randint(1, 5) return stat[0] > 0 +def affichage_stat(stat): + pv, pa, pd = stat -def display_stat(stat): print("<*> Statistiques <*>") - print("Points de vie .: {}".format(stat[0])) - print("Points attaque : {}".format(stat[1])) - print("Points defense : {}".format(stat[2])) + print("Points de vie .: {}".format(pv)) + print("Points attaque : {}".format(pa)) + print("Points defense : {}".format(pd)) -def start(): - my_game = Asci(maps, get_dialogue, fight, display_stat, 10, [100, 0, 0]) - my_game.mainloop() \ No newline at end of file +def mon_jeu(): + rpg_python = Asci(cartes, evenements, combats, affichage_stat, 5, [100, 0, 0]) + rpg_python.mainloop() \ No newline at end of file