home · contact · privacy
More refactoring.
[plomrogue2-experiments] / new / plomrogue / things.py
index 1b3a46d3953a3070c9ebc2021f01ca7fc8415840..aded05c60d777918d975023968c8dd1959111d56 100644 (file)
@@ -1,18 +1,18 @@
 from plomrogue.errors import GameError
 from plomrogue.errors import GameError
-from plomrogue.mapping import YX
+from plomrogue.mapping import YX, Map, FovMapHex
 
 
 
 class ThingBase:
     type_ = '?'
 
 
 
 
 class ThingBase:
     type_ = '?'
 
-    def __init__(self, world, id_=None, position=(YX(0,0), YX(0,0))):
-        self.world = world
-        self.position = position
+    def __init__(self, game, id_=None, position=(YX(0,0), YX(0,0))):
+        self.game = game
         if id_ is None:
         if id_ is None:
-            self.id_ = self.world.new_thing_id()
+            self.id_ = self.game.new_thing_id()
         else:
             self.id_ = id_
         else:
             self.id_ = id_
+        self.position = position
 
     @property
     def position(self):
 
     @property
     def position(self):
@@ -42,6 +42,7 @@ class Thing(ThingBase):
 
     def __init__(self, *args, **kwargs):
         self.inventory = []
 
     def __init__(self, *args, **kwargs):
         self.inventory = []
+        self._radius = 8
         super().__init__(*args, **kwargs)
 
     def proceed(self):
         super().__init__(*args, **kwargs)
 
     def proceed(self):
@@ -50,8 +51,44 @@ class Thing(ThingBase):
     def _position_set(self, pos):
         super()._position_set(pos)
         for t_id in self.inventory:
     def _position_set(self, pos):
         super()._position_set(pos)
         for t_id in self.inventory:
-            t = self.world.get_thing(t_id)
+            t = self.game.get_thing(t_id)
             t.position = self.position
             t.position = self.position
+        if not self.id_ == self.game.player_id:
+            return
+        edge_left = self.position[1].x - self._radius
+        edge_right = self.position[1].x + self._radius
+        edge_up = self.position[1].y - self._radius
+        edge_down = self.position[1].y + self._radius
+        if edge_left < 0:
+            self.game.get_map(self.position[0] + YX(1,-1))
+            self.game.get_map(self.position[0] + YX(0,-1))
+            self.game.get_map(self.position[0] + YX(-1,-1))
+        if edge_right >= self.game.map_size.x:
+            self.game.get_map(self.position[0] + YX(1,1))
+            self.game.get_map(self.position[0] + YX(0,1))
+            self.game.get_map(self.position[0] + YX(-1,1))
+        if edge_up < 0:
+            self.game.get_map(self.position[0] + YX(-1,1))
+            self.game.get_map(self.position[0] + YX(-1,0))
+            self.game.get_map(self.position[0] + YX(-1,-1))
+        if edge_down >= self.game.map_size.y:
+            self.game.get_map(self.position[0] + YX(1,1))
+            self.game.get_map(self.position[0] + YX(1,0))
+            self.game.get_map(self.position[0] + YX(1,-1))
+        #alternative
+        #if self.position[1].x < self._radius:
+        #    self.game.get_map(self.position[0] - YX(0,1))
+        #if self.position[1].y < self._radius:
+        #    self.game.get_map(self.position[0] - YX(1,0))
+        #if self.position[1].x > self.game.map_size.x - self._radius:
+        #    self.game.get_map(self.position[0] + YX(0,1))
+        #if self.position[1].y > self.game.map_size.y - self._radius:
+        #    self.game.get_map(self.position[0] + YX(1,0))
+        #if self.position[1].y < self._radius and \
+        #   self.position[1].x <= [pos for pos in
+        #                          diagonal_distance_edge
+        #                          if pos.y == self.position[1].y][0].x:
+        #    self.game.get_map(self.position[0] - YX(1,1))
 
 
 
 
 
 
@@ -72,12 +109,11 @@ class ThingAnimate(Thing):
         super().__init__(*args, **kwargs)
         self.set_task('WAIT')
         self._last_task_result = None
         super().__init__(*args, **kwargs)
         self.set_task('WAIT')
         self._last_task_result = None
