import contextlib import libtcodpy as libtcod from objects import Object, Fighter import mods def get_pos_pair(x,y): if y is None: if hasattr(x, '__iter__'): x,y = x elif hasattr(x,'x'): x,y = x.x,x.y else: x,y = x.pos return x,y import collections class Slot(object): def __init__(self): self.limit = None self.items = [] @property def display_name(self): if self.items != []: return '%s (x%s)' % (self.items[0].name, len(self.items)) @property def ident(self): if self.items != []: return self.items[0].name def empty(self): return len(self.items) == 0 def _add_item(self, item): self.items.append(item) return True def add_item(self, item): result = False if self.limit is None or len(self.items) <= self.limit: if self.items == []: self.limit = item.item.stack_limit print 'no items' return self._add_item(item) elif (len(self.items) < self.limit) and (self.ident == item.name): print 'add_items %d' % len(self.items) return self._add_item(item) elif self.ident != item.name: raise ValueError('Cannot stack %s with %s' % (self.ident, item.ident)) return result def get_item(self, default=None): result = default if self.items != []: result = self.items[-1] return result def consume(self): self.items.pop() class Inventory(object): def __init__(self): self.objects = {} def __iter__(self): for v in self.objects.itervalues(): for i in v: yield i def __len__(self): return sum(len(x) for x in self.objects.values()) def __contains__(self, it): return it.ident in self.objects def __getitem__(self, k): return self.objects[k][-1].get_item() def __setitem__(self, k,v): if v.ident != k: raise ValueError('Inventory key must equal the item\'s name') self.add_item(v) def keys(self): return self.objects.keys() def add_item(self, item): print 'add_item', item.name slot = self.objects.setdefault(item.name, [Slot()]) while not slot[-1].add_item(item): print 'add slot' slot.append(Slot()) def __delitem__(self, k): self.objects[k][-1].consume() while self.objects[k] != [] and self.objects[k][-1].empty(): self.objects[k].pop() else: if self.objects[k] == []: del self.objects[k] class Player(Object): def triggers_recompute(func): def _inner(self, *a, **kw): self.fov_recompute = True return func(self, *a, **kw) return _inner @triggers_recompute def __init__(self, map, con, x,y, char, color, fighter=None, level=None): Object.__init__(self, None, con, x,y, char, libtcod.namegen_generate('Celtic male'), color, True, fighter=fighter, level=level ) map.player = self self.inventory = Inventory() self.mods = Inventory() class Item: stack_limit = 5 obj = Object(None, con, None,None, 'b', 'boost', color, item=Item()) obj.mod = mods.Boost() self.mods.add_item(obj) def draw(self, player=None): if player is None: player = self return Object.draw(self, player) def pick_up(self, obj): # TODO: limit number of items if len(self.inventory) >= 26: game.message('Your inventory is full, cannot pick up %s' % obj.name, libtcod.red) elif obj is not None: self.inventory.add_item( self.level.claim_object(obj).item.bind_user(self) # returns item.owner ) game.message('you picked up a %s!' % obj.name, libtcod.green) return self def drop(self, obj): obj = self.inventory[obj.name] obj.x, obj.y = self.x, self.y self.level.add_object(obj) del self.inventory[obj.name] return obj def use(self, item): item.owner.enter_level(self.level) success = item.use() if success: del self.inventory[item.name] @contextlib.contextmanager def recategorize_item(self, item_name): item = self.inventory[item_name] yield item del self.inventory[item_name] self.inventory.add_item(item) def modify(self, item_name, mod_name): mod = self.mods[mod_name] with self.recategorize_item(item_name) as item: item.item.modify(mod.mod) del self.mods[mod_name] print list(self.mods) def unmodify(self, item_name, mod_name): with self.recategorize_item(item_name) as item: item.item.unmodify(mod_name) print list(self.mods) def get_mod(self, index): return self.mods[index].mod def get_mod_names(self): return [item.display_name for item in self.mods] def get_mods(self): return [item for item in self.mods] def get_item(self, index): return self.inventory[index].item def get_item_names(self): return [item.display_name for item in self.inventory] def get_items(self): return [item for item in self.inventory] def tick(self): if self.fighter: self.fighter.tick() def can_see(self, x,y=None): x,y = get_pos_pair(x,y) return self.level.is_visible(x,y) torch_radius = 19 @property def pos(self): return self.x, self.y @pos.setter def pos(self, val): #print 'pos:', val self.x, self.y = val @triggers_recompute def move(self, dx, dy): result = Object.move(self, dx,dy) return result def move_or_attack(self, dx, dy): x = self.x + dx y = self.y + dy import monsters target = monsters.monster_at(x,y) if target is not None: self.fighter.attack(target) else: self.move(dx, dy) def enter_level(self, level): print '\nenter level\n' self.level = level level.enter(self) self.x, self.y = self.level.map.map_entrance return self def get_room(self): for room in self.level.map.gen.rooms: if self.pos in room: return room import game