home · contact · privacy
Fix FOV bug by respecting HexMap start indentation consequences.
[plomrogue2-experiments] / new / plomrogue / things.py
index 4f35880b7689644a1e3f1c941f02a93898130077..0e47cc0b6cd6df06fb4f83e6df8b5b856a232456 100644 (file)
@@ -6,10 +6,10 @@ 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
+    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_
         self.position = position
         else:
             self.id_ = id_
         self.position = position
@@ -51,30 +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.world.player_id:
+        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:
             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.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))
+            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:
         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.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))
+            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))
 
 
 
 
 
 
@@ -99,27 +113,29 @@ class ThingAnimate(Thing):
 
     def move_on_dijkstra_map(self, own_pos, targets):
         visible_map = self.get_visible_map()
 
     def move_on_dijkstra_map(self, own_pos, targets):
         visible_map = self.get_visible_map()
-        dijkstra_map = Map(visible_map.size)
+        dijkstra_map = Map(visible_map.size,
+                           start_indented=visible_map.start_indented)
         n_max = 256
         dijkstra_map.terrain = [n_max for i in range(dijkstra_map.size_i)]
         for target in targets:
             dijkstra_map[target] = 0
         shrunk = True
         n_max = 256
         dijkstra_map.terrain = [n_max for i in range(dijkstra_map.size_i)]
         for target in targets:
             dijkstra_map[target] = 0
         shrunk = True
+        get_neighbors = self.game.map_geometry.get_neighbors
         while shrunk:
             shrunk = False
             for pos in dijkstra_map:
                 if visible_map[pos] != '.':
                     continue
         while shrunk:
             shrunk = False
             for pos in dijkstra_map:
                 if visible_map[pos] != '.':
                     continue
-                neighbors = self.world.game.map_geometry.get_neighbors((YX(0,0), pos),
-                                                                       dijkstra_map.size)
+                neighbors = get_neighbors((YX(0,0), pos), dijkstra_map.size,
+                                          dijkstra_map.start_indented)
                 for direction in neighbors:
                     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
                 for direction in neighbors:
                     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 = self.world.game.map_geometry.get_neighbors((YX(0,0), own_pos),
-                                                               dijkstra_map.size)
+        get_neighbors((YX(0,0), own_pos), dijkstra_map.size,
+                      dijkstra_map.start_indented)
         n = n_max
         target_direction = None
         for direction in sorted(neighbors.keys()):
         n = n_max
         target_direction = None
         for direction in sorted(neighbors.keys()):
@@ -133,15 +149,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:
@@ -153,22 +168,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:
@@ -185,7 +199,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
 
@@ -193,8 +207,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).
 
@@ -206,10 +220,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()
@@ -234,40 +248,30 @@ 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 get_surroundings_offset(self):
-        if self._surroundings_offset is not None:
-            return self._surroundings_offset
-        offset = YX(self.position[0].y * self.world.game.map_size.y +
-                    self.position[1].y - self._radius,
-                    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
-        self._surrounding_map = Map(size=YX(self._radius*2+1, self._radius*2+1))
-        offset = self.get_surroundings_offset()
-        for pos in self._surrounding_map:
-            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_ = Map(size=self.world.game.map_size)
-            self._surrounding_map[pos] = map_[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 = Map(surrounding_map.size, ' ')
-        for pos in surrounding_map:
-            if surrounding_map[pos] in {'.', '~'}:
+        m = Map(self.surroundings.size, ' ', self.surroundings.start_indented)
+        for pos in self.surroundings:
+            if self.surroundings[pos] in {'.', '~'}:
                 m[pos] = '.'
         fov_center = YX((m.size.y) // 2, m.size.x // 2)
         self._stencil = FovMapHex(m, fov_center)
                 m[pos] = '.'
         fov_center = YX((m.size.y) // 2, m.size.x // 2)
         self._stencil = FovMapHex(m, fov_center)
@@ -275,20 +279,19 @@ class ThingAnimate(Thing):
 
     def get_visible_map(self):
         stencil = self.get_stencil()
 
     def get_visible_map(self):
         stencil = self.get_stencil()
-        m = Map(self.get_surrounding_map().size, ' ')
+        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):
         stencil = self.get_stencil()
         return m
 
     def get_visible_things(self):
         stencil = self.get_stencil()
-        offset = self.get_surroundings_offset()
         visible_things = []
         visible_things = []
-        for thing in self.world.things:
-            pos = self.world.game.map_geometry.pos_in_projection(thing.position,
-                                                                 offset,
-                                                                 self.world.game.map_size)
+        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
             if pos.y < 0 or pos.x < 0 or\
                pos.y >= stencil.size.y or pos.x >= stencil.size.x:
                 continue
@@ -299,8 +302,8 @@ class ThingAnimate(Thing):
     def get_pickable_items(self):
         pickable_ids = []
         visible_things = self.get_visible_things()
     def get_pickable_items(self):
         pickable_ids = []
         visible_things = self.get_visible_things()
-        neighbor_fields = self.world.game.map_geometry.get_neighbors(self.position,
-                                                                     self.world.game.map_size)
+        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
         for t in [t for t in visible_things
                   if isinstance(t, ThingItem) and
                   (t.position == self.position or