-        self._radius = 8
         self.unset_surroundings()
 
     def move_on_dijkstra_map(self, own_pos, targets):
         visible_map = self.get_visible_map()
         self.unset_surroundings()
 
     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:
         n_max = 256
         dijkstra_map.terrain = [n_max for i in range(dijkstra_map.size_i)]
         for target in targets:
@@ -88,19 +124,22 @@ class ThingAnimate(Thing):
             for pos in dijkstra_map:
                 if visible_map[pos] != '.':
                     continue
             for pos in dijkstra_map:
                 if visible_map[pos] != '.':
                     continue
-                neighbors = dijkstra_map.get_neighbors(pos)
+                neighbors = self.game.map_geometry.get_neighbors((YX(0,0), pos),
+                                                                 dijkstra_map.size)
                 for direction in neighbors:
                 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
                         shrunk = True
-        neighbors = dijkstra_map.get_neighbors(own_pos)
+        neighbors = self.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()):
         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
                 if n_new < n:
                     n = n_new
                     target_direction = direction
@@ -108,15 +147,14 @@ class ThingAnimate(Thing):
 
     def hunt_player(self):
         visible_things = self.get_visible_things()
 
     def hunt_player(self):
         visible_things = self.get_visible_things()
-        offset = self.get_surroundings_offset()
         target = None
         for t in visible_things:
             if t.type_ == 'human':
         target = None
         for t in visible_things:
             if t.type_ == 'human':
-                target = t.position[1] - offset
+                target = t.position[1] - self.view_offset
                 break
         if target is not None:
             try:
                 break
         if target is not None:
             try:
-                offset_self_pos = self.position[1] - offset
+                offset_self_pos = self.position[1] - self.view_offset
                 target_dir = self.move_on_dijkstra_map(offset_self_pos,
                                                        [target])
                 if target_dir is not None:
                 target_dir = self.move_on_dijkstra_map(offset_self_pos,
                                                        [target])
                 if target_dir is not None:
@@ -128,22 +166,21 @@ class ThingAnimate(Thing):
 
     def hunt_food_satisfaction(self):
         for id_ in self.inventory:
 
     def hunt_food_satisfaction(self):
         for id_ in self.inventory:
-            t = self.world.get_thing(id_)
+            t = self.game.get_thing(id_)
             if t.type_ == 'food':
                 self.set_task('EAT', (id_,))
                 return True
         for id_ in self.get_pickable_items():
             if t.type_ == 'food':
                 self.set_task('EAT', (id_,))
                 return True
         for id_ in self.get_pickable_items():
-            t = self.world.get_thing(id_)
+            t = self.game.get_thing(id_)
             if t.type_ == 'food':
                 self.set_task('PICKUP', (id_,))
                 return True
         visible_things = self.get_visible_things()
             if t.type_ == 'food':
                 self.set_task('PICKUP', (id_,))
                 return True
         visible_things = self.get_visible_things()
-        offset = self.get_surroundings_offset()
         food_targets = []
         for t in visible_things:
             if t.type_ == 'food':
         food_targets = []
         for t in visible_things:
             if t.type_ == 'food':
-                food_targets += [t.position[1] - offset]
-        offset_self_pos = self.position[1] - offset
+                food_targets += [t.position[1] - self.view_offset]
+        offset_self_pos = self.position[1] - self.view_offset
         target_dir = self.move_on_dijkstra_map(offset_self_pos,
                                                food_targets)
         if target_dir:
         target_dir = self.move_on_dijkstra_map(offset_self_pos,
                                                food_targets)
         if target_dir:
@@ -160,7 +197,7 @@ class ThingAnimate(Thing):
             self.set_task('WAIT')
 
     def set_task(self, task_name, args=()):
             self.set_task('WAIT')
 
     def set_task(self, task_name, args=()):
-        task_class = self.world.game.tasks[task_name]
+        task_class = self.game.tasks[task_name]
         self.task = task_class(self, args)
         self.task.check()  # will throw GameError if necessary
 
         self.task = task_class(self, args)
         self.task.check()  # will throw GameError if necessary
 
