Working visibility and displaying it, still need to hide things that aren't visible

This commit is contained in:
Nicolas Margulies 2020-12-18 17:04:45 +01:00
parent 62ce2b5c71
commit 86628fdea6
4 changed files with 64 additions and 41 deletions

View File

@ -15,8 +15,15 @@ class MapDisplay(Display):
self.pad = self.newpad(m.height, self.pack.tile_width * m.width + 1) self.pad = self.newpad(m.height, self.pack.tile_width * m.width + 1)
def update_pad(self) -> None: def update_pad(self) -> None:
self.addstr(self.pad, 0, 0, self.map.draw_string(self.pack), for j in range(len(self.map.tiles)):
self.pack.tile_fg_color, self.pack.tile_bg_color) for i in range(len(self.map.tiles[j])):
color = self.pack.tile_fg_visible_color if \
self.map.visibility[j][i] else self.pack.tile_fg_color
self.addstr(self.pad, j, self.pack.tile_width * i,
self.map.tiles[j][i].char(self.pack),
color, self.pack.tile_bg_color)
# self.addstr(self.pad, 0, 0, self.map.draw_string(self.pack),
# self.pack.tile_fg_color, self.pack.tile_bg_color)
for e in self.map.entities: for e in self.map.entities:
self.addstr(self.pad, e.y, self.pack.tile_width * e.x, self.addstr(self.pad, e.y, self.pack.tile_width * e.x,
self.pack[e.name.upper()], self.pack[e.name.upper()],

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import curses import curses
from typing import Any from typing import Any, Union, Tuple
class TexturePack: class TexturePack:
@ -10,10 +10,11 @@ class TexturePack:
name: str name: str
tile_width: int tile_width: int
tile_fg_color: int tile_fg_color: Union[int, Tuple[int, int, int]]
tile_bg_color: int tile_fg_visible_color: Union[int, Tuple[int, int, int]]
entity_fg_color: int tile_bg_color: Union[int, Tuple[int, int, int]]
entity_bg_color: int entity_fg_color: Union[int, Tuple[int, int, int]]
entity_bg_color: Union[int, Tuple[int, int, int]]
BODY_SNATCH_POTION: str BODY_SNATCH_POTION: str
BOMB: str BOMB: str
@ -54,9 +55,10 @@ class TexturePack:
TexturePack.ASCII_PACK = TexturePack( TexturePack.ASCII_PACK = TexturePack(
name="ascii", name="ascii",
tile_width=1, tile_width=1,
tile_fg_visible_color=(1000, 1000, 1000),
tile_fg_color=curses.COLOR_WHITE, tile_fg_color=curses.COLOR_WHITE,
tile_bg_color=curses.COLOR_BLACK, tile_bg_color=curses.COLOR_BLACK,
entity_fg_color=curses.COLOR_WHITE, entity_fg_color=(1000, 1000, 1000),
entity_bg_color=curses.COLOR_BLACK, entity_bg_color=curses.COLOR_BLACK,
BODY_SNATCH_POTION='S', BODY_SNATCH_POTION='S',
@ -80,10 +82,11 @@ TexturePack.ASCII_PACK = TexturePack(
TexturePack.SQUIRREL_PACK = TexturePack( TexturePack.SQUIRREL_PACK = TexturePack(
name="squirrel", name="squirrel",
tile_width=2, tile_width=2,
tile_fg_visible_color=(1000, 1000, 1000),
tile_fg_color=curses.COLOR_WHITE, tile_fg_color=curses.COLOR_WHITE,
tile_bg_color=curses.COLOR_BLACK, tile_bg_color=curses.COLOR_BLACK,
entity_fg_color=curses.COLOR_WHITE, entity_fg_color=(1000, 1000, 1000),
entity_bg_color=curses.COLOR_WHITE, entity_bg_color=(1000, 1000, 1000),
BODY_SNATCH_POTION='🔀', BODY_SNATCH_POTION='🔀',
BOMB='💣', BOMB='💣',

View File

@ -21,7 +21,7 @@ class Player(InventoryHolder, FightingEntity):
strength: int = 5, intelligence: int = 1, charisma: int = 1, strength: int = 5, intelligence: int = 1, charisma: int = 1,
dexterity: int = 1, constitution: int = 1, level: int = 1, dexterity: int = 1, constitution: int = 1, level: int = 1,
current_xp: int = 0, max_xp: int = 10, inventory: list = None, current_xp: int = 0, max_xp: int = 10, inventory: list = None,
hazel: int = 42, *args, **kwargs) \ hazel: int = 42, vision: int = 5, *args, **kwargs) \
-> None: -> None:
super().__init__(name=name, maxhealth=maxhealth, strength=strength, super().__init__(name=name, maxhealth=maxhealth, strength=strength,
intelligence=intelligence, charisma=charisma, intelligence=intelligence, charisma=charisma,
@ -32,6 +32,7 @@ class Player(InventoryHolder, FightingEntity):
self.inventory = self.translate_inventory(inventory or []) self.inventory = self.translate_inventory(inventory or [])
self.paths = dict() self.paths = dict()
self.hazel = hazel self.hazel = hazel
self.vision = vision
def move(self, y: int, x: int) -> None: def move(self, y: int, x: int) -> None:
""" """
@ -42,6 +43,7 @@ class Player(InventoryHolder, FightingEntity):
self.map.currenty = y self.map.currenty = y
self.map.currentx = x self.map.currentx = x
self.recalculate_paths() self.recalculate_paths()
self.map.compute_visibility(self.y, self.x, self.vision)
def level_up(self) -> None: def level_up(self) -> None:
""" """

View File

@ -4,7 +4,8 @@
from enum import Enum, auto from enum import Enum, auto
from math import sqrt from math import sqrt
from random import choice, randint from random import choice, randint
from typing import List, Optional, Union, Tuple, Any from typing import List, Optional, Tuple, Any
from math import ceil
from .display.texturepack import TexturePack from .display.texturepack import TexturePack
from .translations import gettext as _ from .translations import gettext as _
@ -38,19 +39,25 @@ class Slope():
self.Y = y self.Y = y
self.X = x self.X = x
def compare(self, other: Union[Tuple[int, int], "Slope"]) -> int: def compare(self, other: "Slope") -> int:
if isinstance(other, Slope):
y, x = other.Y, other.X y, x = other.Y, other.X
else:
y, x = other
return self.Y * x - self.X * y return self.Y * x - self.X * y
def __lt__(self, other: Union[Tuple[int, int], "Slope"]) -> bool: def __lt__(self, other: "Slope") -> bool:
return self.compare(other) < 0 return self.compare(other) < 0
def __eq__(self, other: Union[Tuple[int, int], "Slope"]) -> bool: def __eq__(self, other: "Slope") -> bool:
return self.compare(other) == 0 return self.compare(other) == 0
def __gt__(self, other: "Slope") -> bool:
return self.compare(other) > 0
def __le__(self, other: "Slope") -> bool:
return self.compare(other) <= 0
def __ge__(self, other: "Slope") -> bool:
return self.compare(other) >= 0
class Map: class Map:
""" """
@ -194,16 +201,16 @@ class Map:
if top.X == 1: if top.X == 1:
top_y = x top_y = x
else: else:
top_y = ((x * 2 - 1) * top.Y + top.X) / (top.X * 2) top_y = ceil(((x * 2 - 1) * top.Y + top.X) / (top.X * 2))
if self.is_wall(top_y, x, octant, origin): if self.is_wall(top_y, x, octant, origin):
if top >= (top_y * 2 + 1, x * 2) and not\ if top >= Slope(top_y * 2 + 1, x * 2) and not\
self.is_wall(top_y + 1, x, octant, origin): self.is_wall(top_y + 1, x, octant, origin):
top_y += 1 top_y += 1
else: else:
ax = x * 2 ax = x * 2
if self.is_wall(top_y + 1, x + 1, octant, origin): if self.is_wall(top_y + 1, x + 1, octant, origin):
ax += 1 ax += 1
if top > (top_y * 2 + 1, ax): if top > Slope(top_y * 2 + 1, ax):
top_y += 1 top_y += 1
return top_y return top_y
@ -212,9 +219,9 @@ class Map:
if bottom.Y == 0: if bottom.Y == 0:
bottom_y = 0 bottom_y = 0
else: else:
bottom_y = ((x * 2 + 1) * bottom.Y + bottom.X) /\ bottom_y = ceil(((x * 2 - 1) * bottom.Y + bottom.X)
(bottom.X * 2) / (bottom.X * 2))
if bottom >= (bottom_y * 2 + 1, x * 2) and\ if bottom >= Slope(bottom_y * 2 + 1, x * 2) and\
self.is_wall(bottom_y, x, octant, origin) and\ self.is_wall(bottom_y, x, octant, origin) and\
not self.is_wall(bottom_y + 1, x, octant, origin): not self.is_wall(bottom_y + 1, x, octant, origin):
bottom_y += 1 bottom_y += 1
@ -223,17 +230,18 @@ class Map:
def compute_visibility_octant(self, octant: int, origin: Tuple[int, int], def compute_visibility_octant(self, octant: int, origin: Tuple[int, int],
max_range: int, distance: int, top: Slope, max_range: int, distance: int, top: Slope,
bottom: Slope) -> None: bottom: Slope) -> None:
for x in range(distance, max_range): for x in range(distance, max_range + 1):
top_y = self.crop_top_visibility(octant, origin, x, top) top_y = self.crop_top_visibility(octant, origin, x, top)
bottom_y = self.crop_bottom_visibility(octant, origin, x, bottom) bottom_y = self.crop_bottom_visibility(octant, origin, x, bottom)
was_opaque = -1 was_opaque = -1
for y in range(top_y, bottom_y - 1, -1): for y in range(top_y, bottom_y - 1, -1):
if sqrt(x**2 + y**2) > max_range: if x + y > max_range:
continue continue
is_opaque = self.is_wall(y, x, octant, origin) is_opaque = self.is_wall(y, x, octant, origin)
is_visible = is_opaque\ is_visible = is_opaque\
or ((y != top_y or top > (y * 4 - 1, x * 4 - 1)) or ((y != top_y or top > Slope(y * 4 - 1, x * 4 + 1))
and (y != bottom_y or bottom < (y * 4 + 1, x * 4 + 1))) and (y != bottom_y
or bottom < Slope(y * 4 + 1, x * 4 - 1)))
if is_visible: if is_visible:
self.set_visible(y, x, octant, origin) self.set_visible(y, x, octant, origin)
if x == max_range: if x == max_range:
@ -242,7 +250,7 @@ class Map:
nx, ny = x * 2, y * 2 + 1 nx, ny = x * 2, y * 2 + 1
if self.is_wall(y + 1, x, octant, origin): if self.is_wall(y + 1, x, octant, origin):
nx -= 1 nx -= 1
if top > (ny, nx): if top > Slope(ny, nx):
if y == bottom_y: if y == bottom_y:
bottom = Slope(ny, nx) bottom = Slope(ny, nx)
break break
@ -257,8 +265,9 @@ class Map:
nx, ny = x * 2, y * 2 + 1 nx, ny = x * 2, y * 2 + 1
if self.is_wall(y + 1, x + 1, octant, origin): if self.is_wall(y + 1, x + 1, octant, origin):
nx += 1 nx += 1
if bottom >= (ny, nx): if bottom >= Slope(ny, nx):
return return
top = Slope(ny, nx)
was_opaque = is_opaque was_opaque = is_opaque
if was_opaque != 0: if was_opaque != 0:
break break
@ -268,30 +277,32 @@ class Map:
origin: Tuple[int, int]) -> Tuple[int, int]: origin: Tuple[int, int]) -> Tuple[int, int]:
ny, nx = origin ny, nx = origin
if octant == 0: if octant == 0:
return nx + x, ny - y return ny - y, nx + x
elif octant == 1: elif octant == 1:
return nx + y, ny - x return ny - x, nx + y
elif octant == 2: elif octant == 2:
return nx - y, ny - x return ny - x, nx - y
elif octant == 3: elif octant == 3:
return nx - x, ny - y return ny - y, nx - x
elif octant == 4: elif octant == 4:
return nx - x, ny + y return ny + y, nx - x
elif octant == 5: elif octant == 5:
return nx - y, ny + x return ny + x, nx - y
elif octant == 6: elif octant == 6:
return nx + y, ny + x return ny + x, nx + y
elif octant == 7: elif octant == 7:
return nx + x, ny + y return ny + y, nx + x
def is_wall(self, y: int, x: int, octant: int, def is_wall(self, y: int, x: int, octant: int,
origin: Tuple[int, int]) -> bool: origin: Tuple[int, int]) -> bool:
y, x = self.translate_coord(y, x, octant, origin) y, x = self.translate_coord(y, x, octant, origin)
return self.tiles[y][x].is_wall() return 0 <= y < len(self.tiles) and 0 <= x < len(self.tiles[0]) and \
self.tiles[y][x].is_wall()
def set_visible(self, y: int, x: int, octant: int, def set_visible(self, y: int, x: int, octant: int,
origin: Tuple[int, int]) -> None: origin: Tuple[int, int]) -> None:
y, x = self.translate_coord(y, x, octant, origin) y, x = self.translate_coord(y, x, octant, origin)
if 0 <= y < len(self.tiles) and 0 <= x < len(self.tiles[0]):
self.visibility[y][x] = True self.visibility[y][x] = True
def tick(self) -> None: def tick(self) -> None: