1 from plomrogue.errors import GameError
8 def __init__(self, world, id_=None, position=(0,0)):
10 self.position = position
12 self.id_ = self.world.new_thing_id()
18 class Thing(ThingBase):
22 def __init__(self, *args, **kwargs):
23 super().__init__(*args, **kwargs)
31 class ThingItem(Thing):
36 class ThingFood(ThingItem):
41 class ThingAnimate(Thing):
44 def __init__(self, *args, **kwargs):
45 super().__init__(*args, **kwargs)
47 self._last_task_result = None
50 def move_towards_position(self, target):
51 dijkstra_map = type(self.world.map_)(self.world.map_.size)
53 dijkstra_map.terrain = [n_max for i in range(dijkstra_map.size_i)]
54 dijkstra_map[target] = 0
56 visible_map = self.get_visible_map()
59 for pos in dijkstra_map:
60 if visible_map[pos] != '.':
62 neighbors = dijkstra_map.get_neighbors(tuple(pos))
63 for direction in neighbors:
64 yx = neighbors[direction]
65 if yx is not None and dijkstra_map[yx] < dijkstra_map[pos] - 1:
66 dijkstra_map[pos] = dijkstra_map[yx] + 1
68 neighbors = dijkstra_map.get_neighbors(tuple(self.position))
70 target_direction = None
71 for direction in sorted(neighbors.keys()):
72 yx = neighbors[direction]
74 n_new = dijkstra_map[yx]
77 target_direction = direction
79 self.set_task('MOVE', (target_direction,))
81 def hunt_player(self):
82 visible_things = self.get_visible_things()
84 for t in visible_things:
85 if t.type_ == 'human':
88 if target is not None:
90 self.move_towards_position(target)
96 def decide_task(self):
97 if not self.hunt_player():
100 def set_task(self, task_name, args=()):
101 task_class = self.world.game.tasks[task_name]
102 self.task = task_class(self, args)
103 self.task.check() # will throw GameError if necessary
105 def proceed(self, is_AI=True):
106 """Further the thing in its tasks, decrease its health.
108 First, ensures an empty map, decrements .health and kills
109 thing if crossing zero (removes from self.world.things for AI
110 thing, or unsets self.world.player_is_alive for player thing);
111 then checks that self.task is still possible and aborts if
112 otherwise (for AI things, decides a new task).
114 Then decrements .task.todo; if it thus falls to <= 0, enacts
115 method whose name is 'task_' + self.task.name and sets .task =
116 None. If is_AI, calls .decide_task to decide a self.task.
122 if self is self.world.player:
123 self.world.player_is_alive = False
125 del self.world.things[self.world.things.index(self)]
129 except GameError as e:
131 self._last_task_result = e
136 self.set_task('WAIT')
139 if self.task.todo <= 0:
140 self._last_task_result = self.task.do()
142 if is_AI and self.task is None:
146 self.set_task('WAIT')
148 def get_stencil(self):
149 if self._stencil is not None:
151 self._stencil = self.world.map_.get_fov_map(self.position)
154 def get_visible_map(self):
155 stencil = self.get_stencil()
156 m = self.world.map_.new_from_shape(' ')
158 if stencil[pos] == '.':
159 m[pos] = self.world.map_[pos]
162 def get_visible_things(self):
163 stencil = self.get_stencil()
165 for thing in self.world.things:
166 if (not thing.in_inventory) and stencil[thing.position] == '.':
167 visible_things += [thing]
168 return visible_things
170 def get_pickable_items(self):
172 for t in [t for t in self.get_visible_things() if
173 isinstance(t, ThingItem) and
174 (t.position == self.position or
176 self.world.map_.get_neighbors(self.position).values())]:
177 pickable_ids += [t.id_]
182 class ThingHuman(ThingAnimate):
188 class ThingMonster(ThingAnimate):