git.fiddlerwoaroof.com
items.py
539d5ff4
 from __future__ import division
b9c8e0f9
 import collections
1d2d26d2
 import os.path
 import glob
 import yaml
539d5ff4
 
76408e86
 import libtcodpy as libtcod
 import game
 import objects
 import utilities
 import monsters
 import random
1d2d26d2
 from main import Game
76408e86
 
 
 class Item(object):
70928ad3
 	stack_limit = 5
b9c8e0f9
 	potency = None
 	item_class = None
 	distance = None
 	probability = 1
 
1d2d26d2
 	def __init__(self, stackable=False):
b9c8e0f9
 		self.mods = collections.defaultdict(set)
1d2d26d2
 
76408e86
 	def __new__(*args):
 		res = object.__new__(*args)
 		return res
1d2d26d2
 	def bind_game(self, game):
 		self.game = game
 	def bind_user(self, user):
 		self.user = user
 		return self.owner
 	def free_user(self):
 		self.user = None
 		return self.owner
 
b9c8e0f9
 	def modify(self, mod):
 		undo = mod.modify(self)
 		self.mods[mod.name].add(mod)
 		self.owner.name = self.name
 
 	def unmodify(self, mod):
 		if hasattr(mod, 'upper'):
 			mods = self.mods[mod]
 		else:
 			mods = self.mods[mod.name]
 		if mods != set():
 			mod = mods.pop()
 			mod.revert(self)
 			self.owner.name = self.name
 			if mods == set():
 				self.mods.pop(mod.name)
 			print 'self.mods', self.mods
 
1d2d26d2
 class ItemLoader(object):
 	def __init__(self, dir):
 		self.dir = dir
 
 	def load_items(self):
 		for fn in glob.glob(os.path.join(self.dir,'*.yml')):
 			print 'fn', fn
 			for doc in yaml.safe_load_all(file(fn)):
 				self.load_item(doc)
 
 	def load_item(self, doc):
b9c8e0f9
 		if doc is None: return
 
1d2d26d2
 		_color = doc.get('color', None)
 		if _color is None:
 			_color = libtcod.green
 		elif hasattr(_color, 'upper'):
 			_color = getattr(libtcod, _color)
 		else:
 			_color = libtcod.Color(*_color)
 
 		item_class = doc['item_class']
 		module, clas = item_class.rsplit('.',1)
 		module = __import__(module)
 		item_class = getattr(module, clas)
 		print 'item class:', item_class
 
 		print 'loading', doc
 		@Game.register_item_type(doc['spawn_chance'])
 		class LoadedItem(item_class):
 			name = doc.get('item_description')
 			char = doc.get('char', '!')
 			color = _color
70928ad3
 			stack_limit = doc.get('stack_limit', Item.stack_limit)
b9c8e0f9
 			potency = doc.get('potency')
 			distance = doc.get('distance')
1d2d26d2
 
76408e86
 
2dda4cb6
 @Game.register_item_type(10)
76408e86
 class HealingPotion(Item):
 	name = 'Healing potion'
 	char = '\x03'
 	color = libtcod.violet
2dda4cb6
 	potency = 15
b9c8e0f9
 	item_class = 'healing'
76408e86
 	def use(self):
 		fighter = self.user.fighter
 
 		result = True
 		if fighter.hp == fighter.max_hp:
b9c8e0f9
 			self.game.message('Full health, can\'t heal', libtcod.red)
76408e86
 			result = False
 		else:
1d2d26d2
 			self.game.message('Healing...')
b9c8e0f9
 			fighter.heal(self.potency)
76408e86
 
 		return result
 
2dda4cb6
 @Game.register_item_type(7)
76408e86
 class SuperHealingPotion(Item):
 	name = 'Super healing potion'
 	char = '\x03'
 	color = libtcod.yellow
b9c8e0f9
 	probability = .5
 	potency = 10
 	item_class = 'healing'
76408e86
 	def use(self):
 		fighter = self.user.fighter
b9c8e0f9
 		if random.random() < self.probability:
 			fighter.max_hp += self.potency
 		fighter.heal(self.potency)
76408e86
 		return True
 
 @Game.register_item_type(1)
 class Confusion(Item):
 	name = 'Confusion'
 	char = 'c'
 	color=libtcod.dark_chartreuse
b9c8e0f9
 	item_class = 'monster defense'
76408e86
 	def use(self):
 		monster = monsters.get_closest_monster(self.user)
 
 		result = False
 		if monster is not None:
1d2d26d2
 			self.game.message('%s becomes confused' % monster.name)
76408e86
 			monsters.ConfusedMonster(random.randrange(10,18)).attach(
 				monster
 			)
 			result = True
 
 		return result
 
 @Game.register_item_type(4)
 class Strengthen(Item):
 	name = 'Strengthen'
 	char = 's'
 	color = libtcod.chartreuse
b9c8e0f9
 	item_class = 'attack'
 	potency = 20
76408e86
 	def use(self):
 		if self.user.fighter:
1d2d26d2
 			self.game.message('%s feels a surge of strength' % self.user.name)
b9c8e0f9
 			self.user.fighter.stat_adjust(self.potency, self.adj)
76408e86
 		return True
 
 	def adj(self, owner):
 		return (
1d2d26d2
 			lambda _: self.game.message('The surge of strength has subsided'),
76408e86
 			owner.fighter.defense,
 			owner.fighter.power+3
 		)
 
 @Game.register_item_type(4)
 class Protect(Item):
 	name = 'Protect'
 	char = 'p'
 	color = libtcod.chartreuse
