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_on_dijkstra_map(self, targets):
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 for target in targets:
55 dijkstra_map[target] = 0
57 visible_map = self.get_visible_map()
60 for pos in dijkstra_map:
61 if visible_map[pos] != '.':
63 neighbors = dijkstra_map.get_neighbors(tuple(pos))
64 for direction in neighbors:
65 yx = neighbors[direction]
66 if yx is not None and dijkstra_map[yx] < dijkstra_map[pos] - 1:
67 dijkstra_map[pos] = dijkstra_map[yx] + 1
69 neighbors = dijkstra_map.get_neighbors(tuple(self.position))
71 target_direction = None
72 for direction in sorted(neighbors.keys()):
73 yx = neighbors[direction]
75 n_new = dijkstra_map[yx]
78 target_direction = direction
79 return 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 target_dir = self.move_on_dijkstra_map([target])
91 if target_dir is not None:
92 self.set_task('MOVE', (target_dir,))
98 def hunt_food_satisfaction(self):
99 for id_ in self.inventory:
100 t = self.world.get_thing(id_)
101 if t.type_ == 'food':
102 self.set_task('EAT', (id_,))
104 for id_ in self.get_pickable_items():
105 t = self.world.get_thing(id_)
106 if t.type_ == 'food':
107 self.set_task('PICKUP', (id_,))
109 visible_things = self.get_visible_things()
111 for t in visible_things:
112 if t.type_ == 'food':
113 food_targets += [t.position]
114 target_dir = self.move_on_dijkstra_map(food_targets)
117 self.set_task('MOVE', (target_dir,))
123 def decide_task(self):
124 #if not self.hunt_player():
125 if not self.hunt_food_satisfaction():
126 self.set_task('WAIT')
128 def set_task(self, task_name, args=()):
129 task_class = self.world.game.tasks[task_name]
130 self.task = task_class(self, args)
131 self.task.check() # will throw GameError if necessary
133 def proceed(self, is_AI=True):
134 """Further the thing in its tasks, decrease its health.
136 First, ensures an empty map, decrements .health and kills
137 thing if crossing zero (removes from self.world.things for AI
138 thing, or unsets self.world.player_is_alive for player thing);
139 then checks that self.task is still possible and aborts if
140 otherwise (for AI things, decides a new task).
142 Then decrements .task.todo; if it thus falls to <= 0, enacts
143 method whose name is 'task_' + self.task.name and sets .task =
144 None. If is_AI, calls .decide_task to decide a self.task.
150 if self is self.world.player:
151 self.world.player_is_alive = False
153 del self.world.things[self.world.things.index(self)]
157 except GameError as e:
159 self._last_task_result = e
164 self.set_task('WAIT')
167 if self.task.todo <= 0:
168 self._last_task_result = self.task.do()
170 if is_AI and self.task is None:
174 self.set_task('WAIT')
176 def get_stencil(self):
177 if self._stencil is not None:
179 self._stencil = self.world.map_.get_fov_map(self.position)
182 def get_visible_map(self):
183 stencil = self.get_stencil()
184 m = self.world.map_.new_from_shape(' ')
186 if stencil[pos] == '.':
187 m[pos] = self.world.map_[pos]
190 def get_visible_things(self):
191 stencil = self.get_stencil()
193 for thing in self.world.things:
194 if (not thing.in_inventory) and stencil[thing.position] == '.':
195 visible_things += [thing]
196 return visible_things
198 def get_pickable_items(self):
200 for t in [t for t in self.get_visible_things() if
201 isinstance(t, ThingItem) and
202 (t.position == self.position or
204 self.world.map_.get_neighbors(self.position).values())]:
205 pickable_ids += [t.id_]
210 class ThingHuman(ThingAnimate):
216 class ThingMonster(ThingAnimate):