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
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_map(self, yx):
41 self.map_ = self.game.map_type(yx)
43 def proceed_to_next_player_turn(self):
44 """Run game world turns until player can decide their next step.
46 Iterates through all non-player things, on each step
47 furthering them in their tasks (and letting them decide new
48 ones if they finish). The iteration order is: first all things
49 that come after the player in the world things list, then
50 (after incrementing the world turn) all that come before the
51 player; then the player's .proceed() is run, and if it does
52 not finish his task, the loop starts at the beginning. Once
53 the player's task is finished, the loop breaks.
56 player = self.get_player()
57 player_i = self.things.index(player)
58 for thing in self.things[player_i+1:]:
61 for thing in self.things[:player_i]:
63 player.proceed(is_AI=False)
64 if player.task is None:
68 return self.get_thing(self.player_id)
70 def make_new(self, yx, seed):
76 if 0 in pos or (yx[0] - 1) == pos[0] or (yx[1] - 1) == pos[1]:
79 self.map_[pos] = random.choice(('.', '.', '.', '.', 'x'))
80 player = self.game.thing_type(self, 0)
81 player.type_ = 'human'
82 player.position = [random.randint(0, yx[0] -1),
83 random.randint(0, yx[1] - 1)]
84 npc = self.game.thing_type(self, 1)
86 npc.position = [random.randint(0, yx[0] -1),
87 random.randint(0, yx[1] -1)]
88 self.things = [player, npc]
95 def __init__(self, game_file_name):
96 self.io = GameIO(game_file_name, self)
97 self.map_type = MapHex
98 self.tasks = {'WAIT': Task_WAIT, 'MOVE': Task_MOVE}
99 self.commands = {'GEN_WORLD': cmd_GEN_WORLD,
100 'GET_GAMESTATE': cmd_GET_GAMESTATE,
102 'THING_TYPE': cmd_THING_TYPE,
103 'THING_POS': cmd_THING_POS,
104 'TERRAIN_LINE': cmd_TERRAIN_LINE,
105 'PLAYER_ID': cmd_PLAYER_ID,
107 'SWITCH_PLAYER': cmd_SWITCH_PLAYER,
109 self.world_type = World
110 self.world = self.world_type(self)
111 self.thing_type = Thing
113 def get_string_options(self, string_option_type):
114 if string_option_type == 'direction':
115 return self.world.map_.get_directions()
118 def send_gamestate(self, connection_id=None):
119 """Send out game state data relevant to clients."""
121 self.io.send('TURN ' + str(self.world.turn))
122 self.io.send('MAP ' + stringify_yx(self.world.map_.size))
123 visible_map = self.world.get_player().get_visible_map()
124 for y, line in visible_map.lines():
125 self.io.send('VISIBLE_MAP_LINE %5s %s' % (y, quote(line)))
126 visible_things = self.world.get_player().get_visible_things()
127 for thing in visible_things:
128 self.io.send('THING_TYPE %s %s' % (thing.id_, thing.type_))
129 self.io.send('THING_POS %s %s' % (thing.id_,
130 stringify_yx(thing.position)))
131 player = self.world.get_player()
132 self.io.send('PLAYER_POS %s' % (stringify_yx(player.position)))
133 self.io.send('GAME_STATE_COMPLETE')
136 """Send turn finish signal, run game world, send new world data.
138 First sends 'TURN_FINISHED' message, then runs game world
139 until new player input is needed, then sends game state.
141 self.io.send('TURN_FINISHED ' + str(self.world.turn))
142 self.world.proceed_to_next_player_turn()
143 msg = str(self.world.get_player()._last_task_result)
144 self.io.send('LAST_PLAYER_TASK_RESULT ' + quote(msg))
145 self.send_gamestate()
147 def get_command(self, command_name):
149 def partial_with_attrs(f, *args, **kwargs):
150 from functools import partial
151 p = partial(f, *args, **kwargs)
152 p.__dict__.update(f.__dict__)
155 def cmd_TASK_colon(task_name, game, *args):
156 game.world.get_player().set_task(task_name, args)
159 def cmd_SET_TASK_colon(task_name, game, thing_id, todo, *args):
160 t = game.world.get_thing(thing_id, False)
162 raise ArgError('No such Thing.')
163 task_class = game.tasks[task_name]
164 t.task = task_class(t, args)
167 def task_prefixed(command_name, task_prefix, task_command,
168 argtypes_prefix=None):
169 if command_name[:len(task_prefix)] == task_prefix:
170 task_name = command_name[len(task_prefix):]
171 if task_name in self.tasks:
172 f = partial_with_attrs(task_command, task_name, self)
173 task = self.tasks[task_name]
175 f.argtypes = argtypes_prefix + ' ' + task.argtypes
177 f.argtypes = task.argtypes
181 command = task_prefixed(command_name, 'TASK:', cmd_TASK_colon)
184 command = task_prefixed(command_name, 'SET_TASK:', cmd_SET_TASK_colon,
185 'int:nonneg int:nonneg ')
188 if command_name in self.commands:
189 f = partial_with_attrs(self.commands[command_name], self)