mirror of
https://github.com/evennia/evennia.git
synced 2026-03-23 00:06:30 +01:00
Prep for shopkeepers
This commit is contained in:
parent
d22b11c723
commit
d97106948b
5 changed files with 157 additions and 12 deletions
|
|
@ -62,7 +62,7 @@ class LivingMixin:
|
|||
Called when attacked and taking damage.
|
||||
|
||||
"""
|
||||
pass
|
||||
self.hp -= damage
|
||||
|
||||
def at_defeat(self):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -288,8 +288,6 @@ class CombatActionAttack(CombatAction):
|
|||
message = f" $You() $conj(hit) $You({defender.key}) for |r{dmg}|n damage!"
|
||||
self.msg(message)
|
||||
|
||||
defender.hp -= dmg
|
||||
|
||||
# call hook
|
||||
defender.at_damage(dmg, attacker=attacker)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ from random import choice
|
|||
|
||||
from evennia import DefaultCharacter
|
||||
from evennia.typeclasses.attributes import AttributeProperty
|
||||
from evennia.utils.evmenu import EvMenu
|
||||
from evennia.utils.utils import make_iter
|
||||
|
||||
from .characters import LivingMixin
|
||||
from .enums import Ability, WieldLocation
|
||||
|
|
@ -95,18 +97,140 @@ class EvAdventureNPC(LivingMixin, DefaultCharacter):
|
|||
pass
|
||||
|
||||
|
||||
class EvAdventureShopKeeper(EvAdventureNPC):
|
||||
class EvAdventureTalkativeNPC(EvAdventureNPC):
|
||||
"""
|
||||
Talkative NPCs can be addressed by `talk [to] <npc>`. This opens a chat menu with
|
||||
communication options. The menu is created with the npc and we override the .create
|
||||
to allow passing in the menu nodes.
|
||||
|
||||
"""
|
||||
|
||||
menudata = AttributeProperty(None, autocreate=False)
|
||||
menu_kwargs = AttributeProperty(None, autocreate=False)
|
||||
# text shown when greeting at the start of a conversation. If this is an
|
||||
# iterable, a random reply will be chosen by the menu
|
||||
hi_text = AttributeProperty("Hi!", autocreate=False)
|
||||
|
||||
def at_damage(self, damage, attacker=None):
|
||||
"""
|
||||
Talkative NPCs are generally immortal (we don't deduct HP here by default)."
|
||||
|
||||
"""
|
||||
attacker.msg(f'{self.key} dodges the damage and shouts "|wHey! What are you doing?|n"')
|
||||
|
||||
@classmethod
|
||||
def create(cls, key, account=None, **kwargs):
|
||||
"""
|
||||
Overriding the creation of the NPC, allowing some extra `**kwargs`.
|
||||
|
||||
Args:
|
||||
key (str): Name of the new object.
|
||||
account (Account, optional): Account to attribute this object to.
|
||||
|
||||
Keyword Args:
|
||||
description (str): Brief description for this object (same as default Evennia)
|
||||
ip (str): IP address of creator (for object auditing) (same as default Evennia).
|
||||
menudata (dict or str): The `menudata` argument to `EvMenu`. This is either a dict of
|
||||
`{"nodename": <node_callable>,...}` or the python-path to a module containing
|
||||
such nodes (see EvMenu docs). This will be used to generate the chat menu
|
||||
chat menu for the character that talks to the NPC (which means the `at_talk` hook
|
||||
is called (by our custom `talk` command).
|
||||
menu_kwargs (dict): This will be passed as `**kwargs` into `EvMenu` when it
|
||||
is created. Make sure this dict can be pickled to an Attribute.
|
||||
|
||||
Returns:
|
||||
tuple: `(new_character, errors)`. On error, the `new_character` is `None` and
|
||||
`errors` is a `list` of error strings (an empty list otherwise).
|
||||
|
||||
|
||||
"""
|
||||
menudata = kwargs.pop("menudata", None)
|
||||
menu_kwargs = kwargs.pop("menu_kwargs", {})
|
||||
|
||||
# since this is a @classmethod we can't use super() here
|
||||
new_object, errors = EvAdventureNPC.create(
|
||||
key, account=account, attributes=(("menudata", menudata), ("menu_kwargs", menu_kwargs))
|
||||
)
|
||||
|
||||
return new_object, errors
|
||||
|
||||
def at_talk(self, talker, startnode="node_start", session=None, **kwargs):
|
||||
"""
|
||||
Called by the `talk` command when another entity addresses us.
|
||||
|
||||
Args:
|
||||
talker (Object): The one talking to us.
|
||||
startnode (str, optional): Allows to start in a different location in the menu tree.
|
||||
The given node must exist in the tree.
|
||||
session (Session, optional): The talker's current session, allows for routing
|
||||
correctly in multi-session modes.
|
||||
**kwargs: This will be passed into the `EvMenu` creation and appended and `menu_kwargs`
|
||||
given to the NPC at creation.
|
||||
|
||||
Notes:
|
||||
We pass `npc=self` into the EvMenu for easy back-reference. This will appear in the
|
||||
`**kwargs` of the start node.
|
||||
|
||||
"""
|
||||
menu_kwargs = {**self.menu_kwargs, **kwargs}
|
||||
EvMenu(talker, self.menudata, startnode=startnode, session=session, npc=self, **menu_kwargs)
|
||||
|
||||
|
||||
def node_start(caller, raw_string, **kwargs):
|
||||
"""
|
||||
This is the intended start menu node for the Talkative NPC interface. It will
|
||||
use on-npc Attributes to build its message and will also pick its options
|
||||
based on nodes named `node_start_*` are available in the node tree.
|
||||
|
||||
"""
|
||||
# we presume a back-reference to the npc this is added when the menu is created
|
||||
npc = kwargs["npc"]
|
||||
|
||||
# grab a (possibly random) welcome text
|
||||
text = choice(make_iter(npc.hi_text))
|
||||
|
||||
# determine options based on `node_start_*` nodes available
|
||||
toplevel_node_keys = [
|
||||
node_key for node_key in caller.ndb._evmenu._menutree if node_key.startswith("node_start_")
|
||||
]
|
||||
options = []
|
||||
for node_key in toplevel_node_keys:
|
||||
option_name = node_key[11:].replace("_", " ").capitalized()
|
||||
|
||||
# we let the menu number the choices, so we don't use key here
|
||||
options.append({"desc": option_name, "goto": node_key})
|
||||
|
||||
return text, options
|
||||
|
||||
|
||||
class EvAdventureQuestGiver(EvAdventureTalkativeNPC):
|
||||
"""
|
||||
An NPC that acts as a dispenser of quests.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class EvAdventureShopKeeper(EvAdventureTalkativeNPC):
|
||||
"""
|
||||
ShopKeeper NPC.
|
||||
|
||||
"""
|
||||
|
||||
# how much extra the shopkeeper adds on top of the item cost
|
||||
upsell_factor = AttributePropert(1.0, autocreate=False)
|
||||
# how much of the raw cost the shopkeep is willing to pay when buying from character
|
||||
miser_factor = Attribute(0.5, autocreate=False)
|
||||
common_ware_prototypes = AttributeProperty([], autocreate=False)
|
||||
|
||||
class EvAdventureQuestGiver(EvAdventureNPC):
|
||||
"""
|
||||
An NPC that acts as a dispenser of quests.
|
||||
def at_damage(self, damage, attacker=None):
|
||||
"""
|
||||
Immortal - we don't deduct any damage here.
|
||||
|
||||
"""
|
||||
"""
|
||||
attacker.msg(
|
||||
f"{self.key} brushes off the hit and shouts "
|
||||
'"|wHey! This is not the way to get a discount!|n"'
|
||||
)
|
||||
|
||||
|
||||
class EvAdventureMob(EvAdventureNPC):
|
||||
|
|
|
|||
|
|
@ -23,14 +23,37 @@ A shop is run by an NPC. It can provide one or more of several possible services
|
|||
All shops are menu-driven. One starts talking to the npc and will then end up in their shop
|
||||
interface.
|
||||
|
||||
|
||||
This is a series of menu nodes meant to be added as a mapping via
|
||||
`EvAdventureShopKeeper.create(menudata={},...)`.
|
||||
|
||||
To make this pluggable, the shopkeeper start page will analyze the available nodes
|
||||
and auto-add options to all nodes in the three named `node_start_*`. The last part of the
|
||||
node name will be the name of the option capitalized, with underscores replaced by spaces, so
|
||||
`node_start_sell_items` will become a top-level option `Sell items`.
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
from random import choice
|
||||
|
||||
from evennia.utils.evmenu import EvMenu
|
||||
from evennia.utils.utils import make_iter
|
||||
|
||||
from .npcs import EvAdventureShopKeeper
|
||||
|
||||
# shop menu nodes to use for building a Shopkeeper npc
|
||||
|
||||
|
||||
def start_npc_menu(caller, shopkeeper, **kwargs):
|
||||
def node_start_buy(caller, raw_string, **kwargs):
|
||||
"""
|
||||
Access function - start the NPC interaction/shop interface.
|
||||
Menu node for the caller to buy items from the shopkeep. This assumes `**kwargs` contains
|
||||
a kwarg `npc` referencing the npc/shopkeep being talked to.
|
||||
|
||||
Items available to sell are a combination of items in the shopkeep's inventory and prototypes
|
||||
the list of `prototypes` stored in the Shopkeep's "common_ware_prototypes` Attribute. In the
|
||||
latter case, the properties will be extracted from the prototype when inspecting it (object will
|
||||
only spawn when bought).
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -2419,8 +2419,8 @@ class DefaultCharacter(DefaultObject):
|
|||
All other kwargs will be passed into the create_object call.
|
||||
|
||||
Returns:
|
||||
character (Object): A newly created Character of the given typeclass.
|
||||
errors (list): A list of errors in string form, if any.
|
||||
tuple: `(new_character, errors)`. On error, the `new_character` is `None` and
|
||||
`errors` is a `list` of error strings (an empty list otherwise).
|
||||
|
||||
"""
|
||||
errors = []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue