Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
event.world.change_map(portal.destination)
class PortalUpstairs(Portal):
pass
@Ascend.perform(PortalUpstairs)
def do_ascend_stairs(event, portal):
event.world.change_map(portal.destination)
# -----------------------------------------------------------------------------
# Doors
class IOpenable(IComponent):
open = static_attribute("""Whether I'm currently open.""")
class Openable(Component, interface=IOpenable):
def __init__(self, *, open=False):
self.open = open
# TODO maybe this merits a check rule? maybe EVERYTHING does.
# TODO only if closed
@Open.perform(Openable)
def do_open(event, openable):
openable.open = True
class ILockable(IComponent):
return sprite, color
health -= weight
@property
def sprite(self):
return self.current_rendering()[0]
@property
def color(self):
return self.current_rendering()[1]
# -----------------------------------------------------------------------------
# Physics
class IPhysics(IComponent):
def blocks(actor):
"""Return True iff this object won't allow `actor` to move on top of
it.
"""
# TODO i'm starting to think it would be nice to eliminate the dummy base class
# i have for like every goddamn component? but how?
# TODO seems like i should /require/ that every entity type has a IPhysics,
# maybe others...
class Physics(Component, interface=IPhysics):
pass
class Solid(Physics):
def blocks(self, actor):
@Walk.check(DoorPhysics)
def cant_walk_through_closed_doors(event, door):
if not IOpenable(door.entity).open:
event.cancel()
@Walk.perform(Physics)
def do_walk(event, _):
event.world.current_map.move(event.actor, event.target.position)
# -----------------------------------------------------------------------------
# Map portal
class IPortal(IComponent):
destination = static_attribute("Name of the destination map.")
class Portal(Component, interface=IPortal):
def __init__(self, *, destination):
self.destination = destination
class PortalDownstairs(Portal):
pass
@Descend.perform(PortalDownstairs)
def do_descend_stairs(event, portal):
event.world.change_map(portal.destination)
def __getattr__(self, key):
cls = type(self)
try:
return self.entity[cls, key]
except KeyError:
raise AttributeError
###############################################################################
# Particular interfaces and components follow.
# -----------------------------------------------------------------------------
# Rendering
class IRender(IComponent):
# TODO consolidate these into a single some-kind-of-object
sprite = static_attribute("")
color = static_attribute("")
class Render(Component, interface=IRender):
def __typeinit__(self, sprite, color):
self.sprite = sprite
self.color = color
class OpenRender(Component, interface=IRender):
def __typeinit__(self, *, open, closed, locked):
self.open = open
self.closed = closed
self.locked = locked
log.info("ooh picking up {}".format(portable.entity.type.name))
# -----------------------------------------------------------------------------
# Equipment
class IBodied(IComponent):
wearing = derived_attribute("")
# TODO this direly wants, like, a list of limbs and how many
class Bodied(Component, interface=IBodied):
wearing = RelationSubject(Wearing)
class IEquipment(IComponent):
# worn_by?
modifiers = static_attribute("Stat modifiers granted by this equipment.")
class Equipment(Component, interface=IEquipment):
# TODO i think this should live on Bodied as a simple dict of body part to
# equipment
# TODO problem is that if the player loses the item /for any reason
# whatsoever/, the item needs to vanish from the dict. ALSO, the existence
# of the item in the dict can block some other actions.
worn_by = RelationObject(Wearing)
def __typeinit__(self, *, modifiers=None):
self.modifiers = modifiers or ()
# TODO recurring problems with events:
def __typeinit__(self, *, health):
self.maximum_health = health
self.current_health = health
# TODO breakables don't /have/ strength. is this separate?
# TODO should interfaces/components be able to say they can only exist
# for entities that also support some other interface?
self.strength = 0
def __init__(self, health_fraction):
self.current_health = health_fraction * self.maximum_health
# -----------------------------------------------------------------------------
# AI
class IActor(IComponent):
"""Implements an entity's active thought process. An entity with an
`IActor` component can decide to perform actions on its own, and has a
sense of speed and time.
"""
def act(world):
"""Return an action to be performed (i.e., an `Event` to be fired), or
`None` to do nothing.
it.
"""
class GenericAI(Component, interface=IActor):
def act(self, world):
from flax.geometry import Direction
from flax.event import Walk
from flax.event import MeleeAttack
# does this
IContainer(event.actor).inventory.remove(event.agent)
@Open.check(Lockable)
def cant_open_locked_things(event, lockable):
if lockable.locked:
log.info("it's locked")
event.cancel()
# -----------------------------------------------------------------------------
# Containment
class IContainer(IComponent):
inventory = static_attribute("Items contained by this container.")
class Container(Component, interface=IContainer):
# TODO surely this isn't called when something is polymorphed. right?
# or... maybe it is, if the entity didn't have an IContainer before?
def __init__(self):
self.inventory = []
# -----------------------------------------------------------------------------
# Combat
class ICombatant(IComponent):
"""Implements an entity's ability to fight and take damage."""
maximum_health = static_attribute("Entity's maximum possible health.")
def do_pick_up(event, portable):
from flax.entity import Layer
assert portable.entity.type.layer is Layer.item
event.world.current_map.remove(portable.entity)
IContainer(event.actor).inventory.append(portable.entity)
@PickUp.announce(Portable)
def announce_pick_up(event, portable):
log.info("ooh picking up {}".format(portable.entity.type.name))
# -----------------------------------------------------------------------------
# Equipment
class IBodied(IComponent):
wearing = derived_attribute("")
# TODO this direly wants, like, a list of limbs and how many
class Bodied(Component, interface=IBodied):
wearing = RelationSubject(Wearing)
class IEquipment(IComponent):
# worn_by?
modifiers = static_attribute("Stat modifiers granted by this equipment.")
class Equipment(Component, interface=IEquipment):
# TODO i think this should live on Bodied as a simple dict of body part to
# equipment
return
# TODO try to walk towards player
world.queue_event(Walk(self.entity, random.choice(list(Direction))))
class PlayerIntelligence(Component, interface=IActor):
def act(self, world):
if world.player_action_queue:
world.queue_immediate_event(world.player_action_queue.popleft())
# -----------------------------------------------------------------------------
# Items
class IPortable(IComponent):
"""Entity can be picked up and placed in containers."""
class Portable(Component, interface=IPortable):
pass
# TODO maybe "actor" could just be an event target, and we'd need fewer
# duplicate events for the source vs the target?
@PickUp.perform(Portable)
def do_pick_up(event, portable):
from flax.entity import Layer
assert portable.entity.type.layer is Layer.item
event.world.current_map.remove(portable.entity)
IContainer(event.actor).inventory.append(portable.entity)
open = static_attribute("""Whether I'm currently open.""")
class Openable(Component, interface=IOpenable):
def __init__(self, *, open=False):
self.open = open
# TODO maybe this merits a check rule? maybe EVERYTHING does.
# TODO only if closed
@Open.perform(Openable)
def do_open(event, openable):
openable.open = True
class ILockable(IComponent):
locked = static_attribute("""Whether I'm currently locked.""")
class Lockable(Component, interface=ILockable):
def __init__(self, *, locked=False):
self.locked = locked
# TODO maybe this merits a check rule? maybe EVERYTHING does.
# TODO only if closed
@Unlock.perform(Lockable)
def do_unlock(event, lockable):
# TODO check that the key is a key, player holds it, etc. (inform has
# touchability rules for all this...)
lockable.locked = False