1 from plomrogue.tasks import Task_WAIT, Task_MOVE
2 from plomrogue.errors import ArgError
3 from plomrogue.commands import (cmd_GEN_WORLD, cmd_GET_GAMESTATE, cmd_MAP,
4 cmd_MAP, cmd_THING_TYPE, cmd_THING_POS,
5 cmd_TERRAIN_LINE, cmd_PLAYER_ID, cmd_TURN,
6 cmd_SWITCH_PLAYER, cmd_SAVE)
7 from plomrogue.mapping import MapHex
8 from plomrogue.parser import Parser
9 from plomrogue.io import GameIO
10 from plomrogue.misc import quote, stringify_yx
11 from plomrogue.things import Thing, ThingMonster, ThingHuman, ThingItem
17 def __init__(self, game):
22 def get_thing(self, id_, create_unfound=True):
23 for thing in self.things:
27 t = self.game.thing_type(self, id_)
34 class World(WorldBase):
36 def __init__(self, *args, **kwargs):
37 super().__init__(*args, **kwargs)
40 def new_thing_id(self):
41 if len(self.things) == 0:
43 return self.things[-1].id_ + 1
45 def new_map(self, yx):
46 self.map_ = self.game.map_type(yx)
48 def proceed_to_next_player_turn(self):
49 """Run game world turns until player can decide their next step.
51 Iterates through all non-player things, on each step
52 furthering them in their tasks (and letting them decide new
53 ones if they finish). The iteration order is: first all things
54 that come after the player in the world things list, then
55 (after incrementing the world turn) all that come before the
56 player; then the player's .proceed() is run, and if it does
57 not finish his task, the loop starts at the beginning. Once
58 the player's task is finished, the loop breaks.
61 player = self.get_player()
62 player_i = self.things.index(player)
63 for thing in self.things[player_i+1:]:
66 for thing in self.things[:player_i]:
68 player.proceed(is_AI=False)
69 if player.task is None:
73 return self.get_thing(self.player_id)
75 def make_new(self, yx, seed):
79 t = self.game.thing_types[type_](self)
80 t.position = [random.randint(0, yx[0] -1),
81 random.randint(0, yx[1] - 1)]
90 if 0 in pos or (yx[0] - 1) == pos[0] or (yx[1] - 1) == pos[1]:
93 self.map_[pos] = random.choice(('.', '.', '.', '.', 'x'))
95 player = add_thing('human')
96 self.player_id = player.id_
107 def __init__(self, game_file_name):
108 self.io = GameIO(game_file_name, self)
109 self.map_type = MapHex
110 self.tasks = {'WAIT': Task_WAIT, 'MOVE': Task_MOVE}
111 self.commands = {'GEN_WORLD': cmd_GEN_WORLD,
112 'GET_GAMESTATE': cmd_GET_GAMESTATE,
114 'THING_TYPE': cmd_THING_TYPE,
115 'THING_POS': cmd_THING_POS,
116 'TERRAIN_LINE': cmd_TERRAIN_LINE,
117 'PLAYER_ID': cmd_PLAYER_ID,
119 'SWITCH_PLAYER': cmd_SWITCH_PLAYER,
121 self.world_type = World
122 self.world = self.world_type(self)
123 self.thing_type = Thing
124 self.thing_types = {'human': ThingHuman,
125 'monster': ThingMonster,
128 def get_string_options(self, string_option_type):
129 if string_option_type == 'direction':
130 return self.world.map_.get_directions()
131 elif string_option_type == 'thingtype':
132 return list(self.thing_types.keys())
135 def send_gamestate(self, connection_id=None):
136 """Send out game state data relevant to clients."""
138 self.io.send('TURN ' + str(self.world.turn))
139 self.io.send('MAP ' + stringify_yx(self.world.map_.size))
140 visible_map = self.world.get_player().get_visible_map()
141 for y, line in visible_map.lines():
142 self.io.send('VISIBLE_MAP_LINE %5s %s' % (y, quote(line)))
143 visible_things = self.world.get_player().get_visible_things()
144 for thing in visible_things:
145 self.io.send('THING_TYPE %s %s' % (thing.id_, thing.type_))
146 self.io.send('THING_POS %s %s' % (thing.id_,
147 stringify_yx(thing.position)))
148 player = self.world.get_player()
149 self.io.send('PLAYER_POS %s' % (stringify_yx(player.position)))
150 self.io.send('GAME_STATE_COMPLETE')
153 """Send turn finish signal, run game world, send new world data.
155 First sends 'TURN_FINISHED' message, then runs game world
156 until new player input is needed, then sends game state.
158 self.io.send('TURN_FINISHED ' + str(self.world.turn))
159 self.world.proceed_to_next_player_turn()
160 msg = str(self.world.get_player()._last_task_result)
161 self.io.send('LAST_PLAYER_TASK_RESULT ' + quote(msg))
162 self.send_gamestate()
164 def get_command(self, command_name):
166 def partial_with_attrs(f, *args, **kwargs):
167 from functools import partial
168 p = partial(f, *args, **kwargs)
169 p.__dict__.update(f.__dict__)
172 def cmd_TASK_colon(task_name, game, *args):
173 game.world.get_player().set_task(task_name, args)
176 def cmd_SET_TASK_colon(task_name, game, thing_id, todo, *args):
177 t = game.world.get_thing(thing_id, False)
179 raise ArgError('No such Thing.')
180 task_class = game.tasks[task_name]
181 t.task = task_class(t, args)
184 def task_prefixed(command_name, task_prefix, task_command,
185 argtypes_prefix=None):
186 if command_name[:len(task_prefix)] == task_prefix:
187 task_name = command_name[len(task_prefix):]
188 if task_name in self.tasks:
189 f = partial_with_attrs(task_command, task_name, self)
190 task = self.tasks[task_name]
192 f.argtypes = argtypes_prefix + ' ' + task.argtypes
194 f.argtypes = task.argtypes
198 command = task_prefixed(command_name, 'TASK:', cmd_TASK_colon)
201 command = task_prefixed(command_name, 'SET_TASK:', cmd_SET_TASK_colon,
202 'int:nonneg int:nonneg ')
205 if command_name in self.commands:
206 f = partial_with_attrs(self.commands[command_name], self)