from plomrogue.parser import ArgError, Parser
from plomrogue.commands import cmd_PLAYER_ID, cmd_THING_HEALTH
from plomrogue.game import Game, WorldBase
-from plomrogue.mapping import MapHex, YX
+from plomrogue.mapping import Map, MapGeometryHex, YX
from plomrogue.io import PlomSocket
from plomrogue.things import ThingBase
import types
import queue
-class ClientMap(MapHex):
+class ClientMap(Map):
def y_cut(self, map_lines, center_y, view_height):
map_height = len(map_lines)
else:
for i in range(len(map_lines)):
map_lines[i] = '0' + map_lines[i]
- self.y_cut(map_lines, center.y, size.y)
+ self.y_cut(map_lines, center[1].y, size.y)
map_width = self.size.x * 2 + 1
- self.x_cut(map_lines, center.x * 2, size.x, map_width)
+ self.x_cut(map_lines, center[1].x * 2, size.x, map_width)
return map_lines
def cmd_THING_POS(game, i, yx):
t = game.world.get_thing(i)
- t.position = yx
+ t.position = YX(0,0), yx
cmd_THING_POS.argtypes = 'int:nonneg yx_tuple:nonneg'
def __init__(self):
self.parser = Parser(self)
self.world = World(self)
+ self.map_geometry = MapGeometryHex()
self.thing_type = ThingBase
self.commands = {'LAST_PLAYER_TASK_RESULT': cmd_LAST_PLAYER_TASK_RESULT,
'TURN_FINISHED': cmd_TURN_FINISHED,
def log(self, msg):
"""Prefix msg plus newline to self.log_text."""
self.log_text = msg + '\n' + self.log_text
- with open('log', 'w') as f:
- f.write(self.log_text)
self.tui.to_update['log'] = True
def symbol_for_type(self, type_):
def get_text_lines(self):
lines = []
pos_i = self.tui.game.world.map_.\
- get_position_index(self.tui.examiner_position)
+ get_position_index(self.tui.examiner_position[1])
terrain = self.tui.game.world.map_.terrain[pos_i]
lines = [terrain]
for t in self.tui.game.world.things_at_pos(self.tui.examiner_position):
if t.id_ in self.tui.game.world.player_inventory:
continue
pos_i = self.tui.game.world.map_.\
- get_position_index(t.position)
+ get_position_index(t.position[1])
symbol = self.tui.game.symbol_for_type(t.type_)
if terrain_as_list[pos_i][0] in {'f', '@', 'm'}:
old_symbol = terrain_as_list[pos_i][0]
terrain_as_list[pos_i] = symbol
if self.tui.examiner_mode:
pos_i = self.tui.game.world.map_.\
- get_position_index(self.tui.examiner_position)
+ get_position_index(self.tui.examiner_position[1])
terrain_as_list[pos_i] = (terrain_as_list[pos_i][0], '?')
return terrain_as_list
def move_examiner(direction):
start_pos = self.examiner_position
- new_examine_pos = self.game.world.map_.move(start_pos, direction)
- if new_examine_pos:
+ new_examine_pos = self.game.map_geometry.move(start_pos, direction,
+ self.game.world.map_.size)
+ if new_examine_pos[0] == (0,0):
self.examiner_position = new_examine_pos
self.to_update['map'] = True
cmd_SEED.argtypes = 'int:nonneg'
def cmd_MAP_SIZE(game, size):
- game.world.map_size = size
+ game.map_size = size
cmd_MAP_SIZE.argtypes = 'yx_tuple:pos'
def cmd_MAP(game, map_pos):
with open(save_file_name, 'w') as f:
write(f, 'TURN %s' % game.world.turn)
write(f, 'SEED %s' % game.world.rand.prngod_seed)
- write(f, 'MAP_SIZE %s' % (game.world.map_size,))
+ write(f, 'MAP_SIZE %s' % (game.map_size,))
for map_pos in game.world.maps:
write(f, 'MAP %s' % (map_pos,))
for map_pos in game.world.maps:
cmd_GET_PICKABLE_ITEMS, cmd_MAP_SIZE,
cmd_TERRAIN_LINE, cmd_PLAYER_ID,
cmd_TURN, cmd_SWITCH_PLAYER, cmd_SAVE)
-from plomrogue.mapping import MapHex, YX
+from plomrogue.mapping import MapGeometryHex, Map, YX
from plomrogue.parser import Parser
from plomrogue.io import GameIO
from plomrogue.misc import quote
self.player_id = 0
self.player_is_alive = True
self.maps = {}
- self.map_size = YX(1,1)
self.rand = PRNGod(0)
@property
def get_map(self, map_pos, create_unfound=True):
if not (map_pos in self.maps and
- self.maps[map_pos].size == self.map_size):
+ self.maps[map_pos].size == self.game.map_size):
if create_unfound:
- self.maps[map_pos] = self.game.map_type(self.map_size)
+ self.maps[map_pos] = Map(self.game.map_size)
for pos in self.maps[map_pos]:
- self.maps[map_pos][pos] = '~'
+ self.maps[map_pos][pos] = '.'
else:
return None
return self.maps[map_pos]
self.rand.seed(seed)
self.turn = 0
self.maps = {}
- self.map_size = yx
+ self.game.map_size = yx
map_ = self.get_map(YX(0,0))
for pos in map_:
- map_[pos] = self.rand.choice(('.', '.', '.', '.', 'x'))
+ map_[pos] = self.rand.choice(('.', '.', '.', '~', 'x'))
player = add_thing_at_random('human')
self.player_id = player.id_
add_thing_at_random('monster')
def __init__(self, game_file_name):
self.io = GameIO(game_file_name, self)
- self.map_type = MapHex
+ self.map_size = None
+ self.map_geometry = MapGeometryHex()
self.tasks = {'WAIT': Task_WAIT,
'MOVE': Task_MOVE,
'PICKUP': Task_PICKUP,
def get_string_options(self, string_option_type):
if string_option_type == 'direction':
- return self.map_type().get_directions()
+ return self.map_geometry.get_directions()
elif string_option_type == 'thingtype':
return list(self.thing_types.keys())
return None
"""Send out game state data relevant to clients."""
def send_thing(offset, thing):
- offset_pos = (thing.position[1] - offset)
+ offset_pos = self.map_geometry.pos_in_projection(thing.position,
+ offset,
+ self.map_size)
self.io.send('THING_TYPE %s %s' % (thing.id_, thing.type_))
self.io.send('THING_POS %s %s' % (thing.id_, offset_pos))
class Map:
- def __init__(self, size=YX(0, 0)):
+ def __init__(self, size=YX(0, 0), init_char = '?'):
self.size = size
- self.terrain = '?'*self.size_i
+ self.terrain = init_char*self.size_i
def __getitem__(self, yx):
return self.terrain[self.get_position_index(yx)]
for y in range(self.size.y):
yield (y, self.terrain[y * width:(y + 1) * width])
- def get_fov_map(self, yx):
- return self.fov_map_type(self, yx)
+
+
+class MapGeometry():
def get_directions(self):
directions = []
directions += [name[5:]]
return directions
- def get_neighbors(self, pos):
+ def get_neighbors(self, pos, map_size):
neighbors = {}
if not hasattr(self, 'neighbors_to'):
self.neighbors_to = {}
- if pos in self.neighbors_to:
- return self.neighbors_to[pos]
+ if not map_size in self.neighbors_to:
+ self.neighbors_to[map_size] = {}
+ if pos in self.neighbors_to[map_size]:
+ return self.neighbors_to[map_size][pos]
for direction in self.get_directions():
- neighbors[direction] = None
- neighbor_pos = self.move(pos, direction)
- if neighbor_pos:
- neighbors[direction] = neighbor_pos
- self.neighbors_to[pos] = neighbors
+ neighbors[direction] = self.move(pos, direction, map_size)
+ self.neighbors_to[map_size][pos] = neighbors
return neighbors
- def new_from_shape(self, init_char):
- import copy
- new_map = copy.deepcopy(self)
- for pos in new_map:
- new_map[pos] = init_char
- return new_map
+ def pos_in_projection(self, pos, offset, maps_size):
+ pos_y = pos[1].y + (maps_size.y * pos[0].y) - offset.y
+ pos_x = pos[1].x + (maps_size.x * pos[0].x) - offset.x
+ return YX(pos_y, pos_x)
+
+ def absolutize_coordinate(self, map_size, big_yx, little_yx):
+
+ def adapt_axis(axis):
+ maps_crossed = little_yx[axis] // map_size[axis]
+ new_big = big_yx[axis] + maps_crossed
+ new_little = little_yx[axis] % map_size[axis]
+ return new_big, new_little
- def move(self, start_pos, direction):
+ new_big_y, new_little_y = adapt_axis(0)
+ new_big_x, new_little_x = adapt_axis(1)
+ return YX(new_big_y, new_big_x), YX(new_little_y, new_little_x)
+
+ def move(self, start_pos, direction, map_size):
mover = getattr(self, 'move_' + direction)
- new_pos = mover(start_pos)
- if new_pos.y < 0 or new_pos.x < 0 or \
- new_pos.y >= self.size.y or new_pos.x >= self.size.x:
- return None
- return new_pos
+ big_yx, little_yx = start_pos
+ unadapted_target = mover(little_yx)
+ return self.absolutize_coordinate(map_size, big_yx, unadapted_target)
-class MapWithLeftRightMoves(Map):
+class MapGeometryWithLeftRightMoves(MapGeometry):
def move_LEFT(self, start_pos):
return YX(start_pos.y, start_pos.x - 1)
-class MapSquare(MapWithLeftRightMoves):
+class MapGeometrySquare(MapGeometryWithLeftRightMoves):
def move_UP(self, start_pos):
return YX(start_pos.y - 1, start_pos.x)
-class MapHex(MapWithLeftRightMoves):
+class MapGeometryHex(MapGeometryWithLeftRightMoves):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
-class FovMap:
+class FovMap(Map):
- def __init__(self, source_map, yx):
+ def __init__(self, source_map, center):
self.source_map = source_map
self.size = self.source_map.size
self.fov_radius = (self.size.y / 2) - 0.5
self.terrain = '?' * self.size_i
- self[yx] = '.'
+ self[center] = '.'
self.shadow_cones = []
- self.circle_out(yx, self.shadow_process_hex)
+ self.circle_out(center, self.shadow_process_hex)
def shadow_process_hex(self, yx, distance_to_center, dir_i, dir_progress):
# Possible optimization: If no shadow_cones yet and self[yx] == '.',
def basic_circle_out_move(self, pos, direction):
"""Move position pos into direction. Return whether still in map."""
- mover = getattr(self, 'move_' + direction)
+ mover = getattr(self.geometry, 'move_' + direction)
pos = mover(pos)
if pos.y < 0 or pos.x < 0 or \
pos.y >= self.size.y or pos.x >= self.size.x:
-class FovMapHex(FovMap, MapHex):
+class FovMapHex(FovMap):
circle_out_directions = ('DOWNLEFT', 'LEFT', 'UPLEFT',
'UPRIGHT', 'RIGHT', 'DOWNRIGHT')
+ def __init__(self, *args, **kwargs):
+ self.geometry = MapGeometryHex()
+ super().__init__(*args, **kwargs)
+
def circle_out_move(self, yx, direction):
return self.basic_circle_out_move(yx, direction)
-class FovMapSquare(FovMap, MapSquare):
+class FovMapSquare(FovMap):
circle_out_directions = (('DOWN', 'LEFT'), ('LEFT', 'UP'),
('UP', 'RIGHT'), ('RIGHT', 'DOWN'))
+ def __init__(self, *args, **kwargs):
+ self.geometry = MapGeometrySquare()
+ super().__init__(*args, **kwargs)
+
def circle_out_move(self, yx, direction):
self.basic_circle_out_move(yx, direction[0])
return self.basic_circle_out_move(yx, direction[1])
+
class Task_MOVE(Task):
argtypes = 'string:direction'
+ def get_move_target(self):
+ return self.thing.world.game.map_geometry.move(self.thing.position,
+ self.args[0],
+ self.thing.world.game.map_size)
+
def check(self):
- test_pos = (YX(0,0),
- self.thing.world.maps[YX(0,0)].
- move(self.thing.position[1], self.args[0]))
- if test_pos == (YX(0,0), None):
- raise GameError('would move outside map bounds')
+ test_pos = self.get_move_target()
if self.thing.world.maps[test_pos[0]][test_pos[1]] != '.':
raise GameError('%s would move into illegal terrain' % self.thing.id_)
for t in self.thing.world.things_at_pos(test_pos):
raise GameError('%s would move into other thing' % self.thing.id_)
def do(self):
- self.thing.position = YX(0,0), self.thing.world.maps[YX(0,0)].\
- move(self.thing.position[1], self.args[0])
+ self.thing.position = self.get_move_target()
from plomrogue.errors import GameError
-from plomrogue.mapping import YX
+from plomrogue.mapping import YX, Map, FovMapHex
edge_up = self.position[1].y - self._radius
edge_down = self.position[1].y + self._radius
if edge_left < 0:
- self.world.get_map(self.position[0] - YX(1,-1))
- self.world.get_map(self.position[0] - YX(0,-1))
- self.world.get_map(self.position[0] - YX(-1,-1))
- if edge_right >= self.world.map_size.x:
+ self.world.get_map(self.position[0] + YX(1,-1))
+ self.world.get_map(self.position[0] + YX(0,-1))
+ self.world.get_map(self.position[0] + YX(-1,-1))
+ if edge_right >= self.world.game.map_size.x:
self.world.get_map(self.position[0] + YX(1,1))
self.world.get_map(self.position[0] + YX(0,1))
self.world.get_map(self.position[0] + YX(-1,1))
if edge_up < 0:
- self.world.get_map(self.position[0] - YX(-1,1))
- self.world.get_map(self.position[0] - YX(-1,0))
- self.world.get_map(self.position[0] - YX(-1,-1))
- if edge_down >= self.world.map_size.y:
+ self.world.get_map(self.position[0] + YX(-1,1))
+ self.world.get_map(self.position[0] + YX(-1,0))
+ self.world.get_map(self.position[0] + YX(-1,-1))
+ if edge_down >= self.world.game.map_size.y:
self.world.get_map(self.position[0] + YX(1,1))
self.world.get_map(self.position[0] + YX(1,0))
self.world.get_map(self.position[0] + YX(1,-1))
def move_on_dijkstra_map(self, own_pos, targets):
visible_map = self.get_visible_map()
- dijkstra_map = self.world.game.map_type(visible_map.size)
+ dijkstra_map = Map(visible_map.size)
n_max = 256
dijkstra_map.terrain = [n_max for i in range(dijkstra_map.size_i)]
for target in targets:
for pos in dijkstra_map:
if visible_map[pos] != '.':
continue
- neighbors = dijkstra_map.get_neighbors(pos)
+ neighbors = self.world.game.map_geometry.get_neighbors((YX(0,0), pos),
+ dijkstra_map.size)
for direction in neighbors:
- yx = neighbors[direction]
- if yx is not None and dijkstra_map[yx] < dijkstra_map[pos] - 1:
- dijkstra_map[pos] = dijkstra_map[yx] + 1
+ big_yx, small_yx = neighbors[direction]
+ if big_yx == YX(0,0) and \
+ dijkstra_map[small_yx] < dijkstra_map[pos] - 1:
+ dijkstra_map[pos] = dijkstra_map[small_yx] + 1
shrunk = True
- neighbors = dijkstra_map.get_neighbors(own_pos)
+ neighbors = self.world.game.map_geometry.get_neighbors((YX(0,0), own_pos),
+ dijkstra_map.size)
n = n_max
target_direction = None
for direction in sorted(neighbors.keys()):
- yx = neighbors[direction]
- if yx is not None:
- n_new = dijkstra_map[yx]
+ big_yx, small_yx = neighbors[direction]
+ if big_yx == (0,0):
+ n_new = dijkstra_map[small_yx]
if n_new < n:
n = n_new
target_direction = direction
if self._surroundings_offset is not None:
return self._surroundings_offset
add_line = self.must_fix_indentation()
- offset = YX(self.position[1].y - self._radius - int(add_line),
- self.position[1].x - self._radius)
+ offset = YX(self.position[0].y * self.world.game.map_size.y + self.position[1].y - self._radius - int(add_line),
+ self.position[0].x * self.world.game.map_size.x + self.position[1].x - self._radius)
self._surroundings_offset = offset
return self._surroundings_offset
def get_surrounding_map(self):
if self._surrounding_map is not None:
return self._surrounding_map
-
- def pan_and_scan(size_of_axis, pos, offset):
- big_pos = 0
- small_pos = pos + offset
- if small_pos < 0:
- big_pos = -1
- small_pos = size_of_axis + small_pos
- elif small_pos >= size_of_axis:
- big_pos = 1
- small_pos = small_pos - size_of_axis
- return big_pos, small_pos
-
add_line = self.must_fix_indentation()
- self._surrounding_map = self.world.game.\
- map_type(size=YX(self._radius*2+1+int(add_line),
- self._radius*2+1))
- size = self.world.map_size
+ self._surrounding_map = Map(size=YX(self._radius*2+1+int(add_line),
+ self._radius*2+1))
offset = self.get_surroundings_offset()
for pos in self._surrounding_map:
- big_y, small_y = pan_and_scan(size.y, pos.y, offset.y)
- big_x, small_x = pan_and_scan(size.x, pos.x, offset.x)
- big_yx = YX(big_y, big_x)
- small_yx = YX(small_y, small_x)
+ offset_pos = pos + offset
+ big_yx, small_yx = self.world.game.map_geometry.absolutize_coordinate(self.world.game.map_size, (0,0), offset_pos)
map_ = self.world.get_map(big_yx, False)
if map_ is None:
- map_ = self.world.game.map_type(size=self.world.map_size)
+ map_ = Map(size=self.world.game.map_size)
self._surrounding_map[pos] = map_[small_yx]
return self._surrounding_map
if self._stencil is not None:
return self._stencil
surrounding_map = self.get_surrounding_map()
- m = surrounding_map.new_from_shape(' ')
+ m = Map(surrounding_map.size, ' ')
for pos in surrounding_map:
if surrounding_map[pos] in {'.', '~'}:
m[pos] = '.'
- offset = self.get_surroundings_offset()
- fov_center = self.position[1] - offset
- self._stencil = m.get_fov_map(fov_center)
+ add_line = self.must_fix_indentation()
+ fov_center = YX((add_line + m.size.y) // 2, m.size.x // 2)
+ self._stencil = FovMapHex(m, fov_center)
return self._stencil
def get_visible_map(self):
stencil = self.get_stencil()
- m = self.get_surrounding_map().new_from_shape(' ')
+ m = Map(self.get_surrounding_map().size, ' ')
for pos in m:
if stencil[pos] == '.':
m[pos] = self._surrounding_map[pos]
return m
def get_visible_things(self):
-
- def calc_pos_in_fov(big_pos, small_pos, offset, size_of_axis):
- pos = small_pos - offset
- if big_pos == -1:
- pos = small_pos - size_of_axis - offset
- elif big_pos == 1:
- pos = small_pos + size_of_axis - offset
- return pos
-
stencil = self.get_stencil()
offset = self.get_surroundings_offset()
visible_things = []
- size = self.world.map_size
- fov_size = self.get_surrounding_map().size
for thing in self.world.things:
- big_pos = thing.position[0]
- small_pos = thing.position[1]
- pos_y = calc_pos_in_fov(big_pos.y, small_pos.y, offset.y, size.y)
- pos_x = calc_pos_in_fov(big_pos.x, small_pos.x, offset.x, size.x)
- if pos_y < 0 or pos_x < 0 or\
- pos_y >= fov_size.y or pos_x >= fov_size.x:
+ pos = self.world.game.map_geometry.pos_in_projection(thing.position,
+ offset,
+ self.world.game.map_size)
+ if pos.y < 0 or pos.x < 0 or\
+ pos.y >= stencil.size.y or pos.x >= stencil.size.x:
continue
- if (not thing.in_inventory) and stencil[YX(pos_y, pos_x)] == '.':
+ if (not thing.in_inventory) and stencil[pos] == '.':
visible_things += [thing]
return visible_things
def get_pickable_items(self):
pickable_ids = []
visible_things = self.get_visible_things()
- for t in [t for t in visible_things if
- isinstance(t, ThingItem) and
+ neighbor_fields = self.world.game.map_geometry.get_neighbors(self.position,
+ self.world.game.map_size)
+ for t in [t for t in visible_things
+ if isinstance(t, ThingItem) and
(t.position == self.position or
- t.position[1] in
- self.world.maps[YX(0,0)].get_neighbors(self.position[1]).values())]:
+ t.position in neighbor_fields.values())]:
pickable_ids += [t.id_]
return pickable_ids