home · contact · privacy
Refactor, add game file handling, replace TERRAIN with TERRAIN_LINE.
[plomrogue2-experiments] / server_ / game.py
1 class GameError(Exception):
2     pass
3
4
5 def move_pos(direction, pos_yx):
6     if direction == 'UP':
7         pos_yx[0] -= 1
8     elif direction == 'DOWN':
9         pos_yx[0] += 1
10     elif direction == 'RIGHT':
11         pos_yx[1] += 1
12     elif direction == 'LEFT':
13         pos_yx[1] -= 1
14
15
16 class World:
17
18     def __init__(self):
19         self.turn = 0
20         self.map_size = (5, 5)
21         self.map_ = 'xxxxx' +\
22                     'x...x' +\
23                     'x.X.x' +\
24                     'x...x' +\
25                     'xxxxx'
26         self.things = [
27             Thing(self, 'human', [3, 3]),
28             Thing(self, 'monster', [1, 1])
29         ]
30         self.player_i = 0
31         self.player = self.things[self.player_i]
32
33     def proceed_to_next_player_turn(self):
34         """Run game world turns until player can decide their next step.
35
36         Iterates through all non-player things, on each step
37         furthering them in their tasks (and letting them decide new
38         ones if they finish). The iteration order is: first all things
39         that come after the player in the world things list, then
40         (after incrementing the world turn) all that come before the
41         player; then the player's .proceed() is run, and if it does
42         not finish his task, the loop starts at the beginning. Once
43         the player's task is finished, the loop breaks.
44         """
45         while True:
46             for thing in self.things[self.player_i+1:]:
47                 thing.proceed()
48             self.turn += 1
49             for thing in self.things[:self.player_i]:
50                 thing.proceed()
51             self.player.proceed(is_AI=False)
52             if self.player.task is None:
53                 break
54
55 class Task:
56
57     def __init__(self, thing, name, args=(), kwargs={}):
58         self.name = name
59         self.thing = thing
60         self.args = args
61         self.kwargs = kwargs
62         self.todo = 1
63
64     def check(self):
65         if self.name == 'move':
66             if len(self.args) > 0:
67                 direction = self.args[0]
68             else:
69                 direction = self.kwargs['direction']
70             test_pos = self.thing.position[:]
71             move_pos(direction, test_pos)
72             if test_pos[0] < 0 or test_pos[1] < 0 or \
73                test_pos[0] >= self.thing.world.map_size[0] or \
74                test_pos[1] >= self.thing.world.map_size[1]:
75                 raise GameError('would move outside map bounds')
76             pos_i = test_pos[0] * self.thing.world.map_size[1] + test_pos[1]
77             map_tile = self.thing.world.map_[pos_i]
78             if map_tile != '.':
79                 raise GameError('would move into illegal terrain')
80
81
82 class Thing:
83
84     def __init__(self, world, type_, position):
85         self.world = world
86         self.type_ = type_
87         self.position = position
88         self.task = Task(self, 'wait')
89
90     def task_wait(self):
91         pass
92
93     def task_move(self, direction):
94         move_pos(direction, self.position)
95
96     def decide_task(self):
97         if self.position[1] > 1:
98             self.set_task('move', 'LEFT')
99         elif self.position[1] < 3:
100             self.set_task('move', 'RIGHT')
101         else:
102             self.set_task('wait')
103
104     def set_task(self, task, *args, **kwargs):
105         self.task = Task(self, task, args, kwargs)
106         self.task.check()
107
108     def proceed(self, is_AI=True):
109         """Further the thing in its tasks.
110
111         Decrements .task.todo; if it thus falls to <= 0, enacts method whose
112         name is 'task_' + self.task.name and sets .task = None. If is_AI, calls
113         .decide_task to decide a self.task.
114         """
115         self.task.todo -= 1
116         if self.task.todo <= 0:
117             task = getattr(self, 'task_' + self.task.name)
118             task(*self.task.args, **self.task.kwargs)
119             self.task = None
120         if is_AI and self.task is None:
121             self.decide_task()