diff --git a/questhelper/map/map_generator.py b/questhelper/map/map_generator.py index 6ef4929..958c8bf 100644 --- a/questhelper/map/map_generator.py +++ b/questhelper/map/map_generator.py @@ -2,7 +2,7 @@ import random from typing import List import map.quest_map -from map.quest_map import QuestMap, MapEncounter, EncounterType +from map.quest_map import QuestMap, MapEncounter, EncounterType, QuestPath as QP def generate_encounter_inaccessible() -> MapEncounter: @@ -21,6 +21,10 @@ def generate_encounter_town(): def generate_map() -> QuestMap: quest_map = QuestMap() + + # Generate encounters + + # TODO: Use sample as if drawing from a deck encounters_rows = [] for r in range(11): row: List[MapEncounter] = [] @@ -39,4 +43,21 @@ def generate_map() -> QuestMap: encounters_rows.append(row) quest_map.encounters = encounters_rows + + # Generate paths + diagonals_deck = [QP.NO_PATH] * 8 + [QP.FORWARD_LEFT] * 5 + [QP.FORWARD_RIGHT] * 5 + random_paths_it = iter(random.sample(diagonals_deck, len(diagonals_deck))) + path_rows = [] + for r in range(11 - 1): + row: List[QP] + if r == 0: + row = [QP.FORWARD, QP.NO_PATH, QP.FORWARD, QP.NO_PATH, QP.FORWARD] + elif r == 9: + row = [QP.NO_PATH, QP.FORWARD_RIGHT, QP.FORWARD, QP.FORWARD_LEFT, QP.NO_PATH] + else: + row = [QP.FORWARD, next(random_paths_it), QP.FORWARD, next(random_paths_it), QP.FORWARD] + path_rows.append(row) + + quest_map.paths = path_rows + return quest_map diff --git a/questhelper/map/map_renderer.py b/questhelper/map/map_renderer.py index a14b79c..6365823 100644 --- a/questhelper/map/map_renderer.py +++ b/questhelper/map/map_renderer.py @@ -1,8 +1,10 @@ -from map.quest_map import MapEncounter, QuestMap, EncounterType +import dataclasses + +from map.quest_map import MapEncounter, QuestMap, EncounterType, QuestPath from typing import List, Dict, Optional -_ICONS = { +_ENCOUNTER_ICONS = { EncounterType.BATTLE_REGULAR: 'noun_Battle_3647629_cropped.png', EncounterType.BATTLE_ELITE: 'noun_Shield_3806325_cropped.png', EncounterType.BATTLE_BOSS: 'noun_dragon_3820621_cropped.png', @@ -18,9 +20,39 @@ _ICONS = { } -def render_map(quest_map: QuestMap) -> List[Dict]: - rendered_encounters = [] +_PATH_ICONS = { + QuestPath.FORWARD: 'arrow_down.png', + QuestPath.FORWARD_LEFT: 'arrow_down_left.png', + QuestPath.FORWARD_RIGHT: 'arrow_down_right.png', +} + +@dataclasses.dataclass(frozen=True) +class RenderedElement: + description: str + src: str + x: int + y: int + w: int + h: int + + +class RenderedEncounter(RenderedElement): + pass + + +class RenderedPath(RenderedElement): + pass + + +@dataclasses.dataclass(frozen=True) +class RenderedMap: + encounters: List[RenderedEncounter] + paths: List[RenderedPath] + + +def render_map(quest_map: QuestMap) -> RenderedMap: + rendered_encounters = [] row: List[MapEncounter] for r, row in enumerate(quest_map.encounters): for c, encounter in enumerate(row): @@ -28,23 +60,62 @@ def render_map(quest_map: QuestMap) -> List[Dict]: if rendered_encounter is not None: rendered_encounters.append(rendered_encounter) - return rendered_encounters + rendered_paths = [] + row: List[QuestPath] + for r, row in enumerate(quest_map.paths): + for c, path in enumerate(row): + rendered_path = _render_path(r, c, path) + if rendered_path is not None: + rendered_paths.append(rendered_path) + + return RenderedMap(rendered_encounters, rendered_paths) -def _render_encounter(r: int, c: int, encounter: MapEncounter) -> Optional[Dict]: +_ENCOUNTER_W = 40 +_ENCOUNTER_H = 40 +_ARROW_W = 40 +_ARROW_H = 20 +_PADDING_W = 10 +_PADDING_V = 5 +_ENCOUNTER_COLUMN_W = _ENCOUNTER_W + _PADDING_W +_PATH_COLUMN_W = _ARROW_W + _PADDING_W +_COLUMN_W = _ENCOUNTER_COLUMN_W + _PATH_COLUMN_W +_ROW_H = _ENCOUNTER_H + _PADDING_V + _ARROW_H + _PADDING_V + + +def _render_encounter(r: int, c: int, encounter: MapEncounter) -> Optional[RenderedEncounter]: if encounter.type == EncounterType.INACCESSIBLE: return None - icon = f'map/{_ICONS[encounter.type]}' - x = 120 * c - y = 100 * r - w = 40 - h = 40 - return { - 'description': encounter.description, - 'src': icon, - 'x': x, - 'y': y, - 'w': w, - 'h': h, - } + icon = f'map/{_ENCOUNTER_ICONS[encounter.type]}' + x = _COLUMN_W * c + y = _ROW_H * r + w = _ENCOUNTER_W + h = _ENCOUNTER_H + return RenderedEncounter( + description=encounter.description, + src=icon, + x=x, + y=y, + w=w, + h=h + ) + + +def _render_path(r: int, c: int, path: QuestPath) -> Optional[RenderedPath]: + if path == QuestPath.NO_PATH: + return None + + icon = f'map/{_PATH_ICONS[path]}' + x = _ENCOUNTER_COLUMN_W * ((c + 1) // 2) + _PATH_COLUMN_W * (c // 2) + y = (_ENCOUNTER_H + _PADDING_V) + _ROW_H * r + w = _ARROW_W + h = _ARROW_H + return RenderedEncounter( + description=path.description, + src=icon, + x=x, + y=y, + w=w, + h=h + ) diff --git a/questhelper/map/quest_map.py b/questhelper/map/quest_map.py index 0587903..2a0cf8b 100644 --- a/questhelper/map/quest_map.py +++ b/questhelper/map/quest_map.py @@ -46,13 +46,17 @@ class QuestPath(enum.Enum): FORWARD_LEFT = 'forward_left' FORWARD_RIGHT = 'forward_right' + @property + def description(self): + return str(self) + @dataclasses.dataclass class MapEncounter: type: EncounterType @property - def description(self): + def description(self) -> str: return str(self.type) @@ -63,5 +67,6 @@ class QuestMap: # Inaccessible encounters can be None (like in last line). self.encounters: List[List[MapEncounter]] = [] - # List of rows of diagonal paths, each row has 2 paths. - self.diagonals: List[List[QuestPath]] = [] + # List of rows of straight and diagonal paths, each row has 5 paths: + # 3 on the columns and 2 between them, sorted from left to right. + self.paths: List[List[QuestPath]] = [] diff --git a/questhelper/map/static/map/arrow_down.png b/questhelper/map/static/map/arrow_down.png new file mode 100644 index 0000000..a6836b4 Binary files /dev/null and b/questhelper/map/static/map/arrow_down.png differ diff --git a/questhelper/map/static/map/arrow_down_left.png b/questhelper/map/static/map/arrow_down_left.png new file mode 100644 index 0000000..654b47e Binary files /dev/null and b/questhelper/map/static/map/arrow_down_left.png differ diff --git a/questhelper/map/static/map/arrow_down_right.png b/questhelper/map/static/map/arrow_down_right.png new file mode 100644 index 0000000..1474c15 Binary files /dev/null and b/questhelper/map/static/map/arrow_down_right.png differ diff --git a/questhelper/map/templates/map/index.html b/questhelper/map/templates/map/index.html index 70ac730..3ccbb0f 100644 --- a/questhelper/map/templates/map/index.html +++ b/questhelper/map/templates/map/index.html @@ -4,7 +4,15 @@