From fb54e8fa4a64298df88baea6c4f1f1a097d1dc28 Mon Sep 17 00:00:00 2001 From: Kalyax Date: Thu, 24 Nov 2022 14:30:36 +0100 Subject: [PATCH] init --- README.md | 9 + game/__pycache__/core.cpython-38.pyc | Bin 0 -> 2025 bytes game/__pycache__/personnage.cpython-38.pyc | Bin 0 -> 3032 bytes game/core.py | 54 ++ game/personnage.py | 73 +++ game/sprites/Elfe.txt | 16 + game/sprites/Guerrier.txt | 14 + game/sprites/Magicien.txt | 16 + game/sprites/Voleur.txt | 16 + getkey/__init__.py | 17 + getkey/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 600 bytes getkey/__pycache__/keynames.cpython-38.pyc | Bin 0 -> 10262 bytes getkey/__pycache__/platforms.cpython-38.pyc | Bin 0 -> 7762 bytes getkey/__pycache__/unikeys.cpython-38.pyc | Bin 0 -> 4552 bytes getkey/keynames.py | 481 ++++++++++++++++++ getkey/platforms.py | 238 +++++++++ getkey/unikeys.py | 167 ++++++ graphics/__pycache__/colors.cpython-38.pyc | Bin 0 -> 1113 bytes graphics/__pycache__/engine.cpython-38.pyc | Bin 0 -> 3983 bytes .../__pycache__/key_listener.cpython-38.pyc | Bin 0 -> 508 bytes graphics/__pycache__/layers.cpython-38.pyc | Bin 0 -> 6085 bytes graphics/colors.py | 44 ++ graphics/engine.py | 98 ++++ graphics/key_listener.py | 10 + graphics/layers.py | 173 +++++++ main.py | 21 + 26 files changed, 1447 insertions(+) create mode 100644 README.md create mode 100644 game/__pycache__/core.cpython-38.pyc create mode 100644 game/__pycache__/personnage.cpython-38.pyc create mode 100644 game/core.py create mode 100644 game/personnage.py create mode 100644 game/sprites/Elfe.txt create mode 100644 game/sprites/Guerrier.txt create mode 100644 game/sprites/Magicien.txt create mode 100644 game/sprites/Voleur.txt create mode 100644 getkey/__init__.py create mode 100644 getkey/__pycache__/__init__.cpython-38.pyc create mode 100644 getkey/__pycache__/keynames.cpython-38.pyc create mode 100644 getkey/__pycache__/platforms.cpython-38.pyc create mode 100644 getkey/__pycache__/unikeys.cpython-38.pyc create mode 100644 getkey/keynames.py create mode 100644 getkey/platforms.py create mode 100644 getkey/unikeys.py create mode 100644 graphics/__pycache__/colors.cpython-38.pyc create mode 100644 graphics/__pycache__/engine.cpython-38.pyc create mode 100644 graphics/__pycache__/key_listener.cpython-38.pyc create mode 100644 graphics/__pycache__/layers.cpython-38.pyc create mode 100644 graphics/colors.py create mode 100644 graphics/engine.py create mode 100644 graphics/key_listener.py create mode 100644 graphics/layers.py create mode 100644 main.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..96b6f86 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# jeu_role + +## Informations +Uniquement fonctionnel dans un terminal qui affiche les couleurs ANSI (CMD et Powershell ne marchent pas). +
+Utilisez les flèches directionnelles pour vous déplacer, TAB et ENTRÉE pour confirmer. + +## Référence +[getkey](https://github.com/kcsaff/getkey) pour récupérer les entrées de clavier diff --git a/game/__pycache__/core.cpython-38.pyc b/game/__pycache__/core.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0021d279a7f46598d9581807e5b550e9fd362a73 GIT binary patch literal 2025 zcmZuxPj4JG6t_KpGrP%dtAbj@VT#0Ik-C8v0SAN%Bnn7$vue`_MnWTN>})2Po!NM1 zqhvKJ4%-jF9U&#$`XS&G@Ckh7l&{be?|HIG8t`cB=jUg?pZ$C9yHqoyehNiwIjduZVCKEOLeWg7mx# z*h_j;(~o*gyDugxt)zB_#pLA#w4UO*Nb@Q|tDB9%*1WC=^y zFoG}P!srN3_%OO+MFcQq;_SV%kk-Js_jx{d#{OV!M-<7*7u9CT<4iQfg32fzELF8vCOM-{XkA*Rb(b1xr=)_mns+d8z>U*d9hpMc&4M0UNh zV8-VM;FF2ASOtVZ?Vq)))q^!eUVCEgb29gi{x+C8wf7tOoh=xwAo`A=Xl2;x4lYdW zV1isAl}#u;25I(qx0se8KbEr)2oTeU;d7bsJb`&8Lns2_q?oEODe@}KAtU?!{*ERW z7(KHOAB96+hC+f(l@@uJa22NcG1L#9D$r&!%>(r=xhMqm#!?LZul zq%zku6#*k&2iLH)m0=F@$wcM?v$B#ZyFGF-mQL&&VC~6HsUumy7Z3(07}Y?*qmX`5@FcUqIU| zpaENh{9L15kZjPmsS6|K>|F{LpzYFG%VbD%&YMN@&fQ|_#EFd`a#dr9jsFQ>+}VM;*iWv@Ad3I1ivnsy2NIMeVeQG&O?2siUMhR55BN2nZAe!(GW#C`w*Z zfh{N~Q0H8r=b}Y>^zZ1u;I$|Jg`$Ukvl1iuk)S|H>~NN|yR$R%&Fns&n=3Os&wD?F z*IdT_qR#YVqO*>c-Uks(@R)VD$2svvY;;V|?xrm$WyVI3Hrg`O=O^c?hT^h&}- z&qdD>Gh3`yKEhh8#`BU25)maCSZAxJqD+P)nSKm(*3r^s5Xn3)m}dwsj91Jvg^AUy z+}#K=+3KqO(88eNA)aP$prsc2^G`Ctl>`D0v~1 zEQplE(pD+m?@ zD@@N87Gi08CE*|frQH1%5l~SO=g#J%?T3#VxmDk+*K_;pyW8m4_wGJ;T+hwB-)%H% zuBu>BHAiHg$Rd$*M3#u0CqmJl+BrE`>FqCoBPJ!{a%=o5`hUs{GI1R(-3FPMQGkaa z3v)DBVUmU^K~$9Sza(Zw1z%UpiFtfy#DZAFw=B+yC46Vad6>SOmp5OB@)Z2Y&l-Ne zff>P15C{QZf}e(>IW&a%+)y_&t8Jq>Es~Xl1?nbGA+;ghhGgcHbPZAmQUytQN?Ou$ zuR!WT`V%CxQ_>ldW))F_e)9n7OKDImH;%~ZM-+O`ebARmMN%D+n>~cL6@`&ZJm(2u z+*d~?{kH0HQy!seu-cr?k$lmgc*FN8osR!O-sEN&WI9}H8p~+@kz)`8?W5>KKFb6Ej|CUPzuP9zxdZ z=vL9mP#T4CV7x?pe@AO0ifwb5{ee}sclaU`+qxE@6yhyM96z*?nlU` zOj7wN4s>T+TJm)iWq%?R53N1VMV6aX?gVo-(g0B#jnl!-{I{iKRR^qG>?UN?=hs0l9- zp7ZjPAnwb$Qe8FeI0F6gh^qH6d<|{vF_$l%=`kt|w1wg!o{*!1dJ_zVvCV#AzZz6% z+gx)v@!N*xP+Hrj=4@~laZMYRIgNqc=yuksgT-wWk*bi@Fb>jG;*b3#!lzHCR(-Gc z=OKz?5|Y4uy1DVFet)f6vnK^f!*&!Zo!4i@>vGU+M&XY1!$1Wg9iM3yA*s`K=t${| zWV~Fw{|v5A#qv!vPkDuKpuIv>c64ik#q1tCKuJO*k4>P#RMWQ5^mVI+?D)R&5@8?m zOYCQ3*TN(|Fg~m5z}1Z0ShdIwA~ADE}(;Y`dg6`q(Z@eQdP_+tM5s!r8WDo0 zq8g`GiA=z&Iek6300CWPQaWvLv@E+eUc+^Ca}~)OwUX!1&9~bb9Rmw374&wZFkOj* mecUFLiBbAuHaaJ1(plPa_x9-acZV_{r5ah`6=U9+FZ~OhCuds# literal 0 HcmV?d00001 diff --git a/game/core.py b/game/core.py new file mode 100644 index 0000000..b18b946 --- /dev/null +++ b/game/core.py @@ -0,0 +1,54 @@ +from game.personnage import * + +from graphics.layers import PopUp + +from random import randint + +class Game: + def __init__(self): + self.personnage = None + self.ennemy = None + + def late_init(self): + self.personnage = Personnage(" ", "Guerrier", "player") + self.ennemy = self.rand_ennemy() + + def rand_ennemy(self): + classes = ["Guerrier", "Magicien", "Voleur", "Elfe"] + noms = ["Bill Gates", "Dark Vador", "Gargamel", "G-Man"] + return Personnage(noms[randint(0, 3)], classes[randint(0, 3)], "OPPONENT") + + def init_personnage(self, nom, class_type): + self.personnage = Personnage(nom, class_type, "PLAYER") + + def attack(self, attacker, victim): + atk_jet = attacker.jet_attaque() + def_jet = victim.jet_defense() + if (atk_jet >= def_jet): + rand = randint(1, 8) + victim.change_pdv(rand) + else: + rand = randint(1, 4) + attacker.change_pdv(rand) + + if self.personnage.get_pdv() == 0: + for i in range(50): + PopUp(1, "Vous avez perdu! Relancez le jeu pour continuer...", True) + if self.ennemy.get_pdv() == 0: + self.ennemy = self.rand_ennemy() + + potions = "" + inv = self.personnage.inventaire + if len(inv) >= 6: + potions = f"- Pas de potion car inventaire plein\n" + else: + maxpot = 3 + if len(inv) > 3: + maxpot = 6-len(inv) + for i in range(randint(0, maxpot)): + random = randint(5, 25) + inv.append(Material.POTION) + potions += f"- Potion de 10HP\n" + + PopUp(1, f"Ennemi vaincu!\n{potions}") + self.personnage.change_exp(1) \ No newline at end of file diff --git a/game/personnage.py b/game/personnage.py new file mode 100644 index 0000000..738526f --- /dev/null +++ b/game/personnage.py @@ -0,0 +1,73 @@ +from random import randint +from graphics.layers import Sprite + +class Category: + def __init__(self, nom, __expcoef, inventaire): + self.nom = nom + self.pdv = __expcoef + self.inventaire = inventaire + +class Material: + POTION = "POTION" + EPEE = "EPEE" + BATON = "BATON" + DAGUE = "DAGUE" + ARC = "ARC" + +class Personnage: + def __init__(self, nom, cat, personnage_type): + self.nom = nom + self.__pdv = 20 + self.__exp = 1 + self.cat = cat + if cat == "Guerrier": + self.inventaire = [Material.EPEE, Material.POTION] + self.__expcoef = 10 + elif cat == "Magicien": + self.inventaire = [Material.BATON, Material.POTION] + self.__expcoef = 10 + elif cat == "Voleur": + self.inventaire = [Material.DAGUE, Material.POTION] + self.__expcoef = 3 + elif cat == "Elfe": + self.inventaire = [Material.ARC, Material.POTION] + self.__expcoef = 8 + + Sprite(3, cat, personnage_type) + + def jet_attaque(self): + damage = randint(1, 20) + self.change_exp(self.__expcoef * self.__exp) + return damage + + def jet_defense(self): + damage = randint(1, 20) + self.change_exp(self.__expcoef * self.__exp) + return damage + + def get_pdv(self): + return self.__pdv + def change_pdv(self, nb_pdv): + if self.__pdv - nb_pdv < 0: + self.__pdv = 0 + else: + self.__pdv -= nb_pdv + + def get_xp(self): + return self.__exp + def change_exp(self, nb_exp): + if nb_exp > 0: + self.__exp += nb_exp + else: + raise ValueError("nb_exp attends un nombre positif") + + def affiche_caracteristiques(self): + return (f"Nom: {self.nom}", + f"Type de classe: {self.cat}", + f"Vie: {self.__pdv}", + f"Expérience: {self.__exp}", + f"XPCOEF: {self.__expcoef}" + ) + + def affiche_inventaire(self): + return ["- "+item for item in self.inventaire] \ No newline at end of file diff --git a/game/sprites/Elfe.txt b/game/sprites/Elfe.txt new file mode 100644 index 0000000..f94ca1b --- /dev/null +++ b/game/sprites/Elfe.txt @@ -0,0 +1,16 @@ + @@@@@@& + @@@&&@&@@@@& + &@@%&@@%&@*@@@& + &@%&@@@%*,,,,@@% + &@&&*@@#,,@@@,@% + *&&**%@/*#*,,,#*/@,&* + %@@&@&&***,,,%&& + %&@@@@@#@@&%%%&#@& + &%#@&/##&%**,,,,,/%@& + ***,,,,,,,,,***%%,,,,,****%&&&@@ @% + %#&@@@@@%@((((&@@@ @ + ** (%&@@/(##%(//*#* ( + %@*/#%/&%(//*% + %*//(#% @#(/**% + @%&&&&@ @&&&&%@ + @%%###@ @###%%@ diff --git a/game/sprites/Guerrier.txt b/game/sprites/Guerrier.txt new file mode 100644 index 0000000..719b773 --- /dev/null +++ b/game/sprites/Guerrier.txt @@ -0,0 +1,14 @@ + + @/, + @/### + %#/%%&@@@%& + @@*(%##&&@@%& + /@@@@@@& &&% + &%,@@,,@@ @( + @%&@&%&&@%&@@@% + @//**@ *%%%&%%&% + .@//*/& /#% %&/ + %@ &%/ + @% @&/ + %% &@ + &%#% @% \ No newline at end of file diff --git a/game/sprites/Magicien.txt b/game/sprites/Magicien.txt new file mode 100644 index 0000000..35a67e7 --- /dev/null +++ b/game/sprites/Magicien.txt @@ -0,0 +1,16 @@ + + &&&&&& + &...*&(&& + ., .%.%%%* + ..... %%&&*(#&&####&&& + (##%%%&&%**#%&##&&#&& + ((/&&&&&&%*##&&&#%&&&#( + .& .&&&(#*&&&&#&& + @@&&&%%/@(&&&#&#//** + .@ &&&&##%@@###&% ## + &&%&&%##%%@####% + %%&&&%%@@@@&### + %&&&&&&& @@@%% + **((( *((((@ + ((### .%#%%# + (((#( .%%%%% diff --git a/game/sprites/Voleur.txt b/game/sprites/Voleur.txt new file mode 100644 index 0000000..e6fff19 --- /dev/null +++ b/game/sprites/Voleur.txt @@ -0,0 +1,16 @@ + + + + ,,, + ,,.%%%. + , ,.%%%. + ,,,..,,. + ,,..(((.,. + ,.,,.///,. + ,./(////,. + ./,,*,,,. + .*,.**,, + ,, *, + . . + + \ No newline at end of file diff --git a/getkey/__init__.py b/getkey/__init__.py new file mode 100644 index 0000000..c8f5ad7 --- /dev/null +++ b/getkey/__init__.py @@ -0,0 +1,17 @@ +from __future__ import absolute_import, print_function +import sys +from .platforms import platform, PlatformError, PlatformInvalid + +try: + __platform = platform() +except PlatformError as err: + print('Error initializing standard platform: {}'.format(err.args[0]), + file=sys.stderr) + __platform = PlatformInvalid() + +getkey = __platform.getkey +keys = __platform.keys +key = keys # alias +bang = __platform.bang + +__version__ = '0.6.5' diff --git a/getkey/__pycache__/__init__.cpython-38.pyc b/getkey/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e66e76414cecd9eb693e2af08af942c5389a50d3 GIT binary patch literal 600 zcmYk2F>ezw7=~@%opZU8Tv`}FV#v^eFyvUmfKY`H3@iup7g*qPOC)Uhkw3rsUim%Gv}0uJ}QThspRV( z^j9|&xkJ8Dh*kr|Kcge`u6t(aEc);J$K)N+?3h5h8j2w@7dhl&gu8vQuX^G@vDajh zUgGP>g!#NYv2EQskX5s8jq}5`skD=ePS0J{>X(-ol1w6>uIth*TGRN!tAD%a#k*u{7%e4@DKPsD?YRh6lD$P7{WmDtetlaXlIKRbkejn6xXJO rlp(d0)Ah!ukDFF?H5`Qxw099Bn$la0(Tt98#(y}w%{b*Wrkwo+1p}s6 literal 0 HcmV?d00001 diff --git a/getkey/__pycache__/keynames.cpython-38.pyc b/getkey/__pycache__/keynames.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9b1c4ec985857cc0ed6fc0b0c10dbc815822519 GIT binary patch literal 10262 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 FzX2`D;p_ka literal 0 HcmV?d00001 diff --git a/getkey/__pycache__/platforms.cpython-38.pyc b/getkey/__pycache__/platforms.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7656e9d5bfcf564e9e94d8fd7fac00c1c8331e02 GIT binary patch literal 7762 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 YVY@1=FWK|5=}P5e=vuT7|7NBB13Oy?eE': 'greater than', # 0x3e + '?': 'question', # 0x3f + '@': 'at', # 0x40 + + '[': 'left bracket', # 0x5b + '\\': 'backslash', # 0x5c + ']': 'right bracket', # 0x5d + '^': 'caret', # 0x5e + '_': 'underscore', # 0x5f + '`': 'backtick', # 0x60 + + '{': 'left brace', # 0x7b + '|': 'pipe', # 0x7c + '}': 'right brace', # 0x7d + '~': 'tilde', # 0x7e +} + + +class UnicodeKeys(object): + # Names from ftp://ftp.unicode.org/Public/UNIDATA/NamesList.txt + NULL = chr(0x00) + START_OF_HEADING = chr(0x01) + + +class JargonKeys(object): + BANG = '!' + SHRIEK = '!' + DOUBLE_QUOTE = '"' + QUOTE = '"' + NUMBER_SIGN = '#' + SHARP = '#' + OCTOTHORPE = '#' + BUCK = '$' + CASH = '$' + STRING = '$' + MOD = '%' + GRAPES = '%' + AMPERSAND = '&' + AMP = '&' + AND_SIGN = '&' + APOSTROPHE = '\'' + PRIME = '\'' + TICK = '\'' + STAR = '*' + SPLAT = '*' + GLOB = '*' + ADD = '+' + + +class IntercalKeys(object): + SPOT = '.' + TWO_SPOT = ':' + TAIL = ',' + HYBRID = ';' + MESH = '#' + HALF_MESH = '=' + SPARK = '\'' + BACKSPARK = '`' + WOW = '!' + WHAT = '?' + RABBIT_EARS = '"' + # RABBIT is `"` over `.` + SPIKE = '|' + DOUBLE_OH_SEVEN = '%' + WORM = '-' + ANGLE = '<' + RIGHT_ANGLE = '>' + WAX = '(' + WANE = ')' + U_TURN = '[' + U_TURN_BACK = ']' + EMBRACE = '{' + BRACELET = '}' + SPLAT = '*' + AMPERSAND = '&' + V = 'V' + BOOK = 'V' + # BOOKWORM is `-` over `V` + BIG_MONEY = '$' + # CHANGE is cent sign + SQUIGGLE = '~' + FLAT_WORM = '_' + # OVERLINE is line on top + INTERSECTION = '+' + SLAT = '/' + BACKSLAT = '\\' + WHIRLPOOL = '@' + # HOOKWORK is logical NOT symbol + SHARK = '^' + SHARKFIN = '^' + # BLOTCH is several characters smashed on top of each other + + +class VT100StandardModeKeys(object): + # http://www.braun-home.net/michael/mbedit/info/misc/VT100_commands.htm + # http://www.ccs.neu.edu/research/gpc/MSim/vona/terminal/VT100_Escape_Codes.html + F1 = '\x1bOP' + F2 = '\x1bOQ' + F3 = '\x1bOR' + F4 = '\x1bOS' + + UP = '\x1b[A' + DOWN = '\x1b[B' + RIGHT = '\x1b[C' + LEFT = '\x1b[D' + + +class VT100ApplicationsModeKeys(object): + F1 = '\x1bOP' + F2 = '\x1bOQ' + F3 = '\x1bOR' + F4 = '\x1bOS' + + UP = '\x1bOA' + DOWN = '\x1bOB' + RIGHT = '\x1bOC' + LEFT = '\x1bOD' + + KEYPAD_0 = '\x1bOp' + KEYPAD_1 = '\x1bOq' + KEYPAD_2 = '\x1bOr' + KEYPAD_3 = '\x1bOs' + KEYPAD_4 = '\x1bOt' + KEYPAD_5 = '\x1bOu' + KEYPAD_6 = '\x1bOv' + KEYPAD_7 = '\x1bOw' + KEYPAD_8 = '\x1bOx' + KEYPAD_9 = '\x1bOy' + KEYPAD_MINUS = '\x1bOm' + KEYPAD_COMMA = '\x1bOl' + KEYPAD_PERIOD = '\x1bOn' + KEYPAD_ENTER = '\x1bOM' + + +class VT220Keys(object): + # F1-F5 didn't exist historically, but were added by later emulators + F1 = '\x1b[11~' + F2 = '\x1b[12~' + F3 = '\x1b[13~' + F4 = '\x1b[14~' + F5 = '\x1b[15~' + + # Historical keys + F6 = '\x1b[17~' + F7 = '\x1b[18~' + F8 = '\x1b[19~' + F9 = '\x1b[20~' + F10 = '\x1b[21~' + F11 = '\x1b[23~' + F12 = '\x1b[24~' + + # F13+ and key combinations to enter them are of limited usefulness today + + +class UnixKeys(object): + # Keys found experimentally, of unknown provenance + ESC = '\x1b' + + HOME = '\x1b[H' + END = '\x1b[F' + PAGE_UP = '\x1b[5' + PAGE_DOWN = '\x1b[6' + + ENTER = '\n' + CR = '\r' + BACKSPACE = '\x7f' + + SPACE = ' ' + + INSERT = '\x1b[2~' + DELETE = '\x1b[3~' + + +class AlternativeUnixFunctionKeys(object): + # Unsure origin: alternate V220 mode? + F1 = '\x1bO11~' + F2 = '\x1bO12~' + F3 = '\x1bO13~' + F4 = '\x1bO14~' + F5 = '\x1bO15~' + F6 = '\x1bO17~' + F7 = '\x1bO18~' + F8 = '\x1bO19~' + F9 = '\x1bO20~' + F10 = '\x1bO21~' + F11 = '\x1bO23~' + F12 = '\x1bO24~' + + +class WindowsKeys(object): + ESC = '\x1b' + + LEFT = '\xe0K' + RIGHT = '\xe0M' + UP = '\xe0H' + DOWN = '\xe0P' + + ENTER = '\r' + BACKSPACE = '\x08' + SPACE = ' ' + + F1 = '\x00;' + F2 = '\x00<' + F3 = '\x00=' + F4 = '\x00>' + F5 = '\x00?' + F6 = '\x00@' + F7 = '\x00A' + F8 = '\x00B' + F9 = '\x00C' + F10 = '\x00D' + F11 = '\xe0\x85' + F12 = '\xe0\x86' + + INSERT = '\xe0R' + DELETE = '\xe0S' + PAGE_UP = '\xe0I' + PAGE_DOWN = '\xe0Q' + HOME = '\xe0G' + END = '\xe0O' + + CTRL_F1 = '\x00^' + CTRL_F2 = '\x00_' + CTRL_F3 = '\x00`' + CTRL_F4 = '\x00a' + CTRL_F5 = '\x00b' + CTRL_F6 = '\x00c' + CTRL_F7 = '\x00d' # Captured by something? + CTRL_F8 = '\x00e' + CTRL_F9 = '\x00f' + CTRL_F10 = '\x00g' + CTRL_F11 = '\xe0\x89' + CTRL_F12 = '\xe0\x8a' + + CTRL_HOME = '\xe0w' + CTRL_END = '\xe0u' + CTRL_INSERT = '\xe0\x92' + CTRL_DELETE = '\xe0\x93' + CTRL_PAGE_DOWN = '\xe0v' + + CTRL_2 = '\x00\x03' + CTRL_UP = '\xe0\x8d' + CTRL_DOWN = '\xe0\x91' + CTRL_LEFT = '\xe0s' + CTRL_RIGHT = '\xe0t' + + CTRL_ALT_A = '\x00\x1e' + CTRL_ALT_B = '\x000' + CTRL_ALT_C = '\x00.' + CTRL_ALT_D = '\x00 ' + CTRL_ALT_E = '\x00\x12' + CTRL_ALT_F = '\x00!' + CTRL_ALT_G = '\x00"' + CTRL_ALT_H = '\x00#' + CTRL_ALT_I = '\x00\x17' + CTRL_ALT_J = '\x00$' + CTRL_ALT_K = '\x00%' + CTRL_ALT_L = '\x00&' + CTRL_ALT_M = '\x002' + CTRL_ALT_N = '\x001' + CTRL_ALT_O = '\x00\x18' + CTRL_ALT_P = '\x00\x19' + CTRL_ALT_Q = '\x00\x10' + CTRL_ALT_R = '\x00\x13' + CTRL_ALT_S = '\x00\x1f' + CTRL_ALT_T = '\x00\x14' + CTRL_ALT_U = '\x00\x16' + CTRL_ALT_V = '\x00/' + CTRL_ALT_W = '\x00\x11' + CTRL_ALT_X = '\x00-' + CTRL_ALT_Y = '\x00\x15' + CTRL_ALT_Z = '\x00,' + CTRL_ALT_1 = '\x00x' + CTRL_ALT_2 = '\x00y' + CTRL_ALT_3 = '\x00z' + CTRL_ALT_4 = '\x00{' + CTRL_ALT_5 = '\x00|' + CTRL_ALT_6 = '\x00}' + CTRL_ALT_7 = '\x00~' + CTRL_ALT_8 = '\x00\x7f' + CTRL_ALT_9 = '\x00\x80' + CTRL_ALT_0 = '\x00\x81' + CTRL_ALT_MINUS = '\x00\x82' + CTRL_ALT_EQUALS = '\x00x83' + CTRL_ALT_BACKSPACE = '\x00\x0e' + + ALT_F1 = '\x00h' + ALT_F2 = '\x00i' + ALT_F3 = '\x00j' + ALT_F4 = '\x00k' + ALT_F5 = '\x00l' + ALT_F6 = '\x00m' + ALT_F7 = '\x00n' + ALT_F8 = '\x00o' + ALT_F9 = '\x00p' + ALT_F10 = '\x00q' + ALT_F11 = '\xe0\x8b' + ALT_F12 = '\xe0\x8c' + ALT_HOME = '\x00\x97' + ALT_END = '\x00\x9f' + ALT_INSERT = '\x00\xa2' + ALT_DELETE = '\x00\xa3' + ALT_PAGE_UP = '\x00\x99' + ALT_PAGE_DOWN = '\x00\xa1' + ALT_LEFT = '\x00\x9b' + ALT_RIGHT = '\x00\x9d' + ALT_UP = '\x00\x98' + ALT_DOWN = '\x00\xa0' + + CTRL_ALT_LEFT_BRACKET = '\x00\x1a' + CTRL_ALT_RIGHT_BRACKET = '\x00\x1b' + CTRL_ALT_SEMICOLON = '\x00\'' + CTRL_ALT_SINGLE_QUOTE = '\x00(' + CTRL_ALT_ENTER = '\x00\x1c' + CTRL_ALT_SLASH = '\x005' + CTRL_ALT_PERIOD = '\x004' + CTRL_ALT_COMMA = '\x003' + + +class ControlKeys(object): + def __init__(self, format='CTRL_{}'): + for i in range(0x20): + low_char = chr(i) + high_char = chr(i + 0x40) + name = ASCII_NAMES.get(high_char, high_char).upper() + ctrl_name = format.format(name) + setattr(self, ctrl_name, low_char) + + +class AsciiKeys(object): + def __init__( + self, + lower_format='{}', upper_format='SHIFT_{}', digit_format='N{}', + ascii_names=ASCII_NAMES, + ): + for letter in string.ascii_lowercase: + name = lower_format.format(letter.upper()) + setattr(self, name, letter) + for letter in string.ascii_uppercase: + name = upper_format.format(letter.upper()) + setattr(self, name, letter) + for digit in string.digits: + name = digit_format.format(digit) + setattr(self, name, digit) + for char, name in ascii_names.items(): + name = name.upper().replace(' ', '_') + setattr(self, name, char) + + +class Keys(object): + def __init__(self, keyclasses): + self.__names = dict() # Map of codes -> names + self.__codes = dict() # Map of names -> codes + + self.__escapes = set() + + for keyclass in keyclasses: + for name in dir(keyclass): + if self._is_key_name(name): + code = getattr(keyclass, name) + self.register(name, code) + + def register(self, name, code): + if name not in self.__codes: + self.__codes[name] = code + if code not in self.__names: + self.__names[code] = name + for i in range(len(code)): + self.__escapes.add(code[:i]) + + # Update towards canonicity + while True: + canon_code = self.canon(code) + canon_canon_code = self.canon(canon_code) + if canon_code != canon_canon_code: + self.__codes[self.name(code)] = canon_canon_code + else: + break + while True: + canon_name = self.name(self.code(name)) + canon_canon_name = self.name(self.code(canon_name)) + if canon_name != canon_canon_name: + self.__names[self.code(name)] = canon_canon_name + else: + break + + @property + def escapes(self): + return self.__escapes + + @property + def names(self): + return self.__codes.keys() + + def name(self, code): + return self.__names.get(code) + + def code(self, name): + return self.__codes.get(name) + + def canon(self, code): + name = self.name(code) + return self.code(name) if name else code + + def __getattr__(self, name): + code = self.code(name) + if code is not None: + return code + else: + return self.__getattribute__(name) + + def _is_key_name(self, name): + return name == name.upper() and not name.startswith('_') + + +def _make_escapes(codes): + escapes = set() + for code in codes: + for i in range(len(code)): + escapes.add(code[:i]) + return escapes + + +unix_keys = Keys([ + VT100StandardModeKeys(), + VT100ApplicationsModeKeys(), + VT220Keys(), + UnixKeys(), + AlternativeUnixFunctionKeys(), + AsciiKeys(), + ControlKeys(), + UnicodeAsciiKeys(), + JargonKeys(), + IntercalKeys() +]) +windows_keys = Keys([ + WindowsKeys(), + AsciiKeys(), + ControlKeys(), + UnicodeAsciiKeys(), + JargonKeys(), + IntercalKeys() +]) + + +PLATFORM_KEYS = { + 'unix': unix_keys, + 'windows': windows_keys, +} diff --git a/getkey/platforms.py b/getkey/platforms.py new file mode 100644 index 0000000..3bb4345 --- /dev/null +++ b/getkey/platforms.py @@ -0,0 +1,238 @@ +# -*- coding: utf-8 -*- +# Initially taken from: +# http://code.activestate.com/recipes/134892/ +# Thanks to Danny Yoo + +from __future__ import absolute_import, print_function +from contextlib import contextmanager +import codecs +import os +import sys +from .keynames import PLATFORM_KEYS + + +class PlatformError(Exception): + pass + + +class Platform(object): + def __init__(self, keys=None, interrupts=None): + keys = keys or self.KEYS + + if isinstance(keys, str): + keys = PLATFORM_KEYS[keys] + self.key = self.keys = keys + if interrupts is None: + interrupts = self.INTERRUPTS + self.interrupts = { + self.keys.code(name): action + for name, action in interrupts.items() + } + + assert( + self.__class__.getchar != Platform.getchar or + self.__class__.getchars != Platform.getchars + ) + + def getkey(self, blocking=True): + buffer = '' + for c in self.getchars(blocking): + buffer += c + if buffer not in self.keys.escapes: + break + + keycode = self.keys.canon(buffer) + if keycode in self.interrupts: + interrupt = self.interrupts[keycode] + if isinstance(interrupt, BaseException) or \ + issubclass(interrupt, BaseException): + raise interrupt + else: + raise NotImplementedError('Unimplemented interrupt: {!r}' + .format(interrupt)) + return keycode + + def bang(self): + while True: + code = self.getkey(True) + name = self.keys.name(code) or '???' + print('{} = {!r}'.format(name, code)) + + # You MUST override at least one of the following + def getchars(self, blocking=True): + char = self.getchar(blocking) + while char: + yield char + char = self.getchar(False) + + def getchar(self, blocking=True): + for char in self.getchars(blocking): + return char + else: + return None + + +class PlatformUnix(Platform): + KEYS = 'unix' + INTERRUPTS = {'CTRL_C': KeyboardInterrupt} + + def __init__(self, keys=None, interrupts=None, + stdin=None, select=None, tty=None, termios=None): + """Make Unix Platform object. + + Arguments: + keys (Keys): Keys object to use for escapes & names. + interrupts (dict): Map of keys to interrupt actions + (Ctrl-C -> KeyboardInterrupt by default) + stdin (file descriptor): file object to use (stdin by default) + select (callable): select function (select.select by default) + tty (module): tty module + termios (module): termios module + """ + super(PlatformUnix, self).__init__(keys, interrupts) + self.stdin = stdin or sys.stdin + if not select: + from select import select + if not tty: + import tty + if not termios: + import termios + self.select = select + self.tty = tty + self.termios = termios + + try: + self.__decoded_stream = OSReadWrapper(self.stdin) + except Exception as err: + raise PlatformError('Cannot use unix platform on non-file-like stream') + + def fileno(self): + return self.__decoded_stream.fileno() + + @contextmanager + def context(self): + fd = self.fileno() + old_settings = self.termios.tcgetattr(fd) + self.tty.setcbreak(fd) + try: + yield + finally: + self.termios.tcsetattr( + fd, self.termios.TCSADRAIN, old_settings + ) + + def getchars(self, blocking=True): + """Get characters on Unix.""" + with self.context(): + if blocking: + yield self.__decoded_stream.read(1) + while self.select([self.fileno()], [], [], 0)[0]: + yield self.__decoded_stream.read(1) + + +class OSReadWrapper(object): + """Wrap os.read binary input with encoding in standard stream interface. + + We need this since os.read works more consistently on unix, but only + returns byte strings. Since the user might be typing on an international + keyboard or pasting unicode, we need to decode that. Fortunately + python's stdin has the fileno & encoding attached to it, so we can + just use that. + """ + def __init__(self, stream, encoding=None): + """Construct os.read wrapper. + + Arguments: + stream (file object): File object to read. + encoding (str): Encoding to use (gets from stream by default) + """ + self.__stream = stream + self.__fd = stream.fileno() + self.encoding = encoding or stream.encoding + self.__decoder = codecs.getincrementaldecoder(self.encoding)() + + def fileno(self): + return self.__fd + + @property + def buffer(self): + return self.__stream.buffer + + def read(self, chars): + buffer = '' + while len(buffer) < chars: + buffer += self.__decoder.decode(os.read(self.__fd, 1)) + return buffer + + +class PlatformWindows(Platform): + KEYS = 'windows' + INTERRUPTS = {'CTRL_C': KeyboardInterrupt} + + def __init__(self, keys=None, interrupts=None, msvcrt=None): + super(PlatformWindows, self).__init__(keys, interrupts) + if msvcrt is None: + import msvcrt + self.msvcrt = msvcrt + + def getchars(self, blocking=True): + """Get characters on Windows.""" + + if blocking: + yield self.msvcrt.getch() + while self.msvcrt.kbhit(): + yield self.msvcrt.getch() + + +class PlatformTest(Platform): + KEYS = 'unix' + INTERRUPTS = {} + + def __init__(self, chars='', keys=None, interrupts=None): + super(PlatformTest, self).__init__(keys, interrupts) + self.chars = chars + self.index = 0 + + def getchar(self, blocking=True): + if self.index >= len(self.chars) and not blocking: + return '' + else: + char = self.chars[self.index] + self.index += 1 + return char + + +class PlatformInvalid(Platform): + KEYS = 'unix' + INTERRUPTS = {'CTRL_C': KeyboardInterrupt} + + def getchar(self, blocking=True): + raise RuntimeError('Cannot getkey on invalid platform!') + + +def windows_or_unix(*args, **kwargs): + try: + import msvcrt + except ImportError: + return PlatformUnix(*args, **kwargs) + else: + return PlatformWindows(*args, **kwargs) + + +PLATFORMS = [ + ('linux', PlatformUnix), + ('darwin', PlatformUnix), + ('win32', PlatformWindows), + ('cygwin', windows_or_unix), +] + + +def platform(name=None, keys=None, interrupts=None): + name = name or sys.platform + for prefix, ctor in PLATFORMS: + if name.startswith(prefix): + return ctor(keys=keys, interrupts=interrupts) + else: + raise NotImplementedError('Unknown platform {!r}'.format(name)) + + diff --git a/getkey/unikeys.py b/getkey/unikeys.py new file mode 100644 index 0000000..3f0e389 --- /dev/null +++ b/getkey/unikeys.py @@ -0,0 +1,167 @@ +class UnicodeAsciiKeys(object): + NULL = '\x00' + START_OF_HEADING = '\x01' + START_OF_TEXT = '\x02' + END_OF_TEXT = '\x03' + END_OF_TRANSMISSION = '\x04' + ENQUIRY = '\x05' + ACKNOWLEDGE = '\x06' + BELL = '\x07' + BACKSPACE = '\x08' + CHARACTER_TABULATION = '\t' + HORIZONTAL_TABULATION = '\t' + TAB = '\t' + LINE_FEED = '\n' + NEW_LINE = '\n' + END_OF_LINE = '\n' + LINE_TABULATION = '\x0b' + VERTICAL_TABULATION = '\x0b' + FORM_FEED = '\x0c' + CARRIAGE_RETURN = '\r' + SHIFT_OUT = '\x0e' + SHIFT_IN = '\x0f' + DATA_LINK_ESCAPE = '\x10' + DEVICE_CONTROL_ONE = '\x11' + DEVICE_CONTROL_TWO = '\x12' + DEVICE_CONTROL_THREE = '\x13' + DEVICE_CONTROL_FOUR = '\x14' + NEGATIVE_ACKNOWLEDGE = '\x15' + SYNCHRONOUS_IDLE = '\x16' + END_OF_TRANSMISSION_BLOCK = '\x17' + CANCEL = '\x18' + END_OF_MEDIUM = '\x19' + SUBSTITUTE = '\x1a' + ESCAPE = '\x1b' + INFORMATION_SEPARATOR_FOUR = '\x1c' + FILE_SEPARATOR = '\x1c' + INFORMATION_SEPARATOR_THREE = '\x1d' + GROUP_SEPARATOR = '\x1d' + INFORMATION_SEPARATOR_TWO = '\x1e' + RECORD_SEPARATOR = '\x1e' + INFORMATION_SEPARATOR_ONE = '\x1f' + UNIT_SEPARATOR = '\x1f' + SPACE = ' ' + EXCLAMATION_MARK = '!' + FACTORIAL = '!' + BANG = '!' + QUOTATION_MARK = '"' + NUMBER_SIGN = '#' + POUND_SIGN = '#' + HASH = '#' + CROSSHATCH = '#' + OCTOTHORPE = '#' + DOLLAR_SIGN = '$' + ESCUDO = '$' + PERCENT_SIGN = '%' + AMPERSAND = '&' + APOSTROPHE = "'" + APOSTROPHE_QUOTE = "'" + APL_QUOTE = "'" + LEFT_PARENTHESIS = '(' + OPENING_PARENTHESIS = '(' + RIGHT_PARENTHESIS = ')' + CLOSING_PARENTHESIS = ')' + ASTERISK = '*' + STAR = '*' + PLUS_SIGN = '+' + COMMA = ',' + DECIMAL_SEPARATOR = ',' + HYPHEN_MINUS = '-' + HYPHEN_OR_MINUS_SIGN = '-' + FULL_STOP = '.' + PERIOD = '.' + DOT = '.' + DECIMAL_POINT = '.' + SOLIDUS = '/' + SLASH = '/' + VIRGULE = '/' + DIGIT_ZERO = '0' + DIGIT_ONE = '1' + DIGIT_TWO = '2' + DIGIT_THREE = '3' + DIGIT_FOUR = '4' + DIGIT_FIVE = '5' + DIGIT_SIX = '6' + DIGIT_SEVEN = '7' + DIGIT_EIGHT = '8' + DIGIT_NINE = '9' + COLON = ':' + SEMICOLON = ';' + LESS_THAN_SIGN = '<' + EQUALS_SIGN = '=' + GREATER_THAN_SIGN = '>' + QUESTION_MARK = '?' + COMMERCIAL_AT = '@' + AT_SIGN = '@' + LATIN_CAPITAL_LETTER_A = 'A' + LATIN_CAPITAL_LETTER_B = 'B' + LATIN_CAPITAL_LETTER_C = 'C' + LATIN_CAPITAL_LETTER_D = 'D' + LATIN_CAPITAL_LETTER_E = 'E' + LATIN_CAPITAL_LETTER_F = 'F' + LATIN_CAPITAL_LETTER_G = 'G' + LATIN_CAPITAL_LETTER_H = 'H' + LATIN_CAPITAL_LETTER_I = 'I' + LATIN_CAPITAL_LETTER_J = 'J' + LATIN_CAPITAL_LETTER_K = 'K' + LATIN_CAPITAL_LETTER_L = 'L' + LATIN_CAPITAL_LETTER_M = 'M' + LATIN_CAPITAL_LETTER_N = 'N' + LATIN_CAPITAL_LETTER_O = 'O' + LATIN_CAPITAL_LETTER_P = 'P' + LATIN_CAPITAL_LETTER_Q = 'Q' + LATIN_CAPITAL_LETTER_R = 'R' + LATIN_CAPITAL_LETTER_S = 'S' + LATIN_CAPITAL_LETTER_T = 'T' + LATIN_CAPITAL_LETTER_U = 'U' + LATIN_CAPITAL_LETTER_V = 'V' + LATIN_CAPITAL_LETTER_W = 'W' + LATIN_CAPITAL_LETTER_X = 'X' + LATIN_CAPITAL_LETTER_Y = 'Y' + LATIN_CAPITAL_LETTER_Z = 'Z' + LEFT_SQUARE_BRACKET = '[' + OPENING_SQUARE_BRACKET = '[' + REVERSE_SOLIDUS = '\\' + BACKSLASH = '\\' + RIGHT_SQUARE_BRACKET = ']' + CLOSING_SQUARE_BRACKET = ']' + CIRCUMFLEX_ACCENT = '^' + LOW_LINE = '_' + SPACING_UNDERSCORE = '_' + GRAVE_ACCENT = '`' + LATIN_SMALL_LETTER_A = 'a' + LATIN_SMALL_LETTER_B = 'b' + LATIN_SMALL_LETTER_C = 'c' + LATIN_SMALL_LETTER_D = 'd' + LATIN_SMALL_LETTER_E = 'e' + LATIN_SMALL_LETTER_F = 'f' + LATIN_SMALL_LETTER_G = 'g' + LATIN_SMALL_LETTER_H = 'h' + LATIN_SMALL_LETTER_I = 'i' + LATIN_SMALL_LETTER_J = 'j' + LATIN_SMALL_LETTER_K = 'k' + LATIN_SMALL_LETTER_L = 'l' + LATIN_SMALL_LETTER_M = 'm' + LATIN_SMALL_LETTER_N = 'n' + LATIN_SMALL_LETTER_O = 'o' + LATIN_SMALL_LETTER_P = 'p' + LATIN_SMALL_LETTER_Q = 'q' + LATIN_SMALL_LETTER_R = 'r' + LATIN_SMALL_LETTER_S = 's' + LATIN_SMALL_LETTER_T = 't' + LATIN_SMALL_LETTER_U = 'u' + LATIN_SMALL_LETTER_V = 'v' + LATIN_SMALL_LETTER_W = 'w' + LATIN_SMALL_LETTER_X = 'x' + LATIN_SMALL_LETTER_Y = 'y' + LATIN_SMALL_LETTER_Z = 'z' + LEFT_CURLY_BRACKET = '{' + OPENING_CURLY_BRACKET = '{' + LEFT_BRACE = '{' + VERTICAL_LINE = '|' + VERTICAL_BAR = '|' + RIGHT_CURLY_BRACKET = '}' + CLOSING_CURLY_BRACKET = '}' + RIGHT_BRACE = '}' + TILDE = '~' + DELETE = '\x7f' diff --git a/graphics/__pycache__/colors.cpython-38.pyc b/graphics/__pycache__/colors.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f316dce83570a5cf71030ba88d5d86e811b99079 GIT binary patch literal 1113 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 H7C-qBRdhJ> literal 0 HcmV?d00001 diff --git a/graphics/__pycache__/key_listener.cpython-38.pyc b/graphics/__pycache__/key_listener.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70d416e0c855dc4fa208801bb4f53d5986e327ac GIT binary patch literal 508 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 JiMfe${{t(?`v(93 literal 0 HcmV?d00001 diff --git a/graphics/colors.py b/graphics/colors.py new file mode 100644 index 0000000..6b49415 --- /dev/null +++ b/graphics/colors.py @@ -0,0 +1,44 @@ +class Colors: + RESET = '\33[0m' + BOLD = '\33[1m' + ITALIC = '\33[3m' + URL = '\33[4m' + BLINK = '\33[5m' + BLINK2 = '\33[6m' + SELECTED = '\33[7m' + + BLACK = '\33[30m' + RED = '\33[31m' + GREEN = '\33[32m' + YELLOW = '\33[33m' + BLUE = '\33[34m' + VIOLET = '\33[35m' + BEIGE = '\33[36m' + WHITE = '\33[37m' + + BLACKBG = '\33[40m' + REDBG = '\33[41m' + GREENBG = '\33[42m' + YELLOWBG = '\33[43m' + BLUEBG = '\33[44m' + VIOLETBG = '\33[45m' + BEIGEBG = '\33[46m' + WHITEBG = '\33[47m' + + GREY = '\33[90m' + RED2 = '\33[91m' + GREEN2 = '\33[92m' + YELLOW2 = '\33[93m' + BLUE2 = '\33[94m' + VIOLET2 = '\33[95m' + BEIGE2 = '\33[96m' + WHITE2 = '\33[97m' + + GREYBG = '\33[100m' + REDBG2 = '\33[101m' + GREENBG2 = '\33[102m' + YELLOWBG2 = '\33[103m' + BLUEBG2 = '\33[104m' + VIOLETBG2 = '\33[105m' + BEIGEBG2 = '\33[106m' + WHITEBG2 = '\33[107m' \ No newline at end of file diff --git a/graphics/engine.py b/graphics/engine.py new file mode 100644 index 0000000..f2bdbc5 --- /dev/null +++ b/graphics/engine.py @@ -0,0 +1,98 @@ +import os +from graphics.colors import Colors + +class Screen: + """Moteur graphique basé sur des claques""" + instance = None + + def __init__(self, game): + Screen.instance = self + + size = os.get_terminal_size() + if size.columns < 120 or size.lines < 30: + raise OSError("terminal is too small") + self.x = size.columns + self.y = size.lines - 2 + self.frame = {} + self.__layers = {} + self.handlers = [] + + game.late_init() + self.game = game + + def set_layer(self, layer): + self.__layers[layer.name] = layer + + def del_layer(self, name): + del self.__layers[name] + + def get_layer(self, name): + if not name in self.__layers.keys(): + raise ValueError("unknown key") + return self.__layers[name] + + def __combine_layers(self): + self.frame = {} + layers = sorted(self.__layers.values(), key=lambda layer: layer.z_index) + for layer in layers: + layer.draw() + self.frame.update(layer.frame) + + def draw(self): + self.__combine_layers() + buffer = "" + for y in range(self.y): + for x in range(self.x): + if (x, y) in self.frame: + buffer += self.frame[(x, y)] + else: + buffer += " " + buffer += "\n" + print("\033[H\033[J", end="") + print(buffer) + + def send_key(self, key): + """Envoie les touches reçues à tous les calques actifs""" + for layer in list(self.__layers.values()): + if layer.handle_keys == True: + layer.key_handler(key) + + +class Layer: + def __init__(self, z_index, name): + self.name = name + self.frame = {} + self.z_index = z_index + self.x = Screen.instance.x + self.y = Screen.instance.y + self.handle_keys = True + + Screen.instance.set_layer(self) + + def put_char(self, char, x, y, colors=[]): + if x > self.x or x < 0 or y > self.y or y < 0: + raise ValueError("out of range pixel") + self.frame[(x, y)] = "".join(colors) + char + Colors.RESET + + def put_string(self, string, x, y, colors=[]): + if x > self.x or x < 0 or y > self.y or y < 0: + raise ValueError("out of range pixel") + string = string.split("\n") + for string_y in range(len(string)): + for string_x in range(len(string[string_y])): + self.frame[(x+string_x, y+string_y)] = "".join(colors) + string[string_y][string_x] + Colors.RESET + + def rect(self, x1, y1, x2, y2, colors=[], template=' '): + if (x1 > self.x or x1 < 0 or y1 > self.y or y1 < 0) or (x2 > self.x or x2 < 0 or y2 > self.y or y2 < 0): + raise ValueError("out of range pixel") + if len(template) > 1: + raise ValueError("template should be 1 char long") + for x in range(x1, x2+1): + for y in range(y1, y2+1): + self.frame[(x, y)] = "".join(colors) + template + Colors.RESET + + def draw(self): + self.frame = {} + + def key_handler(self): + pass \ No newline at end of file diff --git a/graphics/key_listener.py b/graphics/key_listener.py new file mode 100644 index 0000000..45e4d4e --- /dev/null +++ b/graphics/key_listener.py @@ -0,0 +1,10 @@ +from threading import Thread +from getkey import getkey + +def __listener(screen): + while True: + key = getkey() + screen.send_key(key) + +def build_thread(screen): + return Thread(target=__listener, args=(screen,)) diff --git a/graphics/layers.py b/graphics/layers.py new file mode 100644 index 0000000..c3b6720 --- /dev/null +++ b/graphics/layers.py @@ -0,0 +1,173 @@ +from graphics.colors import Colors +from graphics.engine import Layer + +from graphics.engine import Screen + +from getkey import keys +from re import match + +class GUI(Layer): + """Calque du menu principal""" + def __init__(self, z_index): + super().__init__(z_index, "gui") + self.__current = 0 + self.__buttons = ["Attaquer", "Inventaire"] + self.__inventaire = False + self.handle_keys = False + + self.__page = 1 + + def draw(self): + super().draw() + if self.__inventaire == False: + x = 1 + for button in self.__buttons: + color = (Colors.REDBG, Colors.BLACK) if self.__buttons[self.__current] == button else (Colors.WHITEBG, Colors.BLACK) + self.put_string(button, x, self.y-10, color) + x += len(button)+1 + + stats = Screen.instance.game.personnage.affiche_caracteristiques() + for i in range(5): + self.put_string(stats[i], 1, self.y-8+i, [Colors.RED2]) + + ennemy_stats = Screen.instance.game.ennemy.affiche_caracteristiques() + for i in range(5): + self.put_string(ennemy_stats[i], self.x-(self.x-2)//3, self.y-8+i, [Colors.BLUE2]) + + else: + x = 1 + for button in self.__buttons: + color = (Colors.REDBG, Colors.BLACK) if self.__buttons[self.__current] == button else (Colors.WHITEBG, Colors.BLACK) + self.put_string(button, x, self.y-10, color) + x += len(button)+1 + + self.put_string("Votre inventaire:", 1, self.y-8, [Colors.RED2]) + stats = Screen.instance.game.personnage.affiche_inventaire() + for i in range(len(stats)): + self.put_string(stats[i], 1, self.y-7+i, [Colors.RED2]) + + return self + + def key_handler(self, key): + if key == keys.RIGHT and self.__current < len(self.__buttons)-1: + self.__current += 1 + elif key == keys.LEFT and self.__current > 0: + self.__current -= 1 + elif key == keys.ENTER: + if self.__inventaire == False: + if self.__current == 0: + attacker = Screen.instance.game.personnage + victim = Screen.instance.game.ennemy + Screen.instance.game.attack(attacker, victim) + elif self.__current == 1: + self.__inventaire = True + self.__buttons = ["Retour", "Utiliser une potion"] + else: + if self.__current == 0: + self.__inventaire = False + self.__buttons = ["Attaquer", "Inventaire"] + elif self.__current == 1: + perso = Screen.instance.game.personnage + for item in range(len(perso.inventaire)): + if perso.inventaire[item] == "POTION": + perso.change_pdv(-10) + del perso.inventaire[item] + break + + + +class StartPopUp(Layer): + """Calque du menu de lancement""" + def __init__(self, z_index): + super().__init__(z_index, "popup") + self.__classes = ["Guerrier", "Magicien", "Voleur", "Elfe"] + self.__choosen_class = 0 + self.__username = "" + self.__missing_un = False + + def draw(self): + super().draw() + #bg + self.rect(self.x//3, self.y//6, self.x*2//3, self.y//4 + self.y//3, Colors.WHITEBG) + #name + self.put_string("Nom: (A-z)", self.x//3 + 1, self.y//6 + 1, [Colors.WHITEBG, Colors.BLACK]) + self.rect(self.x//3 + 1, self.y//6 + 2, self.x*2//3 - 2, self.y//6 + 2, Colors.REDBG if self.__missing_un else Colors.BLACKBG) + self.put_string(self.__username, self.x//3 + 1, self.y//6 + 2, [Colors.WHITE, Colors.BLACKBG]) + #Classes + self.put_string("Classe perso.: (Flèches)", self.x//3 + 1, self.y//6 + 4, [Colors.WHITEBG, Colors.BLACK]) + y = 0 + for user_class in self.__classes: + colors = [Colors.REDBG, Colors.BLACK] if y == self.__choosen_class else [Colors.GREYBG, Colors.WHITE] + self.put_string(user_class, self.x//3 + 2, self.y//6 + 5 + y, colors) + y += 1 + + self.put_string("TAB pour confirmer", self.x//3 + 1, self.y//4 + self.y//3 -1, [Colors.WHITEBG, Colors.BLACK]) + + return self + + def key_handler(self, key): + if match("[a-zA-Z]", key): + self.__username += key + elif key == keys.BACKSPACE: + self.__username = self.__username[:-1] + elif key == keys.UP and self.__choosen_class > 0: + self.__choosen_class -= 1 + elif key == keys.DOWN and self.__choosen_class < 3: + self.__choosen_class += 1 + elif key == keys.TAB: + if len(self.__username) == 0: + self.__missing_un = True + return + Screen.instance.get_layer("gui").handle_keys = True + Screen.instance.del_layer("popup") + Screen.instance.game.init_personnage(self.__username, self.__classes[self.__choosen_class]) + +class PopUp(Layer): + """Calque du menu de lancement""" + def __init__(self, z_index, message, block=False): + super().__init__(z_index, "popup") + self.message = message + self.block = block + Screen.instance.get_layer("gui").handle_keys = False + + def draw(self): + super().draw() + self.rect(self.x//3, self.y//6, self.x*2//3, self.y//4 + self.y//3, Colors.WHITEBG) + length = (self.x*2//3-1) - (self.x//3+1) + x = 0 + y = 0 + for char in self.message: + if char == "\n": + x = 0 + y += 1 + continue + self.put_char(char, self.x//3 + 1 + x, self.y//6 + 1 + y, [Colors.WHITEBG, Colors.BLACK]) + x += 1 + if x == length: + x = 0 + y += 1 + + if not self.block: + self.put_string("TAB pour confirmer", self.x//3 + 1, self.y//4 + self.y//3 -1, [Colors.WHITEBG, Colors.BLACK]) + + return self + + def key_handler(self, key): + if key == keys.TAB and not self.block: + Screen.instance.get_layer("gui").handle_keys = True + Screen.instance.del_layer("popup") + +class Sprite(Layer): + def __init__(self, z_index, sprite_name, personnage_type): + super().__init__(z_index, personnage_type) + self.personnage_type = personnage_type + self.sprite_name = sprite_name + + def draw(self): + super().draw() + with open(f"game/sprites/{self.sprite_name}.txt", "r") as sprite: + pos = (1, 1) if self.personnage_type == "PLAYER" else (Screen.instance.x*2//3+1, 1) + self.put_string(sprite.read(), *pos) + + def key_handler(self, key): + pass \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..24b582e --- /dev/null +++ b/main.py @@ -0,0 +1,21 @@ +from game.personnage import * +from game.core import Game + +import graphics.layers as layers +from graphics.engine import Screen +import graphics.key_listener as listener + +from time import sleep + +if __name__ == "__main__": + #Initialise la partie graphique + game = Game() + screen = Screen(game) + layers.StartPopUp(1) + layers.GUI(2) + + listener.build_thread(screen).start() + + while True: + screen.draw() + sleep(0.4) \ No newline at end of file