b9c8e0f9
 	item_class = 'defense'
 	potency = 15
76408e86
 	def use(self):
 		if self.user.fighter:
1d2d26d2
 			self.game.message('%s is surrounded by a protecting aura' % self.user.name)
b9c8e0f9
 			self.user.fighter.stat_adjust(self.potency, self.adj)
76408e86
 		return True
 
 	def adj(self, owner):
 		return (
1d2d26d2
 			lambda _: self.game.message('The protecting aura dissipates'),
76408e86
 			owner.fighter.defense+6,
 			owner.fighter.power
 		)
 
 @Game.register_item_type(2)
 class LightningBolt(Item):
 	name = 'Lightning Bolt'
 	char = 'z'
 	color = libtcod.darkest_red
b9c8e0f9
 	item_class = 'attack'
 	potency = 13
76408e86
 	def use(self):
 		monster = monsters.get_closest_monster(self.user)
 		result = False
 		if monster and self.user.can_see(monster.x, monster.y):
1d2d26d2
 			self.game.message('Monster %s has been struck by lightning' % monster.name)
b9c8e0f9
 			monster.fighter.take_damage(self.potency)
76408e86
 			result = True
 		else:
1d2d26d2
 			self.game.message('No target')
76408e86
 		return result
 
539d5ff4
 @Game.register_item_type(5)
 class Jump(Item):
 	name = 'Jump'
 	char = 'j'
 	color= libtcod.dark_green
b9c8e0f9
 	distance = 3
 	item_class = 'movement'
539d5ff4
 	def use(self):
1d2d26d2
 		self.game.select(self.jump)
539d5ff4
 		return True
 	def jump(self, x,y):
 		dist = self.user.distance(x,y)
 
b9c8e0f9
 		if dist <= self.distance:
539d5ff4
 			self.user.x, self.user.y = x,y
1d2d26d2
 			self.game.message('you are transported to a new place')
b9c8e0f9
 		elif random.random() < self.distance/dist:
539d5ff4
 			self.user.x, self.user.y = x,y
1d2d26d2
 			self.game.message('you strain all your power to move %d squares' % int(dist))
539d5ff4
 		else:
1d2d26d2
 			self.game.message('you didn\'t make it')
b9c8e0f9
 			self.user.fighter.take_damage( int(round(2 * dist/self.distance)) )
539d5ff4
 
 @Game.register_item_type(3)
 class Acquire(Item):
 	name = 'Acquire'
 	char = 'a'
 	color= libtcod.dark_green
 	effect_distance = 5
b9c8e0f9
 	item_class = 'pickup'
539d5ff4
 	def use(self):
1d2d26d2
 		self.game.message('what do you want?')
 		self.game.select(self.get)
539d5ff4
 		return True
 	def get(self, x,y):
 		if self.user.distance(x,y) < self.effect_distance:
 			self.user.pick_up(self.user.object_at(x,y))
 
76408e86
 
 @Game.register_item_type(1)
 class Smite(Item):
 	name = 'Smite'
 	char = '\x0f'
 	color = libtcod.red
b9c8e0f9
 	item_class = 'attack'
 	potency = 10
76408e86
 	def use(self):
1d2d26d2
 		self.game.select(self.smite)
76408e86
 		return True
 
 	def smite(self, x,y):
 		monster = monsters.monster_at(x,y)
 		if monster:
b9c8e0f9
 			monster.fighter.take_damage(self.potency)
76408e86
 			if monster.fighter:
1d2d26d2
 				self.game.message('%s is smitten, he only retains %s hp' % (monster.name, monster.fighter.hp))
539d5ff4
 			else:
1d2d26d2
 				self.game.message('%s thought it better to go elsewhere' % monster.name)
76408e86
 
 
539d5ff4
 @Game.register_item_type(2)
76408e86
 class Fireball(Item):
 	name = 'Fireball'
 	char = '*'
 	color = libtcod.darker_red
05dddf7e
 	effect_radius = 5
b9c8e0f9
 	potency = (20,6)
 	item_class = 'splash attack'
76408e86
 
 	def use(self):
1d2d26d2
 		self.game.select(self.smite)
76408e86
 		return True
 
 	def smite(self, x,y):
539d5ff4
 		if random.random() < .1:
b9c8e0f9
 			self.game.message('the fireball is amazingly effective', libtcod.green)
539d5ff4
 			self.effect_radius *= 2
 
b9c8e0f9
 		direct_damage, splash_damage = self.potency
76408e86
 		strikes = []
 		for obj in self.owner.level.objects:
 			if obj.fighter and obj is not self.user:
 				if (obj.x, obj.y) == (x,y):
1d2d26d2
 					self.game.message('%s takes a direct hit from the fireball' % obj.name)
b9c8e0f9
 					obj.fighter.take_damage(direct_damage)
76408e86
 				elif obj.distance(x,y) < self.effect_radius:
b9c8e0f9
 					obj.fighter.take_damage(splash_damage)
76408e86
 					if obj.fighter:
 						strikes.append('%s %s' % (obj.name, obj.fighter.hp))
 					else:
 						strikes.append('%s dead' % obj.name)
1d2d26d2
 		self.game.message('The names of those who were to close for comfort: %s' % ', '.join(strikes))
76408e86