diff --git a/squirrelbattle/display/mapdisplay.py b/squirrelbattle/display/mapdisplay.py index 54d9432..c4f29e3 100644 --- a/squirrelbattle/display/mapdisplay.py +++ b/squirrelbattle/display/mapdisplay.py @@ -15,8 +15,15 @@ class MapDisplay(Display): self.pad = self.newpad(m.height, self.pack.tile_width * m.width + 1) def update_pad(self) -> None: - self.addstr(self.pad, 0, 0, self.map.draw_string(self.pack), - self.pack.tile_fg_color, self.pack.tile_bg_color) + for j in range(len(self.map.tiles)): + 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: self.addstr(self.pad, e.y, self.pack.tile_width * e.x, self.pack[e.name.upper()], diff --git a/squirrelbattle/display/texturepack.py b/squirrelbattle/display/texturepack.py index f72cd97..fb56dd5 100644 --- a/squirrelbattle/display/texturepack.py +++ b/squirrelbattle/display/texturepack.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later import curses -from typing import Any +from typing import Any, Union, Tuple class TexturePack: @@ -10,10 +10,11 @@ class TexturePack: name: str tile_width: int - tile_fg_color: int - tile_bg_color: int - entity_fg_color: int - entity_bg_color: int + tile_fg_color: Union[int, Tuple[int, int, int]] + tile_fg_visible_color: Union[int, Tuple[int, int, int]] + tile_bg_color: Union[int, Tuple[int, int, int]] + entity_fg_color: Union[int, Tuple[int, int, int]] + entity_bg_color: Union[int, Tuple[int, int, int]] BODY_SNATCH_POTION: str BOMB: str @@ -54,9 +55,10 @@ class TexturePack: TexturePack.ASCII_PACK = TexturePack( name="ascii", tile_width=1, + tile_fg_visible_color=(1000, 1000, 1000), tile_fg_color=curses.COLOR_WHITE, tile_bg_color=curses.COLOR_BLACK, - entity_fg_color=curses.COLOR_WHITE, + entity_fg_color=(1000, 1000, 1000), entity_bg_color=curses.COLOR_BLACK, BODY_SNATCH_POTION='S', @@ -80,10 +82,11 @@ TexturePack.ASCII_PACK = TexturePack( TexturePack.SQUIRREL_PACK = TexturePack( name="squirrel", tile_width=2, + tile_fg_visible_color=(1000, 1000, 1000), tile_fg_color=curses.COLOR_WHITE, tile_bg_color=curses.COLOR_BLACK, - entity_fg_color=curses.COLOR_WHITE, - entity_bg_color=curses.COLOR_WHITE, + entity_fg_color=(1000, 1000, 1000), + entity_bg_color=(1000, 1000, 1000), BODY_SNATCH_POTION='🔀', BOMB='💣', diff --git a/squirrelbattle/entities/player.py b/squirrelbattle/entities/player.py index 19c8348..6d18884 100644 --- a/squirrelbattle/entities/player.py +++ b/squirrelbattle/entities/player.py @@ -21,7 +21,7 @@ class Player(InventoryHolder, FightingEntity): strength: int = 5, intelligence: int = 1, charisma: int = 1, dexterity: int = 1, constitution: int = 1, level: int = 1, 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: super().__init__(name=name, maxhealth=maxhealth, strength=strength, intelligence=intelligence, charisma=charisma, @@ -32,6 +32,7 @@ class Player(InventoryHolder, FightingEntity): self.inventory = self.translate_inventory(inventory or []) self.paths = dict() self.hazel = hazel + self.vision = vision def move(self, y: int, x: int) -> None: """ @@ -42,6 +43,7 @@ class Player(InventoryHolder, FightingEntity): self.map.currenty = y self.map.currentx = x self.recalculate_paths() + self.map.compute_visibility(self.y, self.x, self.vision) def level_up(self) -> None: """ diff --git a/squirrelbattle/interfaces.py b/squirrelbattle/interfaces.py index 6458df7..89399f5 100644 --- a/squirrelbattle/interfaces.py +++ b/squirrelbattle/interfaces.py @@ -4,7 +4,8 @@ from enum import Enum, auto from math import sqrt 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 .translations import gettext as _ @@ -38,19 +39,25 @@ class Slope(): self.Y = y self.X = x - def compare(self, other: Union[Tuple[int, int], "Slope"]) -> int: - if isinstance(other, Slope): - y, x = other.Y, other.X - else: - y, x = other + def compare(self, other: "Slope") -> int: + y, x = other.Y, other.X 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 - def __eq__(self, other: Union[Tuple[int, int], "Slope"]) -> bool: + def __eq__(self, other: "Slope") -> bool: 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: """ @@ -194,16 +201,16 @@ class Map: if top.X == 1: top_y = x 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 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): top_y += 1 else: ax = x * 2 if self.is_wall(top_y + 1, x + 1, octant, origin): ax += 1 - if top > (top_y * 2 + 1, ax): + if top > Slope(top_y * 2 + 1, ax): top_y += 1 return top_y @@ -212,9 +219,9 @@ class Map: if bottom.Y == 0: bottom_y = 0 else: - bottom_y = ((x * 2 + 1) * bottom.Y + bottom.X) /\ - (bottom.X * 2) - if bottom >= (bottom_y * 2 + 1, x * 2) and\ + bottom_y = ceil(((x * 2 - 1) * bottom.Y + bottom.X) + / (bottom.X * 2)) + if bottom >= Slope(bottom_y * 2 + 1, x * 2) and\ self.is_wall(bottom_y, x, octant, origin) and\ not self.is_wall(bottom_y + 1, x, octant, origin): bottom_y += 1 @@ -223,17 +230,18 @@ class Map: def compute_visibility_octant(self, octant: int, origin: Tuple[int, int], max_range: int, distance: int, top: Slope, 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) bottom_y = self.crop_bottom_visibility(octant, origin, x, bottom) was_opaque = -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 is_opaque = self.is_wall(y, x, octant, origin) is_visible = is_opaque\ - or ((y != top_y or top > (y * 4 - 1, x * 4 - 1)) - and (y != bottom_y or bottom < (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 < Slope(y * 4 + 1, x * 4 - 1))) if is_visible: self.set_visible(y, x, octant, origin) if x == max_range: @@ -242,7 +250,7 @@ class Map: nx, ny = x * 2, y * 2 + 1 if self.is_wall(y + 1, x, octant, origin): nx -= 1 - if top > (ny, nx): + if top > Slope(ny, nx): if y == bottom_y: bottom = Slope(ny, nx) break @@ -257,8 +265,9 @@ class Map: nx, ny = x * 2, y * 2 + 1 if self.is_wall(y + 1, x + 1, octant, origin): nx += 1 - if bottom >= (ny, nx): + if bottom >= Slope(ny, nx): return + top = Slope(ny, nx) was_opaque = is_opaque if was_opaque != 0: break @@ -268,31 +277,33 @@ class Map: origin: Tuple[int, int]) -> Tuple[int, int]: ny, nx = origin if octant == 0: - return nx + x, ny - y + return ny - y, nx + x elif octant == 1: - return nx + y, ny - x + return ny - x, nx + y elif octant == 2: - return nx - y, ny - x + return ny - x, nx - y elif octant == 3: - return nx - x, ny - y + return ny - y, nx - x elif octant == 4: - return nx - x, ny + y + return ny + y, nx - x elif octant == 5: - return nx - y, ny + x + return ny + x, nx - y elif octant == 6: - return nx + y, ny + x + return ny + x, nx + y elif octant == 7: - return nx + x, ny + y + return ny + y, nx + x def is_wall(self, y: int, x: int, octant: int, origin: Tuple[int, int]) -> bool: 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, origin: Tuple[int, int]) -> None: y, x = self.translate_coord(y, x, octant, origin) - self.visibility[y][x] = True + if 0 <= y < len(self.tiles) and 0 <= x < len(self.tiles[0]): + self.visibility[y][x] = True def tick(self) -> None: """