From f13ddd841316cf3726cbdf16f2209d18fd286cf9 Mon Sep 17 00:00:00 2001 From: Shadow15510 Date: Sat, 14 Aug 2021 17:13:34 +0200 Subject: [PATCH] Update README --- README.md | 381 +++++++++++++++++++++++++----------------- rpg_maker/asci_lib.py | 102 +++++++---- rpg_maker/sample.py | 68 ++++++-- rpg_maker/sample_1.py | 45 +++++ rpg_maker/sample_2.py | 67 ++++++-- 5 files changed, 447 insertions(+), 216 deletions(-) create mode 100644 rpg_maker/sample_1.py diff --git a/README.md b/README.md index dea00f0..405a1e2 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ### Principe -Le moteur repose sur l'évolution de points d'expérience pour déterminer votre avancée dans le jeu. Ces points d'expériences peuvent être donnés au joueur à l'issu de dialogues ou de combats. +Le moteur repose sur l'évolution de points d'expérience pour déterminer votre avancée dans le jeu. Ces points d'expériences sont donnés au joueur à l'issu d'évènements. ### Licence @@ -16,111 +16,127 @@ Tout le projet est soumis à la licence GNU General Public Licence v3.0. ## Utilisation -### Instructions +### Les statistiques -#### Création d'un nouveau projet +Les statistiques sont une liste de variables dont le premier élément est nécessairement les points de vie. Cette liste est donnée au moteur lors de l'initialisation, néanmoins, le moteur ne *modifie en aucun cas* cette variable. Il la stocke pour vous et la modifie sur votre demande, lors des évènements. Il s'agit donc d'une variable maîtresse dans les mécaniques de votre jeu. -Vous devez commencer par copier le fichier `asci_lib.py` dans le répertoire de votre jeu. Créez ensuite un fichier qui va correspondre à votre jeu. Nommez-le comme vous voulez, le nom ne présente pas d'importance pour le moteur. +Les statistiques ne peuvent être modifées que lors d'évènements. Comme vous le verrez dans la suite, les évènements sont des listes dont les derniers éléments ne sont pas déterminés : il s'agit des points que vous pouvez ajouter ou enlever à vos statistiques. -Ici, notre fichier s'appellera `sample.py`. +### Structure du programme -#### Structure du programme +Votre jeu va se diviser en grandes partie : + - création de la carte + - création des évènements + - gestion des combats + - affichage des statistiques + - finalisation -Notre fichier va se découper en plusieurs parties : - - l'importation de la bibliothèque `asci_lib.py` - - la création de la carte - - la création des dialogues - - la création de la fonction qui correspond à votre jeu et finalisation +Vous aurez à plusieurs reprise des fonctions à programmer, ces fonctions auront accès à des variables du moteurs, elles sont toutes en lecture seule, exceptée les statistiques qui peuvent être modifiée par effet de bord. #### Création de la carte -La carte est un grand tuple qui est de la forme : +Vous allez devoir créer une carte du monde, mais aussi les intérieurs des maisons. Pour cela vous allez avoir besoin d'un tuple qui va devoir remplir quelques conditions : + - toutes les cartes sont des r-docstrings `r""" ... """` + - le premier élément du tuple est la carte du monde + - les autres éléments sont eux-même des tuples de la forme : `(carte, (x_entree, y_entree), (x_sortie, y_sortie))` où `(x_entree, y_entree)` sont les coordonnées de la porte de la maison *dans la carte du monde* et où `(x_sortie, y_sortie)` sont les coordonnées de la porte de la maison *dans la carte de la maison* + +#### Création des évènements + +Les évènements sont des listes formatées qui ont cette forme : `[xp_gagnee, "Texte de l'évènement", nb, ...]`. + - `xp_gagnee` : correspond à l'expérience que le joueur gagne lors de l'évènement. + - le texte est ce qui est affiché à l'écran lors de l'évènement. + - `nb` : est une variable utilisée lors de dialogues. C'est une manipulation un peu plus délicate sur laquelle je reviens juste après. + - les `...` correspondent à des modificateurs sur les statistiques. J'y reviendrais également. + +Les dialogues permettent au joueur de choisir sa réponse. Si le joueur ne peux pas choisir de réponse, mettez `nb` à 0, sinon mettez `nb` sur le nombre de réponse possible. Les différentes réponses sont à afficher avec un numéro dans le corps du message. Par exemple : `[0, "Ceci est une question ? 1.Première réponse. 2.Seconde réponse.", 2]`. Le numéro de la question correspond alors au nombre de points d'expérience gagnée par le joueur (il est, de se fait, conseillé de ne pas donner de points d'expérience au joueur lors d'un dialogue). Si il n'y a pas de réponses possible, vous pouvez omettre cet argument. Attention, cette astuce n'est valable que si vous ne comptez pas modifier les statistiques. + +Ces évènements sont stockés dans des dictionnaires dont les clefs correspondent aux points d'expériences, c'est peut-être pas très clair, mais avec un exemple, ça ira mieux. + +Par simplicité, j'utiliserai un dictionnaire par PnJ, vous faites bien comme vous voulez, du moment que vous obtenez un truc qui marche… Ces dictionnaires d'évènements doivent être placés dans une fonction qui doit respecter certaines règles : + - la fonction doit prendre en argument l'expérience, l'id de la map actuelle (qui correspond à son index dans el tuple des maps), les coordonnées du joueur et les statistiques + - la fonction doit renvoyer un dictionnaire d'évènement ou un évènement. + +Concrètement, votre fonction va ressembler à : ``` -carte_monde = ( -, -(, (x_entree1, y_entree1), (x_sortie1, y_sortie1)), -(, (x_entree2, y_entree2), (x_sortie2, y_sortie2)), -...) +def evenement(xp, carte_actuelle, x, y, stat): + coords = (x, y) + + # Si on est en extérieur + if carte_actuelle == 0: + if coords == (X1, Y1): return { + xp_1: [...], + xp_2: [...], + ... + "base": [...] + } + + elif coords == (X2, Y2): return ... + + # Si on est dans la première maison + elif carte_actuelle == 1: + ... + + # Si on a pas encore renvoyé d'évènement, il faut prévoir un "cas par défaut" + return [0, "Hmm ?"] ``` -la `` et les `` sont des r-docstrings. Vous pouvez mettre à peu près n'importe quoi, veillez à bien respecter la légende : - - `@` : caractère réservé au joueur (ne pas utiliser) - - `^` : porte de maison - - `*` : PnJ - - `$` : adversaire +Les tests conditionnels testent quel PnJ le joueur regarde (sur quelle carte, et à quelles coordonnées). -Dans le cas des maisons, le premier tuple correspond aux coordonnées de la porte de la maison *dans la carte du monde*. Le second tuple correspond aux coordonnées de la porte de la maison *dans la carte de la maison*. +Ici, on voit peut-être un peu mieux le fonctionnement : les clefs du dictionnaires d'évènements correspondent à des points d'expérience : si le joueur à `xp_1` points d'expérience, alors c'est ce dialogue là qui sera lu, et si aucun évènement ne correspond, mais que le PnJ a quand même un texte à dire à un moment, l'évènement `"base"` sera lu. -#### Création des dialogues +Cette fonction est appelée lors d'un dialogue avec un PnJ, mais aussi à l'issue d'un combat, si le joueur est vainqueur. Le principe reste le même. -Sur votre carte fraîchement créée, vous avez mis des PnJ (si ce n'est pas le cas, mettez-en, la suite sera plus intéressante ;) ). L'idée est assez simple, il va falloir créer une fonction qui va prendre en argument l'expérience, les points de vie, l'id de la carte (l'index de la carte dans le tuple des maps, 0 : carte du monde, 1 : première maison etc), les coordonnées du joueur et les stat (une liste qui peut contenir des variables nécessaires aux mécaniques de votre jeu). Nous avons donc déjà : +#### Gestion des combats + +Vous êtes (presque) totalement libre ! Votre fonction doit respecter quelques points : + - la fonction, comme pour les évènements, doit prendre en argument l'expérience, le numéro de la carte, les coordonnées du joueur et les statistiques. (vous pouvez toujours objecter que ça fait beaucoup de variables, mais ça peut servir) + - la fonction doit retourner un booleen égal à `True` si le joueur a gagné, `False` sinon. + +Vous devriez avoir une fonction qui ressemble un peu à ça : ``` -def dialogue(xp, pv, carte_actuelle, x, y, stat): +def combats(xp, carte_actuelle, x, y, stat): + ... + return stat[0] > 0 ``` -Cette fonction va renvoyer un dictionnaire *ou* une liste. -C'est assez important, car, si vous renvoyez un dictionnaire, le dialogue sera lu en fonction des points d'expériences du joueur. Si vous renvoyez une liste, c'est le dialogue de la liste qui sera lu. +#### Affichage des statistiques -Le seul impératif que vous devez absolument respecter est la forme du dictionnaire et des listes. +La fonction est assez triviale : + - la fonction devra prendre en argument la liste des statistiques (les points d'expérience, au sens du moteur, sont considérés comme ne faisant pas partie des statistiques) + - la fonction devra afficher elle-même les statistiques. -Le dictionnaire est de la forme : +Vous aurez une fonction qui va ressembler ainsi à quelque chose comme : ``` -dialogues = { - xp_1: [...], - xp_2: [...], - ... - "base": [...] -} +def affichage_stat(stat): + print("<*> Statistiques <*>") + print("Points de vie .: {}".format(stat[0])) ``` -`xp_X` correspond au nombre de points d'expérience à avoir pour déclencher ce dialogue. -`"base"` est le dialogue lancé par défaut si aucun autre cas ne marche. - -Les listes sont, elles, de la forme : -``` -[xp_gagne, "le texte du dialogue", booleen, ...] -``` -`xp_gagne` correspond aux nombres de points d'expérience gagné lors de la lecture de ce dialogue. -`booleen` détermine s'il s'agit d'un monologue du PnJ ou si vous pouvez répondre au PnJ. -`...` correspond à des modificateurs des stats. Vous pouvez tout à fait les oublier en première utilisation - -La question maintenant est de savoir comment relier les dialogues au PnJ. Vous êtes libre de mettre en place un système d'ID, Nous vous proposons un système peut-être plus simple : les coordonnées des PnJ. Nous allons ainsi avoir une fonction qui va ressembler à : -``` -def dialogue(xp, pv, carte_actuelle, x, y, stat): - # Pour des raisons de clareté, on déclare un tuple avec les coordonnées - coords = (x, y) - - # Si nous sommes en extérieur - if carte_actuelle == 0: - if coords == (X1, Y1): - return {...} - elif coords == (X2, Y2): - return {...} - - # Si nous sommes dans la première maison de la liste - elif carte_actuelle == 1: - ... - - # Si le PnJ est bien sur la map, mais n'a aucun dialogue d'assigné : - return [0, "Hmm ?", False] -``` -Vous pouvez également créer des dialogues. Pour cela, il vous suffit de mettre le booleen sur `True` et de mettre les réponses possibles dans le corps du dialogue, par exemple : `[0, "Ceci est une question ? 1. Réponse 1 2. Réponse 2", True]`. Le numéro de la réponse correspond au nombre de point d'expérience qu'elle rapporte, cela vous permet de gérer les différents cas dans al suite du dialogue. #### Finalisation -Il reste à faire une petite fonction qui va créer un "modèle" de jeu de rôle vierge, il faudra lui donner la carte, la fonction des dialogues et ce sera fini ! +Il ne reste plus qu'à faire une petite fonction de nom de votre jeu qui va créer un modèle vierge de jeu rôle et qui va transmettre toutes ces données au modèle. Il vous restera ensuite à lancer cette fonction pour jouer. -La fonction est vraiment triviale : +Cette fonction devra prendre dans l'ordre : + - le tuple des cartes + - la fonction des évènements + - la fonction des combats + - la fonction d'affichages des statistiques + - les points d'expérience de la partie (lorsque l'expérience du joueur atteint cette valeur, le jeu se termine) + - la liste des statistiques (avec les points de vie en première place) + +### Exemples d'utilisation + +#### Exemple de manipulations basique + +Quelques réflexions préliminaires sur les mécaniques de notre petit jeu : + - en terme de stat : PV et Argent suffiront + - un seul dialogue à deux issues et modification de statistiques par les dialogues, on aura un arbre d'XP qui va ressembler à ça : ``` -def mon_jeu(): - rpg_python = Asci(carte_monde, dialogue, 10, [100]) - rpg_python.mainloop() + +--1--+ +-0--+ +--3- + +--2--+ ``` -Les deux premiers arguments `carte_monde` et `dialogue` ont déjà été vu. Le `10` correspond aux nombres de points d'expérience au bout duquel le programme s'arrête, il s'agit de la fin de la partie si vous voulez. La liste passée en dernier argument correspondent aux stats, vous devez impérativement mettre les points de vie de votre personnage. -### Exemples et astuces - -#### Exemples de cartes - -Pour commencer simplement, voici une carte assez banale (ne pas oublier la virgule à la fin !) : +Nous allons commencer par créer une carte simple. Juste le monde, sans maison. ``` carte_monde = ( r""" @@ -134,88 +150,153 @@ r""" |==|==|==|==|==|==|==|""",) ``` -Nous n'avons pas de maisons, juste un PnJ +Nous avons un PnJ aux coordonnées `(2, 5)`, et pas d'adversaire, il nous reste à faire les dialogues avec cet unique PnJ, la fonction de combat ne sera pas traitée ici vu qu'il n'y a pas d'ennemi. -#### Exemple de fonction de dialogue - -Nous allons faire parler notre PnJ ! Et comme on est chaud, on va directement faire un petit dialogue. Pour bien séparer les réactions à la question du reste, je met un niveau d'indentation supplémentaire, ça ne change rien au comportement du code. +Comme il n'y a pas grand chose à faire, je vais en profiter pour vous montrer les dialogues et les statistiques. ``` -def dialogue(xp, pv, carte_actuelle, x, y, stat): +def evenements(xp, carte_actuelle, x, y, stat): coords = (x, y) if carte_actuelle == 0: if coords == (2, 5): return { - 0: [0, "Coucou ! Comment ca va ? 1. Ca va, et toi ? 2. Bof... 3. Je t'emmerde.", True], - 1: [3, "Je vais bien, merci !", False], - 2: [3, "Ow, desole...", False], - 3: [4, "He, reviens quand tu sera de meilleure humeur !", False], + 0: [0, "Mon bon monsieur, vous n'auriez pas quelques sous pour moi ? 1. He non mon brave... 2. Mais si, bien sur, tenez.", 2], + 1: [2, "Radin !"], + # 0 réponse possibles, +0 PV, -1 Argent + 2: [1, "Merci !", 0, 0, -1], - 4: [2, "Bon et bien, je crois bien que cette premiere carte s'est bien passee !", False], - 5: [1, "Je vais y aller, appelle moi si tu as besoin ;)", False], - 6: [1, "A pluche o/", False], + "base": [0, "Hmm ?"] + } - "base": [0, "Oui ?", False] - } - - return [0, "Hmm ?", False] -``` -Pour mettre en place vos dialogues (parce que j'espère que vous aurez un peu plus qu'un seul PnJ) faire un arbre de progression de l'XP peut être une bonne idée ;) je vais essayer de le faire en ASCII-art pour vous montrer, mais avec une feuille et un stylo c'est plus simple. -``` - 1 4 - -=----=--- -0 / 2 5 \ 6 7 -------=----=------=--= - \ 3 / - -=------------ + return [0, "Hmm ?"] ``` -#### Fin de l'exemple et récapitulation +Comme dit plus haut : pas de combat, donc la fonction de combat va se résumer à un simple `def ...: pass` : +``` +def combat(xp, carte_actuelle, x, y, stat): + pass +``` -Il reste la petite fonction à faire : +Pour les statistiques, nous avons des points de vie et de l'argent, on va bricoler un truc simple : +``` +def affichage_stat(stat): + pv, argent = stat + print("Statistiques") + print("PV : {}".format(pv)) + print("Argent : {}".format(argent)) +``` + +Il ne reste plus qu'à tout donner au moteur ! +La limite d'XP de la partie est fixée à 3, on commence la partie avec 100 points de vie et 5 Argent. ``` def mon_jeu(): - rpg_python = Asci(carte_monde, dialogue, 7, []) - rpg_python.mainloop() -``` - -Nous avons le fichier complet : -``` -from asci_lib import * - - -carte_monde = ( -r""" - _ ### -/o\__ ##### -| <>\ ### -|____| /_\ - - * - - -|==|==|==|==|==|==|==|""",) - - -def dialogue(xp, pv, carte_actuelle, x, y, stat): - coords = (x, y) - - if carte_actuelle == 0: - if coords == (2, 5): return { - 0: [0, "Coucou ! Comment ca va ? 1. Ca va, et toi ? 2. Bof... 3. Je t'emmerde.", True], - 1: [3, "Je vais bien, merci !", False], - 2: [3, "Ow, desole...", False], - 3: [4, "He, reviens quand tu sera de meilleure humeur !", False], - - 4: [2, "Bon et bien, je crois bien que cette premiere carte s'est bien passee !", False], - 5: [1, "Je vais y aller, appelle moi si tu as besoin ;)", False], - 6: [1, "A pluche o/", False], - - "base": [0, "Oui ?", False] - } - - return [0, "Hmm ?", False] - - -def mon_jeu(): - rpg_python = Asci(carte_monde, dialogue, 7, []) + rpg_python = Asci(carte_monde, evenements, combat, affichage_stat, 3, [100, 5]) rpg_python.mainloop() +``` + +Et voila ! N'oubliez pas d'importer `asci_lib` ! Pour ceux qui veulent tester, le code complet est dans le fichier `rpg_maker/sample_1.py` + +#### Autre exemple basique + +Nous allons reprendre la même carte que tout à l'heure, mais nous allons ajouter une porte à la maison, aux coordonnées `(1, 3)` : +``` + _ ### +/o\__ ##### +|_ <>\ ### +|^|__| /_\ + + * + + +|==|==|==|==|==|==|==| +``` +Il faut donc dessiner l'intérieur de la maison : +``` ++--+--+--------+--+--+ +| | | * | | *| +| + + + + | +| | +| + + + + | ++--/ \--------/ \--+ +| | ++---|^|--------------+ +``` +La porte à l'intérieur est aux coordonnées `(5, 7)`. Nous avons donc le tuple des cartes : +``` +cartes = ( +r""" + _ ### +/o\__ ##### +|_ <>\ ### +|^|__| /_\ + + * + + +|==|==|==|==|==|==|==|""", + +(r""" ++--+--+--------+--+--+ +| | | * | | *| +| + + + + | +| | +| + + + + | ++--/ \--------/ \--+ +| | ++---|^|--------------+""", +(1, 3), (5, 7) +)) +``` + +Pour les évènements, rien de nouveau, étant donné que nous n'avons a priori pas de statistiques à part la vie, il n'y a pas forcément grand chose à faire, vous pouvez vous amuser à faire des dialogues un peu complexes avec différentes fins. + +``` +def evenements(xp, carte_actuelle, x, y, stat): + coords = (x, y) + + if carte_actuelle == 0: + if coords == (2, 5): return { + 0: [0, "Hey ! J'ai entendu du bruit dans la maison, mais je n'ose pas rentrer... 1. Rien entendu. 2. Je vais jeter un oeil.", 2], + 1: [3, "Etes-vous sourd ?"], + 2: [1, "J'etais sur que vous m'ecouteriez !"], + + 3: [2, "C'est la maison juste au nord."], + 4: [0, "Enfin, vous entendez bien du bruit la ? Et si c'etait un voleur ? 1. Bon ok j'y vais. 2. Mais foutez moi la paix !", 2], + 6: [0, "..."], + + 5: [2, "Soyez prudent !"], + + 12: [1, "J'etais sur d'avoir entendu un truc !"], + "base": [0, "Vous avez entendu quelque chose ?"] + } + + elif carte_actuelle == 1: + if coords == (9, 1): return { + 7: [0, "Je crois que le voleur est dans la piece d'a cote... 1. Je vais regarder. 2. Debrouillez-vous !", 2], + 8: [2, "Merci !"], + 9: [0, "Pleutre ! Hors de ma vue !"], + + 11: [1, "Ah, merci !"], + "base": [0, "J'ai peur de sortir de cette piece"] + } + + elif coords == (20, 1): return { + 10: [1, "Ciel, je suis fait !"], + "base": [0, "File avant que je ne te detrousse !"] + } + + return [0, "Hmm ?"] +``` +De même que pour l'exemple précédent : pas de combat. Je vous laisse gérer l'affichage des statistiques. Il reste la fonction finale : +``` +def mon_jeu(): + rpg_python = Asci(cartes, evenements, combat, affichage_statistique, 13, [100]) + rpg_python.mainloop() +``` +La limite est à 13 xp comme on peut le voir sur l'arbre : +``` + +--6-X + +--1--4--+ +--8--10--11--12--13- +-0--+ +--5--7--+ + +--2--3--+ +--9-X +``` +les `X` symbolise les impasses. \ No newline at end of file diff --git a/rpg_maker/asci_lib.py b/rpg_maker/asci_lib.py index 5e15142..3b8fef3 100644 --- a/rpg_maker/asci_lib.py +++ b/rpg_maker/asci_lib.py @@ -1,5 +1,3 @@ -from random import randint - class Screen: def __init__(self, world, screen_width=21, screen_height=6): # Screen configuration @@ -55,10 +53,10 @@ class Screen: class Asci: - def __init__(self, maps, fn_dialogue, end_game, stat, data=[0, 100, 0, 0, 0], screen_width=21, screen_height=6): + def __init__(self, maps, fn_events, fn_fight, fn_stat, end_game, stat, data=[0, 0, 0, 0], screen_width=21, screen_height=6): # Load save ; data = [XP, map_id, x, y] self.data = data - if not stat: + if not stat or type(stat) != list: self.stat = [100] else: self.stat = stat @@ -68,7 +66,9 @@ class Asci: self.end_game = end_game # Custom functions - self.get_dialogue = fn_dialogue + self._game_event = fn_events + self._game_fight = fn_fight + self._game_stat = fn_stat # Screen configuration self.screen = Screen(maps[data[2]], screen_width, screen_height) @@ -77,21 +77,21 @@ class Asci: def _looked_case(self, direction): # Left if direction == 1: - return self.data[3] + 9, self.data[4] + 3 + return self.data[2] + 9, self.data[3] + 3 # Right elif direction == 3: - return self.data[3] + 11, self.data[4] + 3 + return self.data[2] + 11, self.data[3] + 3 # Up elif direction == 5: - return self.data[3] + 10, self.data[4] + 2 + return self.data[2] + 10, self.data[3] + 2 # Down elif direction == 2: - return self.data[3] + 10, self.data[4] + 4 + return self.data[2] + 10, self.data[3] + 4 - return self.data[3] + 10, self.data[4] + 3 + return self.data[2] + 10, self.data[3] + 3 def _cell_test(self, direction): if direction == 1: @@ -119,34 +119,34 @@ class Asci: cell_test = self._cell_test(key) # Enter house - if cell_test == 2 or (self.data[2] and cell_test < 0): - self.data[2], self.data[3], self.data[4] = self._get_map(key) - if self.data[2]: - self.screen.set_world(self.maps[self.data[2]][0]) + if cell_test == 2 or (self.data[1] and cell_test < 0): + self.data[1], self.data[2], self.data[3] = self._get_map(key) + if self.data[1]: + self.screen.set_world(self.maps[self.data[1]][0]) else: self.screen.set_world(self.maps[0]) - # PnJ + # Talk elif cell_test == 3: - self._chatting(key) + self._talk(key) # Fight elif cell_test == 4: - pass + self._fight(key) # Left - if key == 1 and cell_test == 1: self.data[3] -= 1 + if key == 1 and cell_test == 1: self.data[2] -= 1 # Right - if key == 3 and cell_test == 1: self.data[3] += 1 + if key == 3 and cell_test == 1: self.data[2] += 1 # Up - if key == 5 and cell_test == 1: self.data[4] -= 1 + if key == 5 and cell_test == 1: self.data[3] -= 1 # Down - if key == 2 and cell_test == 1: self.data[4] += 1 + if key == 2 and cell_test == 1: self.data[3] += 1 # Stat if key == 8: self.screen.clear() - print("<*> Statistiques <*>\n") + self._game_stat(self.stat) input() # Quit @@ -156,32 +156,41 @@ class Asci: # /!\ TEST /!\ # if key == 7: - print(self.data[-2:]) + print(self.data) input() # /!\ TEST /!\ # - def _chatting(self, direction): + def _talk(self, direction): x, y = self._looked_case(direction) # Read the dialogue - dialogue = self.get_dialogue(self.data[0], self.data[1], self.data[2], x, y, self.stat) - if type(dialogue) == dict: - if self.data[0] in dialogue: dialogue = dialogue[self.data[0]] - else: dialogue = dialogue["base"] + event = read_event(self.data[0], self._game_event(self.data[0], self.data[1], x, y, self.stat)) - # XP and PV modification - self.data[0] += dialogue[0] + # XP and stat modification + self.data[0] += event.xp_earned + for index in range(len(event.stat)): + self.stat[index] += event.stat[index] - # Stat modification - for index in range(len(dialogue[3:])): - stat[index] += dialogue[3 + index] + answer_selected = convert(self.screen.display_text(event.text)) + if event.answer and (0 < answer_selected <= event.answer): self.data[0] += answer_selected - answer_selected = self.screen.display_text(dialogue[1]) - if dialogue[2]: self.data[0] += convert(answer_selected) + def _fight(self, direction): + x, y = self._looked_case(direction) + + # Run the fight + if self._game_fight(self.data[0], self.data[1], x, y, self.stat): + event = read_event(self.data[0], self._game_event(self.data[0], self.data[1], x, y, self.stat)) + + # XP and stat modification + self.data[0] += event.xp_earned + for index in range(len(event.stat)): + self.stat[index] += event.stat[index] + + self.screen.display_text(event.text) def _get_map(self, direction): x, y = self._looked_case(direction) - current_map = self.data[2] + current_map = self.data[1] if current_map: if (x, y) == self.maps[current_map][2]: @@ -191,7 +200,7 @@ class Asci: if (x, y) == self.maps[index][1]: return index, self.maps[index][2][0] - 10, self.maps[index][2][1] - 3 - return current_map, self.data[3], self.data[4] + return current_map, self.data[2], self.data[3] def mainloop(self): key = key_buffer = 0 @@ -208,6 +217,14 @@ class Asci: self._keyboard(key) +class Event: + def __init__(self, xp_earned, text, answer=0, *stat): + self.xp_earned = xp_earned + self.text = text + self.answer = answer + self.stat = stat + + def convert(string): try: return int(string) except: return 0 @@ -231,3 +248,14 @@ def text_formater(string, screen_width=21, screen_height=6): lines = line_formater(string, screen_width).split("\n") return paragraph_formater(lines, screen_height).split("\n\n") + + +def read_event(xp, event): + if type(event) == dict: + if xp in event: event = event[xp] + else: event = event["base"] + + if type(event) != list: + raise TypeError("event is of type {} instead of list".format(type(event))) + + return Event(*event) diff --git a/rpg_maker/sample.py b/rpg_maker/sample.py index d80bb99..60c5dab 100644 --- a/rpg_maker/sample.py +++ b/rpg_maker/sample.py @@ -1,4 +1,5 @@ from asci_lib import * +from random import randint maps = ( r""" @@ -9,7 +10,7 @@ r""" /_\ |^| * __ __ - ## / \___/ \ ## + $ ## / \___/ \ ## #### |<> <>| #### ## |___|^|___| ## || ||""", @@ -26,38 +27,77 @@ r""" ) -def get_dialogue(xp, pv, current_map, x, y, stat): +def get_dialogue(xp, current_map, 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 !", False], - 1: [0, "Comment vas-tu aujourd'hui ? 1. Tres bien, merci ! Et vous-meme ? 2. La ferme le vieux ! ", True], - 2: [4, "Je vais bien ^.^", False], - 3: [0, "Oh, insultant personnage !", False], + 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], - 6: [0, "Belle journée, n'est-ce pas ?", False], + 6: [1, "Belle journée, n'est-ce pas ? Dommage que ce brigand un peu au sud soit la...", 0], + + 8: [0, "Et bien je crois que c'est un test concluant !", 0], - "base": [0, "Bonjour, besoin d'aide ?", False], + "base": [0, "Bonjour, besoin d'aide ?", 0], } elif coords == (24, 4): - if pv >= 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...", False, 50] - else: return [0, "Tu es en pleine forme !", False] + 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..."] + } + elif current_map == 1: if coords == (4, 3): return { - 3: [0, "Tsst, tu as encore insulte quelqu'un ? 1. Oui... 2. Hein ? Quoi ?", True], - 4: [0, "C'est pas tres malin, tu sais ?", False], - 5: [0, "Je n'aime pas les menteurs. Sort de chez moi.", False], + 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], "base": [0, "Oui ?", False] } return [0, "Hmmm ?", False] + + +def fight(xp, current_map, x, y, stat): + coords = (x, y) + + if current_map == 0: + if coords == (4, 7): + if xp == 6: + enemy = [75, randint(0, 10), 0] + 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) + + if player > adv: + enemy[0] -= (player - enemy[2]) + else: + stat[0] -= (adv - stat[2]) + + return stat[0] > 0 + + + +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])) def start(): - my_game = Asci(maps, get_dialogue, 10, 0) + my_game = Asci(maps, get_dialogue, fight, display_stat, 10, [100, 0, 0]) my_game.mainloop() \ No newline at end of file diff --git a/rpg_maker/sample_1.py b/rpg_maker/sample_1.py new file mode 100644 index 0000000..e030064 --- /dev/null +++ b/rpg_maker/sample_1.py @@ -0,0 +1,45 @@ +from asci_lib import * + +carte_monde = ( +r""" + _ ### +/o\__ ##### +| <>\ ### +|____| /_\ + + * + + +|==|==|==|==|==|==|==|""",) + + +def evenements(xp, carte_actuelle, x, y, stat): + coords = (x, y) + + if carte_actuelle == 0: + if coords == (2, 5): return { + 0: [0, "Mon bon monsieur, vous n'auriez pas quelques sous pour moi ? 1. He non mon brave... 2. Mais si, bien sur, tenez.", 2], + 1: [2, "Radin !"], + # 0 réponse possibles, +0 PV, -1 Argent + 2: [1, "Merci !", 0, 0, -1], + + "base": [0, "Hmm ?"] + } + + return [0, "Hmm ?"] + + +def combat(xp, carte_actuelle, x, y, stat): + pass + + +def affichage_stat(stat): + pv, argent = stat + print("Statistiques") + print("PV : {}".format(pv)) + print("Argent : {}".format(argent)) + + +def mon_jeu(): + rpg_python = Asci(carte_monde, evenements, combat, affichage_stat, 4, [100, 5]) + rpg_python.mainloop() \ No newline at end of file diff --git a/rpg_maker/sample_2.py b/rpg_maker/sample_2.py index 9a1dffa..046c2d0 100644 --- a/rpg_maker/sample_2.py +++ b/rpg_maker/sample_2.py @@ -1,39 +1,76 @@ from asci_lib import * -carte_monde = ( +cartes = ( r""" _ ### /o\__ ##### -| <>\ ### -|____| /_\ +|_ <>\ ### +|^|__| /_\ * -|==|==|==|==|==|==|==|""",) +|==|==|==|==|==|==|==|""", + +(r""" ++--+--+--------+--+--+ +| | | * | | *| +| + + + + | +| | +| + + + + | ++--/ \--------/ \--+ +| | ++---|^|--------------+""", +(1, 3), (5, 7) +)) -def dialogue(xp, pv, carte_actuelle, x, y, stat): +def evenements(xp, carte_actuelle, x, y, stat): coords = (x, y) if carte_actuelle == 0: if coords == (2, 5): return { - 0: [0, "Coucou ! Comment ca va ? 1. Ca va, et toi ? 2. Bof... 3. Je t'emmerde.", True], - 1: [3, "Je vais bien, merci !", False], - 2: [3, "Ow, desole...", False], - 3: [4, "He, reviens quand tu sera de meilleure humeur !", False], + 0: [0, "Hey ! J'ai entendu du bruit dans la maison, mais je n'ose pas rentrer... 1. Rien entendu. 2. Je vais jeter un oeil.", 2], + 1: [3, "Etes-vous sourd ?"], + 2: [1, "J'etais sur que vous m'ecouteriez !"], - 4: [2, "Bon et bien, je crois bien que cette premiere carte s'est bien passee !", False], - 5: [1, "Je vais y aller, appelle moi si tu as besoin ;)", False], - 6: [1, "A pluche o/", False], + 3: [2, "C'est la maison juste au nord."], + 4: [0, "Enfin, vous entendez bien du bruit la ? Et si c'etait un voleur ? 1. Bon ok j'y vais. 2. Mais foutez moi la paix !", 2], + 6: [0, "..."], - "base": [0, "Oui ?", False] + 5: [2, "Soyez prudent !"], + + 12: [1, "J'etais sur d'avoir entendu un truc !"], + "base": [0, "Vous avez entendu quelque chose ?"] } - return [0, "Hmm ?", False] + elif carte_actuelle == 1: + if coords == (9, 1): return { + 7: [0, "Je crois que le voleur est dans la piece d'a cote... 1. Je vais regarder. 2. Debrouillez-vous !", 2], + 8: [2, "Merci !"], + 9: [0, "Pleutre ! Hors de ma vue !"], + + 11: [1, "Ah, merci !"], + "base": [0, "J'ai peur de sortir de cette piece"] + } + + elif coords == (20, 1): return { + 10: [1, "Ciel, je suis fait !"], + "base": [0, "File avant que je ne te detrousse !"] + } + + return [0, "Hmm ?"] + + +def combat(xp, carte_actuelle, x, y, stat): + pass + +def affichage_statistique(stat): + print("Statistiques :") + print("Points de Vie : {}".format(stat[0])) def mon_jeu(): - rpg_python = Asci(carte_monde, dialogue, 7, []) + rpg_python = Asci(cartes, evenements, combat, affichage_statistique, 13, [100]) rpg_python.mainloop() \ No newline at end of file