Kalyax
2 years ago
commit
fb54e8fa4a
26 changed files with 1447 additions and 0 deletions
@ -0,0 +1,9 @@ |
|||||
|
# jeu_role |
||||
|
|
||||
|
## Informations |
||||
|
Uniquement fonctionnel dans un terminal qui affiche les couleurs ANSI (CMD et Powershell ne marchent pas). |
||||
|
<br> |
||||
|
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 |
Binary file not shown.
Binary file not shown.
@ -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) |
@ -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] |
@ -0,0 +1,16 @@ |
|||||
|
@@@@@@& |
||||
|
@@@&&@&@@@@& |
||||
|
&@@%&@@%&@*@@@& |
||||
|
&@%&@@@%*,,,,@@% |
||||
|
&@&&*@@#,,@@@,@% |
||||
|
*&&**%@/*#*,,,#*/@,&* |
||||
|
%@@&@&&***,,,%&& |
||||
|
%&@@@@@#@@&%%%&#@& |
||||
|
&%#@&/##&%**,,,,,/%@& |
||||
|
***,,,,,,,,,***%%,,,,,****%&&&@@ @% |
||||
|
%#&@@@@@%@((((&@@@ @ |
||||
|
** (%&@@/(##%(//*#* ( |
||||
|
%@*/#%/&%(//*% |
||||
|
%*//(#% @#(/**% |
||||
|
@%&&&&@ @&&&&%@ |
||||
|
@%%###@ @###%%@ |
@ -0,0 +1,14 @@ |
|||||
|
|
||||
|
@/, |
||||
|
@/### |
||||
|
%#/%%&@@@%& |
||||
|
@@*(%##&&@@%& |
||||
|
/@@@@@@& &&% |
||||
|
&%,@@,,@@ @( |
||||
|
@%&@&%&&@%&@@@% |
||||
|
@//**@ *%%%&%%&% |
||||
|
.@//*/& /#% %&/ |
||||
|
%@ &%/ |
||||
|
@% @&/ |
||||
|
%% &@ |
||||
|
&%#% @% |
@ -0,0 +1,16 @@ |
|||||
|
|
||||
|
&&&&&& |
||||
|
&...*&(&& |
||||
|
., .%.%%%* |
||||
|
..... %%&&*(#&&####&&& |
||||
|
(##%%%&&%**#%&##&&#&& |
||||
|
((/&&&&&&%*##&&&#%&&&#( |
||||
|
.& .&&&(#*&&&&#&& |
||||
|
@@&&&%%/@(&&&#&#//** |
||||
|
.@ &&&&##%@@###&% ## |
||||
|
&&%&&%##%%@####% |
||||
|
%%&&&%%@@@@&### |
||||
|
%&&&&&&& @@@%% |
||||
|
**((( *((((@ |
||||
|
((### .%#%%# |
||||
|
(((#( .%%%%% |
@ -0,0 +1,16 @@ |
|||||
|
|
||||
|
|
||||
|
|
||||
|
,,, |
||||
|
,,.%%%. |
||||
|
, ,.%%%. |
||||
|
,,,..,,. |
||||
|
,,..(((.,. |
||||
|
,.,,.///,. |
||||
|
,./(////,. |
||||
|
./,,*,,,. |
||||
|
.*,.**,, |
||||
|
,, *, |
||||
|
. . |
||||
|
|
||||
|
|
@ -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' |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,481 @@ |
|||||
|
# Which key(s) were pressed |
||||
|
# What chars to print (if any) |
||||
|
# Keycode(s) generating event |
||||
|
import string |
||||
|
from .unikeys import UnicodeAsciiKeys |
||||
|
|
||||
|
|
||||
|
# These are used for the names of ctrl keys, etc. |
||||
|
ASCII_NAMES = { |
||||
|
'\t': 'tab', |
||||
|
|
||||
|
' ': 'space', # 0x20 |
||||
|
'!': 'exclamation', # 0x21 |
||||
|
'"': 'double quote', # 0x22 |
||||
|
'#': 'hash', # 0x23 |
||||
|
'$': 'dollar', # 0x24 |
||||
|
'%': 'percent', # 0x25 |
||||
|
'&': 'ampersand', # 0x26 |
||||
|
'\'': 'single quote', # 0x27 |
||||
|
'(': 'open paren', # 0x28 |
||||
|
')': 'close paren', # 0x29 |
||||
|
'*': 'asterisk', # 0x2a |
||||
|
'+': 'plus', # 0x2b |
||||
|
',': 'comma', # 0x2c |
||||
|
'-': 'minus', # 0x2d |
||||
|
'.': 'period', # 0x2e |
||||
|
'/': 'slash', # 0x2f |
||||
|
|
||||
|
':': 'colon', # 0x3a |
||||
|
';': 'semicolon', # 0x3b |
||||
|
'<': 'less than', # 0x3c |
||||
|
'=': 'equals', # 0x3d |
||||
|
'>': '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, |
||||
|
} |
@ -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)) |
||||
|
|
||||
|
|
@ -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' |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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' |
@ -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 |
@ -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,)) |
@ -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 |
@ -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) |
Loading…
Reference in new issue