home · contact · privacy
Allow player movement beyond central map. Lots of mapping rewrite.
authorChristian Heller <c.heller@plomlompom.de>
Tue, 30 Apr 2019 03:04:07 +0000 (05:04 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Tue, 30 Apr 2019 03:04:07 +0000 (05:04 +0200)
new/example_client.py
new/plomrogue/commands.py
new/plomrogue/game.py
new/plomrogue/mapping.py
new/plomrogue/tasks.py
new/plomrogue/things.py

index 230b045ac916deead9c79a21e5780664b7c51454..0ea2db602ff55b91aff63e6f5120d410f169b022 100755 (executable)
@@ -5,14 +5,14 @@ import threading
 from plomrogue.parser import ArgError, Parser
 from plomrogue.commands import cmd_PLAYER_ID, cmd_THING_HEALTH
 from plomrogue.game import Game, WorldBase
-from plomrogue.mapping import MapHex, YX
+from plomrogue.mapping import Map, MapGeometryHex, YX
 from plomrogue.io import PlomSocket
 from plomrogue.things import ThingBase
 import types
 import queue
 
 
-class ClientMap(MapHex):
+class ClientMap(Map):
 
     def y_cut(self, map_lines, center_y, view_height):
         map_height = len(map_lines)
@@ -62,9 +62,9 @@ class ClientMap(MapHex):
         else:
             for i in range(len(map_lines)):
                 map_lines[i] = '0' + map_lines[i]
-        self.y_cut(map_lines, center.y, size.y)
+        self.y_cut(map_lines, center[1].y, size.y)
         map_width = self.size.x * 2 + 1
-        self.x_cut(map_lines, center.x * 2, size.x, map_width)
+        self.x_cut(map_lines, center[1].x * 2, size.x, map_width)
         return map_lines
 
 
@@ -136,7 +136,7 @@ cmd_THING_TYPE.argtypes = 'int:nonneg string'
 
 def cmd_THING_POS(game, i, yx):
     t = game.world.get_thing(i)
-    t.position = yx
+    t.position = YX(0,0), yx
 cmd_THING_POS.argtypes = 'int:nonneg yx_tuple:nonneg'
 
 
@@ -157,6 +157,7 @@ class Game:
     def __init__(self):
         self.parser = Parser(self)
         self.world = World(self)
+        self.map_geometry = MapGeometryHex()
         self.thing_type = ThingBase
         self.commands = {'LAST_PLAYER_TASK_RESULT': cmd_LAST_PLAYER_TASK_RESULT,
                          'TURN_FINISHED': cmd_TURN_FINISHED,
@@ -203,8 +204,6 @@ class Game:
     def log(self, msg):
         """Prefix msg plus newline to self.log_text."""
         self.log_text = msg + '\n' + self.log_text
-        with open('log', 'w') as f:
-            f.write(self.log_text)
         self.tui.to_update['log'] = True
 
     def symbol_for_type(self, type_):
@@ -338,7 +337,7 @@ class DescriptorWidget(TextLinesWidget):
     def get_text_lines(self):
         lines = []
         pos_i = self.tui.game.world.map_.\
-                get_position_index(self.tui.examiner_position)
+                get_position_index(self.tui.examiner_position[1])
         terrain = self.tui.game.world.map_.terrain[pos_i]
         lines = [terrain]
         for t in self.tui.game.world.things_at_pos(self.tui.examiner_position):
@@ -408,7 +407,7 @@ class MapWidget(Widget):
                 if t.id_ in self.tui.game.world.player_inventory:
                     continue
                 pos_i = self.tui.game.world.map_.\
-                        get_position_index(t.position)
+                        get_position_index(t.position[1])
                 symbol = self.tui.game.symbol_for_type(t.type_)
                 if terrain_as_list[pos_i][0] in {'f', '@', 'm'}:
                     old_symbol = terrain_as_list[pos_i][0]
@@ -419,7 +418,7 @@ class MapWidget(Widget):
                     terrain_as_list[pos_i] = symbol
             if self.tui.examiner_mode:
                 pos_i = self.tui.game.world.map_.\
-                        get_position_index(self.tui.examiner_position)
+                        get_position_index(self.tui.examiner_position[1])
                 terrain_as_list[pos_i] = (terrain_as_list[pos_i][0], '?')
             return terrain_as_list
 
@@ -570,8 +569,9 @@ class TUI:
 
         def move_examiner(direction):
             start_pos = self.examiner_position
-            new_examine_pos = self.game.world.map_.move(start_pos, direction)
-            if new_examine_pos:
+            new_examine_pos = self.game.map_geometry.move(start_pos, direction,
+                                                          self.game.world.map_.size)
+            if new_examine_pos[0] == (0,0):
                 self.examiner_position = new_examine_pos
             self.to_update['map'] = True
 
index bd740b7404999e7d894da1ff8b1ce14e6f86204f..bcab2d10702c13bda99a2fee684e210b5e7fa979 100644 (file)
@@ -15,7 +15,7 @@ def cmd_SEED(game, seed):
 cmd_SEED.argtypes = 'int:nonneg'
 
 def cmd_MAP_SIZE(game, size):
-    game.world.map_size = size
+    game.map_size = size
 cmd_MAP_SIZE.argtypes = 'yx_tuple:pos'
 
 def cmd_MAP(game, map_pos):
@@ -104,7 +104,7 @@ def cmd_SAVE(game):
     with open(save_file_name, 'w') as f:
         write(f, 'TURN %s' % game.world.turn)
         write(f, 'SEED %s' % game.world.rand.prngod_seed)
-        write(f, 'MAP_SIZE %s' % (game.world.map_size,))
+        write(f, 'MAP_SIZE %s' % (game.map_size,))
         for map_pos in game.world.maps:
             write(f, 'MAP %s' % (map_pos,))
         for map_pos in game.world.maps:
index 669fae3dd0b42483d3800e5ba989bdce37428daf..db71f21e21df5adf7412f7e2279f3a48177a1c5d 100755 (executable)
@@ -8,7 +8,7 @@ from plomrogue.commands import (cmd_GEN_WORLD, cmd_GET_GAMESTATE,
                                 cmd_GET_PICKABLE_ITEMS, cmd_MAP_SIZE,
                                 cmd_TERRAIN_LINE, cmd_PLAYER_ID,
                                 cmd_TURN, cmd_SWITCH_PLAYER, cmd_SAVE)
-from plomrogue.mapping import MapHex, YX
+from plomrogue.mapping import MapGeometryHex, Map, YX
 from plomrogue.parser import Parser
 from plomrogue.io import GameIO
 from plomrogue.misc import quote
@@ -67,7 +67,6 @@ class World(WorldBase):
         self.player_id = 0
         self.player_is_alive = True
         self.maps = {}
-        self.map_size = YX(1,1)
         self.rand = PRNGod(0)
 
     @property
@@ -81,11 +80,11 @@ class World(WorldBase):
 
     def get_map(self, map_pos, create_unfound=True):
         if not (map_pos in self.maps and
-                self.maps[map_pos].size == self.map_size):
+                self.maps[map_pos].size == self.game.map_size):
             if create_unfound:
-                self.maps[map_pos] = self.game.map_type(self.map_size)
+                self.maps[map_pos] = Map(self.game.map_size)
                 for pos in self.maps[map_pos]:
-                    self.maps[map_pos][pos] = '~'
+                    self.maps[map_pos][pos] = '.'
             else:
                 return None
         return self.maps[map_pos]
@@ -143,10 +142,10 @@ class World(WorldBase):
         self.rand.seed(seed)
         self.turn = 0
         self.maps = {}
-        self.map_size = yx
+        self.game.map_size = yx
         map_ = self.get_map(YX(0,0))
         for pos in map_:
-            map_[pos] = self.rand.choice(('.', '.', '.', '.', 'x'))
+            map_[pos] = self.rand.choice(('.', '.', '.', '~', 'x'))
         player = add_thing_at_random('human')
         self.player_id = player.id_
         add_thing_at_random('monster')
@@ -163,7 +162,8 @@ class Game:
 
     def __init__(self, game_file_name):
         self.io = GameIO(game_file_name, self)
-        self.map_type = MapHex
+        self.map_size = None
+        self.map_geometry = MapGeometryHex()
         self.tasks = {'WAIT': Task_WAIT,
                       'MOVE': Task_MOVE,
                       'PICKUP': Task_PICKUP,
@@ -193,7 +193,7 @@ class Game:
 
     def get_string_options(self, string_option_type):
         if string_option_type == 'direction':
-            return self.map_type().get_directions()
+            return self.map_geometry.get_directions()
         elif string_option_type == 'thingtype':
             return list(self.thing_types.keys())
         return None
@@ -202,7 +202,9 @@ class Game:
         """Send out game state data relevant to clients."""
 
         def send_thing(offset, thing):
-            offset_pos = (thing.position[1] - offset)
+            offset_pos = self.map_geometry.pos_in_projection(thing.position,
+                                                             offset,
+                                                             self.map_size)
             self.io.send('THING_TYPE %s %s' % (thing.id_, thing.type_))
             self.io.send('THING_POS %s %s' % (thing.id_, offset_pos))
 
index ee3e9401677e947d0c9fedd64234f9bb94d59ffd..bec311b56e5064258ec4a7c3cc85869d0cfa546b 100644 (file)
@@ -18,9 +18,9 @@ class YX(collections.namedtuple('YX', ('y', 'x'))):
 
 class Map:
 
-    def __init__(self, size=YX(0, 0)):
+    def __init__(self, size=YX(0, 0), init_char = '?'):
         self.size = size
-        self.terrain = '?'*self.size_i
+        self.terrain = init_char*self.size_i
 
     def __getitem__(self, yx):
         return self.terrain[self.get_position_index(yx)]
@@ -61,8 +61,9 @@ class Map:
         for y in range(self.size.y):
             yield (y, self.terrain[y * width:(y + 1) * width])
 
-    def get_fov_map(self, yx):
-        return self.fov_map_type(self, yx)
+
+
+class MapGeometry():
 
     def get_directions(self):
         directions = []
@@ -71,38 +72,45 @@ class Map:
                 directions += [name[5:]]
         return directions
 
-    def get_neighbors(self, pos):
+    def get_neighbors(self, pos, map_size):
         neighbors = {}
         if not hasattr(self, 'neighbors_to'):
             self.neighbors_to = {}
-        if pos in self.neighbors_to:
-            return self.neighbors_to[pos]
+        if not map_size in self.neighbors_to:
+            self.neighbors_to[map_size] = {}
+        if pos in self.neighbors_to[map_size]:
+            return self.neighbors_to[map_size][pos]
         for direction in self.get_directions():
-            neighbors[direction] = None
-            neighbor_pos = self.move(pos, direction)
-            if neighbor_pos:
-                neighbors[direction] = neighbor_pos
-        self.neighbors_to[pos] = neighbors
+            neighbors[direction] = self.move(pos, direction, map_size)
+        self.neighbors_to[map_size][pos] = neighbors
         return neighbors
 
-    def new_from_shape(self, init_char):
-        import copy
-        new_map = copy.deepcopy(self)
-        for pos in new_map:
-            new_map[pos] = init_char
-        return new_map
+    def pos_in_projection(self, pos, offset, maps_size):
+        pos_y = pos[1].y + (maps_size.y * pos[0].y) - offset.y
+        pos_x = pos[1].x + (maps_size.x * pos[0].x) - offset.x
+        return YX(pos_y, pos_x)
+
+    def absolutize_coordinate(self, map_size, big_yx, little_yx):
+
+        def adapt_axis(axis):
+            maps_crossed = little_yx[axis] // map_size[axis]
+            new_big = big_yx[axis] + maps_crossed
+            new_little = little_yx[axis] % map_size[axis]
+            return new_big, new_little
 
-    def move(self, start_pos, direction):
+        new_big_y, new_little_y = adapt_axis(0)
+        new_big_x, new_little_x = adapt_axis(1)
+        return YX(new_big_y, new_big_x), YX(new_little_y, new_little_x)
+
+    def move(self, start_pos, direction, map_size):
         mover = getattr(self, 'move_' + direction)
-        new_pos = mover(start_pos)
-        if new_pos.y < 0 or new_pos.x < 0 or \
-                new_pos.y >= self.size.y or new_pos.x >= self.size.x:
-            return None
-        return new_pos
+        big_yx, little_yx = start_pos
+        unadapted_target = mover(little_yx)
+        return self.absolutize_coordinate(map_size, big_yx, unadapted_target)
 
 
 
-class MapWithLeftRightMoves(Map):
+class MapGeometryWithLeftRightMoves(MapGeometry):
 
     def move_LEFT(self, start_pos):
         return YX(start_pos.y, start_pos.x - 1)
@@ -112,7 +120,7 @@ class MapWithLeftRightMoves(Map):
 
 
 
-class MapSquare(MapWithLeftRightMoves):
+class MapGeometrySquare(MapGeometryWithLeftRightMoves):
 
     def move_UP(self, start_pos):
         return YX(start_pos.y - 1, start_pos.x)
@@ -122,7 +130,7 @@ class MapSquare(MapWithLeftRightMoves):
 
 
 
-class MapHex(MapWithLeftRightMoves):
+class MapGeometryHex(MapGeometryWithLeftRightMoves):
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
@@ -154,16 +162,16 @@ class MapHex(MapWithLeftRightMoves):
 
 
 
-class FovMap:
+class FovMap(Map):
 
-    def __init__(self, source_map, yx):
+    def __init__(self, source_map, center):
         self.source_map = source_map
         self.size = self.source_map.size
         self.fov_radius = (self.size.y / 2) - 0.5
         self.terrain = '?' * self.size_i
-        self[yx] = '.'
+        self[center] = '.'
         self.shadow_cones = []
-        self.circle_out(yx, self.shadow_process_hex)
+        self.circle_out(center, self.shadow_process_hex)
 
     def shadow_process_hex(self, yx, distance_to_center, dir_i, dir_progress):
         # Possible optimization: If no shadow_cones yet and self[yx] == '.',
@@ -234,7 +242,7 @@ class FovMap:
 
     def basic_circle_out_move(self, pos, direction):
         """Move position pos into direction. Return whether still in map."""
-        mover = getattr(self, 'move_' + direction)
+        mover = getattr(self.geometry, 'move_' + direction)
         pos = mover(pos)
         if pos.y < 0 or pos.x < 0 or \
             pos.y >= self.size.y or pos.x >= self.size.x:
@@ -271,19 +279,28 @@ class FovMap:
 
 
 
-class FovMapHex(FovMap, MapHex):
+class FovMapHex(FovMap):
     circle_out_directions = ('DOWNLEFT', 'LEFT', 'UPLEFT',
                              'UPRIGHT', 'RIGHT', 'DOWNRIGHT')
 
+    def __init__(self, *args, **kwargs):
+        self.geometry = MapGeometryHex()
+        super().__init__(*args, **kwargs)
+
     def circle_out_move(self, yx, direction):
         return self.basic_circle_out_move(yx, direction)
 
 
 
-class FovMapSquare(FovMap, MapSquare):
+class FovMapSquare(FovMap):
     circle_out_directions = (('DOWN', 'LEFT'), ('LEFT', 'UP'),
                              ('UP', 'RIGHT'), ('RIGHT', 'DOWN'))
 
+    def __init__(self, *args, **kwargs):
+        self.geometry = MapGeometrySquare()
+        super().__init__(*args, **kwargs)
+
     def circle_out_move(self, yx, direction):
         self.basic_circle_out_move(yx, direction[0])
         return self.basic_circle_out_move(yx, direction[1])
+
index 3bc0f56ebf50245ee974ba68bbb8644949245118..6d67c35b1b088b0bf5b617525530668d8c1acbac 100644 (file)
@@ -38,12 +38,13 @@ class Task_WAIT(Task):
 class Task_MOVE(Task):
     argtypes = 'string:direction'
 
+    def get_move_target(self):
+        return self.thing.world.game.map_geometry.move(self.thing.position,
+                                                       self.args[0],
+                                                       self.thing.world.game.map_size)
+
     def check(self):
-        test_pos = (YX(0,0),
-                    self.thing.world.maps[YX(0,0)].
-                    move(self.thing.position[1], self.args[0]))
-        if test_pos == (YX(0,0), None):
-            raise GameError('would move outside map bounds')
+        test_pos = self.get_move_target()
         if self.thing.world.maps[test_pos[0]][test_pos[1]] != '.':
             raise GameError('%s would move into illegal terrain' % self.thing.id_)
         for t in self.thing.world.things_at_pos(test_pos):
@@ -51,8 +52,7 @@ class Task_MOVE(Task):
                 raise GameError('%s would move into other thing' % self.thing.id_)
 
     def do(self):
-        self.thing.position = YX(0,0), self.thing.world.maps[YX(0,0)].\
-                                     move(self.thing.position[1], self.args[0])
+        self.thing.position = self.get_move_target()
 
 
 
index ed3b5474d6a64bf978c86ef8b41436043171565b..c47e55384c72732469929e0a054468301ad93e79 100644 (file)
@@ -1,5 +1,5 @@
 from plomrogue.errors import GameError
-from plomrogue.mapping import YX
+from plomrogue.mapping import YX, Map, FovMapHex
 
 
 
@@ -60,18 +60,18 @@ class Thing(ThingBase):
         edge_up = self.position[1].y - self._radius
         edge_down = self.position[1].y + self._radius
         if edge_left < 0:
-            self.world.get_map(self.position[0] - YX(1,-1))
-            self.world.get_map(self.position[0] - YX(0,-1))
-            self.world.get_map(self.position[0] - YX(-1,-1))
-        if edge_right >= self.world.map_size.x:
+            self.world.get_map(self.position[0] + YX(1,-1))
+            self.world.get_map(self.position[0] + YX(0,-1))
+            self.world.get_map(self.position[0] + YX(-1,-1))
+        if edge_right >= self.world.game.map_size.x:
             self.world.get_map(self.position[0] + YX(1,1))
             self.world.get_map(self.position[0] + YX(0,1))
             self.world.get_map(self.position[0] + YX(-1,1))
         if edge_up < 0:
-            self.world.get_map(self.position[0] - YX(-1,1))
-            self.world.get_map(self.position[0] - YX(-1,0))
-            self.world.get_map(self.position[0] - YX(-1,-1))
-        if edge_down >= self.world.map_size.y:
+            self.world.get_map(self.position[0] + YX(-1,1))
+            self.world.get_map(self.position[0] + YX(-1,0))
+            self.world.get_map(self.position[0] + YX(-1,-1))
+        if edge_down >= self.world.game.map_size.y:
             self.world.get_map(self.position[0] + YX(1,1))
             self.world.get_map(self.position[0] + YX(1,0))
             self.world.get_map(self.position[0] + YX(1,-1))
@@ -99,7 +99,7 @@ class ThingAnimate(Thing):
 
     def move_on_dijkstra_map(self, own_pos, targets):
         visible_map = self.get_visible_map()
-        dijkstra_map = self.world.game.map_type(visible_map.size)
+        dijkstra_map = Map(visible_map.size)
         n_max = 256
         dijkstra_map.terrain = [n_max for i in range(dijkstra_map.size_i)]
         for target in targets:
@@ -110,19 +110,22 @@ class ThingAnimate(Thing):
             for pos in dijkstra_map:
                 if visible_map[pos] != '.':
                     continue
-                neighbors = dijkstra_map.get_neighbors(pos)
+                neighbors = self.world.game.map_geometry.get_neighbors((YX(0,0), pos),
+                                                                       dijkstra_map.size)
                 for direction in neighbors:
-                    yx = neighbors[direction]
-                    if yx is not None and dijkstra_map[yx] < dijkstra_map[pos] - 1:
-                        dijkstra_map[pos] = dijkstra_map[yx] + 1
+                    big_yx, small_yx = neighbors[direction]
+                    if big_yx == YX(0,0) and \
+                       dijkstra_map[small_yx] < dijkstra_map[pos] - 1:
+                        dijkstra_map[pos] = dijkstra_map[small_yx] + 1
                         shrunk = True
-        neighbors = dijkstra_map.get_neighbors(own_pos)
+        neighbors = self.world.game.map_geometry.get_neighbors((YX(0,0), own_pos),
+                                                               dijkstra_map.size)
         n = n_max
         target_direction = None
         for direction in sorted(neighbors.keys()):
-            yx = neighbors[direction]
-            if yx is not None:
-                n_new = dijkstra_map[yx]
+            big_yx, small_yx = neighbors[direction]
+            if big_yx == (0,0):
+                n_new = dijkstra_map[small_yx]
                 if n_new < n:
                     n = n_new
                     target_direction = direction
@@ -241,40 +244,24 @@ class ThingAnimate(Thing):
         if self._surroundings_offset is not None:
             return self._surroundings_offset
         add_line = self.must_fix_indentation()
-        offset = YX(self.position[1].y - self._radius - int(add_line),
-                    self.position[1].x - self._radius)
+        offset = YX(self.position[0].y * self.world.game.map_size.y + self.position[1].y - self._radius - int(add_line),
+                    self.position[0].x * self.world.game.map_size.x + self.position[1].x - self._radius)
         self._surroundings_offset = offset
         return self._surroundings_offset
 
     def get_surrounding_map(self):
         if self._surrounding_map is not None:
             return self._surrounding_map
-
-        def pan_and_scan(size_of_axis, pos, offset):
-            big_pos = 0
-            small_pos = pos + offset
-            if small_pos < 0:
-                big_pos = -1
-                small_pos = size_of_axis + small_pos
-            elif small_pos >= size_of_axis:
-                big_pos = 1
-                small_pos = small_pos - size_of_axis
-            return big_pos, small_pos
-
         add_line = self.must_fix_indentation()
-        self._surrounding_map = self.world.game.\
-                                map_type(size=YX(self._radius*2+1+int(add_line),
-                                                 self._radius*2+1))
-        size = self.world.map_size
+        self._surrounding_map = Map(size=YX(self._radius*2+1+int(add_line),
+                                            self._radius*2+1))
         offset = self.get_surroundings_offset()
         for pos in self._surrounding_map:
-            big_y, small_y = pan_and_scan(size.y, pos.y, offset.y)
-            big_x, small_x = pan_and_scan(size.x, pos.x, offset.x)
-            big_yx = YX(big_y, big_x)
-            small_yx = YX(small_y, small_x)
+            offset_pos = pos + offset
+            big_yx, small_yx = self.world.game.map_geometry.absolutize_coordinate(self.world.game.map_size, (0,0), offset_pos)
             map_ = self.world.get_map(big_yx, False)
             if map_ is None:
-                map_ = self.world.game.map_type(size=self.world.map_size)
+                map_ = Map(size=self.world.game.map_size)
             self._surrounding_map[pos] = map_[small_yx]
         return self._surrounding_map
 
@@ -282,58 +269,47 @@ class ThingAnimate(Thing):
         if self._stencil is not None:
             return self._stencil
         surrounding_map = self.get_surrounding_map()
-        m = surrounding_map.new_from_shape(' ')
+        m = Map(surrounding_map.size, ' ')
         for pos in surrounding_map:
             if surrounding_map[pos] in {'.', '~'}:
                 m[pos] = '.'
-        offset = self.get_surroundings_offset()
-        fov_center = self.position[1] - offset
-        self._stencil = m.get_fov_map(fov_center)
+        add_line = self.must_fix_indentation()
+        fov_center = YX((add_line + m.size.y) // 2, m.size.x // 2)
+        self._stencil = FovMapHex(m, fov_center)
         return self._stencil
 
     def get_visible_map(self):
         stencil = self.get_stencil()
-        m = self.get_surrounding_map().new_from_shape(' ')
+        m = Map(self.get_surrounding_map().size, ' ')
         for pos in m:
             if stencil[pos] == '.':
                 m[pos] = self._surrounding_map[pos]
         return m
 
     def get_visible_things(self):
-
-        def calc_pos_in_fov(big_pos, small_pos, offset, size_of_axis):
-            pos = small_pos - offset
-            if big_pos == -1:
-                pos = small_pos - size_of_axis - offset
-            elif big_pos == 1:
-                pos = small_pos + size_of_axis - offset
-            return pos
-
         stencil = self.get_stencil()
         offset = self.get_surroundings_offset()
         visible_things = []
-        size = self.world.map_size
-        fov_size = self.get_surrounding_map().size
         for thing in self.world.things:
-            big_pos = thing.position[0]
-            small_pos = thing.position[1]
-            pos_y = calc_pos_in_fov(big_pos.y, small_pos.y, offset.y, size.y)
-            pos_x = calc_pos_in_fov(big_pos.x, small_pos.x, offset.x, size.x)
-            if pos_y < 0 or pos_x < 0 or\
-               pos_y >= fov_size.y or pos_x >= fov_size.x:
+            pos = self.world.game.map_geometry.pos_in_projection(thing.position,
+                                                                 offset,
+                                                                 self.world.game.map_size)
+            if pos.y < 0 or pos.x < 0 or\
+               pos.y >= stencil.size.y or pos.x >= stencil.size.x:
                 continue
-            if (not thing.in_inventory) and stencil[YX(pos_y, pos_x)] == '.':
+            if (not thing.in_inventory) and stencil[pos] == '.':
                 visible_things += [thing]
         return visible_things
 
     def get_pickable_items(self):
         pickable_ids = []
         visible_things = self.get_visible_things()
-        for t in [t for t in visible_things if
-                  isinstance(t, ThingItem) and
+        neighbor_fields = self.world.game.map_geometry.get_neighbors(self.position,
+                                                                     self.world.game.map_size)
+        for t in [t for t in visible_things
+                  if isinstance(t, ThingItem) and
                   (t.position == self.position or
-                   t.position[1] in
-                   self.world.maps[YX(0,0)].get_neighbors(self.position[1]).values())]:
+                   t.position in neighbor_fields.values())]:
             pickable_ids += [t.id_]
         return pickable_ids