1414
1515_FOVTYPES = {'BASIC' : 0 , 'DIAMOND' : 1 , 'SHADOW' : 2 , 'RESTRICTIVE' : 12 , 'PERMISSIVE' : 11 }
1616
17-
18- #_PATHCALL = CFUNCTYPE(c_float, c_int, c_int, c_int, c_int, py_object)
19-
2017def _get_fov_type (fov ):
2118 "Return a FOV from a string"
2219 oldFOV = fov
@@ -27,10 +24,182 @@ def _get_fov_type(fov):
2724 return 4 + int (fov [10 ])
2825 raise _tdl .TDLError ('No such fov option as %s' % oldFOV )
2926
27+ class Map (object ):
28+ """Fast field-of-view and path-finding on stored data.
29+
30+ Set map conditions with the walkable and transparency attributes, this
31+ object can be iterated and checked for containment similar to consoles.
32+
33+ For example, you can set all tiles and transparent and walkable with the
34+ following code::
35+
36+ map = tdl.map.Map(80, 60)
37+ for x,y in map:
38+ map.transparent[x,y] = true
39+ map.walkable[x,y] = true
40+
41+ @ivar transparent: Map transparency, access this attribute with
42+ map.transparency[x,y]
43+
44+ Set to True to allow field-of-view rays, False will
45+ block field-of-view.
46+
47+ Transparent tiles only affect field-of-view.
48+
49+ @ivar walkable: Map accessibility, access this attribute with
50+ map.walkable[x,y]
51+
52+ Set to True to allow path-finding through that tile,
53+ False will block passage to that tile.
54+
55+ Walkable tiles only affect path-finding.
56+
57+ @ivar fov: Map tiles touched by a field-of-view computation,
58+ access this attribute with map.fov[x,y]
59+
60+ Is True if a the tile is if view, otherwise False.
61+
62+ You can set to this attribute if you want, but you'll typically
63+ be using it to read the field-of-view of a L{compute_fov} call.
64+ """
65+
66+ class _MapAttribute (object ):
67+ def __init__ (self , map , bit_index ):
68+ self .map = map
69+ self .bit_index = bit_index
70+ self .bit = 1 << bit_index
71+ self .bit_inverse = 0xFFFF ^ self .bit
72+
73+ def __getitem__ (self , key ):
74+ return bool (self .map ._array_cdata [key [1 ]][key [0 ]] & self .bit )
75+
76+ def __setitem__ (self , key , value ):
77+ self .map ._array_cdata [key [1 ]][key [0 ]] = (
78+ (self .map ._array_cdata [key [1 ]][key [0 ]] & self .bit_inverse ) |
79+ (self .bit * bool (value ))
80+ )
81+
82+ def __init__ (self , width , height ):
83+ """Create a new Map with width and height.
84+
85+ @type width: int
86+ @type height: int
87+ @param width: Width of the new Map instance, in tiles.
88+ @param width: Height of the new Map instance, in tiles.
89+ """
90+ self .width = width
91+ self .height = height
92+ self ._map_cdata = _lib .TCOD_map_new (width , height )
93+ # cast array into cdata format: int16[y][x]
94+ # for quick Python access
95+ self ._array_cdata = _ffi .new ('int16[%i][%i]' % (width , height ))
96+ # flat array to pass to TDL's C helpers
97+ self ._array_cdata_flat = _ffi .cast ('int16 *' , self ._array_cdata )
98+ self .transparent = self ._MapAttribute (self , 0 )
99+ self .walkable = self ._MapAttribute (self , 1 )
100+ self .fov = self ._MapAttribute (self , 2 )
101+
102+ def __del__ (self ):
103+ if self ._map_cdata :
104+ _lib .TCOD_map_delete (self ._map_cdata )
105+ self ._map_cdata = None
106+
107+ def compute_fov (self , x , y , fov = 'PERMISSIVE' , radius = None , light_walls = True ,
108+ sphere = True , cumulative = False ):
109+ """Compute the field-of-view of this Map and return an iterator of the
110+ points touched.
111+
112+ @type x: int
113+ @type y: int
114+
115+ @param x: x center of the field-of-view
116+ @param y: y center of the field-of-view
117+ @type fov: string
118+ @param fov: The type of field-of-view to be used. Available types are:
119+
120+ 'BASIC', 'DIAMOND', 'SHADOW', 'RESTRICTIVE', 'PERMISSIVE',
121+ 'PERMISSIVE0', 'PERMISSIVE1', ..., 'PERMISSIVE8'
122+ @type radius: int
123+ @param radius: Raduis of the field-of-view.
124+ @type light_walls: boolean
125+ @param light_walls: Include or exclude wall tiles in the field-of-view.
126+ @type sphere: boolean
127+ @param sphere: True for a spherical field-of-view.
128+ False for a square one.
129+ @type cumulative: boolean
130+ @param cumulative:
131+
132+ @rtype: iter((x, y), ...)
133+ @return: An iterator of (x, y) points of tiles touched by the
134+ field-of-view.
135+
136+ Unexpected behaviour can happen if you modify the Map while
137+ using the iterator.
138+
139+ You can use the Map's fov attribute as an alternative to this
140+ iterator.
141+ """
142+ # refresh cdata
143+ _lib .TDL_map_data_from_buffer (self ._map_cdata ,
144+ self ._array_cdata_flat )
145+ if radius is None : # infinite radius
146+ radius = max (self .width , self .height )
147+ _lib .TCOD_map_compute_fov (self .cdata , x , y , radius , light_walls ,
148+ _get_fov_type (fov ))
149+ _lib .TDL_map_fov_to_buffer (self ._map_cdata ,
150+ self ._array_cdata_flat , cumulative )
151+ def iterate_fov ():
152+ _array_cdata = self ._array_cdata
153+ for y in range (self .width ):
154+ for x in range (self .height ):
155+ if (_array_cdata [y ][x ] & 4 ):
156+ yield (x , y )
157+ return iterate_fov ()
158+
159+
160+
161+ def compute_path (self , start_x , start_y , dest_x , dest_y ,
162+ diagonal_cost = _math .sqrt (2 )):
163+ """
164+
165+ @type diagnalCost: float
166+ @param diagnalCost: Multiplier for diagonal movement.
167+
168+ Can be set to zero to disable diagonal movement
169+ entirely.
170+ """
171+ # refresh cdata
172+ _lib .TDL_map_data_from_buffer (self ._map_cdata ,
173+ self ._array_cdata_flat )
174+ path_cdata = _lib .TCOD_path_new_using_map (self ._map_cdata , diagonal_cost )
175+ try :
176+ _lib .TCOD_path_compute (path_cdata , start_x , start_y , dest_x , dest_y )
177+ x = _ffi .new ('int *' )
178+ y = _ffi .new ('int *' )
179+ length = _lib .TCOD_path_size (path_cdata )
180+ path = [None ] * length
181+ for i in range (length ):
182+ _lib .TCOD_path_get (path_cdata , i , x , y )
183+ path [i ] = ((x [0 ], y [0 ]))
184+ finally :
185+ _lib .TCOD_path_delete (path_cdata )
186+ return path
187+
188+ def __iter__ (self ):
189+ return _itertools .product (range (self .width ), range (self .height ))
190+
191+ def __contains__ (self , position ):
192+ x , y = position
193+ return (0 <= x < self .width ) and (0 <= y < self .height )
194+
195+
196+
30197class AStar (object ):
31198 """A* pathfinder
32199
33200 Using this class requires a callback detailed in L{AStar.__init__}
201+
202+ @undocumented: getPath
34203 """
35204
36205 __slots__ = ('_as_parameter_' , '_callback' , '__weakref__' )
@@ -92,8 +261,8 @@ def newCallback(sourceX, sourceY, destX, destY, null):
92261 if pathCost :
93262 return pathCost
94263 return 0.0
264+ # float(int, int, int, int, void*)
95265 self ._callback = _ffi .callback ('TCOD_path_func_t' )(newCallback )
96- """A cffi callback to be kept in memory."""
97266
98267 self ._as_parameter_ = _lib .TCOD_path_new_using_function (width , height ,
99268 self ._callback , _ffi .NULL , diagnalCost )
@@ -103,7 +272,7 @@ def __del__(self):
103272 _lib .TCOD_path_delete (self ._as_parameter_ )
104273 self ._as_parameter_ = None
105274
106- def getPath (self , origX , origY , destX , destY ):
275+ def get_path (self , origX , origY , destX , destY ):
107276 """
108277 Get the shortest path from origXY to destXY.
109278
@@ -175,25 +344,18 @@ def quick_fov(x, y, callback, fov='PERMISSIVE', radius=7.5, lightWalls=True, sph
175344 setProp = _lib .TCOD_map_set_properties # make local
176345 inFOV = _lib .TCOD_map_is_in_fov
177346
178- #cTrue = _ffi.new('bool *', True)
179- #cFalse = _ffi.new('bool *', False)
180- #cFalse = _ctypes.c_bool(False)
181347 tcodMap = _lib .TCOD_map_new (mapSize , mapSize )
182348 try :
183- # pass one, write callback data to the tcodMap
184- #for (x_, cX), (y_, cY) in _itertools.product(((i, _ctypes.c_int(i)) for i in range(mapSize)),
185- # ((i, _ctypes.c_int(i)) for i in range(mapSize))):
349+ # pass no.1, write callback data to the tcodMap
186350 for x_ , y_ in _itertools .product (range (mapSize ), range (mapSize )):
187351 pos = (x_ + x - radius ,
188352 y_ + y - radius )
189353 transparent = bool (callback (* pos ))
190354 setProp (tcodMap , x_ , y_ , transparent , False )
191355
192- # pass two , compute fov and build a list of points
356+ # pass no.2 , compute fov and build a list of points
193357 _lib .TCOD_map_compute_fov (tcodMap , radius , radius , radius , lightWalls , fov )
194358 touched = set () # points touched by field of view
195- #for (x_, cX),(y_, cY) in _itertools.product(((i, _ctypes.c_int(i)) for i in range(mapSize)),
196- # ((i, _ctypes.c_int(i)) for i in range(mapSize))):
197359 for x_ , y_ in _itertools .product (range (mapSize ), range (mapSize )):
198360 if sphere and _math .hypot (x_ - radius , y_ - radius ) > trueRadius :
199361 continue
@@ -245,6 +407,8 @@ def bresenham(x1, y1, x2, y2):
245407 points .reverse ()
246408 return points
247409
410+
248411__all__ = [_var for _var in locals ().keys () if _var [0 ] != '_' ]
249412
250413quickFOV = _style .backport (quick_fov )
414+ AStar .getPath = _style .backport (AStar .get_path )
0 commit comments