From c3fe82f82695223367ed8f6dcecf94e22b6a8d96 Mon Sep 17 00:00:00 2001 From: lxgr-linux Date: Fri, 10 Jul 2026 11:16:42 +0200 Subject: [PATCH 1/4] feat: added pyright config --- pyproject.toml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c671c6b..f924a2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "scrap_engine" authors = [{ name = "lxgr", email = "lxgr@protonmail.com" }] description = "A 2D ascii game engine for the terminal" keywords = ["game", "Ascii"] -version = "1.5.4" +version = "1.5.5" license = { text = "GPL-3.0-only" } readme = "README.md" requires-python = ">=3.12" @@ -21,6 +21,16 @@ Homepage = "https://github.com/lxgr-linux/scrap_engine" Issues = "https://github.com/lxgr-linux/scrap_engine/issue" Repository = "https://github.com/lxgr-linux/scrap_engine.git" +[tool.basedpyright] +reportMissingTypeStubs = false +reportUnknownMemberType = false +reportUnannotatedClassAttribute = false +deprecateTypingAliases = false +reportImplicitStringConcatenation = false +executionEnvironments = [ + { root = "src" }, +] + [tool.ruff] line-length = 88 target-version = "py312" From 56a00e1dfa40199c45e398e084cb43c0c125cd39 Mon Sep 17 00:00:00 2001 From: lxgr-linux Date: Fri, 10 Jul 2026 11:22:12 +0200 Subject: [PATCH 2/4] feat: added ArgProto --- src/scrap_engine/addable/misc/box.py | 7 +++++++ src/scrap_engine/addable/misc/circle.py | 4 ++-- src/scrap_engine/addable/misc/frame.py | 8 +++----- src/scrap_engine/addable/misc/line.py | 2 +- src/scrap_engine/addable/misc/square.py | 6 ++---- src/scrap_engine/addable/misc/text.py | 4 ++-- src/scrap_engine/addable/object.py | 19 +++++++++++++------ 7 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/scrap_engine/addable/misc/box.py b/src/scrap_engine/addable/misc/box.py index fd742be..1d92391 100644 --- a/src/scrap_engine/addable/misc/box.py +++ b/src/scrap_engine/addable/misc/box.py @@ -1,3 +1,5 @@ +from typing import override + from scrap_engine.addable.addable import Addable from scrap_engine.addable.area import HasArea from scrap_engine.addable.object_group import ObjectGroup @@ -16,13 +18,16 @@ def __init__(self, height: int, width: int): self.__width: int = width @property + @override def height(self) -> int: return self.__height @property + @override def width(self) -> int: return self.__width + @override def add(self, _map, x: int, y: int): """ Adds the box to a certain coordinate on a certain map. @@ -34,6 +39,7 @@ def add(self, _map, x: int, y: int): obj.add(self.map, obj.rx + self.x, obj.ry + self.y) self.added = True + @override def add_ob(self, obj: Addable, x: int, y: int): """ Adds an object(group) to a certain coordinate relative to the box. @@ -56,6 +62,7 @@ def set_ob(self, obj: Addable, x: int, y: int): if self.added: obj.set(obj.rx + self.x, obj.ry + self.y) + @override def remove(self): """ Removes the box from the map. diff --git a/src/scrap_engine/addable/misc/circle.py b/src/scrap_engine/addable/misc/circle.py index f84ebf5..556af82 100644 --- a/src/scrap_engine/addable/misc/circle.py +++ b/src/scrap_engine/addable/misc/circle.py @@ -3,7 +3,7 @@ from scrap_engine.addable.state import DEFAULT_STATE, State -from ..object import Object +from ..object import ArgProto, Object from .box import Box @@ -18,7 +18,7 @@ def __init__( radius: int, state: State = DEFAULT_STATE, ob_class: Type[Object] = Object, - ob_args=None, + ob_args: ArgProto = None, ): super().__init__(0, 0) if ob_args is None: diff --git a/src/scrap_engine/addable/misc/frame.py b/src/scrap_engine/addable/misc/frame.py index 8e9dace..a875a59 100644 --- a/src/scrap_engine/addable/misc/frame.py +++ b/src/scrap_engine/addable/misc/frame.py @@ -2,7 +2,7 @@ from scrap_engine.addable.state import DEFAULT_STATE, State -from ..object import Object +from ..object import ArgProto, Object from .box import Box from .square import Square @@ -28,7 +28,7 @@ def __init__( vertical_chars: Optional[list[str]] = None, state: State = DEFAULT_STATE, ob_class: Type[Object] = Object, - ob_args=None, + ob_args: ArgProto = None, ): super().__init__(height, width) if ob_args is None: @@ -88,9 +88,7 @@ def __gen_obs(self): for obj, rx, ry in zip(self.verticals, [0, self.width - 1], [1, 1]): self.add_ob(obj, rx, ry) - def rechar( - self, corner_chars=None, horizontal_chars=None, vertical_chars=None - ): + def rechar(self, corner_chars=None, horizontal_chars=None, vertical_chars=None): """ Rechars the frame. """ diff --git a/src/scrap_engine/addable/misc/line.py b/src/scrap_engine/addable/misc/line.py index 89891e6..c0ccfdf 100644 --- a/src/scrap_engine/addable/misc/line.py +++ b/src/scrap_engine/addable/misc/line.py @@ -22,7 +22,7 @@ def __init__( l_type: LineType = "straight", state: State = DEFAULT_STATE, ob_class: Type[Object] = Object, - ob_args=None, + ob_args: ArgProto = None, ): super().__init__(0, 0) if ob_args is None: diff --git a/src/scrap_engine/addable/misc/square.py b/src/scrap_engine/addable/misc/square.py index cc9ef86..8fbc042 100644 --- a/src/scrap_engine/addable/misc/square.py +++ b/src/scrap_engine/addable/misc/square.py @@ -18,7 +18,7 @@ def __init__( height, state: State = DEFAULT_STATE, ob_class: Type[Object] = Object, - ob_args=None, + ob_args: ArgProto = None, ): super().__init__(height, width) if ob_args is None: @@ -34,9 +34,7 @@ def __create(self): for ry in range(self.height): for rx in range(self.width): self.add_ob( - self.ob_class( - self.char, self.state, arg_proto=self.ob_args - ), + self.ob_class(self.char, self.state, arg_proto=self.ob_args), rx, ry, ) diff --git a/src/scrap_engine/addable/misc/text.py b/src/scrap_engine/addable/misc/text.py index 9e9e25b..f1c380e 100644 --- a/src/scrap_engine/addable/misc/text.py +++ b/src/scrap_engine/addable/misc/text.py @@ -3,7 +3,7 @@ from scrap_engine.addable.area import HasArea from scrap_engine.addable.state import DEFAULT_STATE, State -from ..object import Object +from ..object import ArgProto, Object from ..object_group import ObjectGroup T = TypeVar("T", bound=Object) @@ -21,7 +21,7 @@ def __init__( state: State = DEFAULT_STATE, esccode="", ob_class: type[T] = Object, - ob_args=None, + ob_args: ArgProto = None, ignore="", ): super().__init__([], state) diff --git a/src/scrap_engine/addable/object.py b/src/scrap_engine/addable/object.py index 3b76f70..86f151b 100644 --- a/src/scrap_engine/addable/object.py +++ b/src/scrap_engine/addable/object.py @@ -1,16 +1,22 @@ +from typing import Any, Optional, override + from ..error import CoordinateError from ..map.map import Map from .addable import Addable from .area import HasArea from .state import DEFAULT_STATE, State +type ArgProto = Optional[dict[str, Any]] # pyright: ignore[reportExplicitAny] + class Object(HasArea, Addable): """ An object, containing a character, that can be added to a map. """ - def __init__(self, char: str, state: State = DEFAULT_STATE, arg_proto=None): + def __init__( + self, char: str, state: State = DEFAULT_STATE, arg_proto: ArgProto = None + ): if arg_proto is None: arg_proto = {} super().__init__(state) @@ -74,10 +80,12 @@ def redraw(self): return 0 @property + @override def height(self) -> int: return 1 @property + @override def width(self) -> int: return 1 @@ -91,9 +99,7 @@ def __backup_setter(self): ].backup = self.backup else: self.map.map[self.y][self.x] = self.backup - del self.map.obmap[self.y][self.x][ - self.map.obmap[self.y][self.x].index(self) - ] + del self.map.obmap[self.y][self.x][self.map.obmap[self.y][self.x].index(self)] def action(self, ob): """ @@ -101,7 +107,7 @@ def action(self, ob): """ return - def bump(self, ob, x, y, side=False): + def bump(self, ob, x: int, y: int, side=False): """ This is triggered, when this object is tried to be set onto another solid object. Or it hits the side of the map, in which case `side == True`. @@ -118,7 +124,7 @@ def pull_ob(self): """ return - def rechar(self, char): + def rechar(self, char: str): """ Changes the objects character. """ @@ -129,6 +135,7 @@ def rechar(self, char): self.redraw() return 0 + @override def remove(self): """ Removes the object from the map. From 75890e68f647c5e4b815aad22cde25853eb975ea Mon Sep 17 00:00:00 2001 From: lxgr-linux Date: Fri, 10 Jul 2026 13:30:39 +0200 Subject: [PATCH 3/4] feat: seperated concerns --- src/scrap_engine/addable/addable.py | 6 +- src/scrap_engine/addable/misc/line.py | 2 +- src/scrap_engine/addable/misc/square.py | 2 +- src/scrap_engine/addable/object.py | 63 ++++++++------------ src/scrap_engine/interfaces/__init__.py | 56 ++++++++++++++++++ src/scrap_engine/map/map.py | 79 +++++++++++++++++++------ src/tests/__init__.py | 3 +- src/tests/stack_test.py | 21 +++++++ 8 files changed, 171 insertions(+), 61 deletions(-) create mode 100644 src/scrap_engine/interfaces/__init__.py diff --git a/src/scrap_engine/addable/addable.py b/src/scrap_engine/addable/addable.py index 5c03eba..0542866 100644 --- a/src/scrap_engine/addable/addable.py +++ b/src/scrap_engine/addable/addable.py @@ -1,6 +1,8 @@ from abc import abstractmethod from typing import Optional, Protocol +from scrap_engine.interfaces import IMap + from ..map.map import Map from .state import DEFAULT_STATE, State @@ -17,7 +19,7 @@ class Addable(Protocol): added: bool group: Optional["Addable"] state: State - map: Optional[Map] + map: Optional[IMap] def __init__(self, state: State = DEFAULT_STATE): self.x: int = -1 @@ -28,7 +30,7 @@ def __init__(self, state: State = DEFAULT_STATE): self.added: bool = False self.group: Optional[Addable] = None self.state: State = state - self.map: Optional[Map] = None + self.map: Optional[IMap] = None def set_state(self, state: State): self.state = state diff --git a/src/scrap_engine/addable/misc/line.py b/src/scrap_engine/addable/misc/line.py index c0ccfdf..c03f660 100644 --- a/src/scrap_engine/addable/misc/line.py +++ b/src/scrap_engine/addable/misc/line.py @@ -3,7 +3,7 @@ from scrap_engine.addable.state import DEFAULT_STATE, State -from ..object import Object +from ..object import ArgProto, Object from .box import Box LineType = Literal["straight", "crippled"] diff --git a/src/scrap_engine/addable/misc/square.py b/src/scrap_engine/addable/misc/square.py index 8fbc042..91147b5 100644 --- a/src/scrap_engine/addable/misc/square.py +++ b/src/scrap_engine/addable/misc/square.py @@ -2,7 +2,7 @@ from scrap_engine.addable.state import DEFAULT_STATE, State -from ..object import Object +from ..object import ArgProto, Object from .box import Box diff --git a/src/scrap_engine/addable/object.py b/src/scrap_engine/addable/object.py index 86f151b..51d38a3 100644 --- a/src/scrap_engine/addable/object.py +++ b/src/scrap_engine/addable/object.py @@ -1,7 +1,8 @@ from typing import Any, Optional, override +from scrap_engine.interfaces import IMap, IObject + from ..error import CoordinateError -from ..map.map import Map from .addable import Addable from .area import HasArea from .state import DEFAULT_STATE, State @@ -22,22 +23,19 @@ def __init__( super().__init__(state) self.char: str = char self.arg_proto = arg_proto - self.backup = None + self.backup: str = "" - def add(self, _map: Map, x: int, y: int): + def add(self, _map: IMap, x: int, y: int): """ Adds the object to a certain coordinate on a certain map. """ if not 0 <= x < _map.width or not 0 <= y < _map.height: raise CoordinateError(self, _map, x, y) - if len(lis := _map.obmap[y][x]) != 0 and lis[-1].state == "solid": + if _map.check_collision(x, y): return 1 - self.backup = _map.map[y][x] self.x = x self.y = y - _map.map[y][x] = self.char - _map.obmap[y][x].append(self) - _map.obs.append(self) + self.backup = _map.add_object_to_pos(self, x, y) self.map = _map self.added = True return 0 @@ -46,6 +44,7 @@ def set(self, x: int, y: int): """ Sets the object to a certain coordinate. """ + assert self.map if not self.added: return 1 elif not (0 <= x < self.map.width and 0 <= y < self.map.height): @@ -54,19 +53,15 @@ def set(self, x: int, y: int): elif self.x > self.map.width - 1 or self.y > self.map.height - 1: self.pull_ob() return 1 - for obj in self.map.obmap[y][x]: - if obj.state == "solid": - self.bump(obj, x - self.x, y - self.y) - return 1 - self.__backup_setter() - self.map.obmap[y][x].append(self) - self.backup = self.map.map[y][x] + for obj in self.map.get_collision_obs(x, y, "solid"): + self.bump(obj, x - self.x, y - self.y) + return 1 + self.map.remove_ob_from_pos(self) + self.backup = self.map.set_object_to_pos(self, x, y) self.x = x self.y = y - self.map.map[y][x] = self.char - for obj in self.map.obmap[y][x]: - if obj.state == "float": - obj.action(self) + for obj in self.map.get_collision_obs(x, y, "float"): + obj.action(self) return 0 def redraw(self): @@ -75,8 +70,9 @@ def redraw(self): """ if not self.added: return 1 - self.backup = self.map.map[self.y][self.x] - self.map.map[self.y][self.x] = self.char + assert self.map + self.backup = self.map.get_char(self.x, self.y) + self.map.set_char(self.char, self.x, self.y) return 0 @property @@ -89,19 +85,7 @@ def height(self) -> int: def width(self) -> int: return 1 - def __backup_setter(self): - if ( - len(self.map.obmap[self.y][self.x]) - > self.map.obmap[self.y][self.x].index(self) + 1 - ): - self.map.obmap[self.y][self.x][ - self.map.obmap[self.y][self.x].index(self) + 1 - ].backup = self.backup - else: - self.map.map[self.y][self.x] = self.backup - del self.map.obmap[self.y][self.x][self.map.obmap[self.y][self.x].index(self)] - - def action(self, ob): + def action(self, ob: IObject): """ This is triggered when another object is set over this one. """ @@ -131,10 +115,15 @@ def rechar(self, char: str): self.char = char if not self.added: return 1 - self.map.map[self.y][self.x] = self.backup + assert self.map + self.map.set_char(self.backup, self.x, self.y) self.redraw() return 0 + @override + def __repr__(self) -> str: + return f"Object[{self.char}]" + @override def remove(self): """ @@ -142,7 +131,7 @@ def remove(self): """ if not self.added: return 1 + assert self.map self.added = False - self.__backup_setter() - del self.map.obs[self.map.obs.index(self)] + self.map.remove_ob(self) return 0 diff --git a/src/scrap_engine/interfaces/__init__.py b/src/scrap_engine/interfaces/__init__.py new file mode 100644 index 0000000..b9e9964 --- /dev/null +++ b/src/scrap_engine/interfaces/__init__.py @@ -0,0 +1,56 @@ +from typing import Literal, Protocol + +from scrap_engine.addable.state import State + + +class IObject(Protocol): + x: int + y: int + state: State + char: str + backup: str + + def redraw(self) -> Literal[0, 1]: ... + + def action(self, ob: "IObject"): ... + + +class IMap(Protocol): + height: int + width: int + + def show(self, init: bool = False): ... + + def add_object_to_pos( + self, + ob: IObject, + x: int, + y: int, + ) -> str: ... + + def set_object_to_pos(self, ob: IObject, x: int, y: int) -> str: ... + + def get_collision_obs(self, x: int, y: int, state: State) -> list[IObject]: ... + + def remove_ob_from_pos(self, ob: IObject): ... + + def get_char(self, x: int, y: int) -> str: ... + + def set_char(self, char: str, x: int, y: int): ... + + def remove_ob(self, ob: IObject): ... + + def check_collision(self, x: int, y: int) -> bool: ... + + def blur_in( + self, + blurmap: "IMap", + esccode: str = "\033[37m", + ): ... + + def resize( + self, + height: int, + width: int, + background: str = "#", + ): ... diff --git a/src/scrap_engine/map/map.py b/src/scrap_engine/map/map.py index 518a42d..7f74b9c 100644 --- a/src/scrap_engine/map/map.py +++ b/src/scrap_engine/map/map.py @@ -1,4 +1,8 @@ import functools +from typing import Callable + +from scrap_engine.addable.state import State +from scrap_engine.interfaces import IObject from ..consts import MAXCACHE_FRAME, MAXCACHE_LINE, screen_height, screen_width @@ -10,23 +14,60 @@ class Map: def __init__( self, - height=screen_height - 1, - width=screen_width, - background="#", - dynfps=True, + height: int = screen_height - 1, + width: int = screen_width, + background: str = "#", + dynfps: bool = True, ): - self.height = height - self.width = width - self.dynfps = dynfps - self.background = background - self.map = [ + self.height: int = height + self.width: int = width + self.dynfps: bool = dynfps + self.background: str = background + self.map: list[list[str]] = [ [self.background for _ in range(width)] for _ in range(height) ] - self.obmap = [[[] for _ in range(width)] for _ in range(height)] - self.obs = [] - self.out_old = "" + self.obmap: list[list[list[IObject]]] = [ + [[] for _ in range(width)] for _ in range(height) + ] + self.obs: list[IObject] = [] + self.out_old: str = "" + + def remove_ob_from_pos(self, ob: IObject): + if len(self.obmap[ob.y][ob.x]) > self.obmap[ob.y][ob.x].index(ob) + 1: + self.obmap[ob.y][ob.x][ + self.obmap[ob.y][ob.x].index(ob) + 1 + ].backup = ob.backup + else: + self.map[ob.y][ob.x] = ob.backup + del self.obmap[ob.y][ob.x][self.obmap[ob.y][ob.x].index(ob)] + + def get_char(self, x: int, y: int) -> str: + return self.map[y][x] + + def set_char(self, char: str, x: int, y: int): + self.map[y][x] = char - def blur_in(self, blurmap, esccode="\033[37m"): + def remove_ob(self, ob: IObject): + self.remove_ob_from_pos(ob) + del self.obs[self.obs.index(ob)] + + def check_collision(self, x: int, y: int) -> bool: + return len(lis := self.obmap[y][x]) != 0 and lis[-1].state == "solid" + + def add_object_to_pos(self, ob: IObject, x: int, y: int) -> str: + self.obs.append(ob) + return self.set_object_to_pos(ob, x, y) + + def get_collision_obs(self, x: int, y: int, state: State) -> list[IObject]: + return [obj for obj in self.obmap[y][x] if obj.state == state] + + def set_object_to_pos(self, ob: IObject, x: int, y: int) -> str: + backup = self.map[y][x] + self.map[y][x] = ob.char + self.obmap[y][x].append(ob) + return backup + + def blur_in(self, blurmap, esccode: str = "\033[37m"): """ Sets another maps content as its background. """ @@ -55,7 +96,9 @@ def show(self, init=False): @staticmethod @functools.lru_cache(MAXCACHE_FRAME) - def __show_map(show_line, _map): + def __show_map( + show_line: Callable[[tuple[str]], str], _map: tuple[tuple[str]] + ) -> str: out = "\033[H" for arr in _map: out += show_line(arr) @@ -63,20 +106,18 @@ def __show_map(show_line, _map): @staticmethod @functools.lru_cache(MAXCACHE_LINE) - def __show_line(arr): + def __show_line(arr: tuple[str]) -> str: out_line = "" for char in arr: out_line += char return out_line - def resize(self, height, width, background="#"): + def resize(self, height: int, width: int, background: str = "#"): """ Resizes the map to a certain size. """ self.background = background - self.map = [ - [self.background for _ in range(width)] for _ in range(height) - ] + self.map = [[self.background for _ in range(width)] for _ in range(height)] self.obmap = [ [[] for _ in range(max(width, self.width))] for _ in range(max(height, self.height)) diff --git a/src/tests/__init__.py b/src/tests/__init__.py index 7990c43..697672b 100644 --- a/src/tests/__init__.py +++ b/src/tests/__init__.py @@ -1,11 +1,12 @@ from .add_text_test import TextTest from .circle import CircleTest from .circler import CirclerTest -from .stack_test import StackTest +from .stack_test import StackTest, StackTest2 __all__ = [ "TextTest", "CircleTest", "CirclerTest", "StackTest", + "StackTest2", ] diff --git a/src/tests/stack_test.py b/src/tests/stack_test.py index dce37e1..33375f8 100644 --- a/src/tests/stack_test.py +++ b/src/tests/stack_test.py @@ -1,4 +1,5 @@ import unittest + import scrap_engine as se @@ -18,3 +19,23 @@ def test_stack(self): c.set(0, 0) map.show() + + +class StackTest2(unittest.TestCase): + def test_stack(self): + map = se.Map(background=" ", height=5, width=5) + + a = se.Object("a", state="float") + b = se.Object("b", state="float") + c = se.Object("c", state="float") + + a.add(map, 1, 1) + b.add(map, 1, 1) + c.add(map, 1, 1) + + b.set(0, 0) + c.set(0, 0) + + c.set(1, 1) + + map.show() From 2b5ba89cab8b4f0ab059dbe89e57c6a918ff0adf Mon Sep 17 00:00:00 2001 From: lxgr-linux Date: Sun, 12 Jul 2026 17:52:28 +0200 Subject: [PATCH 4/4] feat: More use of interfaces --- src/scrap_engine/addable/addable.py | 3 +-- src/scrap_engine/addable/misc/box.py | 3 ++- src/scrap_engine/addable/misc/circle.py | 6 +++--- src/scrap_engine/addable/misc/line.py | 6 +++--- src/scrap_engine/addable/misc/square.py | 13 ++++++------- src/scrap_engine/addable/object.py | 10 ++++++---- src/scrap_engine/addable/object_group.py | 5 ++++- src/scrap_engine/interfaces/__init__.py | 6 +++--- src/scrap_engine/map/map.py | 21 ++++++++++++++++----- 9 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/scrap_engine/addable/addable.py b/src/scrap_engine/addable/addable.py index 0542866..9e3f6c6 100644 --- a/src/scrap_engine/addable/addable.py +++ b/src/scrap_engine/addable/addable.py @@ -3,7 +3,6 @@ from scrap_engine.interfaces import IMap -from ..map.map import Map from .state import DEFAULT_STATE, State @@ -36,7 +35,7 @@ def set_state(self, state: State): self.state = state @abstractmethod - def add(self, _map: Map, x: int, y: int): ... + def add(self, _map: IMap, x: int, y: int): ... @abstractmethod def remove(self): ... diff --git a/src/scrap_engine/addable/misc/box.py b/src/scrap_engine/addable/misc/box.py index 1d92391..88884fc 100644 --- a/src/scrap_engine/addable/misc/box.py +++ b/src/scrap_engine/addable/misc/box.py @@ -4,6 +4,7 @@ from scrap_engine.addable.area import HasArea from scrap_engine.addable.object_group import ObjectGroup from scrap_engine.addable.state import DEFAULT_STATE +from scrap_engine.interfaces import IMap class Box(ObjectGroup[Addable], HasArea): @@ -28,7 +29,7 @@ def width(self) -> int: return self.__width @override - def add(self, _map, x: int, y: int): + def add(self, _map: IMap, x: int, y: int): """ Adds the box to a certain coordinate on a certain map. """ diff --git a/src/scrap_engine/addable/misc/circle.py b/src/scrap_engine/addable/misc/circle.py index 556af82..98201e4 100644 --- a/src/scrap_engine/addable/misc/circle.py +++ b/src/scrap_engine/addable/misc/circle.py @@ -29,7 +29,7 @@ def __init__( self.state = state self.__gen(radius) - def __gen(self, radius): + def __gen(self, radius: float): self.radius = radius for i in range(-(int(radius) + 1), int(radius + 1) + 1): for j in range(-(int(radius) + 1), int(radius + 1) + 1): @@ -42,7 +42,7 @@ def __gen(self, radius): j, ) - def rechar(self, char): + def rechar(self, char: str): """ Changes the chars the circle is filled with. """ @@ -50,7 +50,7 @@ def rechar(self, char): for obj in self.obs: obj.rechar(char) - def resize(self, radius): + def resize(self, radius: float): """ Resizes the circle. """ diff --git a/src/scrap_engine/addable/misc/line.py b/src/scrap_engine/addable/misc/line.py index c03f660..8e39519 100644 --- a/src/scrap_engine/addable/misc/line.py +++ b/src/scrap_engine/addable/misc/line.py @@ -27,10 +27,10 @@ def __init__( super().__init__(0, 0) if ob_args is None: ob_args = {} - self.char = char + self.char: str = char self.ob_class = ob_class self.ob_args = ob_args - self.state = state + self.state: State = state self.type: LineType = l_type self.__gen(cx, cy) @@ -70,7 +70,7 @@ def __gen(self, cx: int, cy: int): j, ) - def rechar(self, char): + def rechar(self, char: str): """ Changes the chars the line is made from. """ diff --git a/src/scrap_engine/addable/misc/square.py b/src/scrap_engine/addable/misc/square.py index 91147b5..3b8b4bc 100644 --- a/src/scrap_engine/addable/misc/square.py +++ b/src/scrap_engine/addable/misc/square.py @@ -13,9 +13,9 @@ class Square(Box): def __init__( self, - char, - width, - height, + char: str, + width: int, + height: int, state: State = DEFAULT_STATE, ob_class: Type[Object] = Object, ob_args: ArgProto = None, @@ -23,8 +23,7 @@ def __init__( super().__init__(height, width) if ob_args is None: ob_args = {} - if state is not None: - self.state = state + self.state = state self.ob_class = ob_class self.char = char self.ob_args = ob_args @@ -39,7 +38,7 @@ def __create(self): ry, ) - def rechar(self, char): + def rechar(self, char: str): """ Changes the chars the Square is filled with. """ @@ -47,7 +46,7 @@ def rechar(self, char): for obj in self.obs: obj.rechar(char) - def resize(self, width, height): + def resize(self, width: int, height: int): """ Resizes the rectangle to a certain size. """ diff --git a/src/scrap_engine/addable/object.py b/src/scrap_engine/addable/object.py index 51d38a3..fcfb8b5 100644 --- a/src/scrap_engine/addable/object.py +++ b/src/scrap_engine/addable/object.py @@ -1,4 +1,4 @@ -from typing import Any, Optional, override +from typing import Any, Optional, Self, override from scrap_engine.interfaces import IMap, IObject @@ -10,7 +10,7 @@ type ArgProto = Optional[dict[str, Any]] # pyright: ignore[reportExplicitAny] -class Object(HasArea, Addable): +class Object(HasArea, Addable, IObject): """ An object, containing a character, that can be added to a map. """ @@ -64,6 +64,7 @@ def set(self, x: int, y: int): obj.action(self) return 0 + @override def redraw(self): """ Redraws the object on the map. @@ -85,13 +86,14 @@ def height(self) -> int: def width(self) -> int: return 1 - def action(self, ob: IObject): + @override + def action(self, ob: Self): """ This is triggered when another object is set over this one. """ return - def bump(self, ob, x: int, y: int, side=False): + def bump(self, ob: Self, x: int, y: int, side=False): """ This is triggered, when this object is tried to be set onto another solid object. Or it hits the side of the map, in which case `side == True`. diff --git a/src/scrap_engine/addable/object_group.py b/src/scrap_engine/addable/object_group.py index 9b1a61c..5ab9537 100644 --- a/src/scrap_engine/addable/object_group.py +++ b/src/scrap_engine/addable/object_group.py @@ -1,4 +1,4 @@ -from typing import Generic, TypeVar +from typing import Generic, TypeVar, override from .addable import Addable from .state import DEFAULT_STATE, State @@ -54,6 +54,7 @@ def move(self, x: int = 0, y: int = 0): for obj in self.obs: obj.add(self.map, obj.x + x, obj.y + y) + @override def remove(self): """ Removes all objects from their maps. @@ -61,6 +62,7 @@ def remove(self): for obj in self.obs: obj.remove() + @override def set(self, x: int, y: int): """ Sets the group to a certain coordinate. @@ -70,6 +72,7 @@ def set(self, x: int, y: int): self.x = x self.y = y + @override def set_state(self, state: State): """ Sets all objects states to a certain state. diff --git a/src/scrap_engine/interfaces/__init__.py b/src/scrap_engine/interfaces/__init__.py index b9e9964..cabaefe 100644 --- a/src/scrap_engine/interfaces/__init__.py +++ b/src/scrap_engine/interfaces/__init__.py @@ -1,4 +1,4 @@ -from typing import Literal, Protocol +from typing import Literal, Protocol, Self from scrap_engine.addable.state import State @@ -12,7 +12,7 @@ class IObject(Protocol): def redraw(self) -> Literal[0, 1]: ... - def action(self, ob: "IObject"): ... + def action(self, ob: Self): ... class IMap(Protocol): @@ -44,7 +44,7 @@ def check_collision(self, x: int, y: int) -> bool: ... def blur_in( self, - blurmap: "IMap", + blurmap: Self, esccode: str = "\033[37m", ): ... diff --git a/src/scrap_engine/map/map.py b/src/scrap_engine/map/map.py index 7f74b9c..c6e492a 100644 --- a/src/scrap_engine/map/map.py +++ b/src/scrap_engine/map/map.py @@ -1,13 +1,13 @@ import functools -from typing import Callable +from typing import Callable, override from scrap_engine.addable.state import State -from scrap_engine.interfaces import IObject +from scrap_engine.interfaces import IMap, IObject from ..consts import MAXCACHE_FRAME, MAXCACHE_LINE, screen_height, screen_width -class Map: +class Map(IMap): """ The map, objects can be added to. """ @@ -32,6 +32,7 @@ def __init__( self.obs: list[IObject] = [] self.out_old: str = "" + @override def remove_ob_from_pos(self, ob: IObject): if len(self.obmap[ob.y][ob.x]) > self.obmap[ob.y][ob.x].index(ob) + 1: self.obmap[ob.y][ob.x][ @@ -41,33 +42,41 @@ def remove_ob_from_pos(self, ob: IObject): self.map[ob.y][ob.x] = ob.backup del self.obmap[ob.y][ob.x][self.obmap[ob.y][ob.x].index(ob)] + @override def get_char(self, x: int, y: int) -> str: return self.map[y][x] + @override def set_char(self, char: str, x: int, y: int): self.map[y][x] = char + @override def remove_ob(self, ob: IObject): self.remove_ob_from_pos(ob) del self.obs[self.obs.index(ob)] + @override def check_collision(self, x: int, y: int) -> bool: return len(lis := self.obmap[y][x]) != 0 and lis[-1].state == "solid" + @override def add_object_to_pos(self, ob: IObject, x: int, y: int) -> str: self.obs.append(ob) return self.set_object_to_pos(ob, x, y) + @override def get_collision_obs(self, x: int, y: int, state: State) -> list[IObject]: return [obj for obj in self.obmap[y][x] if obj.state == state] + @override def set_object_to_pos(self, ob: IObject, x: int, y: int) -> str: backup = self.map[y][x] self.map[y][x] = ob.char self.obmap[y][x].append(ob) return backup - def blur_in(self, blurmap, esccode: str = "\033[37m"): + @override + def blur_in(self, blurmap: "Map", esccode: str = "\033[37m"): """ Sets another maps content as its background. """ @@ -84,7 +93,8 @@ def blur_in(self, blurmap, esccode: str = "\033[37m"): for obj in self.obs: obj.redraw() - def show(self, init=False): + @override + def show(self, init: bool = False): """ Prints the maps content. """ @@ -112,6 +122,7 @@ def __show_line(arr: tuple[str]) -> str: out_line += char return out_line + @override def resize(self, height: int, width: int, background: str = "#"): """ Resizes the map to a certain size.