Generate treasure hoards

This commit is contained in:
henriquenakashima 2021-03-28 18:36:08 -04:00
parent 541991d404
commit 97782ab212
7 changed files with 132 additions and 9 deletions

View file

@ -2,7 +2,8 @@ import random
from typing import List from typing import List
import map.quest_map 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) # 27 cards (21 are drawn)
@ -26,9 +27,10 @@ def generate_encounter_inaccessible() -> MapEncounter:
return MapEncounter(ET.INACCESSIBLE) 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 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): def generate_encounter_town(town_type: ET):
@ -36,7 +38,7 @@ def generate_encounter_town(town_type: ET):
return MapEncounter(town_type) return MapEncounter(town_type)
def generate_map() -> QuestMap: def generate_map(level: int) -> QuestMap:
quest_map = QuestMap() quest_map = QuestMap()
# Generate encounters # Generate encounters
@ -46,13 +48,13 @@ def generate_map() -> QuestMap:
row: List[MapEncounter] = [] row: List[MapEncounter] = []
if r == 10: if r == 10:
row.append(generate_encounter_inaccessible()) 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()) row.append(generate_encounter_inaccessible())
elif r in (1, 4, 7): elif r in (1, 4, 7):
elite_column = random.randrange(4) # 75% chance of elite elite_column = random.randrange(4) # 75% chance of elite
for c in range(3): for c in range(3):
battle_type = ET.BATTLE_ELITE if c == elite_column else ET.BATTLE_REGULAR 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: else:
for c in range(3): for c in range(3):
town_type = next(town_deck_it) town_type = next(town_deck_it)

View file

@ -37,10 +37,12 @@ class RenderedElement:
h: int h: int
@dataclasses.dataclass(frozen=True)
class RenderedEncounter(RenderedElement): class RenderedEncounter(RenderedElement):
pass pass
@dataclasses.dataclass(frozen=True)
class RenderedPath(RenderedElement): class RenderedPath(RenderedElement):
pass pass

View file

@ -3,6 +3,8 @@ import enum
from typing import List from typing import List
from map.treasure_hoard import TreasureHoard
class EncounterType(enum.Enum): class EncounterType(enum.Enum):
INACCESSIBLE = 'inaccessible' INACCESSIBLE = 'inaccessible'
@ -60,6 +62,15 @@ class MapEncounter:
return str(self.type) 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: class QuestMap:
def __init__(self): def __init__(self):
# List of rows of encounters, each row has 3 encounters. # List of rows of encounters, each row has 3 encounters.

View file

@ -1,7 +1,7 @@
{% load static %} {% load static %}
<head></head> <head></head>
<body> <body>
<h1>Map</h1> <h1>Map of {{level_ordinal}} quest</h1>
<div style="position: relative"> <div style="position: relative">
{% for e in map.encounters %} {% for e in map.encounters %}

View file

@ -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} + ?'

View file

@ -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()

View file

@ -7,10 +7,15 @@ from map.map_renderer import RenderedMap
from map.quest_map import QuestMap from map.quest_map import QuestMap
def _ordinal(level):
return {1: '1st', 2: '2nd', 3: '3rd', 4: '4th', 5: '5th'}[level]
def index(request): 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) rendered_map: RenderedMap = map_renderer.render_map(quest_map)
template = loader.get_template('map/index.html') 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)) return HttpResponse(template.render(context, request))