diff --git a/questhelper/map/map_generator.py b/questhelper/map/map_generator.py
index 35c5907..bf5a275 100644
--- a/questhelper/map/map_generator.py
+++ b/questhelper/map/map_generator.py
@@ -2,7 +2,8 @@ import random
from typing import List
import map.quest_map
-from map.quest_map import QuestMap, MapEncounter, EncounterType as ET, QuestPath as QP
+import map.treasure_hoard_generator
+from map.quest_map import QuestMap, MapEncounter, BattleEncounter, EncounterType as ET, QuestPath as QP
# 27 cards (21 are drawn)
@@ -26,9 +27,10 @@ def generate_encounter_inaccessible() -> MapEncounter:
return MapEncounter(ET.INACCESSIBLE)
-def generate_encounter_battle(battle_type: ET):
+def generate_encounter_battle(battle_type: ET, level: int):
assert battle_type in map.quest_map.ENCOUNTER_TYPES_BATTLE
- return MapEncounter(battle_type)
+ hoard = map.treasure_hoard_generator.generate_hoard(battle_type, level)
+ return BattleEncounter(battle_type, hoard)
def generate_encounter_town(town_type: ET):
@@ -36,7 +38,7 @@ def generate_encounter_town(town_type: ET):
return MapEncounter(town_type)
-def generate_map() -> QuestMap:
+def generate_map(level: int) -> QuestMap:
quest_map = QuestMap()
# Generate encounters
@@ -46,13 +48,13 @@ def generate_map() -> QuestMap:
row: List[MapEncounter] = []
if r == 10:
row.append(generate_encounter_inaccessible())
- row.append(generate_encounter_battle(ET.BATTLE_BOSS))
+ row.append(generate_encounter_battle(ET.BATTLE_BOSS, level))
row.append(generate_encounter_inaccessible())
elif r in (1, 4, 7):
elite_column = random.randrange(4) # 75% chance of elite
for c in range(3):
battle_type = ET.BATTLE_ELITE if c == elite_column else ET.BATTLE_REGULAR
- row.append(generate_encounter_battle(battle_type))
+ row.append(generate_encounter_battle(battle_type, level))
else:
for c in range(3):
town_type = next(town_deck_it)
diff --git a/questhelper/map/map_renderer.py b/questhelper/map/map_renderer.py
index 702e45d..6c6c01b 100644
--- a/questhelper/map/map_renderer.py
+++ b/questhelper/map/map_renderer.py
@@ -37,10 +37,12 @@ class RenderedElement:
h: int
+@dataclasses.dataclass(frozen=True)
class RenderedEncounter(RenderedElement):
pass
+@dataclasses.dataclass(frozen=True)
class RenderedPath(RenderedElement):
pass
diff --git a/questhelper/map/quest_map.py b/questhelper/map/quest_map.py
index 2a0cf8b..fd33025 100644
--- a/questhelper/map/quest_map.py
+++ b/questhelper/map/quest_map.py
@@ -3,6 +3,8 @@ import enum
from typing import List
+from map.treasure_hoard import TreasureHoard
+
class EncounterType(enum.Enum):
INACCESSIBLE = 'inaccessible'
@@ -60,6 +62,15 @@ class MapEncounter:
return str(self.type)
+@dataclasses.dataclass
+class BattleEncounter(MapEncounter):
+ treasure_hoard: TreasureHoard
+
+ @property
+ def description(self) -> str:
+ return f'{self.type} [{self.treasure_hoard.description}]'
+
+
class QuestMap:
def __init__(self):
# List of rows of encounters, each row has 3 encounters.
diff --git a/questhelper/map/templates/map/index.html b/questhelper/map/templates/map/index.html
index 3ccbb0f..0ed830f 100644
--- a/questhelper/map/templates/map/index.html
+++ b/questhelper/map/templates/map/index.html
@@ -1,7 +1,7 @@
{% load static %}
-Map
+Map of {{level_ordinal}} quest
{% for e in map.encounters %}
diff --git a/questhelper/map/treasure_hoard.py b/questhelper/map/treasure_hoard.py
new file mode 100644
index 0000000..c488ffb
--- /dev/null
+++ b/questhelper/map/treasure_hoard.py
@@ -0,0 +1,38 @@
+import dataclasses
+import enum
+
+
+class TreasureType(enum.Enum):
+ GOLD = 'gold'
+ INK = 'ink'
+ COG = 'cog'
+ DEED = 'deed'
+ GEMS = 'bag of gems'
+ ART_OBJECT = 'art object'
+ CONSUMABLE = 'consumable'
+ LIFE = 'life'
+ BLESSING = 'blessing'
+ NOBILITY_TITLE = 'nobility title'
+ RELIC = 'relic'
+
+
+@dataclasses.dataclass(frozen=True)
+class Treasure:
+ amount: int
+ treasure_type: TreasureType
+
+ @property
+ def description(self) -> str:
+ word = str(self.treasure_type.value)
+ word = word.capitalize()
+
+ return f'{self.amount} {word}'
+
+
+@dataclasses.dataclass(frozen=True)
+class TreasureHoard:
+ revealed: Treasure
+
+ @property
+ def description(self) -> str:
+ return f'{self.revealed.description} + ?'
\ No newline at end of file
diff --git a/questhelper/map/treasure_hoard_generator.py b/questhelper/map/treasure_hoard_generator.py
new file mode 100644
index 0000000..c6e6032
--- /dev/null
+++ b/questhelper/map/treasure_hoard_generator.py
@@ -0,0 +1,65 @@
+import random
+from typing import List, Tuple
+
+from map.quest_map import EncounterType
+from map.treasure_hoard import TreasureHoard, Treasure, TreasureType as TT
+
+
+class HoardTable:
+ def __init__(self, input: List[Tuple[int, int, TT]]):
+ self.input = input
+
+ def roll(self) -> Treasure:
+ dice_total = random.randint(1, 6) + random.randint(1, 6)
+ for top_of_band, amount, treasure_type in self.input:
+ if dice_total <= top_of_band:
+ return Treasure(amount, treasure_type)
+
+
+_TABLES = {
+ 1: {
+ EncounterType.BATTLE_REGULAR: HoardTable([
+ (2, 200, TT.GOLD),
+ (4, 2, TT.COG),
+ (5, 1, TT.CONSUMABLE),
+ (6, 1, TT.DEED),
+ (8, 50, TT.GOLD),
+ (9, 1, TT.GEMS),
+ (11, 1, TT.ART_OBJECT),
+ (12, 1, TT.LIFE),
+ ]),
+ EncounterType.BATTLE_ELITE: HoardTable([
+ (2, 300, TT.GOLD),
+ (4, 4, TT.COG),
+ (5, 2, TT.CONSUMABLE),
+ (6, 2, TT.DEED),
+ (8, 100, TT.GOLD),
+ (9, 2, TT.GEMS),
+ (10, 2, TT.ART_OBJECT),
+ (11, 1, TT.NOBILITY_TITLE),
+ (12, 1, TT.LIFE),
+ ]),
+ EncounterType.BATTLE_BOSS: HoardTable([
+ (2, 400, TT.GOLD),
+ (4, 6, TT.COG),
+ (5, 3, TT.CONSUMABLE),
+ (6, 3, TT.DEED),
+ (8, 150, TT.GOLD),
+ (9, 3, TT.GEMS),
+ (11, 1, TT.NOBILITY_TITLE),
+ (12, 1, TT.RELIC),
+ ]),
+ }
+}
+
+
+def generate_hoard(battle_type: EncounterType, level: int):
+ return TreasureHoard(_roll_treasure(battle_type, level))
+
+
+def _roll_treasure(battle_type: EncounterType, level: int):
+ # TODO: Handle more quest levels
+ assert level == 1
+
+ table: HoardTable = _TABLES[level][battle_type]
+ return table.roll()
diff --git a/questhelper/map/views.py b/questhelper/map/views.py
index b0036e2..fec3de6 100644
--- a/questhelper/map/views.py
+++ b/questhelper/map/views.py
@@ -7,10 +7,15 @@ from map.map_renderer import RenderedMap
from map.quest_map import QuestMap
+def _ordinal(level):
+ return {1: '1st', 2: '2nd', 3: '3rd', 4: '4th', 5: '5th'}[level]
+
+
def index(request):
- quest_map: QuestMap = map_generator.generate_map()
+ level = 1
+ quest_map: QuestMap = map_generator.generate_map(level)
rendered_map: RenderedMap = map_renderer.render_map(quest_map)
template = loader.get_template('map/index.html')
- context = {'map': rendered_map}
+ context = {'level_ordinal': _ordinal(level), 'map': rendered_map}
return HttpResponse(template.render(context, request))