Browse Source

init

master
Kalyax 2 years ago
commit
fb54e8fa4a
  1. 9
      README.md
  2. BIN
      game/__pycache__/core.cpython-38.pyc
  3. BIN
      game/__pycache__/personnage.cpython-38.pyc
  4. 54
      game/core.py
  5. 73
      game/personnage.py
  6. 16
      game/sprites/Elfe.txt
  7. 14
      game/sprites/Guerrier.txt
  8. 16
      game/sprites/Magicien.txt
  9. 16
      game/sprites/Voleur.txt
  10. 17
      getkey/__init__.py
  11. BIN
      getkey/__pycache__/__init__.cpython-38.pyc
  12. BIN
      getkey/__pycache__/keynames.cpython-38.pyc
  13. BIN
      getkey/__pycache__/platforms.cpython-38.pyc
  14. BIN
      getkey/__pycache__/unikeys.cpython-38.pyc
  15. 481
      getkey/keynames.py
  16. 238
      getkey/platforms.py
  17. 167
      getkey/unikeys.py
  18. BIN
      graphics/__pycache__/colors.cpython-38.pyc
  19. BIN
      graphics/__pycache__/engine.cpython-38.pyc
  20. BIN
      graphics/__pycache__/key_listener.cpython-38.pyc
  21. BIN
      graphics/__pycache__/layers.cpython-38.pyc
  22. 44
      graphics/colors.py
  23. 98
      graphics/engine.py
  24. 10
      graphics/key_listener.py
  25. 173
      graphics/layers.py
  26. 21
      main.py

9
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).
<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

BIN
game/__pycache__/core.cpython-38.pyc

Binary file not shown.

BIN
game/__pycache__/personnage.cpython-38.pyc

Binary file not shown.

54
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)

73
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]

16
game/sprites/Elfe.txt

@ -0,0 +1,16 @@
@@@@@@&
@@@&&@&@@@@&
&@@%&@@%&@*@@@&
&@%&@@@%*,,,,@@%
&@&&*@@#,,@@@,@%
*&&**%@/*#*,,,#*/@,&*
%@@&@&&***,,,%&&
%&@@@@@#@@&%%%&#@&
&%#@&/##&%**,,,,,/%@&
***,,,,,,,,,***%%,,,,,****%&&&@@ @%
%#&@@@@@%@((((&@@@ @
** (%&@@/(##%(//*#* (
%@*/#%/&%(//*%
%*//(#% @#(/**%
@%&&&&@ @&&&&%@
@%%###@ @###%%@

14
game/sprites/Guerrier.txt

@ -0,0 +1,14 @@
@/,
@/###
%#/%%&@@@%&
@@*(%##&&@@%&
/@@@@@@& &&%
&%,@@,,@@ @(
@%&@&%&&@%&@@@%
@//**@ *%%%&%%&%
.@//*/& /#% %&/
%@ &%/
@% @&/
%% &@
&%#% @%

16
game/sprites/Magicien.txt

@ -0,0 +1,16 @@
&&&&&&
&...*&(&&
., .%.%%%*
..... %%&&*(#&&####&&&
(##%%%&&%**#%&##&&#&&
((/&&&&&&%*##&&&#%&&&#(
.& .&&&(#*&&&&#&&
@@&&&%%/@(&&&#&#//**
.@ &&&&##%@@###&% ##
&&%&&%##%%@####%
%%&&&%%@@@@&###
%&&&&&&& @@@%%
**((( *((((@
((### .%#%%#
(((#( .%%%%%

16
game/sprites/Voleur.txt

@ -0,0 +1,16 @@
,,,
,,.%%%.
, ,.%%%.
,,,..,,.
,,..(((.,.
,.,,.///,.
,./(////,.
./,,*,,,.
.*,.**,,
,, *,
. .

17
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'

BIN
getkey/__pycache__/__init__.cpython-38.pyc

Binary file not shown.

BIN
getkey/__pycache__/keynames.cpython-38.pyc

Binary file not shown.

BIN
getkey/__pycache__/platforms.cpython-38.pyc

Binary file not shown.

BIN
getkey/__pycache__/unikeys.cpython-38.pyc

Binary file not shown.

481
getkey/keynames.py

@ -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,
}

238
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))

167
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'

BIN
graphics/__pycache__/colors.cpython-38.pyc

Binary file not shown.

BIN
graphics/__pycache__/engine.cpython-38.pyc

Binary file not shown.

BIN
graphics/__pycache__/key_listener.cpython-38.pyc

Binary file not shown.

BIN
graphics/__pycache__/layers.cpython-38.pyc

Binary file not shown.

44
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'

98
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

10
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,))

173
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

21
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)
Loading…
Cancel
Save