mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Add all needed evadventure commands
This commit is contained in:
parent
e1439104e0
commit
2848e31f4b
8 changed files with 490 additions and 61 deletions
|
|
@ -2,9 +2,10 @@
|
|||
General Character commands usually available to all characters
|
||||
"""
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from evennia.utils import utils
|
||||
from evennia.typeclasses.attributes import NickTemplateInvalid
|
||||
from evennia.utils import utils
|
||||
|
||||
COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||
|
||||
|
|
@ -501,7 +502,7 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
|
|||
Usage:
|
||||
give <inventory obj> <to||=> <target>
|
||||
|
||||
Gives an items from your inventory to another character,
|
||||
Gives an item from your inventory to another person,
|
||||
placing it in their inventory.
|
||||
"""
|
||||
|
||||
|
|
@ -538,7 +539,7 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
|
||||
# give object
|
||||
success = to_give.move_to(target, quiet=True, move_type="get")
|
||||
success = to_give.move_to(target, quiet=True, move_type="give")
|
||||
if not success:
|
||||
caller.msg("This could not be given.")
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@ Character class.
|
|||
|
||||
from evennia.objects.objects import DefaultCharacter
|
||||
from evennia.typeclasses.attributes import AttributeProperty
|
||||
from evennia.utils.evmenu import ask_yes_no
|
||||
from evennia.utils.logger import log_trace
|
||||
from evennia.utils.utils import lazy_property
|
||||
|
||||
from . import rules
|
||||
from .equipment import EquipmentHandler
|
||||
from .equipment import EquipmentError, EquipmentHandler
|
||||
from .quests import EvAdventureQuestHandler
|
||||
from .utils import get_obj_stats
|
||||
|
||||
|
||||
class LivingMixin:
|
||||
|
|
@ -79,7 +82,7 @@ class LivingMixin:
|
|||
"""
|
||||
pass
|
||||
|
||||
def at_loot(self, looted):
|
||||
def at_do_loot(self, looted):
|
||||
"""
|
||||
Called when looting another entity.
|
||||
|
||||
|
|
@ -87,9 +90,9 @@ class LivingMixin:
|
|||
looted: The thing to loot.
|
||||
|
||||
"""
|
||||
looted.get_loot()
|
||||
looted.at_looted()
|
||||
|
||||
def get_loot(self, looter):
|
||||
def at_looted(self, looter):
|
||||
"""
|
||||
Called when being looted (after defeat).
|
||||
|
||||
|
|
@ -186,12 +189,14 @@ class EvAdventureCharacter(LivingMixin, DefaultCharacter):
|
|||
Args:
|
||||
moved_object (Object): Object to move into this one (that is, into inventory).
|
||||
source_location (Object): Source location moved from.
|
||||
**kwargs: Passed from move operation; unused here.
|
||||
**kwargs: Passed from move operation; the `move_type` is useful; if someone is giving
|
||||
us something (`move_type=='give'`) we want to ask first.
|
||||
|
||||
Returns:
|
||||
bool: If move should be allowed or not.
|
||||
|
||||
"""
|
||||
# this will raise EquipmentError if inventory is full
|
||||
return self.equipment.validate_slot_usage(moved_object)
|
||||
|
||||
def at_object_receive(self, moved_object, source_location, **kwargs):
|
||||
|
|
@ -205,15 +210,18 @@ class EvAdventureCharacter(LivingMixin, DefaultCharacter):
|
|||
**kwargs: Passed from move operation; unused here.
|
||||
|
||||
"""
|
||||
self.equipment.add(moved_object)
|
||||
try:
|
||||
self.equipment.add(moved_object)
|
||||
except EquipmentError as err:
|
||||
log_trace(f"at_object_receive error: {err}")
|
||||
|
||||
def at_pre_object_leave(self, leaving_object, destination, **kwargs):
|
||||
"""
|
||||
Hook called when dropping an item. We don't allow to drop weilded/worn items
|
||||
(need to unwield/remove them first).
|
||||
(need to unwield/remove them first). Return False to
|
||||
|
||||
"""
|
||||
return self.equipment.can_remove(leaving_object)
|
||||
return True
|
||||
|
||||
def at_object_leave(self, moved_object, destination, **kwargs):
|
||||
"""
|
||||
|
|
@ -264,7 +272,7 @@ class EvAdventureCharacter(LivingMixin, DefaultCharacter):
|
|||
# don't allow looting in pvp
|
||||
return not self.location.allow_pvp
|
||||
|
||||
def get_loot(self, looter):
|
||||
def at_looted(self, looter):
|
||||
"""
|
||||
Called when being looted.
|
||||
|
||||
|
|
|
|||
|
|
@ -765,7 +765,7 @@ class EvAdventureCombatHandler(DefaultScript):
|
|||
for enemy in defeated_enemies:
|
||||
try:
|
||||
if ally.pre_loot(enemy):
|
||||
enemy.get_loot(ally)
|
||||
enemy.at_looted(ally)
|
||||
ally.post_loot(enemy)
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
|
|
|
|||
|
|
@ -9,13 +9,35 @@ New commands:
|
|||
inventory
|
||||
wield/wear <item>
|
||||
unwield/remove <item>
|
||||
give <item> to <target>
|
||||
give <item or coin> to <character>
|
||||
talk <npc>
|
||||
|
||||
To install, add the `EvAdventureCmdSet` from this module to the default character cmdset:
|
||||
|
||||
```python
|
||||
# in mygame/commands/default_cmds.py
|
||||
|
||||
from evennia.contrib.tutorials.evadventure.commands import EvAdventureCmdSet # <---
|
||||
|
||||
# ...
|
||||
|
||||
class CharacterCmdSet(CmdSet):
|
||||
def at_cmdset_creation(self):
|
||||
# ...
|
||||
self.add(EvAdventureCmdSet) # <-----
|
||||
|
||||
```
|
||||
"""
|
||||
|
||||
from evennia import Command, default_cmds
|
||||
from evennia import CmdSet, Command, InterruptCommand
|
||||
from evennia.utils.evmenu import EvMenu
|
||||
from evennia.utils.utils import inherits_from
|
||||
|
||||
from .combat_turnbased import CombatFailure, join_combat
|
||||
from .enums import WieldLocation
|
||||
from .equipment import EquipmentError
|
||||
from .npcs import EvAdventureTalkativeNPC
|
||||
from .utils import get_obj_stats
|
||||
|
||||
|
||||
class EvAdventureCommand(Command):
|
||||
|
|
@ -93,12 +115,343 @@ class CmdInventory(EvAdventureCommand):
|
|||
self.caller.msg(self.caller.equipment.display_loadout())
|
||||
|
||||
|
||||
class CmdWield(EvAdventureCommand):
|
||||
class CmdWieldOrWear(EvAdventureCommand):
|
||||
"""
|
||||
Wield a weapon/shield or wear armor.
|
||||
Wield a weapon/shield, or wear a piece of armor or a helmet.
|
||||
|
||||
Usage:
|
||||
wield <item>
|
||||
wear <item>
|
||||
|
||||
The item will automatically end up in the suitable spot, replacing whatever
|
||||
was there previously.
|
||||
|
||||
"""
|
||||
|
||||
key = "wield"
|
||||
aliases = ("wear",)
|
||||
|
||||
out_txts = {
|
||||
WieldLocation.BACKPACK: "You shuffle the position of {key} around in your backpack.",
|
||||
WieldLocation.TWO_HANDS: "You hold {key} with both hands.",
|
||||
WieldLocation.WEAPON_HAND: "You hold {key} in your strongest hand, ready for action.",
|
||||
WieldLocation.SHIELD_HAND: "You hold {key} in your off hand, ready to protect you.",
|
||||
WieldLocation.BODY: "You strap {key} on yourself.",
|
||||
WieldLocation.HEAD: "You put {key} on your head.",
|
||||
}
|
||||
|
||||
def func(self):
|
||||
# find the item among those in equipment
|
||||
item = self.caller.search(self.args, candidates=self.caller.equipment.all(only_objs=True))
|
||||
if not item:
|
||||
# An 'item not found' error will already have been reported; we add another line
|
||||
# here for clarity.
|
||||
self.caller.msg("You must carry the item you want to wield or wear.")
|
||||
return
|
||||
|
||||
use_slot = getattr(item, "inventory_use_slot", WieldLocation.BACKPACK)
|
||||
|
||||
# check what is currently in this slot
|
||||
current = self.caller.equipment.slots[use_slot]
|
||||
|
||||
if current == item:
|
||||
self.caller.msg(f"You are already using {item.key} here.")
|
||||
return
|
||||
|
||||
# move it to the right slot based on the type of object
|
||||
self.caller.equipment.use(item)
|
||||
|
||||
# inform the user of the change (and potential swap)
|
||||
if current:
|
||||
self.caller.msg(f"Returning {current.key} to the backpack.")
|
||||
self.caller.msg(self.out_txts[use_slot].format(key=item.key))
|
||||
|
||||
|
||||
class CmdRemove(EvAdventureCommand):
|
||||
"""
|
||||
Remove a remove a weapon/shield, armor or helmet.
|
||||
|
||||
Usage:
|
||||
remove <item>
|
||||
unwield <item>
|
||||
unwear <item>
|
||||
|
||||
To remove an item from the backpack, use |wdrop|n instead.
|
||||
|
||||
"""
|
||||
|
||||
key = "remove"
|
||||
aliases = ("unwield", "unwear")
|
||||
|
||||
def func(self):
|
||||
caller = self.caller
|
||||
|
||||
# find the item among those in equipment
|
||||
item = caller.search(self.args, candidates=caller.equipment.all(only_objs=True))
|
||||
if not item:
|
||||
# An 'item not found' error will already have been reported
|
||||
return
|
||||
|
||||
current_slot = caller.equipment.get_current_slot(item)
|
||||
|
||||
if current_slot is WieldLocation.BACKPACK:
|
||||
# we don't allow dropping this way since it may be unexepected by users who forgot just
|
||||
# where their item currently is.
|
||||
caller.msg(
|
||||
f"You already stashed away {item.key} in your backpack. Use 'drop' if "
|
||||
"you want to get rid of it."
|
||||
)
|
||||
return
|
||||
|
||||
caller.equipment.remove(item)
|
||||
caller.equipment.add(item)
|
||||
caller.msg(f"You stash {item.key} in your backpack.")
|
||||
|
||||
|
||||
# give / accept menu
|
||||
|
||||
|
||||
def _rescind_gift(caller, raw_string, **kwargs):
|
||||
"""
|
||||
Called when giver rescinds their gift in `node_give` below.
|
||||
It means they entered 'cancel' on the gift screen.
|
||||
|
||||
"""
|
||||
# kill the gift menu for the receiver immediately
|
||||
receiver = kwargs["receiver"]
|
||||
receiver.ndb._evmenu.close_menu()
|
||||
receiver.msg("The offer was rescinded.")
|
||||
return "node_end"
|
||||
|
||||
|
||||
def node_give(caller, raw_string, **kwargs):
|
||||
"""
|
||||
This will show to the giver until receiver accepts/declines. It allows them
|
||||
to rescind their offer.
|
||||
|
||||
The `caller` here is the one giving the item. We also make sure to feed
|
||||
the 'item' and 'receiver' into the Evmenu.
|
||||
|
||||
"""
|
||||
item = kwargs["item"]
|
||||
receiver = kwargs["receiver"]
|
||||
text = f"""
|
||||
You are offering {item.key} to {receiver.get_display_name(looker=caller)}.
|
||||
|wWaiting for them to accept or reject the offer ...|n
|
||||
""".strip()
|
||||
|
||||
options = {
|
||||
"key": ("cancel", "abort"),
|
||||
"desc": "Rescind your offer.",
|
||||
"goto": (_rescind_gift, kwargs),
|
||||
}
|
||||
return text, options
|
||||
|
||||
|
||||
def _accept_or_reject_gift(caller, raw_string, **kwargs):
|
||||
"""
|
||||
Called when receiver enters yes/no in `node_receive` below. We first need to
|
||||
figure out which.
|
||||
|
||||
"""
|
||||
item = kwargs["item"]
|
||||
giver = kwargs["giver"]
|
||||
if raw_string.lower() in ("yes", "y"):
|
||||
# they accepted - move the item!
|
||||
item = giver.equipment.remove(item)
|
||||
if item:
|
||||
try:
|
||||
# this will also add them to the equipment backpack, if possible
|
||||
item.move_to(caller, quiet=True, move_type="give")
|
||||
except EquipmentError:
|
||||
caller.location.msg_contents(
|
||||
f"$You({giver.key.key}) $conj(try) to give "
|
||||
f"{item.key} to $You({caller.key}), but they can't accept it since their "
|
||||
"inventory is full.",
|
||||
mapping={giver.key: giver, caller.key: caller},
|
||||
)
|
||||
else:
|
||||
caller.location.msg_contents(
|
||||
f"$You({giver.key}) $conj(give) {item.key} to $You({caller.key}), "
|
||||
"and they accepted the offer.",
|
||||
mapping={giver.key: giver, caller.key: caller},
|
||||
)
|
||||
giver.ndb._evmenu.close_menu()
|
||||
return "node_end"
|
||||
|
||||
|
||||
def node_receive(caller, raw_string, **kwargs):
|
||||
"""
|
||||
Will show to the receiver and allow them to accept/decline the offer for
|
||||
as long as the giver didn't rescind it.
|
||||
|
||||
The `caller` here is the one receiving the item. We also make sure to feed
|
||||
the 'item' and 'giver' into the EvMenu.
|
||||
|
||||
"""
|
||||
item = kwargs["item"]
|
||||
giver = kwargs["giver"]
|
||||
text = f"""
|
||||
{giver.get_display_name()} is offering you {item.key}:
|
||||
|
||||
{get_obj_stats(item)}
|
||||
|
||||
[Your inventory usage: {caller.equipment.get_slot_usage_string()}]
|
||||
|wDo you want to accept the given item? Y/[N]
|
||||
"""
|
||||
options = ({"key": "_default", "goto": (_accept_or_reject_gift, kwargs)},)
|
||||
return text, options
|
||||
|
||||
|
||||
def node_end(caller, raw_string, **kwargs):
|
||||
return "", None
|
||||
|
||||
|
||||
class CmdGive(EvAdventureCommand):
|
||||
"""
|
||||
Give item or money to another person. Items need to be accepted before
|
||||
they change hands. Money changes hands immediately with no wait.
|
||||
|
||||
Usage:
|
||||
give <item> to <receiver>
|
||||
give <number of coins> [coins] to receiver
|
||||
|
||||
If item name includes ' to ', surround it in quotes.
|
||||
|
||||
Examples:
|
||||
give apple to ranger
|
||||
give "road to happiness" to sad ranger
|
||||
give 10 coins to ranger
|
||||
give 12 to ranger
|
||||
|
||||
"""
|
||||
|
||||
key = "give"
|
||||
|
||||
def parse(self):
|
||||
"""
|
||||
Parsing is a little more complex for this command.
|
||||
|
||||
"""
|
||||
super().parse()
|
||||
args = self.args
|
||||
if " to " not in args:
|
||||
self.caller.msg(
|
||||
"Usage: give <item> to <recevier>. Specify e.g. '10 coins' to pay money. "
|
||||
"Use quotes around the item name it if includes the substring ' to '. "
|
||||
)
|
||||
raise InterruptCommand
|
||||
|
||||
self.item_name = ""
|
||||
self.coins = 0
|
||||
|
||||
# make sure we can use '...' to include items with ' to ' in the name
|
||||
if args.startswith('"') and args.count('"') > 1:
|
||||
end_ind = args[1:].index('"') + 1
|
||||
item_name = args[:end_ind]
|
||||
_, receiver_name = args.split(" to ", 1)
|
||||
elif args.startswith("'") and args.count("'") > 1:
|
||||
end_ind = args[1:].index("'") + 1
|
||||
item_name = args[:end_ind]
|
||||
_, receiver_name = args.split(" to ", 1)
|
||||
else:
|
||||
item_name, receiver_name = args.split(" to ", 1)
|
||||
|
||||
# a coin count rather than a normal name
|
||||
if " coins" in item_name:
|
||||
item_name = item_name[:-6]
|
||||
if item_name.isnumeric():
|
||||
self.coins = max(0, int(item_name))
|
||||
|
||||
self.item_name = item_name
|
||||
self.receiver_name = receiver_name
|
||||
|
||||
def func(self):
|
||||
caller = self.caller
|
||||
|
||||
receiver = caller.search(self.receiver_name)
|
||||
if not receiver:
|
||||
return
|
||||
|
||||
# giving of coins is always accepted
|
||||
|
||||
if self.coins:
|
||||
current_coins = caller.coins
|
||||
if caller.coins < current_coins:
|
||||
caller.msg("You only have |y{current_coins}|n to give.")
|
||||
return
|
||||
# do transaction
|
||||
caller.coins -= self.coins
|
||||
receiver.coins += self.coins
|
||||
caller.location.msg_contents(
|
||||
f"$You() $conj(give) $You(receiver.key) {self.coins} coins."
|
||||
)
|
||||
return
|
||||
|
||||
# giving of items require acceptance before it happens
|
||||
|
||||
item = caller.search(self.item_name, candidates=caller.equipment.all(only_objs=True))
|
||||
if not item:
|
||||
return
|
||||
|
||||
# testing hook
|
||||
if not item.at_pre_give(caller, receiver):
|
||||
return
|
||||
|
||||
# before we start menus, we must check so either part is not already in a menu,
|
||||
# that would be annoying otherwise
|
||||
if receiver.ndb._evmenu:
|
||||
caller.msg(
|
||||
f"{receiver.get_display_name(looker=caller)} seems busy talking to someone else."
|
||||
)
|
||||
return
|
||||
if caller.ndb._evmenu:
|
||||
caller.msg("Close the current menu first.")
|
||||
return
|
||||
|
||||
# this starts evmenus for both parties
|
||||
EvMenu(
|
||||
receiver, {"node_receive": node_receive, "node_end": node_end}, item=item, giver=caller
|
||||
)
|
||||
EvMenu(caller, {"node_give": node_give, "node_end": node_end}, item=item, receiver=receiver)
|
||||
|
||||
|
||||
class CmdTalk(EvAdventureCommand):
|
||||
"""
|
||||
Start a conversations with shop keepers and other NPCs in the world.
|
||||
|
||||
Args:
|
||||
talk <npc>
|
||||
|
||||
"""
|
||||
|
||||
key = "talk"
|
||||
|
||||
def func(self):
|
||||
target = self.search(self.args)
|
||||
if not target:
|
||||
return
|
||||
|
||||
if not inherits_from(target, EvAdventureTalkativeNPC):
|
||||
self.caller.msg(
|
||||
f"{target.get_display_name(looker=self.caller)} does not seem very talkative."
|
||||
)
|
||||
return
|
||||
target.at_talk(self.caller)
|
||||
|
||||
|
||||
class EvAdventureCmdSet(CmdSet):
|
||||
"""
|
||||
Groups all commands in one cmdset which can be added in one go to the DefaultCharacter cmdset.
|
||||
|
||||
"""
|
||||
|
||||
key = "evadventure"
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
self.add(CmdAttackTurnBased())
|
||||
self.add(CmdInventory())
|
||||
self.add(CmdWieldOrWear())
|
||||
self.add(CmdRemove())
|
||||
self.add(CmdGive())
|
||||
self.add(CmdTalk())
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ Knave has a system of Slots for its inventory.
|
|||
|
||||
"""
|
||||
|
||||
from evennia.utils.utils import inherits_from
|
||||
|
||||
from .enums import Ability, WieldLocation
|
||||
from .objects import WeaponEmptyHand
|
||||
from .objects import EvAdventureObject, WeaponEmptyHand
|
||||
|
||||
|
||||
class EquipmentError(TypeError):
|
||||
|
|
@ -81,6 +83,16 @@ class EquipmentHandler:
|
|||
"""
|
||||
return getattr(self.obj, Ability.CON.value, 1) + 10
|
||||
|
||||
def get_slot_usage_string(self):
|
||||
"""
|
||||
Get a slot usage/max string for display.
|
||||
|
||||
Returns:
|
||||
str: The usage string.
|
||||
|
||||
"""
|
||||
return f"|b{self.count_slots()}/{self.max_slots}|n"
|
||||
|
||||
def validate_slot_usage(self, obj):
|
||||
"""
|
||||
Check if obj can fit in equipment, based on its size.
|
||||
|
|
@ -92,7 +104,10 @@ class EquipmentHandler:
|
|||
EquipmentError: If there's not enough room.
|
||||
|
||||
"""
|
||||
size = getattr(obj, "size", 0)
|
||||
if not inherits_from(obj, EvAdventureObject):
|
||||
raise EquipmentError(f"{obj.key} is not something that can be equipped.")
|
||||
|
||||
size = obj.size
|
||||
max_slots = self.max_slots
|
||||
current_slot_usage = self.count_slots()
|
||||
if current_slot_usage + size > max_slots:
|
||||
|
|
@ -104,25 +119,21 @@ class EquipmentHandler:
|
|||
)
|
||||
return True
|
||||
|
||||
def all(self):
|
||||
def get_current_slot(self, obj):
|
||||
"""
|
||||
Get all objects in inventory, regardless of location.
|
||||
Check which slot-type the given object is in.
|
||||
|
||||
Args:
|
||||
obj (EvAdventureObject): The object to check.
|
||||
|
||||
Returns:
|
||||
list: A flat list of item tuples `[(item, WieldLocation),...]`
|
||||
starting with the wielded ones, backpack content last.
|
||||
WieldLocation: A location the object is in. None if the object
|
||||
is not in the inventory at all.
|
||||
|
||||
"""
|
||||
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]]
|
||||
for equipment_item, slot in self.all():
|
||||
if obj == equipment_item:
|
||||
return slot
|
||||
|
||||
@property
|
||||
def armor(self):
|
||||
|
|
@ -205,10 +216,10 @@ class EquipmentHandler:
|
|||
|
||||
return f"{weapon_str}{shield_str}\n{armor_str}{helmet_str}"
|
||||
|
||||
def use(self, obj):
|
||||
def move(self, obj):
|
||||
"""
|
||||
Make use of item - this makes use of the object's wield slot to decide where
|
||||
it goes. If it doesn't have any, it goes into backpack.
|
||||
Moves item to the place it things it should be in - this makes use of the object's wield
|
||||
slot to decide where it goes. If it doesn't have any, it goes into backpack.
|
||||
|
||||
Args:
|
||||
obj (EvAdventureObject): Thing to use.
|
||||
|
|
@ -238,7 +249,7 @@ class EquipmentHandler:
|
|||
slots[WieldLocation.WEAPON_HAND] = slots[WieldLocation.SHIELD_HAND] = None
|
||||
slots[use_slot] = obj
|
||||
elif use_slot in (WieldLocation.WEAPON_HAND, WieldLocation.SHIELD_HAND):
|
||||
# can't keep a two-handed weapon if adding a one-handede weapon or shield
|
||||
# can't keep a two-handed weapon if adding a one-handed weapon or shield
|
||||
slots[WieldLocation.TWO_HANDS] = None
|
||||
slots[use_slot] = obj
|
||||
elif use_slot is WieldLocation.BACKPACK:
|
||||
|
|
@ -255,19 +266,19 @@ class EquipmentHandler:
|
|||
"""
|
||||
Put something in the backpack specifically (even if it could be wield/worn).
|
||||
|
||||
Args:
|
||||
obj (EvAdventureObject): The object to add.
|
||||
|
||||
Notes:
|
||||
This will not change the object's `.location`, this must be done
|
||||
by the calling code.
|
||||
|
||||
"""
|
||||
# check if we have room
|
||||
self.validate_slot_usage(obj)
|
||||
self.slots[WieldLocation.BACKPACK].append(obj)
|
||||
self._save()
|
||||
|
||||
def can_remove(self, leaving_object):
|
||||
"""
|
||||
Called to check if the object can be removed.
|
||||
|
||||
"""
|
||||
return True # TODO - some things may not be so easy, like mud
|
||||
|
||||
def remove(self, obj_or_slot):
|
||||
"""
|
||||
Remove specific object or objects from a slot.
|
||||
|
|
@ -279,6 +290,10 @@ class EquipmentHandler:
|
|||
Returns:
|
||||
list: A list of 0, 1 or more objects emptied from the inventory.
|
||||
|
||||
Notes:
|
||||
This will not change the object's `.location`, this must be done separately
|
||||
by the calling code.
|
||||
|
||||
"""
|
||||
slots = self.slots
|
||||
ret = []
|
||||
|
|
@ -354,21 +369,28 @@ class EquipmentHandler:
|
|||
character = self.obj
|
||||
return [obj for obj in self.slots[WieldLocation.BACKPACK] if obj.at_pre_use(character)]
|
||||
|
||||
def get_obj_stats(self, obj):
|
||||
def all(self, only_objs=False):
|
||||
"""
|
||||
Get a string of stats about the object.
|
||||
Get all objects in inventory, regardless of location.
|
||||
|
||||
Keyword Args:
|
||||
only_objs (bool): Only return a flat list of objects, not tuples.
|
||||
|
||||
Returns:
|
||||
list: A list of item tuples `[(item, WieldLocation),...]`
|
||||
starting with the wielded ones, backpack content last. If `only_objs` is set,
|
||||
this will just be a flat list of objects.
|
||||
|
||||
"""
|
||||
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}"""
|
||||
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
|
||||
if only_objs:
|
||||
return [tup[0] for tup in lst if tup[0]]
|
||||
return [tup for tup in lst if tup[0]]
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ class EvAdventureMob(EvAdventureNPC):
|
|||
"""
|
||||
self.at_death()
|
||||
|
||||
def at_loot(self, looted):
|
||||
def at_do_loot(self, looted):
|
||||
"""
|
||||
Called when mob gets to loot a PC.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,3 +2,47 @@
|
|||
Various utilities.
|
||||
|
||||
"""
|
||||
|
||||
_OBJ_STATS = """
|
||||
|c{key}|n Value: approx. |y{value}|n coins {carried}
|
||||
|
||||
{desc}
|
||||
|
||||
Slots: |w{size}|n Used from: |w{use_slot_name}|n
|
||||
Quality: |w{quality}|n Uses: |wuses|n
|
||||
Attacks using: |w{attack_type_name}|n against |w{defense_type_value}|n
|
||||
Damage roll: |w{damage_roll}""".strip()
|
||||
|
||||
|
||||
def get_obj_stats(obj, owner=None):
|
||||
"""
|
||||
Get a string of stats about the object.
|
||||
|
||||
Args:
|
||||
obj (EvAdventureObject): The object to get stats for.
|
||||
owner (EvAdventureCharacter, optional): If given, it allows us to
|
||||
also get information about if the item is currently worn/wielded.
|
||||
|
||||
Returns:
|
||||
str: A stat string to show about the object.
|
||||
|
||||
"""
|
||||
carried = ""
|
||||
if owner:
|
||||
objmap = dict(owner.equipment.all())
|
||||
carried = objmap.get(obj)
|
||||
carried = f"Worn: [{carried.value}]" if carried else ""
|
||||
|
||||
return _OBJ_STATS.format(
|
||||
key=obj.key,
|
||||
value=obj.value,
|
||||
carried=carried,
|
||||
desc=obj.db.desc,
|
||||
size=obj.size,
|
||||
use_slot=obj.use_slot.value,
|
||||
quality=obj.quality,
|
||||
uses=obj.uses,
|
||||
attack_type=obj.attack_type.value,
|
||||
defense_type=obj.defense_type.value,
|
||||
damage_roll=obj.damage_roll,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1744,10 +1744,11 @@ def ask_yes_no(
|
|||
**kwargs,
|
||||
):
|
||||
"""
|
||||
A helper question for asking a simple yes/no question. This will cause
|
||||
A helper function for asking a simple yes/no question. This will cause
|
||||
the system to pause and wait for input from the player.
|
||||
|
||||
Args:
|
||||
caller (Object): The entity being asked.
|
||||
prompt (str): The yes/no question to ask. This takes an optional formatting
|
||||
marker `{options}` which will be filled with 'Y/N', '[Y]/N' or
|
||||
'Y/[N]' depending on the setting of `default`. If `allow_abort` is set,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue