First design of shop menu nodes for plugging in
This commit is contained in:
parent
e6e632c13a
commit
4b856b84f7
5 changed files with 361 additions and 39 deletions
|
|
@ -1,5 +1,15 @@
|
||||||
"""
|
"""
|
||||||
nextEvAdventure commands and cmdsets.
|
EvAdventure commands and cmdsets. We don't need that many stand-alone new
|
||||||
|
commands since a lot of functionality is managed in menus. These commands
|
||||||
|
are in additional to normal Evennia commands and should be added
|
||||||
|
to the CharacterCmdSet
|
||||||
|
|
||||||
|
New commands:
|
||||||
|
attack/hit <target>[,...]
|
||||||
|
inventory
|
||||||
|
wield/wear <item>
|
||||||
|
unwield/remove <item>
|
||||||
|
give <item> to <target>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -65,3 +75,30 @@ class CmdAttackTurnBased(EvAdventureCommand):
|
||||||
self.caller.msg(f"|r{err}|n")
|
self.caller.msg(f"|r{err}|n")
|
||||||
else:
|
else:
|
||||||
self.caller.msg("|rFound noone to attack.|n")
|
self.caller.msg("|rFound noone to attack.|n")
|
||||||
|
|
||||||
|
|
||||||
|
class CmdInventory(EvAdventureCommand):
|
||||||
|
"""
|
||||||
|
View your inventory
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
inventory
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = "inventory"
|
||||||
|
aliases = ("i", "inv")
|
||||||
|
|
||||||
|
def func(self):
|
||||||
|
self.caller.msg(self.caller.equipment.display_loadout())
|
||||||
|
|
||||||
|
|
||||||
|
class CmdWield(EvAdventureCommand):
|
||||||
|
"""
|
||||||
|
Wield a weapon/shield or wear armor.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
wield <item>
|
||||||
|
wear <item>
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ class EquipmentHandler:
|
||||||
"""
|
"""
|
||||||
self.obj.attributes.add(self.save_attribute, self.slots, category="inventory")
|
self.obj.attributes.add(self.save_attribute, self.slots, category="inventory")
|
||||||
|
|
||||||
def _count_slots(self):
|
def count_slots(self):
|
||||||
"""
|
"""
|
||||||
Count slot usage. This is fetched from the .size Attribute of the
|
Count slot usage. This is fetched from the .size Attribute of the
|
||||||
object. The size can also be partial slots.
|
object. The size can also be partial slots.
|
||||||
|
|
@ -94,7 +94,7 @@ class EquipmentHandler:
|
||||||
"""
|
"""
|
||||||
size = getattr(obj, "size", 0)
|
size = getattr(obj, "size", 0)
|
||||||
max_slots = self.max_slots
|
max_slots = self.max_slots
|
||||||
current_slot_usage = self._count_slots()
|
current_slot_usage = self.count_slots()
|
||||||
if current_slot_usage + size > max_slots:
|
if current_slot_usage + size > max_slots:
|
||||||
slots_left = max_slots - current_slot_usage
|
slots_left = max_slots - current_slot_usage
|
||||||
raise EquipmentError(
|
raise EquipmentError(
|
||||||
|
|
@ -104,6 +104,26 @@ class EquipmentHandler:
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def all(self):
|
||||||
|
"""
|
||||||
|
Get all objects in inventory, regardless of location.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: A flat list of item tuples `[(item, WieldLocation),...]`
|
||||||
|
starting with the wielded ones, backpack content last.
|
||||||
|
|
||||||
|
"""
|
||||||
|
slots = self.slots
|
||||||
|
lst = [
|
||||||
|
(slots[WieldLocation.WEAPON_HAND], WieldLocation.WEAPON_HAND),
|
||||||
|
(slots[WieldLocation.SHIELD_HAND], WieldLocation.SHIELD_HAND),
|
||||||
|
(slots[WieldLocation.TWO_HANDS], WieldLocation.TWO_HANDS),
|
||||||
|
(slots[WieldLocation.BODY], WieldLocation.BODY),
|
||||||
|
(slots[WieldLocation.HEAD], WieldLocation.HEAD),
|
||||||
|
] + [(item, WieldLocation.BACKPACK) for item in slots[WieldLocation.BACKPACK]]
|
||||||
|
# remove any None-results from empty slots
|
||||||
|
return [tup for tup in lst if item[0]]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def armor(self):
|
def armor(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -333,3 +353,22 @@ class EquipmentHandler:
|
||||||
"""
|
"""
|
||||||
character = self.obj
|
character = self.obj
|
||||||
return [obj for obj in self.slots[WieldLocation.BACKPACK] if obj.at_pre_use(character)]
|
return [obj for obj in self.slots[WieldLocation.BACKPACK] if obj.at_pre_use(character)]
|
||||||
|
|
||||||
|
def get_obj_stats(self, obj):
|
||||||
|
"""
|
||||||
|
Get a string of stats about the object.
|
||||||
|
|
||||||
|
"""
|
||||||
|
objmap = dict(self.all())
|
||||||
|
carried = objmap.get(obj)
|
||||||
|
carried = f"Worn: [{carried.value}]" if carried else ""
|
||||||
|
|
||||||
|
return f"""
|
||||||
|
|c{self.key}|n Value: |y{self.value}|n coins {carried}
|
||||||
|
|
||||||
|
{self.desc}
|
||||||
|
|
||||||
|
Slots: |w{self.size}|n Used from: |w{self.use_slot.value}|n
|
||||||
|
Quality: |w{self.quality}|n Uses: |wself.uses|n
|
||||||
|
Attacks using: |w{self.attack_type.value}|n against |w{self.defense_type.value}|n
|
||||||
|
Damage roll: |w{self.damage_roll}"""
|
||||||
|
|
|
||||||
|
|
@ -217,9 +217,9 @@ class EvAdventureShopKeeper(EvAdventureTalkativeNPC):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# how much extra the shopkeeper adds on top of the item cost
|
# how much extra the shopkeeper adds on top of the item cost
|
||||||
upsell_factor = AttributePropert(1.0, autocreate=False)
|
upsell_factor = AttributeProperty(1.0, autocreate=False)
|
||||||
# how much of the raw cost the shopkeep is willing to pay when buying from character
|
# how much of the raw cost the shopkeep is willing to pay when buying from character
|
||||||
miser_factor = Attribute(0.5, autocreate=False)
|
miser_factor = AttributeProperty(0.5, autocreate=False)
|
||||||
# prototypes of common wares
|
# prototypes of common wares
|
||||||
common_ware_prototypes = AttributeProperty([], autocreate=False)
|
common_ware_prototypes = AttributeProperty([], autocreate=False)
|
||||||
|
|
||||||
|
|
@ -241,7 +241,7 @@ class EvAdventureMob(EvAdventureNPC):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# chance (%) that this enemy will loot you when defeating you
|
# chance (%) that this enemy will loot you when defeating you
|
||||||
loot_chance = AttributeProperty(75)
|
loot_chance = AttributeProperty(75, autocreate=False)
|
||||||
|
|
||||||
def ai_combat_next_action(self, combathandler):
|
def ai_combat_next_action(self, combathandler):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -37,16 +37,16 @@ node name will be the name of the option capitalized, with underscores replaced
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from random import choice
|
|
||||||
|
|
||||||
from evennia.prototypes.prototypes import search_prototype
|
from evennia.prototypes.prototypes import search_prototype
|
||||||
from evennia.prototypes.spawner import flatten_prototype
|
from evennia.prototypes.spawner import flatten_prototype, spawn
|
||||||
from evennia.utils.evmenu import EvMenu, list_node
|
from evennia.utils.evmenu import list_node
|
||||||
from evennia.utils.logger import log_err, log_trace
|
from evennia.utils.logger import log_err, log_trace
|
||||||
from evennia.utils.utils import make_iter
|
|
||||||
|
|
||||||
from .enums import Ability, ObjType, WieldLocation
|
from .enums import ObjType, WieldLocation
|
||||||
from .npcs import EvAdventureShopKeeper
|
from .equipment import EquipmentError
|
||||||
|
|
||||||
|
# ------------------------------------ Buying from an NPC
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -170,8 +170,9 @@ class BuyItem:
|
||||||
obj_type = _get_attr_value("obj_type", prototype, optional=False)
|
obj_type = _get_attr_value("obj_type", prototype, optional=False)
|
||||||
size = _get_attr_value("size", prototype, optional=False)
|
size = _get_attr_value("size", prototype, optional=False)
|
||||||
use_slot = _get_attr_value("use_slot", prototype, optional=False)
|
use_slot = _get_attr_value("use_slot", prototype, optional=False)
|
||||||
value = int(_get_attr_value("value", prototype, optional=False)
|
value = int(
|
||||||
* shopkeeper.upsell_factor)
|
_get_attr_value("value", prototype, optional=False) * shopkeeper.upsell_factor
|
||||||
|
)
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
# not a buyable item
|
# not a buyable item
|
||||||
log_trace("Not a buyable item")
|
log_trace("Not a buyable item")
|
||||||
|
|
@ -194,12 +195,12 @@ class BuyItem:
|
||||||
prototype=prototype,
|
prototype=prototype,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_sdesc(self):
|
def __str__(self):
|
||||||
"""
|
"""
|
||||||
Get the short description to show in buy list.
|
Get the short description to show in buy list.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.key
|
return f"{self.key} [|y{self.value}|n coins]"
|
||||||
|
|
||||||
def get_detail(self):
|
def get_detail(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -207,11 +208,48 @@ class BuyItem:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return f"""
|
return f"""
|
||||||
|c{self.key}|n
|
|c{self.key}|n Cost: |y{self.value}|n coins
|
||||||
{self.desc}
|
|
||||||
|
|
||||||
Slots: {self.size} Used from: {self.use_slot.value}
|
{self.desc}
|
||||||
|
|
||||||
|
Slots: |w{self.size}|n Used from: |w{self.use_slot.value}|n
|
||||||
|
Quality: |w{self.quality}|n Uses: |wself.uses|n
|
||||||
|
Attacks using: |w{self.attack_type.value}|n against |w{self.defense_type.value}|n
|
||||||
|
Damage roll: |w{self.damage_roll}"""
|
||||||
|
|
||||||
|
def to_obj(self):
|
||||||
|
"""
|
||||||
|
Convert this into an actual database object that we can trade. This either means
|
||||||
|
using the stored `.prototype` to spawn a new instance of the object, or to
|
||||||
|
use the `.obj` reference to get the already existing object.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if self.obj:
|
||||||
|
return self.obj
|
||||||
|
return spawn(self.prototype)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_or_create_buymap(caller, shopkeep):
|
||||||
|
"""
|
||||||
|
Helper that fetches or creates the mapping of `{"short description": BuyItem, ...}`
|
||||||
|
we need for the buy menu. We cache it on the `_evmenu` object on the caller.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not caller.ndb._evmenu.buymap:
|
||||||
|
# buymap not in cache - build it and store in memory on _evmenu object - this way
|
||||||
|
# it will be removed automatically when the menu closes. We will need to reset this
|
||||||
|
# when the shopkeep buys new things.
|
||||||
|
# items carried by the shopkeep are sellable (these are items already created, such as
|
||||||
|
# things sold to the shopkeep earlier). We
|
||||||
|
obj_wares = [BuyItem.create_from_obj(obj) for obj in list(shopkeep.contents)]
|
||||||
|
prototype_wares = [
|
||||||
|
BuyItem.create_from_prototype(prototype)
|
||||||
|
for prototype in shopkeep.common_ware_prototypes
|
||||||
|
]
|
||||||
|
wares = obj_wares + prototype_wares
|
||||||
|
caller.ndb._evmenu.buymap = {str(ware): ware for ware in wares if ware}
|
||||||
|
|
||||||
|
return caller.ndb._evmenu.buymap
|
||||||
|
|
||||||
|
|
||||||
# Helper functions for building the shop listings and select a ware to buy
|
# Helper functions for building the shop listings and select a ware to buy
|
||||||
|
|
@ -224,19 +262,61 @@ def _get_all_wares_to_buy(caller, raw_string, **kwargs):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
shopkeep = kwargs["npc"]
|
shopkeep = kwargs["npc"]
|
||||||
# items carried by the shopkeep are sellable (these are items already created, such as
|
buymap = _get_or_create_buymap(caller, shopkeep)
|
||||||
# things sold to the shopkeep earlier). We
|
return [ware_desc for ware_desc in buymap]
|
||||||
wares = [BuyItem.create_from_obj(obj) for obj in list(shopkeep.contents)] + [
|
|
||||||
BuyItem.create_from_prototype(prototype) for prototype in shopkeep.common_ware_prototypes
|
|
||||||
]
|
|
||||||
# clean out any ByItems that failed to create for some reason
|
|
||||||
wares = [ware for ware in wares if ware]
|
|
||||||
|
|
||||||
|
|
||||||
# shop menu nodes to use for building a Shopkeeper npc
|
def _select_ware_to_buy(caller, selected_ware_desc, **kwargs):
|
||||||
|
"""
|
||||||
|
This helper is used by `EvMenu.list_node` to operate on what the user selected.
|
||||||
|
We return `item` in the kwargs to the `node_select_buy` node.
|
||||||
|
|
||||||
|
"""
|
||||||
|
shopkeep = kwargs["npc"]
|
||||||
|
buymap = _get_or_create_buymap(caller, shopkeep)
|
||||||
|
kwargs["item"] = buymap[selected_ware_desc]
|
||||||
|
|
||||||
|
return "node_confirm_buy", kwargs
|
||||||
|
|
||||||
|
|
||||||
@list_node(_get_all_wares_to_buy, select=_select_ware_to_buy, pagesize=10)
|
def _back_to_previous_node(caller, raw_string, **kwargs):
|
||||||
|
"""
|
||||||
|
Back to previous node is achieved by returning a node of None.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return None, kwargs
|
||||||
|
|
||||||
|
|
||||||
|
def _buy_ware(caller, raw_string, **kwargs):
|
||||||
|
"""
|
||||||
|
Complete the purchase of a ware. At this point the money is deducted
|
||||||
|
and the item is either spawned from a prototype or simply moved from
|
||||||
|
the sellers inventory to that of the buyer.
|
||||||
|
|
||||||
|
We will have kwargs `item` and `npc` passed along to refer to the BuyItem we bought
|
||||||
|
and the shopkeep selling it.
|
||||||
|
|
||||||
|
"""
|
||||||
|
item = kwargs["item"] # a BuyItem instance
|
||||||
|
shopkeep = kwargs["npc"]
|
||||||
|
|
||||||
|
# exchange money
|
||||||
|
caller.coins -= item.value
|
||||||
|
shopkeep += item.value
|
||||||
|
|
||||||
|
# get the item - if not enough room, dump it on the ground
|
||||||
|
obj = item.to_obj()
|
||||||
|
try:
|
||||||
|
caller.equipment.add(obj)
|
||||||
|
except EquipmentError as err:
|
||||||
|
obj.location = caller.location
|
||||||
|
caller.msg(err)
|
||||||
|
caller.msg(f"|w{obj.key} ends up on the ground.|n")
|
||||||
|
|
||||||
|
caller.msg("|gYou bought |w{obj.key}|g for |y{item.value}|g coins.|n")
|
||||||
|
|
||||||
|
|
||||||
|
@list_node(_get_all_wares_to_buy, select=_select_ware_to_buy, pagesize=40)
|
||||||
def node_start_buy(caller, raw_string, **kwargs):
|
def node_start_buy(caller, raw_string, **kwargs):
|
||||||
"""
|
"""
|
||||||
Menu node for the caller to buy items from the shopkeep. This assumes `**kwargs` contains
|
Menu node for the caller to buy items from the shopkeep. This assumes `**kwargs` contains
|
||||||
|
|
@ -248,3 +328,170 @@ def node_start_buy(caller, raw_string, **kwargs):
|
||||||
only spawn when bought).
|
only spawn when bought).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
coins = caller.coins
|
||||||
|
used_slots = caller.equipment.count_slots()
|
||||||
|
max_slots = caller.equipment.max_slots
|
||||||
|
|
||||||
|
text = (
|
||||||
|
f'"Seeing something you like?" [you have |y{coins}|n coins, '
|
||||||
|
f"using |b{used_slots}/{max_slots}|n slots]"
|
||||||
|
)
|
||||||
|
# this will be in addition to the options generated by the list-node
|
||||||
|
extra_options = [{"key": ("[c]ancel", "b", "c", "cancel"), "goto": "node_start"}]
|
||||||
|
|
||||||
|
return text, extra_options
|
||||||
|
|
||||||
|
|
||||||
|
def node_confirm_buy(caller, raw_string, **kwargs):
|
||||||
|
"""
|
||||||
|
Menu node reached when a user selects an item in the buy menu. The `item` passed
|
||||||
|
along in `**kwargs` is the selected item (see `_select_ware_to_buy`, where this is injected).
|
||||||
|
|
||||||
|
"""
|
||||||
|
# this was injected in _select_ware_to_buy. This is an BuyItem instance.
|
||||||
|
item = kwargs["item"]
|
||||||
|
|
||||||
|
coins = caller.coins
|
||||||
|
used_slots = caller.equipment.count_slots()
|
||||||
|
max_slots = caller.equipment.max_slots
|
||||||
|
|
||||||
|
text = item.get_detail()
|
||||||
|
text += f"\n\n[You have |y{coins}|n coins] and are using |b{used_slots}/{max_slots}|n slots]"
|
||||||
|
|
||||||
|
options = []
|
||||||
|
|
||||||
|
if caller.coins >= item.value and item.size <= (max_slots - used_slots):
|
||||||
|
options.append({"desc": f"Buy [{item.value} coins]", "goto": (_buy_ware, kwargs)})
|
||||||
|
options.append({"desc": "Cancel", "goto": (_back_to_previous_node, kwargs)})
|
||||||
|
|
||||||
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# node tree to inject for buying things
|
||||||
|
node_tree_buy = {"node_start_buy": node_start_buy, "node_confirm_buy": node_confirm_buy}
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------- Selling to an NPC
|
||||||
|
|
||||||
|
|
||||||
|
def _get_or_create_sellmap(self, caller, shopkeep):
|
||||||
|
if not caller.ndb._evmenu.sellmap:
|
||||||
|
# no sellmap, build one anew
|
||||||
|
|
||||||
|
sellmap = {}
|
||||||
|
for obj, wieldlocation in caller.equipment.all():
|
||||||
|
key = obj.key
|
||||||
|
value = int(obj.value * shopkeep.miser_factor)
|
||||||
|
if value > 0 and obj.obj_type is not ObjType.QUEST:
|
||||||
|
sellmap[f"|w{key}|n [{wieldlocation.value}] - sell price |y{value}|n coins"] = (
|
||||||
|
obj,
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
caller.ndb._evmenu.sellmap = sellmap
|
||||||
|
|
||||||
|
sellmap = caller.ndb._evmenu.sellmap
|
||||||
|
|
||||||
|
return sellmap
|
||||||
|
|
||||||
|
|
||||||
|
def _get_all_wares_to_sell(caller, raw_string, **kwargs):
|
||||||
|
"""
|
||||||
|
Get all wares available to sell from caller's inventory. We need to build a
|
||||||
|
mapping between the descriptors and the items.
|
||||||
|
|
||||||
|
"""
|
||||||
|
shopkeep = kwargs["npc"]
|
||||||
|
sellmap = _get_or_create_sellmap(caller, shopkeep)
|
||||||
|
return [ware_desc for ware_desc in sellmap]
|
||||||
|
|
||||||
|
|
||||||
|
def _sell_ware(caller, raw_string, **kwargs):
|
||||||
|
"""
|
||||||
|
Complete the sale of a ware. This is were money is gained and the item is removed.
|
||||||
|
|
||||||
|
We will have kwargs `item`, `value` and `npc` passed along to refer to the inventory item we
|
||||||
|
sold, its (adjusted) sales cost and the shopkeep buying it.
|
||||||
|
|
||||||
|
"""
|
||||||
|
item = kwargs["item"]
|
||||||
|
value = kwargs["value"]
|
||||||
|
shopkeep = kwargs["npc"]
|
||||||
|
|
||||||
|
# move item to shopkeep
|
||||||
|
obj = caller.equipment.remove(item)
|
||||||
|
obj.location = shopkeep
|
||||||
|
|
||||||
|
# exchange money - shopkeep always have money to pay, so we don't deduct from them
|
||||||
|
caller.coins += value
|
||||||
|
|
||||||
|
caller.msg("|gYou sold |w{obj.key}|g for |y{value}|g coins.|n")
|
||||||
|
|
||||||
|
|
||||||
|
def _select_ware_to_sell(caller, selected_ware_desc, **kwargs):
|
||||||
|
"""
|
||||||
|
Selected one ware to sell. Figure out which one it is using the sellmap.
|
||||||
|
Store the result as "item" kwarg.
|
||||||
|
|
||||||
|
"""
|
||||||
|
shopkeep = kwargs["npc"]
|
||||||
|
sellmap = _get_or_create_sellmap(caller, shopkeep)
|
||||||
|
kwargs["item"], kwargs["value"] = sellmap[selected_ware_desc]
|
||||||
|
|
||||||
|
return "node_examine_sell", kwargs
|
||||||
|
|
||||||
|
|
||||||
|
@list_node(_get_all_wares_to_sell, select=_select_ware_to_sell, pagesize=20)
|
||||||
|
def node_start_sell(caller, raw_string, **kwargs):
|
||||||
|
"""
|
||||||
|
The start-level node for selling items from the user's inventory. This assumes
|
||||||
|
`**kwargs` contains a kwarg `npc` referencing the npc/shopkeep being talked to.
|
||||||
|
|
||||||
|
Items available to sell are all items in the player's equipment handler, including
|
||||||
|
things in their hands.
|
||||||
|
|
||||||
|
"""
|
||||||
|
coins = caller.coins
|
||||||
|
used_slots = caller.equipment.count_slots()
|
||||||
|
max_slots = caller.equipment.max_slots
|
||||||
|
|
||||||
|
text = (
|
||||||
|
f'"Anything you want to sell?" [you have |y{coins}|n coins, '
|
||||||
|
f"using |b{used_slots}/{max_slots}|n slots]"
|
||||||
|
)
|
||||||
|
# this will be in addition to the options generated by the list-node
|
||||||
|
extra_options = [{"key": ("[c]ancel", "b", "c", "cancel"), "goto": "node_start"}]
|
||||||
|
|
||||||
|
return text, extra_options
|
||||||
|
|
||||||
|
|
||||||
|
def node_confirm_sell(caller, raw_string, **kwargs):
|
||||||
|
"""
|
||||||
|
In this node we confirm the sell by first investigating the item we are about to sell.
|
||||||
|
|
||||||
|
We have `item` and `value` available in kwargs here, added by `_select_ware_to_sell` earler.
|
||||||
|
|
||||||
|
"""
|
||||||
|
item = kwargs["item"]
|
||||||
|
value = kwargs["value"]
|
||||||
|
|
||||||
|
coins = caller.coins
|
||||||
|
used_slots = caller.equipment.count_slots()
|
||||||
|
max_slots = caller.equipment.max_slots
|
||||||
|
|
||||||
|
text = caller.equipment.get_obj_stats(item)
|
||||||
|
text += f"\n\n[You have |y{coins}|n coins] and are using |b{used_slots}/{max_slots}|n slots]"
|
||||||
|
|
||||||
|
options = (
|
||||||
|
{"desc": f"Sell [{value} coins]", "goto": (_sell_ware, kwargs)},
|
||||||
|
{"desc": "Cancel", "goto": (_back_to_previous_node, kwargs)},
|
||||||
|
)
|
||||||
|
|
||||||
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# node tree to inject for selling things
|
||||||
|
node_tree_sell = {"node_start_sell": node_start_sell, "node_confirm_sell": node_confirm_sell}
|
||||||
|
|
||||||
|
|
||||||
|
# Full shopkeep node tree - inject into ShopKeep NPC menu to add buy/sell submenus
|
||||||
|
node_tree_shopkeep = {**node_tree_buy, **node_tree_sell}
|
||||||
|
|
|
||||||
|
|
@ -269,24 +269,23 @@ they will be tested in sequence.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
|
||||||
import inspect
|
import inspect
|
||||||
|
import re
|
||||||
from ast import literal_eval
|
from ast import literal_eval
|
||||||
from fnmatch import fnmatch
|
from fnmatch import fnmatch
|
||||||
|
from inspect import getargspec, isfunction
|
||||||
from math import ceil
|
from math import ceil
|
||||||
|
|
||||||
from inspect import isfunction, getargspec
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from evennia import Command, CmdSet
|
|
||||||
from evennia.utils import logger
|
|
||||||
from evennia.utils.evtable import EvTable, EvColumn
|
|
||||||
from evennia.utils.ansi import strip_ansi
|
|
||||||
from evennia.utils.utils import mod_import, make_iter, pad, to_str, m_len, is_iter, dedent, crop
|
|
||||||
from evennia.commands import cmdhandler
|
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
from evennia import CmdSet, Command
|
||||||
|
from evennia.commands import cmdhandler
|
||||||
|
from evennia.utils import logger
|
||||||
|
from evennia.utils.ansi import strip_ansi
|
||||||
|
from evennia.utils.evtable import EvColumn, EvTable
|
||||||
|
from evennia.utils.utils import crop, dedent, is_iter, m_len, make_iter, mod_import, pad, to_str
|
||||||
|
|
||||||
# read from protocol NAWS later?
|
# read from protocol NAWS later?
|
||||||
_MAX_TEXT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
|
_MAX_TEXT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
|
||||||
|
|
@ -1394,9 +1393,9 @@ def list_node(option_generator, select=None, pagesize=10):
|
||||||
# we assume a string was given, we inject the result into the kwargs
|
# we assume a string was given, we inject the result into the kwargs
|
||||||
# to pass on to the next node
|
# to pass on to the next node
|
||||||
kwargs["selection"] = selection
|
kwargs["selection"] = selection
|
||||||
return str(select)
|
return str(select), kwargs
|
||||||
# this means the previous node will be re-run with these same kwargs
|
# this means the previous node will be re-run with these same kwargs
|
||||||
return None
|
return None, kwargs
|
||||||
|
|
||||||
def _list_node(caller, raw_string, **kwargs):
|
def _list_node(caller, raw_string, **kwargs):
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue