From: Christian Heller <c.heller@plomlompom.de>
Date: Sun, 13 Dec 2020 01:23:07 +0000 (+0100)
Subject: Make terrain types configurable.
X-Git-Url: https://plomlompom.com/repos/%22https:/validator.w3.org/static/blog?a=commitdiff_plain;h=a789724e6b1b5eb514f82ac4d7092f7575180c31;p=plomrogue2
Make terrain types configurable.
---
diff --git a/plomrogue/commands.py b/plomrogue/commands.py
index 026f996..df4b7e2 100644
--- a/plomrogue/commands.py
+++ b/plomrogue/commands.py
@@ -1,5 +1,6 @@
from plomrogue.misc import quote
from plomrogue.errors import GameError, ArgError
+from plomrogue.misc import Terrain
@@ -16,11 +17,17 @@ def cmd_THING_TYPES(game, connection_id):
cmd_THING_TYPES.argtypes = ''
def cmd_TERRAINS(game, connection_id):
- for t in game.terrains.keys():
- game.io.send('TERRAIN %s %s' % (quote(t), quote(game.terrains[t])),
- connection_id)
+ for t in game.terrains.values():
+ game.io.send('TERRAIN %s %s' % (quote(t.character),
+ quote(t.description)), connection_id)
cmd_TERRAINS.argtypes = ''
+def cmd_TERRAIN(game, character, description,
+ blocks_light, blocks_sound, blocks_movement):
+ game.terrains[character] = Terrain(character, description, blocks_light,
+ blocks_sound, blocks_movement)
+cmd_TERRAIN.argtypes = 'char string bool bool bool'
+
def cmd_ALL(game, msg, connection_id):
speaker = game.get_player(connection_id)
if not speaker:
@@ -226,6 +233,7 @@ def cmd_MAP(game, geometry, size):
if geometry == 'Hex':
map_geometry_class = MapGeometryHex
game.new_world(map_geometry_class(size))
+ game.terrains = {}
cmd_MAP.argtypes = 'string:map_geometry yx_tuple:pos'
def cmd_MAP_CONTROL_LINE(game, big_yx, y, line):
diff --git a/plomrogue/game.py b/plomrogue/game.py
index e1c92cf..7859814 100755
--- a/plomrogue/game.py
+++ b/plomrogue/game.py
@@ -12,7 +12,7 @@ class GameBase:
def __init__(self):
self.turn = 0
self.things = []
- self.map_geometry = MapGeometrySquare(YX(24, 40))
+ self.map_geometry = MapGeometrySquare(YX(32, 32))
self.commands = {}
def get_thing(self, id_):
@@ -115,6 +115,7 @@ import os
class Game(GameBase):
def __init__(self, save_file, *args, **kwargs):
+ from plomrogue.misc import Terrain
super().__init__(*args, **kwargs)
self.changed = True
self.changed_tiles = []
@@ -137,15 +138,11 @@ class Game(GameBase):
self.last_send_gamestate = datetime.datetime.now() -\
self.send_gamestate_interval
self.terrains = {
- '.': 'floor',
- 'X': 'wall',
- '=': 'window',
- '#': 'bed',
- 'T': 'desk',
- '8': 'cupboard',
- '[': 'glass door',
- 'o': 'sink',
- 'O': 'toilet'
+ '.': Terrain('.', 'floor'),
+ 'X': Terrain('X', 'wall', blocks_light=True, blocks_sound=True,
+ blocks_movement=True),
+ '=': Terrain('=', 'glass', blocks_sound=True, blocks_movement=True),
+ 'T': Terrain('T', 'table', blocks_movement=True),
}
if os.path.exists(self.io.save_file):
if not os.path.isfile(self.io.save_file):
@@ -431,6 +428,28 @@ class Game(GameBase):
self.player_char_i = 0
return self.player_chars[self.player_char_i]
+ def get_foo_blockers(self, foo):
+ foo_blockers = ''
+ for t in self.terrains.values():
+ block_attr = getattr(t, 'blocks_' + foo)
+ if block_attr:
+ foo_blockers += t.character
+ return foo_blockers
+
+ def get_sound_blockers(self):
+ return self.get_foo_blockers('sound')
+
+ def get_light_blockers(self):
+ return self.get_foo_blockers('light')
+
+ def get_movement_blockers(self):
+ return self.get_foo_blockers('movement')
+
+ def get_flatland(self):
+ for t in self.terrains.values:
+ if not t.blocks_movement:
+ return t.character
+
def save(self):
def write(f, msg):
@@ -440,6 +459,12 @@ class Game(GameBase):
write(f, 'TURN %s' % self.turn)
map_geometry_shape = self.get_map_geometry_shape()
write(f, 'MAP %s %s' % (map_geometry_shape, self.map_geometry.size,))
+ for terrain in self.terrains.values():
+ write(f, 'TERRAIN %s %s %s %s %s' % (quote(terrain.character),
+ quote(terrain.description),
+ int(terrain.blocks_light),
+ int(terrain.blocks_sound),
+ int(terrain.blocks_movement)))
for big_yx in [yx for yx in self.maps if self.maps[yx].modified]:
for y, line in self.maps[big_yx].lines():
write(f, 'MAP_LINE %s %5s %s' % (big_yx, y, quote(line)))
diff --git a/plomrogue/mapping.py b/plomrogue/mapping.py
index 2b19f56..e3c071f 100644
--- a/plomrogue/mapping.py
+++ b/plomrogue/mapping.py
@@ -165,7 +165,7 @@ class Map():
def __init__(self, map_geometry):
self.geometry = map_geometry
- self.terrain = '.' * self.size_i
+ self.terrain = '.' * self.size_i # TODO: use Game.get_flatland()?
def __getitem__(self, yx):
return self.terrain[self.get_position_index(yx)]
@@ -210,7 +210,9 @@ class Map():
class SourcedMap(Map):
- def __init__(self, things, source_maps, source_center, radius, get_map):
+ def __init__(self, block_chars, things, source_maps, source_center, radius,
+ get_map):
+ self.block_chars = block_chars
self.radius = radius
example_map = get_map(YX(0, 0))
self.source_geometry = example_map.geometry
@@ -231,7 +233,7 @@ class SourcedMap(Map):
for yx in self: # TODO: iter and source_yxyx expensive, cache earlier?
big_yx, little_yx = self.source_yxyx(yx)
if big_yx in obstacles and little_yx in obstacles[big_yx]:
- self.source_map_segment += 'X'
+ self.source_map_segment += self.block_chars[0]
else:
self.source_map_segment += source_maps[big_yx][little_yx]
@@ -270,7 +272,7 @@ class DijkstraMap(SourcedMap):
while shrunk:
shrunk = False
for i in range(self.size_i):
- if self.source_map_segment[i] in 'X=':
+ if self.source_map_segment[i] in self.block_chars:
continue
neighbors = self.geometry.get_neighbors_i(i)
for direction in [d for d in neighbors if neighbors[d]]:
@@ -310,7 +312,8 @@ class FovMap(SourcedMap):
return self
def throws_shadow(self, yx):
- return self.source_map_segment[self.get_position_index(yx)] == 'X'
+ return self.source_map_segment[self.get_position_index(yx)]\
+ in self.block_chars
def shadow_process(self, yx, distance_to_center, dir_i, dir_progress):
# Possible optimization: If no shadow_cones yet and self[yx] == '.',
@@ -377,8 +380,7 @@ class FovMap(SourcedMap):
return mover(pos)
def circle_out(self, yx, f):
- # Optimization potential: Precalculate movement positions. (How to check
- # circle_in_map then?)
+ # Optimization potential: Precalculate movement positions.
# Optimization potential: Precalculate what tiles are shaded by what tile
# and skip evaluation of already shaded tile. (This only works if tiles
# shading implies they completely lie in existing shades; otherwise we
diff --git a/plomrogue/misc.py b/plomrogue/misc.py
index a3f7298..84b0a8a 100644
--- a/plomrogue/misc.py
+++ b/plomrogue/misc.py
@@ -1,3 +1,15 @@
+class Terrain:
+
+ def __init__(self, character, description, blocks_light=False,
+ blocks_sound=False, blocks_movement=False):
+ self.character = character
+ self.description = description
+ self.blocks_light = blocks_light
+ self.blocks_sound = blocks_sound
+ self.blocks_movement = blocks_movement
+
+
+
def quote(string):
"""Quote & escape string so client interprets it as single token."""
quoted = []
diff --git a/plomrogue/tasks.py b/plomrogue/tasks.py
index 4b63634..f7fb312 100644
--- a/plomrogue/tasks.py
+++ b/plomrogue/tasks.py
@@ -34,10 +34,11 @@ class Task_MOVE(Task):
def check(self):
test_yxyx = self._get_move_target()
+ move_blockers = self.thing.game.get_movement_blockers()
if test_yxyx in [t.position for t in self.thing.game.things
if t.blocking]:
raise PlayError('blocked by other thing')
- elif self.thing.game.maps[test_yxyx[0]][test_yxyx[1]] != '.':
+ elif self.thing.game.maps[test_yxyx[0]][test_yxyx[1]] in move_blockers:
raise PlayError('blocked by impassable tile')
def do(self):
@@ -77,7 +78,7 @@ class Task_FLATTEN_SURROUNDINGS(Task):
self.thing.position).values()):
if not self.thing.game.can_do_tile_with_pw(*yxyx, self.args[0]):
continue
- self.thing.game.maps[yxyx[0]][yxyx[1]] = '.'
+ self.thing.game.maps[yxyx[0]][yxyx[1]] = self.game.get_flatland()
self.thing.game.record_fov_change(yxyx)
diff --git a/plomrogue/things.py b/plomrogue/things.py
index 8885aa0..70d9994 100644
--- a/plomrogue/things.py
+++ b/plomrogue/things.py
@@ -70,7 +70,8 @@ class Thing(ThingBase):
largest_audible_distance = 20
# player's don't block sound (or should they?)
things = [t for t in self.game.things if t.type_ != 'Player']
- dijkstra_map = DijkstraMap(things, self.game.maps, self.position,
+ sound_blockers = self.game.get_sound_blockers()
+ dijkstra_map = DijkstraMap(sound_blockers, things, self.game.maps, self.position,
largest_audible_distance, self.game.get_map)
url_limits = []
for m in re.finditer('https?://[^\s]+', msg):
@@ -182,7 +183,8 @@ class Thing_Bottle(Thing):
# and ThingPlayer.fov_test
fov_map_class = self.game.map_geometry.fov_map_class
fov_radius = 12
- fov = fov_map_class(self.game.things, self.game.maps,
+ light_blockers = self.game.get_light_blockers()
+ fov = fov_map_class(light_blockers, self.game.things, self.game.maps,
self.position, fov_radius, self.game.get_map)
fov.init_terrain()
visible_players = []
@@ -439,7 +441,8 @@ class ThingAnimate(Thing):
def prepare_multiprocessible_fov_stencil(self):
fov_map_class = self.game.map_geometry.fov_map_class
fov_radius = 3 if self.drunk > 0 else 12
- self._fov = fov_map_class(self.game.things, self.game.maps,
+ light_blockers = self.game.get_light_blockers()
+ self._fov = fov_map_class(light_blockers, self.game.things, self.game.maps,
self.position, fov_radius, self.game.get_map)
def multiprocessible_fov_stencil(self):
diff --git a/rogue_chat.py b/rogue_chat.py
index 8187583..d7dd64b 100755
--- a/rogue_chat.py
+++ b/rogue_chat.py
@@ -11,7 +11,7 @@ from plomrogue.commands import (cmd_ALL, cmd_LOGIN, cmd_NICK, cmd_PING, cmd_THIN
cmd_GOD_THING_PROTECTION, cmd_THING_PROTECTION,
cmd_SET_MAP_CONTROL_PASSWORD, cmd_SPAWN_POINT,
cmd_THING_MUSICPLAYER_SETTINGS, cmd_THING_HAT_DESIGN,
- cmd_THING_MUSICPLAYER_PLAYLIST_ITEM,
+ cmd_THING_MUSICPLAYER_PLAYLIST_ITEM, cmd_TERRAIN,
cmd_THING_BOTTLE_EMPTY, cmd_PLAYER_FACE,
cmd_GOD_PLAYER_FACE, cmd_GOD_PLAYER_HAT)
from plomrogue.tasks import (Task_WAIT, Task_MOVE, Task_WRITE, Task_PICK_UP,
@@ -32,6 +32,7 @@ game.register_command(cmd_LOGIN)
game.register_command(cmd_NICK)
game.register_command(cmd_TURN)
game.register_command(cmd_MAP)
+game.register_command(cmd_TERRAIN)
game.register_command(cmd_MAP_LINE)
game.register_command(cmd_MAP_CONTROL_LINE)
game.register_command(cmd_MAP_CONTROL_PW)