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 ThingAnimate(Thing):
39 def __init__(self, *args, **kwargs):
40 super().__init__(*args, **kwargs)
42 self._last_task_result = None
45 def move_towards_target(self, target):
46 dijkstra_map = type(self.world.map_)(self.world.map_.size)
48 dijkstra_map.terrain = [n_max for i in range(dijkstra_map.size_i)]
49 dijkstra_map[target] = 0
51 visible_map = self.get_visible_map()
54 for pos in dijkstra_map:
55 if visible_map[pos] != '.':
57 neighbors = dijkstra_map.get_neighbors(tuple(pos))
58 for direction in neighbors:
59 yx = neighbors[direction]
60 if yx is not None and dijkstra_map[yx] < dijkstra_map[pos] - 1:
61 dijkstra_map[pos] = dijkstra_map[yx] + 1
63 neighbors = dijkstra_map.get_neighbors(tuple(self.position))
65 target_direction = None
66 for direction in sorted(neighbors.keys()):
67 yx = neighbors[direction]
69 n_new = dijkstra_map[yx]
72 target_direction = direction
74 self.set_task('MOVE', (target_direction,))
76 def decide_task(self):
77 visible_things = self.get_visible_things()
79 for t in visible_things:
80 if t.type_ == 'human':
83 if target is not None:
85 self.move_towards_target(target)
91 def set_task(self, task_name, args=()):
92 task_class = self.world.game.tasks[task_name]
93 self.task = task_class(self, args)
94 self.task.check() # will throw GameError if necessary
96 def proceed(self, is_AI=True):
97 """Further the thing in its tasks, decrease its health.
99 First, ensures an empty map, decrements .health and kills
100 thing if crossing zero (removes from self.world.things for AI
101 thing, or unsets self.world.player_is_alive for player thing);
102 then checks that self.task is still possible and aborts if
103 otherwise (for AI things, decides a new task).
105 Then decrements .task.todo; if it thus falls to <= 0, enacts
106 method whose name is 'task_' + self.task.name and sets .task =
107 None. If is_AI, calls .decide_task to decide a self.task.
113 if self is self.world.player:
114 self.world.player_is_alive = False
116 del self.world.things[self.world.things.index(self)]
120 except GameError as e:
122 self._last_task_result = e
127 self.set_task('WAIT')
130 if self.task.todo <= 0:
131 self._last_task_result = self.task.do()
133 if is_AI and self.task is None:
137 self.set_task('WAIT')
139 def get_stencil(self):
140 if self._stencil is not None:
142 self._stencil = self.world.map_.get_fov_map(self.position)
145 def get_visible_map(self):
146 stencil = self.get_stencil()
147 m = self.world.map_.new_from_shape(' ')
149 if stencil[pos] == '.':
150 m[pos] = self.world.map_[pos]
153 def get_visible_things(self):
154 stencil = self.get_stencil()
156 for thing in self.world.things:
157 if (not thing.in_inventory) and stencil[thing.position] == '.':
158 visible_things += [thing]
159 return visible_things
161 def get_pickable_items(self):
163 for t in [t for t in self.get_visible_things() if
164 isinstance(t, ThingItem) and
165 (t.position == self.position or
167 self.world.map_.get_neighbors(self.position).values())]:
168 pickable_ids += [t.id_]
173 class ThingHuman(ThingAnimate):
179 class ThingMonster(ThingAnimate):