home · contact · privacy
More refactoring.
[plomrogue2-experiments] / new / plomrogue / things.py
1 from plomrogue.errors import GameError
2
3
4
5 class ThingBase:
6
7     def __init__(self, world, id_, type_='?', position=[0,0]):
8         self.world = world
9         self.id_ = id_
10         self.type_ = type_
11         self.position = position
12
13
14
15 class Thing(ThingBase):
16
17     def __init__(self, *args, **kwargs):
18         super().__init__(*args, **kwargs)
19         self.set_task('WAIT')
20         self._last_task_result = None
21         self._stencil = None
22
23     def move_towards_target(self, target):
24         dijkstra_map = type(self.world.map_)(self.world.map_.size)
25         n_max = 256
26         dijkstra_map.terrain = [n_max for i in range(dijkstra_map.size_i)]
27         dijkstra_map[target] = 0
28         shrunk = True
29         visible_map = self.get_visible_map()
30         while shrunk:
31             shrunk = False
32             for pos in dijkstra_map:
33                 if visible_map[pos] != '.':
34                     continue
35                 neighbors = dijkstra_map.get_neighbors(tuple(pos))
36                 for direction in neighbors:
37                     yx = neighbors[direction]
38                     if yx is not None and dijkstra_map[yx] < dijkstra_map[pos] - 1:
39                         dijkstra_map[pos] = dijkstra_map[yx] + 1
40                         shrunk = True
41         neighbors = dijkstra_map.get_neighbors(tuple(self.position))
42         n = n_max
43         target_direction = None
44         for direction in neighbors:
45             yx = neighbors[direction]
46             if yx is not None:
47                 n_new = dijkstra_map[yx]
48                 if n_new < n:
49                     n = n_new
50                     target_direction = direction
51         if target_direction:
52             self.set_task('MOVE', (target_direction,))
53
54     def decide_task(self):
55         visible_things = self.get_visible_things()
56         target = None
57         for t in visible_things:
58             if t.type_ == 'human':
59                 target = t.position
60                 break
61         if target is not None:
62             try:
63                 self.move_towards_target(target)
64                 return
65             except GameError:
66                 pass
67         self.set_task('WAIT')
68
69     def set_task(self, task_name, args=()):
70         task_class = self.world.game.tasks[task_name]
71         self.task = task_class(self, args)
72         self.task.check()  # will throw GameError if necessary
73
74     def proceed(self, is_AI=True):
75         """Further the thing in its tasks.
76
77         Decrements .task.todo; if it thus falls to <= 0, enacts method
78         whose name is 'task_' + self.task.name and sets .task =
79         None. If is_AI, calls .decide_task to decide a self.task.
80
81         Before doing anything, ensures an empty map visibility stencil
82         and checks that task is still possible, and aborts it
83         otherwise (for AI things, decides a new task).
84
85         """
86         self._stencil = None
87         try:
88             self.task.check()
89         except GameError as e:
90             self.task = None
91             self._last_task_result = e
92             if is_AI:
93                 try:
94                     self.decide_task()
95                 except GameError:
96                     self.set_task('WAIT')
97             return
98         self.task.todo -= 1
99         if self.task.todo <= 0:
100             self._last_task_result = self.task.do()
101             self.task = None
102         if is_AI and self.task is None:
103             try:
104                 self.decide_task()
105             except GameError:
106                 self.set_task('WAIT')
107
108     def get_stencil(self):
109         if self._stencil is not None:
110             return self._stencil
111         self._stencil = self.world.map_.get_fov_map(self.position)
112         return self._stencil
113
114     def get_visible_map(self):
115         stencil = self.get_stencil()
116         m = self.world.map_.new_from_shape(' ')
117         for pos in m:
118             if stencil[pos] == '.':
119                 m[pos] = self.world.map_[pos]
120         return m
121
122     def get_visible_things(self):
123         stencil = self.get_stencil()
124         visible_things = []
125         for thing in self.world.things:
126             if stencil[thing.position] == '.':
127                 visible_things += [thing]
128         return visible_things