Package tdl |
[frames] | no frames]

# Source Code for Package tdl

       1  """
       2      The documentation for python-tdl.  A Pythonic port of
       3      U{libtcod<http://doryen.eptalys.net/libtcod/>}.
       4
       5      You can find the project page on Google Code
       6      U{here<http://code.google.com/p/python-tdl/>}.
       7
       8      Getting Started
       9      ===============
      10        Once the library is imported you can load the font you want to use with
      11        L{tdl.setFont}.
      12        This is optional and when skipped will use a decent default font.
      13
      14        After that you call L{tdl.init} to set the size of the window and get the
      15        root console in return.
      16        This console is the canvas to what will appear on the screen.
      17
      18      Indexing Consoles
      19      =================
      20        For most methods taking a position you can use Python-style negative
      21        indexes to refer to the opposite side of a console with (-1, -1)
      22        starting at the bottom right.
      23        You can also check if a point is part of a console using containment
      24        logic i.e. ((x, y) in console).
      25
      26      Drawing
      27      =======
      28        Once you have the root console from L{tdl.init} you can start drawing on
      29        it using a method such as L{Console.drawChar}.
      30        When using this method you can have the char parameter be an integer or a
      31        single character string.
      32        The fgcolor and bgcolor parameters expect a three item list
      33        [red, green, blue] with integers in the 0-255 range with [0, 0, 0] being
      34        black and [255, 255, 255] being white.
      35        Or instead you can use None for any of the three parameters to tell the
      36        library to keep what is at that spot instead of overwriting it.
      37        After the drawing functions are called a call to L{tdl.flush} will update
      38        the screen.
      39  """
      40
      41  import sys
      42  import os
      43
      44  import ctypes
      45  import weakref
      46  import array
      47  import itertools
      48  import textwrap
      49  import struct
      50  import re
      51  import warnings
      52
      53  from . import event, map, noise
      54  from .__tcod import _lib, _Color, _unpackfile
      55
      56  _IS_PYTHON3 = (sys.version_info[0] == 3)
      57
      58  if _IS_PYTHON3: # some type lists to use with isinstance
      59      _INTTYPES = (int,)
      60      _NUMTYPES = (int, float)
      61      _STRTYPES = (str, bytes)
      62  else:
      63      _INTTYPES = (int, long)
      64      _NUMTYPES = (int, long, float)
      65      _STRTYPES = (str,)
      66
      67 -def _encodeString(string): # still used for filepaths, and that's about it
      68      "changes string into bytes if running in python 3, for sending to ctypes"
      69      if _IS_PYTHON3 and isinstance(string, str):
      70          return string.encode()
      71      return string
      72
      73  #def _formatString(string):
      74  #    pass
      75
      76 -def _formatChar(char):
      77      """Prepares a single character for passing to ctypes calls, needs to return
      78      an integer but can also pass None which will keep the current character
      79      instead of overwriting it.
      80
      81      This is called often and needs to be optimized whenever possible.
      82      """
      83      if char is None:
      84          return None
      85      if isinstance(char, _INTTYPES):
      86          return char
      87      if isinstance(char, _STRTYPES) and len(char) == 1:
      88          return ord(char)
      89      raise TypeError('Expected char parameter to be a single character string, number, or None, got: %s' % repr(char))
      90
      91  _fontinitialized = False
      92  _rootinitialized = False
      93  _rootConsoleRef = None
      94  # remove dots from common functions
      95  _setchar = _lib.TCOD_console_set_char
      96  _setfore = _lib.TCOD_console_set_char_foreground
      97  _setback = _lib.TCOD_console_set_char_background
      98  _setcharEX = _lib.TCOD_console_put_char_ex
      99 -def _verify_colors(*colors):
     100      """Used internally.
     101      Raise an assertion error if the parameters can not be converted into colors.
     102      """
     103      for color in colors:
     104          assert _iscolor(color), 'a color must be a 3 item tuple, web format, or None, received %s' % repr(color)
     105      return True
     106
     107 -def _iscolor(color):
     108      """Used internally.
     109      A debug function to see if an object can be used as a TCOD color struct.
     110      None counts as a parameter to keep the current colors instead.
     111
     112      This function is often part of an inner-loop and can slow a program down.
     113      It has been made to work with assert and can be skipped with the -O flag.
     114      Still it's called often and must be optimized.
     115      """
     116      if color is None:
     117          return True
     118      if isinstance(color, (tuple, list, _Color)):
     119          return len(color) == 3
     120      if isinstance(color, _INTTYPES):
     121          return True
     122      return False
     123
     124  ## not using this for now
     125  #class Color(object):
     126  #
     127  #    def __init__(self, r, g, b):
     128  #        self._color = (r, g, b)
     129  #        self._ctype = None
     130  #
     131  #    def _getCType(self):
     132  #        if not self._ctype:
     133  #            self._ctype = _Color(*self._color)
     134  #        return self._ctype
     135  #
     136  #    def __len__(self):
     137  #        return 3
     138
     139 -def _formatColor(color):
     140      """Format the color to ctypes
     141      """
     142      if color is None:
     143          return None
     144      if isinstance(color, _Color):
     145          return color
     146      #if isinstance(color, Color):
     147      #    return color._getCType()
     148      if isinstance(color, _INTTYPES):
     149          # format a web style color with the format 0xRRGGBB
     150          return _Color(color >> 16 & 0xff, color >> 8 & 0xff, color & 0xff)
     151      return _Color(*color)
     152
     153 -def _getImageSize(filename):
     154      """Try to get the width and height of a bmp of png image file"""
     155      file = open(filename, 'rb')
     156      if file.read(8) == b'\x89PNG\r\n\x1a\n': # PNG
     157          while 1:
     158              length, = struct.unpack('>i', file.read(4))
     159              chunkID = file.read(4)
     160              if chunkID == '': # EOF
     161                  return None
     162              if chunkID == b'IHDR':
     163                  # return width, height
     164                  return struct.unpack('>ii', file.read(8))
     165              file.seek(4 + length, 1)
     166      file.seek(0)
     167      if file.read(8) == b'BM': # Bitmap
     168          file.seek(18, 0) # skip to size data
     169          # return width, height
     170          return struct.unpack('<ii', file.read(8))
     171      # return None on error, unknown file
     172
     173 -class TDLError(Exception):
     174      """
     175      The catch all for most TDL specific errors.
     176      """
     177
     178 -class _MetaConsole(object):
     179      """
     180      Contains methods shared by both the L{Console} and L{Window} classes.
     181      """
     182      __slots__ = ('width', 'height', 'console', '__weakref__', '__dict__')
     183
     184 -    def drawChar(self, x, y, char, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
     185          """Draws a single character.
     186
     187          @type x: int
     188          @param x: X coordinate to draw at.
     189          @type y: int
     190          @param y: Y coordinate to draw at.
     191
     192          @type char: int, string, or None
     193          @param char: Should be an integer, single character string, or None.
     194
     195                       You can set the char parameter as None if you only want to change
     196                       the colors of the tile.
     197
     198          @type fgcolor: (r, g, b) or None
     199          @param fgcolor: For fgcolor and bgcolor you use a 3 item list with
     200                          integers ranging 0-255 or None.
     201
     202                          None will keep the current color at this position unchanged.
     203          @type bgcolor: (r, g, b) or None
     204          @param bgcolor: Background color.  See fgcolor
     205
     206          @raise AssertionError: Having x or y values that can't be placed inside
     207                                 of the console will raise an AssertionError.
     208                                 You can use always use ((x, y) in console) to
     209                                 check if a tile is drawable.
     210          """
     211
     212          assert _verify_colors(fgcolor, bgcolor)
     213          x, y = self._normalizePoint(x, y)
     214          x, y = ctypes.c_int(x), ctypes.c_int(y)
     215          self._setChar(x, y, _formatChar(char),
     216                        _formatColor(fgcolor), _formatColor(bgcolor))
     217
     218 -    def drawStr(self, x, y, string, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
     219          """Draws a string starting at x and y.  Optinally colored.
     220
     221          A string that goes past the right side will wrap around.  A string
     222          wraping to below the console will raise a L{TDLError} but will still be
     223          written out.  This means you can safely ignore the errors with a
     224          try... except block if you're fine with partily written strings.
     225
     226          \\r and \\n are drawn on the console as normal character tiles.  No
     227          special encoding is done and any string will translate to the character
     228          table as is.
     229
     230          For a string drawing operation that respects special characters see the
     231          L{Typewriter} class.
     232
     233          @type x: int
     234          @param x: X coordinate to draw at.
     235          @type y: int
     236          @param y: Y coordinate to draw at.
     237
     238          @type string: string or iterable
     239          @param string: Can be a string or an iterable of numbers.
     240
     241                         Special characters are ignored and rendered as any other
     242                         character.
     243
     244          @type fgcolor: (r, g, b) or None
     245          @param fgcolor: For fgcolor and bgcolor you use a 3 item list with
     246                          integers ranging 0-255 or None.
     247
     248                          None will keep the current color at this position unchanged.
     249          @type bgcolor: (r, g, b) or None
     250          @param bgcolor: Background color.  See fgcolor
     251
     252          @raise AssertionError: Having x or y values that can't be placed inside
     253                                 of the console will raise an AssertionError.
     254
     255                                 You can use always use ((x, y) in console) to
     256                                 check if a tile is drawable.
     257          """
     258
     259          x, y = self._normalizePoint(x, y)
     260          assert _verify_colors(fgcolor, bgcolor)
     261          fgcolor, bgcolor = _formatColor(fgcolor), _formatColor(bgcolor)
     262          width, height = self.getSize()
     263          batch = [] # prepare a batch operation
     264          def _drawStrGen(x=x, y=y, string=string, width=width, height=height):
     265              """Generator for drawStr
     266
     267              Iterates over ((x, y), ch) data for _setCharBatch, raising an
     268              error if the end of the console is reached.
     269              """
     270              for char in string:
     271                  if y == height:
     272                      raise TDLError('End of console reached.')
     273                  #batch.append(((x, y), _formatChar(char))) # ((x, y), ch)
     274                  yield((x, y), _formatChar(char))
     275                  x += 1 # advance cursor
     276                  if x == width: # line break
     277                      x = 0
     278                      y += 1
     279          self._setCharBatch(_drawStrGen(), fgcolor, bgcolor)
     280
     281 -    def drawRect(self, x, y, width, height, string, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
     282          """Draws a rectangle starting from x and y and extending to width and height.
     283
     284          If width or height are None then it will extend to the edge of the console.
     285
     286          @type x: int
     287          @param x: x coordinate to draw at.
     288          @type y: int
     289          @param y: y coordinate to draw at.
     290
     291          @type width: int or None
     292          @param width: Width of the rectangle.
     293
     294                        Can be None to extend to the bottom right of the
     295                        console or can be a negative number to be sized reltive
     296                        to the total size of the console.
     297          @type height: int or None
     298          @param height: Height of the rectangle.  See width.
     299
     300          @type string: int, string, or None
     301          @param string: Should be an integer, single character string, or None.
     302
     303                         You can set the char parameter as None if you only want
     304                         to change the colors of an area.
     305
     306          @type fgcolor: (r, g, b) or None
     307          @param fgcolor: For fgcolor and bgcolor you use a 3 item list with
     308                          integers ranging 0-255 or None.
     309
     310                          None will keep the current color at this position unchanged.
     311          @type bgcolor: (r, g, b) or None
     312          @param bgcolor: Background color.  See fgcolor
     313
     314          @raise AssertionError: Having x or y values that can't be placed inside
     315                                 of the console will raise an AssertionError.
     316
     317                                 You can use always use ((x, y) in console) to
     318                                 check if a tile is drawable.
     319          """
     320          x, y, width, height = self._normalizeRect(x, y, width, height)
     321          assert _verify_colors(fgcolor, bgcolor)
     322          fgcolor, bgcolor = _formatColor(fgcolor), _formatColor(bgcolor)
     323          char = _formatChar(string)
     324          # use itertools to make an x,y grid
     325          # using ctypes here reduces type converstions later
     326          grid = itertools.product((ctypes.c_int(x) for x in range(x, x + width)),
     327                                   (ctypes.c_int(y) for y in range(y, y + height)))
     328          # zip the single character in a batch variable
     329          batch = zip(grid, itertools.repeat(char, width * height))
     330          self._setCharBatch(batch, fgcolor, bgcolor, nullChar=(char is None))
     331
     332 -    def drawFrame(self, x, y, width, height, string, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
     333          """Similar to L{drawRect} but only draws the outline of the rectangle.
     334
     335          @type x: int
     336          @param x: x coordinate to draw at.
     337          @type y: int
     338          @param y: y coordinate to draw at.
     339
     340          @type width: int or None
     341          @param width: Width of the rectangle.
     342
     343                        Can be None to extend to the bottom right of the
     344                        console or can be a negative number to be sized reltive
     345                        to the total size of the console.
     346          @type height: int or None
     347          @param height: Height of the rectangle.  See width.
     348
     349          @type string: int, string, or None
     350          @param string: Should be an integer, single character string, or None.
     351
     352                         You can set the char parameter as None if you only want
     353                         to change the colors of an area.
     354
     355          @type fgcolor: (r, g, b) or None
     356          @param fgcolor: For fgcolor and bgcolor you use a 3 item list with
     357                          integers ranging 0-255 or None.
     358
     359                          None will keep the current color at this position unchanged.
     360          @type bgcolor: (r, g, b) or None
     361          @param bgcolor: Background color.  See fgcolor
     362
     363          @raise AssertionError: Having x or y values that can't be placed inside
     364                                 of the console will raise an AssertionError.
     365
     366                                 You can use always use ((x, y) in console) to
     367                                 check if a tile is drawable.
     368          """
     369          x, y, width, height = self._normalizeRect(x, y, width, height)
     370          assert _verify_colors(fgcolor, bgcolor)
     371          fgcolor, bgcolor = _formatColor(fgcolor), _formatColor(bgcolor)
     372          char = _formatChar(string)
     373          if width == 1 or height == 1: # it's just a single width line here
     374              return self.drawRect(x, y, width, height, char, fgcolor, bgcolor)
     375
     376          # draw sides of frame with drawRect
     377          self.drawRect(x, y, 1, height, char, fgcolor, bgcolor)
     378          self.drawRect(x, y, width, 1, char, fgcolor, bgcolor)
     379          self.drawRect(x + width - 1, y, 1, height, char, fgcolor, bgcolor)
     380          self.drawRect(x, y + height - 1, width, 1, char, fgcolor, bgcolor)
     381
     382 -    def _normalizePoint(self, x, y):
     383          """Check if a point is in bounds and make minor adjustments.
     384
     385          Respects Pythons negative indexes.  -1 starts at the bottom right.
     386          Replaces the _drawable function
     387          """
     388          assert isinstance(x, _INTTYPES), 'x must be an integer, got %s' % repr(x)
     389          assert isinstance(y, _INTTYPES), 'y must be an integer, got %s' % repr(y)
     390
     391          assert (-self.width <= x < self.width) and (-self.height <= y < self.height), \
     392                  ('(%i, %i) is an invalid postition on %s' % (x, y, self))
     393
     394          # handle negative indexes
     395          if x < 0:
     396              x += self.width
     397          if y < 0:
     398              y += self.height
     399          return (x, y)
     400
     401 -    def _normalizeRect(self, x, y, width, height):
     402          """Check if the rectangle is in bounds and make minor adjustments.
     403          raise AssertionError's for any problems
     404          """
     405          x, y = self._normalizePoint(x, y) # inherit _normalizePoint logic
     406
     407          assert width is None or isinstance(width, _INTTYPES), 'width must be an integer or None, got %s' % repr(width)
     408          assert height is None or isinstance(height, _INTTYPES), 'height must be an integer or None, got %s' % repr(height)
     409
     410          # if width or height are None then extend them to the edge
     411          if width is None:
     412              width = self.width - x
     413          elif width < 0: # handle negative numbers
     414              width += self.width
     415              width = max(0, width) # a 'too big' negative is clamped zero
     416          if height is None:
     417              height = self.height - y
     418              height = max(0, height)
     419          elif height < 0:
     420              height += self.height
     421
     422          # reduce rect size to bounds
     423          width = min(width, self.width - x)
     424          height = min(height, self.height - y)
     425
     426          return x, y, width, height
     427
     428 -    def blit(self, source, x=0, y=0, width=None, height=None, srcX=0, srcY=0):
     429          """Blit another console or Window onto the current console.
     430
     431          By default it blits the entire source to the topleft corner.
     432
     433          @type source: L{Console} or L{Window}
     434          @param source: Source window can be a L{Console} or L{Window} instance.
     435                         It can even blit to itself without any problems.
     436
     437          @type x: int
     438          @param x: X coordinate to blit to.
     439          @type y: int
     440          @param y: Y coordinate to blit to.
     441
     442          @type width: int or None
     443          @param width: Width of the rectangle.
     444
     445                        Can be None to extend as far as possible to the
     446                        bottom right corner of the blit area or can be a negative
     447                        number to be sized reltive to the total size of the
     448                        B{destination} console.
     449          @type height: int or None
     450          @param height: Height of the rectangle.  See width.
     451
     452          @type srcX: int
     453          @param srcX: The source consoles x coordinate to blit from.
     454          @type srcY: int
     455          @param srcY: The source consoles y coordinate to blit from.
     456          """
     457          # hardcode alpha settings for now
     458          fgalpha=1.0
     459          bgalpha=1.0
     460
     461          assert isinstance(source, (Console, Window)), "source muse be a Window or Console instance"
     462
     463          # handle negative indexes and rects
     464          # negative width and height will be set realtive to the destination
     465          # and will also be clamped to the smallest Console
     466          x, y, width, height = self._normalizeRect(x, y, width, height)
     467          srcX, srcY, width, height = source._normalizeRect(srcX, srcY, width, height)
     468
     469          # translate source and self if any of them are Window instances
     470          srcX, srcY = source._translate(srcX, srcY)
     471          source = source.console
     472          x, y = self._translate(x, y)
     473          self = self.console
     474
     475          if self == source:
     476              # if we are the same console then we need a third console to hold
     477              # onto the data, otherwise it tries to copy into itself and
     478              # starts destroying everything
     479              tmp = Console(width, height)
     480              _lib.TCOD_console_blit(source, srcX, srcY, width, height, tmp, 0, 0, fgalpha, bgalpha)
     481              _lib.TCOD_console_blit(tmp, 0, 0, width, height, self, x, y, fgalpha, bgalpha)
     482          else:
     483              _lib.TCOD_console_blit(source, srcX, srcY, width, height, self, x, y, fgalpha, bgalpha)
     484
     485 -    def getSize(self):
     486          """Return the size of the console as (width, height)
     487
     488          @rtype: (int, int)
     489          """
     490          return self.width, self.height
     491
     492 -    def scroll(self, x, y):
     493          """Scroll the contents of the console in the direction of x,y.
     494
     495          Uncovered areas will be cleared.
     496          @type x: int
     497          @param x: Distance to scroll along x-axis
     498          @type y: int
     499          @param y: Distance to scroll along y-axis
     500          """
     501          assert isinstance(x, _INTTYPES), "x must be an integer, got %s" % repr(x)
     502          assert isinstance(y, _INTTYPES), "y must be an integer, got %s" % repr(x)
     503          def getSlide(x, length):
     504              """get the parameters needed to scroll the console in the given
     505              direction with x
     506              returns (x, length, srcx)
     507              """
     508              if x > 0:
     509                  srcx = 0
     510                  length -= x
     511              elif x < 0:
     512                  srcx = abs(x)
     513                  x = 0
     514                  length -= srcx
     515              else:
     516                  srcx = 0
     517              return x, length, srcx
     518          def getCover(x, length):
     519              """return the (x, width) ranges of what is covered and uncovered"""
     520              cover = (0, length) # everything covered
     521              uncover = None  # nothing uncovered
     522              if x > 0: # left side uncovered
     523                  cover = (x, length - x)
     524                  uncover = (0, x)
     525              elif x < 0: # right side uncovered
     526                  x = abs(x)
     527                  cover = (0, length - x)
     528                  uncover = (length - x, x)
     529              return cover, uncover
     530
     531          width, height = self.getSize()
     532          if abs(x) >= width or abs(y) >= height:
     533              return self.clear() # just clear the console normally
     534
     535          # get the ranges of the areas that will be uncovered
     536          coverX, uncoverX = getCover(x, width)
     537          coverY, uncoverY = getCover(y, height)
     538          # so at this point we know that coverX and coverY makes a rect that
     539          # encases the area that we end up blitting to.  uncoverX/Y makes a
     540          # rect in the corner of the uncovered area.  So we need to combine
     541          # the uncoverX/Y with coverY/X to make what's left of the uncovered
     542          # area.  Explaining it makes it mush easier to do now.
     543
     544          # But first we need to blit.
     545          x, width, srcx = getSlide(x, width)
     546          y, height, srcy = getSlide(y, height)
     547          self.blit(self, x, y, width, height, srcx, srcy)
     548
     549          if uncoverX: # clear sides (0x20 is space)
     550              self.drawRect(uncoverX[0], coverY[0], uncoverX[1], coverY[1], 0x20)
     551          if uncoverY: # clear top/bottom
     552              self.drawRect(coverX[0], uncoverY[0], coverX[1], uncoverY[1], 0x20)
     553          if uncoverX and uncoverY: # clear corner
     554              self.drawRect(uncoverX[0], uncoverY[0], uncoverX[1], uncoverY[1], 0x20)
     555
     556 -    def getChar(self, x, y):
     557          """Return the character and colors of a tile as (ch, fg, bg)
     558
     559          This method runs very slowly as is not recommended to be called
     560          frequently.
     561
     562          @rtype: (int, (r, g, b), (r, g, b))
     563          @returns: Returns a 3-item tuple.  The first item is an integer of the
     564                    character at the position (x, y) the second and third are the
     565                    foreground and background colors respectfully.
     566          """
     567          raise NotImplementedError('Method here only exists for the docstring')
     568
     569 -    def __contains__(self, position):
     570          """Use ((x, y) in console) to check if a position is drawable on this console.
     571          """
     572          x, y = position
     573          return (0 <= x < self.width) and (0 <= y < self.height)
     574
     575 -class Console(_MetaConsole):
     576      """Contains character and color data and can be drawn to.
     577
     578      The console created by the L{tdl.init} function is the root console and is the
     579      console that is rendered to the screen with L{flush}.
     580
     581      Any console created from the Console class is an off-screen console that
     582      can be drawn on before being L{blit} to the root console.
     583      """
     584
     585      __slots__ = ('_as_parameter_', '_typewriter')
     586
     587 -    def __init__(self, width, height):
     588          """Create a new offscreen console.
     589
     590          @type width: int
     591          @param width: Width of the console in tiles
     592          @type height: int
     593          @param height: Height of the console in tiles
     594          """
     595          if not _rootinitialized:
     596              raise TDLError('Can not create Console\'s before tdl.init')
     597          self._as_parameter_ = _lib.TCOD_console_new(width, height)
     598          self.console = self
     599          self.width = width
     600          self.height = height
     601          self._typewriter = None # "typewriter lock", makes sure the colors are set to the typewriter
     602
     603      @classmethod
     604 -    def _newConsole(cls, console):
     605          """Make a Console instance, from a console ctype"""
     606          self = cls.__new__(cls)
     607          self._as_parameter_ = console
     608          self.console = self
     609          self.width = _lib.TCOD_console_get_width(self)
     610          self.height = _lib.TCOD_console_get_height(self)
     611          self._typewriter = None
     612          return self
     613
     614 -    def __del__(self):
     615          """
     616          If the main console is garbage collected then the window will be closed as well
     617          """
     618          # If this is the root console the window will close when collected
     619          try:
     620              if isinstance(self._as_parameter_, ctypes.c_void_p):
     621                  global _rootinitialized, _rootConsoleRef
     622                  _rootinitialized = False
     623                  _rootConsoleRef = None
     624              _lib.TCOD_console_delete(self)
     625          except StandardError:
     626              pass # I forget why I put this here but I'm to afraid to delete it
     627
     628 -    def _replace(self, console):
     629          """Used internally
     630
     631          Mostly used just to replace this Console object with the root console
     632          If another Console object is used then they are swapped
     633          """
     634          if isinstance(console, Console):
     635              self._as_parameter_, console._as_parameter_ = \
     636                console._as_parameter_, self._as_parameter_ # swap tcod consoles
     637          else:
     638              self._as_parameter_ = console
     639          self.width = _lib.TCOD_console_get_width(self)
     640          self.height = _lib.TCOD_console_get_height(self)
     641          return self
     642
     643 -    def _translate(self, x, y):
     644          """Convertion x and y to their position on the root Console for this Window
     645
     646          Because this is a Console instead of a Window we return the paramaters
     647          untouched"""
     648          return x, y
     649
     650 -    def clear(self, fgcolor=(0, 0, 0), bgcolor=(0, 0, 0)):
     651          """Clears the entire Console.
     652
     653          @type fgcolor: (r, g, b)
     654          @param fgcolor: Foreground color.
     655
     656                          Must be a 3-item list with integers that range 0-255.
     657
     658                          Unlike most other operations you can not use None here.
     659          @type bgcolor: (r, g, b)
     660          @param bgcolor: Background color.  See fgcolor.
     661          """
     662          assert _verify_colors(fgcolor, bgcolor)
     663          assert fgcolor and bgcolor, 'Can not use None with clear'
     664          self._typewriter = None
     665          _lib.TCOD_console_set_default_background(self, _formatColor(bgcolor))
     666          _lib.TCOD_console_set_default_foreground(self, _formatColor(fgcolor))
     667          _lib.TCOD_console_clear(self)
     668
     669 -    def _setChar(self, x, y, char, fgcolor=None, bgcolor=None, bgblend=1):
     670          """
     671          Sets a character.
     672          This is called often and is designed to be as fast as possible.
     673
     674          Because of the need for speed this function will do NO TYPE CHECKING
     675          AT ALL, it's up to the drawing functions to use the functions:
     676          _formatChar and _formatColor before passing to this."""
     677          # buffer values as ctypes objects
     678          console = self._as_parameter_
     679
     680          if char is not None and fgcolor is not None and bgcolor is not None:
     681              _setcharEX(console, x, y, char, fgcolor, bgcolor)
     682              return
     683          if char is not None:
     684              _setchar(console, x, y, char)
     685          if fgcolor is not None:
     686              _setfore(console, x, y, fgcolor)
     687          if bgcolor is not None:
     688              _setback(console, x, y, bgcolor, bgblend)
     689
     690 -    def _setCharBatch(self, batch, fgcolor, bgcolor, bgblend=1, nullChar=False):
     691          """
     692          Try to perform a batch operation otherwise fall back to _setChar.
     693          If fgcolor and bgcolor are defined then this is faster but not by very
     694          much.
     695
     696          batch is a iterable of [(x, y), ch] items
     697          """
     698          if fgcolor and not nullChar:
     699              # buffer values as ctypes objects
     700              self._typewriter = None # clear the typewriter as colors will be set
     701              console = self._as_parameter_
     702              if not bgcolor:
     703                  bgblend = 0
     704              bgblend = ctypes.c_int(bgblend)
     705
     706              _lib.TCOD_console_set_default_background(console, bgcolor)
     707              _lib.TCOD_console_set_default_foreground(console, fgcolor)
     708              _putChar = _lib.TCOD_console_put_char # remove dots and make local
     709              for (x, y), char in batch:
     710                  _putChar(console, x, y, char, bgblend)
     711          else:
     712              for (x, y), char in batch:
     713                  self._setChar(x, y, char, fgcolor, bgcolor, bgblend)
     714
     715 -    def getChar(self, x, y):
     716          # inherit docstring
     717          x, y = self._normalizePoint(x, y)
     718          char = _lib.TCOD_console_get_char(self, x, y)
     719          bgcolor = _lib.TCOD_console_get_char_background_wrapper(self, x, y)
     720          fgcolor = _lib.TCOD_console_get_char_foreground_wrapper(self, x, y)
     721          return char, tuple(fgcolor), tuple(bgcolor)
     722
     723 -    def __repr__(self):
     724          return "<Console (Width=%i Height=%i)>" % (self.width, self.height)
     725
     726
     727 -class Window(_MetaConsole):
     728      """A Window contains a small isolated part of a Console.
     729
     730      Drawing on the Window draws on the Console.
     731
     732      Making a Window and setting its width or height to None will extend it to
     733      the edge of the console.
     734      """
     735
     736      __slots__ = ('parent', 'x', 'y')
     737
     738 -    def __init__(self, console, x, y, width, height):
     739          """Isolate part of a L{Console} or L{Window} instance.
     740
     741          @type console: L{Console} or L{Window}
     742          @param console: The parent object which can be a L{Console} or another
     743                          L{Window} instance.
     744
     745          @type x: int
     746          @param x: X coordinate to place the Window.
     747
     748                    This follows the normal rules for indexing so you can use a
     749                    negative integer to place the Window relative to the bottom
     750                    right of the parent Console instance.
     751          @type y: int
     752          @param y: Y coordinate to place the Window.
     753
     754                    See x.
     755
     756          @type width: int or None
     757          @param width: Width of the Window.
     758
     759                        Can be None to extend as far as possible to the
     760                        bottom right corner of the parent Console or can be a
     761                        negative number to be sized reltive to the Consoles total
     762                        size.
     763          @type height: int or None
     764          @param height: Height of the Window.
     765
     766                         See width.
     767          """
     768          assert isinstance(console, (Console, Window)), 'console parameter must be a Console or Window instance, got %s' % repr(console)
     769          self.parent = console
     770          self.x, self.y, self.width, self.height = console._normalizeRect(x, y, width, height)
     771          if isinstance(console, Console):
     772              self.console = console
     773          else:
     774              self.console = self.parent.console
     775
     776 -    def _translate(self, x, y):
     777          """Convertion x and y to their position on the root Console"""
     778          # we add our position relative to our parent and then call then next parent up
     779          return self.parent._translate((x + self.x), (y + self.y))
     780
     781 -    def clear(self, fgcolor=(0, 0, 0), bgcolor=(0, 0, 0)):
     782          """Clears the entire Window.
     783
     784          @type fgcolor: (r, g, b)
     785          @param fgcolor: Foreground color.
     786
     787                          Must be a 3-item list with integers that range 0-255.
     788
     789                          Unlike most other operations you can not use None here.
     790          @type bgcolor: (r, g, b)
     791          @param bgcolor: Background color.  See fgcolor.
     792          """
     793          assert _verify_colors(fgcolor, bgcolor)
     794          assert fgcolor and bgcolor, 'Can not use None with clear'
     795          self.draw_rect(0, 0, None, None, 0x20, fgcolor, bgcolor)
     796
     797 -    def _setChar(self, x, y, char=None, fgcolor=None, bgcolor=None, bgblend=1):
     798          self.parent._setChar((x + self.x), (y + self.y), char, fgcolor, bgcolor, bgblend)
     799
     800 -    def _setCharBatch(self, batch, fgcolor, bgcolor, bgblend=1):
     801          myX = self.x # remove dots for speed up
     802          myY = self.y
     803          self.parent._setCharBatch((((x + myX, y + myY), ch) for ((x, y), ch) in batch),
     804                                    fgcolor, bgcolor, bgblend)
     805
     806
     807 -    def drawChar(self, x, y, char, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
     808          # inherit docstring
     809          x, y = self._normalizePoint(x, y)
     810          self.parent.drawChar(x + self.x, y + self.y, char, fgcolor, bgcolor)
     811
     812 -    def drawRect(self, x, y, width, height, string, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
     813          # inherit docstring
     814          x, y, width, height = self._normalizeRect(x, y, width, height)
     815          self.parent.drawRect(x + self.x, y + self.y, width, height, string, fgcolor, bgcolor)
     816
     817 -    def drawFrame(self, x, y, width, height, string, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
     818          # inherit docstring
     819          x, y, width, height = self._normalizeRect(x, y, width, height)
     820          self.parent.drawFrame(x + self.x, y + self.y, width, height, string, fgcolor, bgcolor)
     821
     822 -    def getChar(self, x, y):
     823          # inherit docstring
     824          x, y = self._normalizePoint(x, y)
     825          return self.console.getChar(self._translate(x, y))
     826
     827 -    def __repr__(self):
     828          return "<Window(X=%i Y=%i Width=%i Height=%i)>" % (self.x, self.y,
     829                                                            self.width,
     830                                                            self.height)
     831
     832
     833 -class Typewriter(object):
     834      """Converts a console into a scrolling text log that respects special
     835      characters.
     836
     837      This class works best on a L{Window} or off-screen L{Console} instance.
     838      In a L{Window} for example the scrolling text is limited to the L{Window}'s
     839      isolated area.
     840      """
     841
     842 -    def __init__(self, console):
     843          """Add a virtual cursor to a L{Console} or L{Window} instance.
     844
     845          @type console: L{Console} or L{Window}
     846          """
     847          assert isinstance(console, (Console, Window)), 'console parameter must be a Console or Window instance, got %s' % repr(console)
     848          self.parent = console
     849          if isinstance(self.parent, Console):
     850              self.console = self.parent
     851          else:
     852              self.console = self.parent.console
     853          self.cursor = (0, 0) # cursor position
     854          self.scrollMode = 'scroll' #can be 'scroll', 'error'
     855          self.fgcolor = _formatColor((255, 255, 255))
     856          self.bgcolor = _formatColor((0, 0, 0))
     857          self._bgblend = 1 # SET
     858
     859 -    def _normalize(self, x, y):
     860          """return the normalized the cursor position."""
     861          width, height = self.parent.getSize()
     862          while x >= width:
     863              x -= width
     864              y += 1
     865          while y >= height:
     866              if self.scrollMode == 'scroll':
     867                  y -= 1
     868                  self.parent.scroll(0, -1)
     869              elif self.scrollMode == 'error':
     870                  # reset the cursor on error
     871                  self.cursor = (0, 0)
     872                  raise TDLError('Typewriter cursor has reached the end of the console')
     873          return (x, y)
     874
     875 -    def getCursor(self):
     876          """Return the virtual cursor position.
     877
     878          @rtype: (int, int)
     879          @return: Returns (x, y) a 2-integer tuple containing where the next
     880                   L{addChar} or L{addStr} will start at.
     881
     882                   This can be changed with the L{move} method."""
     883          x, y = self.cursor
     884          width, height = self.parent.getSize()
     885          while x >= width:
     886              x -= width
     887              y += 1
     888          if y >= height and self.scrollMode == 'scroll':
     889              y = height - 1
     890          return x, y
     891
     892 -    def move(self, x, y):
     893          """Move the virtual cursor.
     894
     895          @type x: int
     896          @param x: X position to place the cursor.
     897          @type y: int
     898          @param y: Y position to place the cursor.
     899          """
     900          self.cursor = self.parent._normalizePoint(x, y)
     901
     902 -    def setFG(self, color):
     903          """Change the foreground color"""
     904          assert _iscolor(color)
     905          assert color is not None
     906          self.fgcolor = _formatColor(color)
     907          if self.console._typewriter is self:
     908              _lib.TCOD_console_set_default_foreground(self.console, self.fgcolor)
     909
     910 -    def setBG(self, color):
     911          """Change the background color"""
     912          assert _iscolor(color)
     913          assert color is not None
     914          self.bgcolor = _formatColor(color)
     915          if self.console._typewriter is self:
     916              _lib.TCOD_console_set_default_background(self.console, self.bgcolor)
     917
     918 -    def _updateConsole(self):
     919          """Make sure the colors on a console match the Typewriter instance"""
     920          if self.console._typewriter is not self:
     921              self.console._typewriter = self
     922
     923              _lib.TCOD_console_set_default_background(self.console, self.bgcolor)
     924              _lib.TCOD_console_set_default_foreground(self.console, self.fgcolor)
     925
     926
     927 -    def addChar(self, char):
     928          """Draw a single character at the cursor."""
     929          if char == '\n': # line break
     930              x = 0
     931              y += 1
     932              return
     933          if char == '\r': # return
     934              x = 0
     935              return
     936          x, y = self._normalize(*self.cursor)
     937          self.cursor = [x + 1, y] # advance cursor on next draw
     938          self._updateConsole()
     939          x, y = self.parent._translate(x, y)
     940          _lib.TCOD_console_put_char(self.console._as_parameter_, x, y, _formatChar(char), self._bgblend)
     941
     942
     943 -    def addStr(self, string):
     944          """Write a string at the cursor.  Handles special characters such as newlines.
     945
     946          @type string: string
     947          @param string:
     948          """
     949          x, y = self.cursor
     950          for char in string:
     951              if char == '\n': # line break
     952                  x = 0
     953                  y += 1
     954                  continue
     955              if char == '\r': # return
     956                  x = 0
     957                  continue
     958              x, y = self._normalize(x, y)
     959              self.parent.drawChar(x, y, char, self.fgcolor, self.bgcolor)
     960              x += 1
     961          self.cursor = (x, y)
     962
     963 -    def write(self, string):
     964          """This method mimics basic file-like behaviour.
     965
     966          Because of this method you can replace sys.stdout or sys.stderr with
     967          a L{Typewriter} instance.
     968
     969          @type string: string
     970          """
     971          # some 'basic' line buffer stuff.
     972          # there must be an easier way to do this.  The textwrap module didn't
     973          # help much.
     974          x, y = self._normalize(*self.cursor)
     975          width, height = self.parent.getSize()
     976          wrapper = textwrap.TextWrapper(initial_indent=(' '*x), width=width)
     977          writeLines = []
     978          for line in string.split('\n'):
     979              if line:
     980                  writeLines += wrapper.wrap(line)
     981                  wrapper.initial_indent = ''
     982              else:
     983                  writeLines.append([])
     984
     985          for line in writeLines:
     986              x, y = self._normalize(x, y)
     987              self.parent.drawStr(x, y, line[x:], self.fgcolor, self.bgcolor)
     988              y += 1
     989              x = 0
     990          y -= 1
     991          self.cursor = (x, y)
     992
     993
     994 -def init(width, height, title=None, fullscreen=False, renderer='OPENGL'):
     995      """Start the main console with the given width and height and return the
     996      root console.
     997
     998      Call the consoles drawing functions.  Then remember to use L{tdl.flush} to
     999      make what's drawn visible on the console.
    1000
    1001      @type width: int
    1002      @param width: width of the root console (in tiles)
    1003
    1004      @type height: int
    1005      @param height: height of the root console (in tiles)
    1006
    1007      @type title: string
    1008      @param title: Text to display as the window title.
    1009
    1010                    If left None it defaults to the running scripts filename.
    1011
    1012      @type fullscreen: boolean
    1013      @param fullscreen: Can be set to True to start in fullscreen mode.
    1014
    1015      @type renderer: string
    1016      @param renderer: Can be one of 'GLSL', 'OPENGL', or 'SDL'.
    1017
    1018                       Due to way Python works you're unlikely to see much of an
    1019                       improvement by using 'GLSL' or 'OPENGL' as most of the
    1020                       time Python is slow interacting with the console and the
    1021                       rendering itself is pretty fast even on 'SDL'.
    1022
    1023      @rtype: L{Console}
    1024      @return: The root console.  Only what is drawn on the root console is
    1025               what's visible after a call to L{tdl.flush}.
    1026               After the root console is garbage collected, the window made by
    1027               this function will close.
    1028      """
    1029      RENDERERS = {'GLSL': 0, 'OPENGL': 1, 'SDL': 2}
    1030      global _rootinitialized, _rootConsoleRef
    1031      if not _fontinitialized: # set the default font to the one that comes with tdl
    1032          setFont(_unpackfile('terminal8x8.png'), None, None, True, True)
    1033
    1034      if renderer.upper() not in RENDERERS:
    1035          raise TDLError('No such render type "%s", expected one of "%s"' % (renderer, '", "'.join(RENDERERS)))
    1036      renderer = RENDERERS[renderer.upper()]
    1037
    1038      # If a console already exists then make a clone to replace it
    1039      if _rootConsoleRef and _rootConsoleRef():
    1040          oldroot = _rootConsoleRef()
    1041          rootreplacement = Console(oldroot.width, oldroot.height)
    1042          rootreplacement.blit(oldroot)
    1043          oldroot._replace(rootreplacement)
    1044          del rootreplacement
    1045
    1046      if title is None: # use a default title
    1047          if sys.argv:
    1048              # Use the script filename as the title.
    1049              title = os.path.basename(sys.argv[0])
    1050          else:
    1051              title = 'python-tdl'
    1052
    1053      _lib.TCOD_console_init_root(width, height, _encodeString(title), fullscreen, renderer)
    1054
    1055      #event.get() # flush the libtcod event queue to fix some issues
    1056      # issues may be fixed already
    1057
    1058      event._eventsflushed = False
    1059      _rootinitialized = True
    1060      rootconsole = Console._newConsole(ctypes.c_void_p())
    1061      _rootConsoleRef = weakref.ref(rootconsole)
    1062
    1063      return rootconsole
    1064
    1065 -def flush():
    1066      """Make all changes visible and update the screen.
    1067
    1068      Remember to call this function after drawing operations.
    1069      Calls to flush will enfore the frame rate limit set by L{tdl.setFPS}.
    1070
    1071      This function can only be called after L{tdl.init}
    1072      """
    1073      if not _rootinitialized:
    1074          raise TDLError('Cannot flush without first initializing with tdl.init')
    1075
    1076      _lib.TCOD_console_flush()
    1077
    1078 -def setFont(path, columns=None, rows=None, columnFirst=False,
    1079              greyscale=False, altLayout=False):
    1080      """Changes the font to be used for this session.
    1081      This should be called before L{tdl.init}
    1082
    1083      If the font specifies its size in its filename (i.e. font_NxN.png) then this
    1084      function can auto-detect the tileset formatting and the parameters columns
    1085      and rows can be left None.
    1086
    1087      While it's possible you can change the font mid program it can sometimes
    1088      break in rare circumstances.  So use caution when doing this.
    1089
    1090      @type path: string
    1091      @param path: Must be a string filepath where a bmp or png file is found.
    1092
    1093      @type columns: int
    1094      @param columns: Number of columns in the tileset.
    1095
    1096                      Can be left None for auto-detection.
    1097
    1098      @type rows: int
    1099      @param rows: Number of rows in the tileset.
    1100
    1101                   Can be left None for auto-detection.
    1102
    1103      @type columnFirst: boolean
    1104      @param columnFirst: Defines if the characer order goes along the rows or
    1105                          colomns.
    1106                          It should be True if the charater codes 0-15 are in the
    1107                          first column.
    1108                          And should be False if the characters 0-15
    1109                          are in the first row.
    1110
    1111      @type greyscale: boolean
    1112      @param greyscale: Creates an anti-aliased font from a greyscale bitmap.
    1113                        Otherwise it uses the alpha channel for anti-aliasing.
    1114
    1115                        Unless you actually need anti-aliasing from a font you
    1116                        know uses a smooth greyscale channel you should leave
    1117                        this on False.
    1118
    1119      @type altLayout: boolean
    1120      @param altLayout: An alternative layout with space in the upper left
    1121                        corner.
    1122                        The colomn parameter is ignored if this is True,
    1123                        find examples of this layout in the font/libtcod/
    1124                        directory included with the python-tdl source.
    1125
    1126      @raise TDLError: Will be raised if no file is found at path or if auto-
    1127                       detection fails.
    1128
    1129      @note: A png file that's been optimized can fail to load correctly on
    1130             MAC OS X creating a garbled mess when rendering.
    1131             Don't use a program like optipng or just use bmp files instead if
    1132             you want your program to work on macs.
    1133      """
    1134      # put up some constants that are only used here
    1135      FONT_LAYOUT_ASCII_INCOL = 1
    1136      FONT_LAYOUT_ASCII_INROW = 2
    1137      FONT_TYPE_GREYSCALE = 4
    1138      FONT_LAYOUT_TCOD = 8
    1139      global _fontinitialized
    1140      _fontinitialized = True
    1141      flags = 0
    1142      if altLayout:
    1143          flags |= FONT_LAYOUT_TCOD
    1144      elif columnFirst:
    1145          flags |= FONT_LAYOUT_ASCII_INCOL
    1146      else:
    1147          flags |= FONT_LAYOUT_ASCII_INROW
    1148      if greyscale:
    1149          flags |= FONT_TYPE_GREYSCALE
    1150      if not os.path.exists(path):
    1151          raise TDLError('no file exists at: "%s"' % path)
    1152      path = os.path.abspath(path)
    1153
    1154      # and the rest is the auto-detect script
    1155      imgSize = _getImageSize(path) # try to find image size
    1156      if imgSize:
    1157          imgWidth, imgHeight = imgSize
    1158          # try to get font size from filename
    1159          match = re.match('.*?([0-9]+)[xX]([0-9]+)', os.path.basename(path))
    1160          if match:
    1161              fontWidth, fontHeight = match.groups()
    1162              fontWidth, fontHeight = int(fontWidth), int(fontHeight)
    1163
    1164              # estimate correct tileset size
    1165              estColumns, remC = divmod(imgWidth, fontWidth)
    1166              estRows, remR = divmod(imgHeight, fontHeight)
    1167              if remC or remR:
    1168                  warnings.warn("Font may be incorrectly formatted.")
    1169
    1170              if not columns:
    1171                  columns = estColumns
    1172              if not rows:
    1173                  rows = estRows
    1174          else:
    1175              # the font name excluded the fonts size
    1176              if not (columns and rows):
    1177                  # no matched font size and no tileset is given
    1178                  raise TDLError('%s has no font size in filename' % os.path.basename(path))
    1179
    1180          if columns and rows:
    1181              # confirm user set options
    1182              if (fontWidth * columns != imgWidth or
    1183                  fontHeight * rows != imgHeight):
    1184                  warnings.warn("setFont parameters are set as if the image size is (%d, %d) when the detected size is actually (%i, %i)"
    1185                               % (fontWidth * columns, fontHeight * rows,
    1186                                  imgWidth, imgHeight))
    1187      else:
    1188          warnings.warn("%s is probably not an image." % os.path.basename(path))
    1189
    1190      if not (columns and rows):
    1191          # didn't auto-detect
    1192          raise TDLError('Can not auto-detect the tileset of %s' % os.path.basename(path))
    1193
    1194      _lib.TCOD_console_set_custom_font(_encodeString(path), flags, columns, rows)
    1195
    1196 -def getFullscreen():
    1197      """Returns True if program is fullscreen.
    1198
    1199      @rtype: boolean
    1200      @return: Returns True if the window is in fullscreen mode.
    1201               Otherwise returns False.
    1202      """
    1203      if not _rootinitialized:
    1204          raise TDLError('Initialize first with tdl.init')
    1205      return _lib.TCOD_console_is_fullscreen()
    1206
    1207 -def setFullscreen(fullscreen):
    1208      """Changes the fullscreen state.
    1209
    1210      @type fullscreen: boolean
    1211      """
    1212      if not _rootinitialized:
    1213          raise TDLError('Initialize first with tdl.init')
    1214      _lib.TCOD_console_set_fullscreen(fullscreen)
    1215
    1216 -def setTitle(title):
    1217      """Change the window title.
    1218
    1219      @type title: string
    1220      """
    1221      if not _rootinitialized:
    1222          raise TDLError('Not initilized.  Set title with tdl.init')
    1223      _lib.TCOD_console_set_window_title(_encodeString(title))
    1224
    1225 -def screenshot(path=None):
    1226      """Capture the screen and save it as a png file
    1227
    1228      @type path: string
    1229      @param path: The filepath to save the screenshot.
    1230
    1231                   If path is None then the image will be placed in the current
    1232                   folder with the names:
    1233                   screenshot001.png, screenshot002.png, ...
    1234      """
    1235      if not _rootinitialized:
    1236          raise TDLError('Initialize first with tdl.init')
    1237      if isinstance(fileobj, str):
    1238          _lib.TCOD_sys_save_screenshot(_encodeString(fileobj))
    1239      elif isinstance(fileobj, file): # save to temp file and copy to file-like obj
    1240          tmpname = os.tempnam()
    1241          _lib.TCOD_sys_save_screenshot(_encodeString(tmpname))
    1242          with tmpname as tmpfile:
    1243              fileobj.write(tmpfile.read())
    1244          os.remove(tmpname)
    1245      elif fileobj is None: # save to screenshot001.png, screenshot002.png, ...
    1246          filelist = os.listdir('.')
    1247          n = 1
    1248          filename = 'screenshot%.3i.png' % n
    1249          while filename in filelist:
    1250              n += 1
    1251              filename = 'screenshot%.4i.png' % n
    1252          _lib.TCOD_sys_save_screenshot(_encodeString(filename))
    1253      else:
    1254          raise TypeError('fileobj is an invalid type: %s' % type(fileobj))
    1255
    1256 -def setFPS(frameRate):
    1257      """Set the maximum frame rate.
    1258
    1259      @type frameRate: int
    1260      @param frameRate: Further calls to L{tdl.flush} will limit the speed of
    1261                        the program to run at <frameRate> frames per second. Can
    1262                        also be set to 0 to run without a limit.
    1263
    1264                        Defaults to None.
    1265      """
    1266      if frameRate is None:
    1267          frameRate = 0
    1268      assert isinstance(frameRate, _INTTYPES), 'frameRate must be an integer or None, got: %s' % repr(frameRate)
    1269      _lib.TCOD_sys_set_fps(frameRate)
    1270
    1271 -def getFPS():
    1272      """Return the current frames per second of the running program set by
    1273      L{setFPS}
    1274
    1275      @rtype: int
    1276      @return: Returns the frameRate set by setFPS.
    1277               If set to no limit, this will return 0.
    1278      """
    1279      return _lib.TCOD_sys_get_fps()
    1280
    1281 -def forceResolution(width, height):
    1282      """Change the fullscreen resoulution
    1283
    1284      @type width: int
    1285      @type height: int
    1286      """
    1287      _lib.TCOD_sys_force_fullscreen_resolution(width, height)
    1288
    1289  __all__ = [_var for _var in locals().keys() if _var[0] != '_' and _var not in ['sys', 'os', 'ctypes', 'array', 'weakref', 'itertools', 'textwrap', 'struct', 're', 'warnings']]
    1290  __all__ += ['_MetaConsole'] # keep this object public to show the documentation in epydoc
    1291