From 213b11c0bddb4cc476db297350f5f7e9a92a8513 Mon Sep 17 00:00:00 2001 From: rr- Date: Mon, 5 Nov 2018 17:12:53 +0100 Subject: [PATCH] ui: add inventory view --- pqcli/mechanic.py | 27 ++++++++----- pqcli/ui/game_view.py | 89 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 18 deletions(-) diff --git a/pqcli/mechanic.py b/pqcli/mechanic.py index e44d505..3452c87 100644 --- a/pqcli/mechanic.py +++ b/pqcli/mechanic.py @@ -99,15 +99,17 @@ class QuestBook: @dataclass -class Item: +class InventoryItem: name: str quantity: int -class Inventory: +class Inventory(SignalMixin): + signals = ["gold_change", "item_add", "item_change", "item_del"] + def __init__(self, capacity: int = 0) -> None: self._gold = 0 - self._items: T.List[Item] = [] + self._items: T.List[InventoryItem] = [] self.encum_bar = Bar(max_=capacity) @property @@ -117,9 +119,12 @@ class Inventory: def __len__(self) -> int: return len(self._items) - def __iter__(self) -> T.Iterator[Item]: + def __iter__(self) -> T.Iterator[InventoryItem]: return iter(self._items) + def __getitem__(self, idx: int) -> InventoryItem: + return self._items[idx] + def add_gold(self, quantity: int) -> None: logger.info( "%s %s", @@ -127,24 +132,26 @@ class Inventory: indefinite("gold piece", abs(quantity)), ) self._gold += quantity - - def item_at(self, index: int) -> Item: - return self._items[index] + self.emit("gold_change") def pop(self, index: int) -> None: item = self._items[index] logger.info("Lost %s (qty=%d)", item.name, item.quantity) self._items.pop(index) self.sync_encumbrance() + self.emit("item_del", item) def add(self, item_name: str, quantity: int) -> None: logger.info("Gained %s", indefinite(item_name, quantity)) for item in self._items: if item.name == item_name: item.quantity += quantity + self.emit("item_change", item) break else: - self._items.append(Item(name=item_name, quantity=quantity)) + item = InventoryItem(name=item_name, quantity=quantity) + self._items.append(item) + self.emit("item_add", item) self.sync_encumbrance() def sync_encumbrance(self) -> None: @@ -449,7 +456,7 @@ class Simulation: elif isinstance(self.player.task, (HeadingToMarketTask, SellTask)): if isinstance(self.player.task, SellTask): - item = self.player.inventory.item_at(0) + item = self.player.inventory[0] amount = item.quantity * self.player.level if " of " in item.name: amount *= (1 + random.below_low(10)) * ( @@ -458,7 +465,7 @@ class Simulation: self.player.inventory.pop(0) self.player.inventory.add_gold(amount) if len(self.player.inventory): - item = self.player.inventory.item_at(0) + item = self.player.inventory[0] self.player.set_task( SellTask( "Selling " + indefinite(item.name, item.quantity), diff --git a/pqcli/ui/game_view.py b/pqcli/ui/game_view.py index 48fc55f..cf0528e 100644 --- a/pqcli/ui/game_view.py +++ b/pqcli/ui/game_view.py @@ -5,7 +5,7 @@ import urwid from pqcli.config import StatType from pqcli.lingo import to_roman -from pqcli.mechanic import Player, Simulation, Spell +from pqcli.mechanic import InventoryItem, Player, Simulation, Spell from pqcli.ui.custom_line_box import CustomLineBox from pqcli.ui.custom_progress_bar import CustomProgressBar @@ -99,6 +99,73 @@ class SpellBookView(CustomLineBox): widget.contents[1][0].set_text(to_roman(spell.level)) +class InventoryView(urwid.Pile): + def __init__(self, player: Player) -> None: + self.player = player + + self.gold_text = urwid.Text("") + self.list_box = urwid.ListBox( + [urwid.Columns([urwid.Text("Gold"), self.gold_text])] + ) + self.encumbrance_bar = CustomProgressBar() + + self.player.inventory.connect("gold_change", self.sync_gold) + self.player.inventory.connect("item_add", self.sync_item_add) + self.player.inventory.connect("item_del", self.sync_item_del) + self.player.inventory.connect("item_change", self.sync_item_change) + self.player.inventory.encum_bar.connect( + "change", self.sync_encumbrance_position + ) + self.sync_gold() + self.sync_items() + self.sync_encumbrance_position() + + super().__init__( + [ + CustomLineBox(self.list_box, title="Inventory"), + (1, urwid.Filler(urwid.Text("Encumbrance"))), + (1, urwid.Filler(self.encumbrance_bar)), + ] + ) + + def sync_gold(self) -> None: + self.gold_text.set_text(str(self.player.inventory.gold)) + + def sync_items(self) -> None: + del self.list_box.body[1:] + for item in self.player.inventory: + self.sync_item_add(item) + + def sync_encumbrance_position(self) -> None: + self.encumbrance_bar.set_completion( + self.player.inventory.encum_bar.position + ) + self.encumbrance_bar.set_max(self.player.inventory.encum_bar.max_) + + def sync_item_add(self, item: InventoryItem) -> None: + self.list_box.body.append( + urwid.Columns( + [urwid.Text(item.name), urwid.Text(str(item.quantity))] + ) + ) + + def sync_item_del(self, item: InventoryItem) -> None: + idx = self.get_item_idx_by_name(item.name) + if idx is not None: + del self.list_box.body[idx] + + def sync_item_change(self, item: InventoryItem) -> None: + idx = self.get_item_idx_by_name(item.name) + if idx is not None: + self.list_box.body[idx].contents[1][0].set_text(str(item.quantity)) + + def get_item_idx_by_name(self, name: str) -> T.Optional[int]: + for i, column_widget in enumerate(self.list_box.body): + if column_widget.contents[0][0].text == name: + return i + return None + + class TaskView(urwid.Pile): def __init__(self, player: Player) -> None: self.player = player @@ -138,19 +205,25 @@ class GameView(urwid.Pile): self.character_sheet_view = CharacterSheetView(player) self.experience_view = ExperienceView(player) self.spell_book_view = SpellBookView(player) + self.inventory_view = InventoryView(player) self.task_view = TaskView(player) super().__init__( [ urwid.Columns( [ - urwid.Pile( - [ - self.character_sheet_view, - ("pack", self.experience_view), - self.spell_book_view, - ] - ) + ( + "weight", + 1, + urwid.Pile( + [ + self.character_sheet_view, + ("pack", self.experience_view), + self.spell_book_view, + ] + ), + ), + ("weight", 2, urwid.Pile([self.inventory_view])), ] ), ("pack", self.task_view),