laneya

multiplayer roguelike game
git clone https://git.ce9e.org/laneya.git

commit
b8879d299a1d6868216f6aa923a13756109b2f23
parent
a7771dbef586a628ac172d5bc76445f61572b89c
Author
Tobias Bengfort <tobias.bengfort@gmx.net>
Date
2014-10-06 20:15
create dirtywords

dirtywords is a curses replacement. It is build on a minimal set of
functions that can be implemented with a variety of backend, e.g. curses
or pygame.

It is relatively hard to install either curses or pygame. They can not
simply be installed with pip. So dirtywords offers an abstraction layer
that provides the best possible experience on the target machiene.

Diffstat

A laneya/dirtywords/__init__.py 11 +++++++++++
A laneya/dirtywords/base.py 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A laneya/dirtywords/curses_dirtywords.py 33 +++++++++++++++++++++++++++++++++
A laneya/dirtywords/example.py 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
A laneya/dirtywords/pygame_dirtywords.py 41 +++++++++++++++++++++++++++++++++++++++++
A laneya/dirtywords/stupid_dirtywords.py 28 ++++++++++++++++++++++++++++

6 files changed, 250 insertions, 0 deletions


diff --git a/laneya/dirtywords/__init__.py b/laneya/dirtywords/__init__.py

@@ -0,0 +1,11 @@
   -1     1 # flake8: noqa
   -1     2 
   -1     3 try:
   -1     4     from pygame_dirtywords import Screen
   -1     5 except ImportError:
   -1     6     try:
   -1     7         from curses_dirtywords import Screen
   -1     8     except ImportError:
   -1     9         from stupid_dirtywords import Screen
   -1    10 
   -1    11 from base import Window

diff --git a/laneya/dirtywords/base.py b/laneya/dirtywords/base.py

@@ -0,0 +1,83 @@
   -1     1 class BaseScreen(object):
   -1     2     def __init__(self, height, width):
   -1     3         """Initialize screen."""
   -1     4         self.height = height
   -1     5         self.width = width
   -1     6         self.data = [[' ' for xx in range(width)] for yy in range(height)]
   -1     7 
   -1     8     def getch(self):
   -1     9         """Get next keystroke (blocking)."""
   -1    10         raise NotImplementedError
   -1    11 
   -1    12     def putstr(self, y, x, s):
   -1    13         """Write string to position."""
   -1    14         for i, ch in enumerate(s):
   -1    15             try:
   -1    16                 self.data[y][x + i] = ch
   -1    17             except IndexError:
   -1    18                 pass
   -1    19 
   -1    20     def refresh(self):
   -1    21         """Print the current state to the screen."""
   -1    22         raise NotImplementedError
   -1    23 
   -1    24     def cleanup(self):
   -1    25         """Deinitialize screen."""
   -1    26         pass
   -1    27 
   -1    28 
   -1    29 class Screen(BaseScreen):
   -1    30     """Additional utility functions for :py:class:`BaseScreen`."""
   -1    31 
   -1    32     def delch(self, y, x):
   -1    33         """Delete character at position."""
   -1    34         self.putstr(y, x, ' ')
   -1    35 
   -1    36     def fill_row(self, y, ch):
   -1    37         """Fill a complete row with character."""
   -1    38         self.putstr(y, 0, ch * self.width)
   -1    39 
   -1    40     def fill_column(self, x, ch):
   -1    41         """Fill a complete column with character."""
   -1    42         for y in range(self.height):
   -1    43             self.putstr(y, x, ch)
   -1    44 
   -1    45     def fill(self, ch):
   -1    46         """Fill whole screen with character."""
   -1    47         for y in range(self.height):
   -1    48             self.row(y, ch)
   -1    49 
   -1    50     def clear(self):
   -1    51         """Clear whole screen."""
   -1    52         self.fill(' ')
   -1    53 
   -1    54     def border(self, ls='|', rs='|', ts='-', bs='-',
   -1    55                tl='+', tr='+', bl='+', br='+'):
   -1    56         """Draw border around screen."""
   -1    57         self.fill_column(0, ls)
   -1    58         self.fill_column(self.width - 1, rs)
   -1    59         self.fill_row(0, ts)
   -1    60         self.fill_row(self.height - 1, bs)
   -1    61         self.putstr(0, 0, tl)
   -1    62         self.putstr(0, self.width - 1, tr)
   -1    63         self.putstr(self.height - 1, 0, bl)
   -1    64         self.putstr(self.height - 1, self.width - 1, br)
   -1    65 
   -1    66 
   -1    67 class Window(Screen):
   -1    68     """A screen that is rendered onto another screen."""
   -1    69 
   -1    70     def __init__(self, parent, height, width, y, x):
   -1    71         super(Window, self).__init__(height, width)
   -1    72         self.parent = parent
   -1    73         self.y = y
   -1    74         self.x = x
   -1    75 
   -1    76     def getch(self):
   -1    77         return self.parent.getch()
   -1    78 
   -1    79     def refresh(self):
   -1    80         for y in range(self.height):
   -1    81             for x in range(self.width):
   -1    82                 self.parent.putstr(self.y + y, self.x + x, self.data[y][x])
   -1    83         self.parent.refresh()

diff --git a/laneya/dirtywords/curses_dirtywords.py b/laneya/dirtywords/curses_dirtywords.py

