Beispiel #1
0
class Furniture(object):
	""" Any object placed on map that is not a part of the terrain.
	Like stairs, doors, levers etc or even inert objects like statues.
	"""
	class Locked(Exception): # pragma: no cover
		""" Should be thrown when object is locked and requires specific item. """
		def __init__(self, key_item_type):
			self.key_item_type = key_item_type
		def __str__(self):
			return "Locked; required {0} to unlock".format(self.key_item_type)
	sprite = classfield('_sprite', '?')
	name = classfield('_name', 'object')
Beispiel #2
0
class LevelPassage(Furniture):
	""" Object that allows travel between levels.
	Each passage should be connected to another passage on target level.
	Passages on the same level are differentiated by ID.
	Passage ID can be an arbitrary value.
	"""
	id = classfield('_id', 'enter')
	can_go_down = classfield('_can_go_down', False)
	can_go_up = classfield('_can_go_up', False)
	def __init__(self, level_id, connected_passage): # pragma: no cover
		self.level_id = level_id
		self.connected_passage = connected_passage
	def use(self, who): # pragma: no cover
		""" Additional actions performed before actual travelling.
		By default there are none.
		"""
		pass
Beispiel #3
0
class MessageEvent(object):
	""" Simple text message with formatting.
	Each subclass should overrider field _message.
	Placeholders should be named and correspond to keyword args which are used to create new event.
	Formatted message is available via operator str().
	"""
	message = classfield('_message', '')
	def __init__(self, **kwargs):
		self.keywords = kwargs
	def __str__(self):
		return self.message.format(**(self.keywords))
Beispiel #4
0
class Monster(object):
	def __init__(self):
		self.pos = None
		self.wielding = None
		self.wearing = None
		self.inventory = []
		self.hp = self.max_hp
	sprite = classfield('_sprite', NotImplemented)
	name = classfield('_name', NotImplemented)
	max_hp = classfield('_max_hp', 0)
	base_attack = classfield('_attack', None)
	drops = classfield('_drops', [])
	max_inventory = classfield('_max_inventory', [])
	hostile_to = classfield('_hostile_to', [])
	def is_hostile_to(self, other):
		""" Return True if this monster is hostile towards other monster and can attack it. """
		for monster_class in self.hostile_to:
			if isinstance(other, monster_class):
				return True
		return False
	def heal(self, amount):
		""" Increase health by specified amount, but no more than max_hp. """
		assert amount >= 0
		self.hp += amount
		if self.hp > self.max_hp:
			self.hp = self.max_hp
	def has_item(self, item_class, **properties):
		""" Returns True if inventory contains an item of specified class
		with exact values for given properties.
		"""
		for item in self.inventory:
			if not isinstance(item, item_class):
				continue
			for name, expected_value in properties.items():
				if not hasattr(item, name) or getattr(item, name) != expected_value:
					break
			else:
				return True
		return False
	def _unequip(self, item):
		events = []
		if self.wielding == item:
			self.wielding = None
			events.append(Event.Unwielding(self, item))
		if self.wearing == item:
			self.wearing = None
			events.append(Event.TakingOff(self, item))
		return events
	def wield(self, item):
		""" Tries to wield item.
		Returns list of happened events.
		"""
		if item is None:
			events = []
			if self.wielding:
				events.append(Event.Unwielding(self, self.wielding))
			self.wielding = None
			return events
		events = self._unequip(item)
		if self.wielding:
			events.append(Event.Unwielding(self, self.wielding))
			self.wielding = None
		self.wielding = item
		events.append(Event.Wielding(self, item))
		return events
	def wear(self, item):
		""" Tries to wear item.
		Returns list of happened events.
		"""
		if item is None:
			events = []
			if self.wearing:
				events.append(Event.TakingOff(self, self.wearing))
			self.wearing = None
			return events
		if not isinstance(item, Wearable):
			return [Event.NotWearable(item)]
		events = self._unequip(item)
		if self.wearing:
			events.append(Event.TakingOff(self, self.wearing))
			self.wearing = None
		self.wearing = item
		events.append(Event.Wearing(self, item))
		return events
	def drop(self, item):
		""" Tries to drop item from inventory.
		Returns list of happened events.
		"""
		events = self._unequip(item)
		self.inventory.remove(item)
		events.append(Event.MonsterDroppedItem(self, item))
		return events
	def consume(self, item):
		""" Tries to consume item.
		Returns list of happened events.
		"""
		if not isinstance(item, Consumable):
			return [Event.NotConsumable(item)]
		events = self._unequip(item)
		if not item.consume_by(self):
			return events
		self.inventory.remove(item)
		events.append(Event.MonsterConsumedItem(self, item))
		return events
	def get_attack_damage(self):
		""" Final attack damage with all modifiers. """
		if self.base_attack is None:
			return 0
		result = self.base_attack
		if self.wielding:
			result += self.wielding.attack
		return result
	def get_protection(self):
		""" Final protection from damage with all modifiers. """
		if self.wearing:
			return self.wearing.protection
		return 0
	def is_alive(self):
		return self.hp > 0
	def attack(self, other):
		""" Inflicts damage on other actor (considering all modifiers on both actors).
		Returns value of real inflicted damage.
		"""
		damage = max(0, self.get_attack_damage() - other.get_protection())
		other.hp -= damage
		return damage
	def __setstate__(self, data): # pragma: no cover -- TODO
		self.inventory = []
		self.pos = data.pos
		self.inventory = data.inventory
		self.wielding = None
		if 'wielding' in data:
			wielding = data.wielding
			if wielding is not None:
				self.wielding = self.inventory[wielding]
		self.wearing = None
		if 'wearing' in data:
			wearing = data.wearing
			if wearing is not None:
				self.wearing = self.inventory[wearing]
		if data.get('hp'):
			self.hp = data.hp
		else:
			self.hp = self.max_hp
	def __getstate__(self): # pragma: no cover -- TODO
		data = dotdict()
		data._class = self.__class__.__name__
		data.pos = self.pos
		data.inventory = self.inventory
		data.hp = self.hp
		data.wielding = self.inventory.index(self.wielding) if self.wielding else None
		data.wearing = self.inventory.index(self.wearing) if self.wearing else None
		return data
Beispiel #5
0
class Wearable(object):
	protection = classfield('_protection', 0)
Beispiel #6
0
class Item(object):
	""" Basic pickable and carryable item. """
	sprite = classfield('_sprite', '*')
	name = classfield('_name', 'mcguffin')
	attack = classfield('_attack', 0)
Beispiel #7
0
 class BaseField:
     name = utils.classfield('_name', 'default')