7 class GameError(Exception):
11 def move_pos(direction, pos_yx):
14 elif direction == 'DOWN':
16 elif direction == 'RIGHT':
18 elif direction == 'LEFT':
22 class World(game_common.World):
26 self.Thing = Thing # use local Thing class instead of game_common's
29 def proceed_to_next_player_turn(self):
30 """Run game world turns until player can decide their next step.
32 Iterates through all non-player things, on each step
33 furthering them in their tasks (and letting them decide new
34 ones if they finish). The iteration order is: first all things
35 that come after the player in the world things list, then
36 (after incrementing the world turn) all that come before the
37 player; then the player's .proceed() is run, and if it does
38 not finish his task, the loop starts at the beginning. Once
39 the player's task is finished, the loop breaks.
42 player = self.get_player()
43 player_i = self.things.index(player)
44 for thing in self.things[player_i+1:]:
47 for thing in self.things[:player_i]:
49 player.proceed(is_AI=False)
50 if player.task is None:
54 return self.get_thing(self.player_id)
59 def __init__(self, thing, name, args=(), kwargs={}):
67 if self.name == 'move':
68 if len(self.args) > 0:
69 direction = self.args[0]
71 direction = self.kwargs['direction']
72 test_pos = self.thing.position[:]
73 move_pos(direction, test_pos)
74 if test_pos[0] < 0 or test_pos[1] < 0 or \
75 test_pos[0] >= self.thing.world.map_size[0] or \
76 test_pos[1] >= self.thing.world.map_size[1]:
77 raise GameError('would move outside map bounds')
78 pos_i = test_pos[0] * self.thing.world.map_size[1] + test_pos[1]
79 map_tile = self.thing.world.terrain_map[pos_i]
81 raise GameError('would move into illegal terrain')
82 for t in self.thing.world.things:
83 if t.position == test_pos:
84 raise GameError('would move into other thing')
87 class Thing(game_common.Thing):
89 def __init__(self, *args, **kwargs):
90 super().__init__(*args, **kwargs)
91 self.task = Task(self, 'wait')
92 self.last_task_result = None
97 def task_move(self, direction):
98 move_pos(direction, self.position)
101 def decide_task(self):
102 if self.position[1] > 1:
103 self.set_task('move', 'LEFT')
104 elif self.position[1] < 3:
105 self.set_task('move', 'RIGHT')
107 self.set_task('wait')
109 def set_task(self, task_name, *args, **kwargs):
110 self.task = Task(self, task_name, args, kwargs)
113 def proceed(self, is_AI=True):
114 """Further the thing in its tasks.
116 Decrements .task.todo; if it thus falls to <= 0, enacts method whose
117 name is 'task_' + self.task.name and sets .task = None. If is_AI, calls
118 .decide_task to decide a self.task.
120 Before doing anything, checks that task is still possible, and aborts
121 it otherwise (for AI things, decides a new task).
125 except GameError as e:
127 self.last_task_result = e
132 if self.task.todo <= 0:
133 task = getattr(self, 'task_' + self.task.name)
134 self.last_task_result = task(*self.task.args, **self.task.kwargs)
136 if is_AI and self.task is None:
142 def cmd_MOVE(self, direction):
143 """Set player task to 'move' with direction arg, finish player turn."""
144 if direction not in {'UP', 'DOWN', 'RIGHT', 'LEFT'}:
145 raise parser.ArgError('Move argument must be one of: '
146 'UP, DOWN, RIGHT, LEFT')
147 self.world.get_player().set_task('move', direction=direction)
149 cmd_MOVE.argtypes = 'string'
152 """Set player task to 'wait', finish player turn."""
153 self.world.get_player().set_task('wait')
156 def cmd_GET_GAMESTATE(self, connection_id):
157 """Send game state jto caller."""
158 self.send_gamestate(connection_id)
160 def cmd_ECHO(self, msg, connection_id):
161 """Send msg to caller."""
162 self.send(msg, connection_id)
163 cmd_ECHO.argtypes = 'string'
165 def cmd_ALL(self, msg, connection_id):
166 """Send msg to all clients."""
168 cmd_ALL.argtypes = 'string'