@@ -0,0 +1,33 @@
   -1     1 try:
   -1     2     from ncurses import curses
   -1     3 except ImportError:
   -1     4     import curses
   -1     5 
   -1     6 import base
   -1     7 
   -1     8 
   -1     9 class Screen(base.Screen):
   -1    10     def __init__(self, height, width):
   -1    11         self.height = height
   -1    12         self.width = width
   -1    13 
   -1    14         curses.initscr()
   -1    15         curses.noecho()
   -1    16         curses.curs_set(0)
   -1    17         self.curses_window = curses.newwin(height, width, 0, 0)
   -1    18 
   -1    19     def getch(self):
   -1    20         return self.curses_window.getch()
   -1    21 
   -1    22     def putstr(self, y, x, s):
   -1    23         for i, ch in enumerate(s):
   -1    24             try:
   -1    25                 self.curses_window.addstr(y, x + i, ch)
   -1    26             except:
   -1    27                 pass
   -1    28 
   -1    29     def refresh(self):
   -1    30         self.curses_window.refresh()
   -1    31 
   -1    32     def cleanup(self):
   -1    33         curses.endwin()

diff --git a/laneya/dirtywords/example.py b/laneya/dirtywords/example.py

@@ -0,0 +1,54 @@
   -1     1 import sys
   -1     2 
   -1     3 try:
   -1     4     from pygame_dirtywords import Screen
   -1     5 except ImportError:
   -1     6     try:
   -1     7         from curses_dirtywords import Screen
   -1     8     except ImportError:
   -1     9         from stupid_dirtywords import Screen
   -1    10 
   -1    11 
   -1    12 class Player(object):
   -1    13     def __init__(self, win):
   -1    14         self.win = win
   -1    15         self.y = win.height / 2
   -1    16         self.x = win.width / 2
   -1    17 
   -1    18     def move(self, direction):
   -1    19         self.win.putstr(self.y, self.x, ' ')
   -1    20 
   -1    21         if direction == 'up':
   -1    22             self.y -= 1
   -1    23         elif direction == 'right':
   -1    24             self.x += 1
   -1    25         elif direction == 'down':
   -1    26             self.y += 1
   -1    27         elif direction == 'left':
   -1    28             self.x -= 1
   -1    29 
   -1    30         self.win.putstr(self.y, self.x, 'X')
   -1    31         self.win.refresh()
   -1    32 
   -1    33 
   -1    34 if __name__ == '__main__':
   -1    35     scr = Screen(32, 100)
   -1    36 
   -1    37     scr.border()
   -1    38 
   -1    39     player = Player(scr)
   -1    40     player.move('down')  # initial refresh
   -1    41 
   -1    42     while 1:
   -1    43         ch = scr.getch()
   -1    44         if ch == ord('h'):
   -1    45             player.move('left')
   -1    46         elif ch == ord('j'):
   -1    47             player.move('down')
   -1    48         elif ch == ord('k'):
   -1    49             player.move('up')
   -1    50         elif ch == ord('l'):
   -1    51             player.move('right')
   -1    52         elif ch == ord('q'):
   -1    53             scr.cleanup()
   -1    54             sys.exit()

diff --git a/laneya/dirtywords/pygame_dirtywords.py b/laneya/dirtywords/pygame_dirtywords.py

@@ -0,0 +1,41 @@
   -1     1 import pygame
   -1     2 from pygame.locals import KEYDOWN
   -1     3 
   -1     4 import base
   -1     5 
   -1     6 
   -1     7 class Screen(base.Screen):
   -1     8     def __init__(self, height, width):
   -1     9         super(Screen, self).__init__(height, width)
   -1    10 
   -1    11         pygame.init()
   -1    12         self.clock = pygame.time.Clock()
   -1    13 
   -1    14         self.fg_color = pygame.Color('white')
   -1    15         self.bg_color = pygame.Color('black')
   -1    16 
   -1    17         self.font = pygame.font.SysFont('monospace', 10)
   -1    18         _width, self.fontheight = self.font.size(' ' * self.width)
   -1    19         _height = height * self.fontheight
   -1    20 
   -1    21         self.pygame_screen = pygame.display.set_mode((_width, _height))
   -1    22 
   -1    23     def getch(self):
   -1    24         while True:
   -1    25             event = pygame.event.wait()
   -1    26             if event.type == KEYDOWN:
   -1    27                 return event.key
   -1    28 
   -1    29     def refresh(self):
   -1    30         self.pygame_screen.fill(self.bg_color)
   -1    31 
   -1    32         for y in range(self.height):
   -1    33             s = ''.join(self.data[y])
   -1    34             rendered = self.font.render(s, True, self.fg_color, self.bg_color)
   -1    35             self.pygame_screen.blit(rendered, (0, y * self.fontheight))
   -1    36 
   -1    37         self.clock.tick()
   -1    38         pygame.display.flip()
   -1    39 
   -1    40     def cleanup(self):
   -1    41         pygame.quit()

diff --git a/laneya/dirtywords/stupid_dirtywords.py b/laneya/dirtywords/stupid_dirtywords.py

@@ -0,0 +1,28 @@
   -1     1 import sys
   -1     2 
   -1     3 import base
   -1     4 
   -1     5 
   -1     6 class Screen(base.Screen):
   -1     7     def getch(self):
   -1     8         # http://code.activestate.com/recipes/134892/
   -1     9 
   -1    10         try:
   -1    11             import msvcrt
   -1    12             return msvcrt.getch()
   -1    13         except ImportError:
   -1    14             import termios
   -1    15             import tty
   -1    16             fd = sys.stdin.fileno()
   -1    17             old_settings = termios.tcgetattr(fd)
   -1    18             try:
   -1    19                 tty.setraw(sys.stdin.fileno())
   -1    20                 ch = sys.stdin.read(1)
   -1    21             finally:
   -1    22                 termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
   -1    23             return ord(ch)
   -1    24 
   -1    25     def refresh(self):
   -1    26         spacing = '\n' * self.height * 2
   -1    27         s = '\n'.join([''.join(row) for row in self.data])
   -1    28         print(spacing + s)