@@ -168,8 +205,8 @@ class ThingAnimate(Thing):
         """Further the thing in its tasks, decrease its health.
 
         First, ensures an empty map, decrements .health and kills
         """Further the thing in its tasks, decrease its health.
 
         First, ensures an empty map, decrements .health and kills
-        thing if crossing zero (removes from self.world.things for AI
-        thing, or unsets self.world.player_is_alive for player thing);
+        thing if crossing zero (removes from self.game.things for AI
+        thing, or unsets self.game.player_is_alive for player thing);
         then checks that self.task is still possible and aborts if
         otherwise (for AI things, decides a new task).
 
         then checks that self.task is still possible and aborts if
         otherwise (for AI things, decides a new task).
 
@@ -181,10 +218,10 @@ class ThingAnimate(Thing):
         self.unset_surroundings()
         self.health -= 1
         if self.health <= 0:
         self.unset_surroundings()
         self.health -= 1
         if self.health <= 0:
-            if self is self.world.player:
-                self.world.player_is_alive = False
+            if self is self.game.player:
+                self.game.player_is_alive = False
             else:
             else:
-                del self.world.things[self.world.things.index(self)]
+                del self.game.things[self.game.things.index(self)]
             return
         try:
             self.task.check()
             return
         try:
             self.task.check()
@@ -209,106 +246,66 @@ class ThingAnimate(Thing):
 
     def unset_surroundings(self):
         self._stencil = None
 
     def unset_surroundings(self):
         self._stencil = None
-        self._surrounding_map = None
-        self._surroundings_offset = None
-
-    def must_fix_indentation(self):
-        return self._radius % 2 != self.position[1].y % 2
-
-    def get_surroundings_offset(self):
-        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)
-        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
-        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)
-            self._surrounding_map[pos] = self.world.maps[big_yx][small_yx]
-        return self._surrounding_map
+        self._surroundings = None
+
+    @property
+    def view_offset(self):
+        return self.game.map_geometry.get_view_offset(self.game.map_size,
+                                                      self.position,
+                                                      self._radius)
+
+    @property
+    def surroundings(self):
+        if self._surroundings is not None:
+            return self._surroundings
+        s = self.game.map_geometry.get_view(self.game.map_size,
+                                            self.game.get_map,
+                                            self._radius, self.view_offset)
+        self._surroundings = s
+        return self._surroundings
 
     def get_stencil(self):
         if self._stencil is not None:
             return self._stencil
 
     def get_stencil(self):
         if self._stencil is not None:
             return self._stencil
-        surrounding_map = self.get_surrounding_map()
-        m = surrounding_map.new_from_shape(' ')
-        for pos in surrounding_map:
-            if surrounding_map[pos] in {'.', '~'}:
+        m = Map(self.surroundings.size, ' ')
+        for pos in self.surroundings:
+            if self.surroundings[pos] in {'.', '~'}:
                 m[pos] = '.'
                 m[pos] = '.'
-        offset = self.get_surroundings_offset()
-        fov_center = self.position[1] - offset
-        self._stencil = m.get_fov_map(fov_center)
+        fov_center = YX((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()
         return self._stencil
 
     def get_visible_map(self):
         stencil = self.get_stencil()
-        m = self.get_surrounding_map().new_from_shape(' ')
+        m = Map(self.surroundings.size, ' ')
         for pos in m:
             if stencil[pos] == '.':
         for pos in m:
             if stencil[pos] == '.':
-                m[pos] = self._surrounding_map[pos]
+                m[pos] = self.surroundings[pos]
         return m
 
     def get_visible_things(self):
         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()
         stencil = self.get_stencil()
-        offset = self.get_surroundings_offset()
         visible_things = []
         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:
+        for thing in self.game.things:
+            pos = self.game.map_geometry.pos_in_view(thing.position,
+                                                     self.view_offset,
+                                                     self.game.map_size)
+            if pos.y < 0 or pos.x < 0 or\
+               pos.y >= stencil.size.y or pos.x >= stencil.size.x:
                 continue
                 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()
                 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.game.map_geometry.get_neighbors(self.position,
+                                                               self.game.map_size)
+        for t in [t for t in visible_things
+                  if isinstance(t, ThingItem) and
                   (t.position == self.position or
                   (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
 
             pickable_ids += [t.id_]
         return pickable_ids