Wieldables.
authorNeil Moore <neil@s-z.org>
Wed, 28 May 2008 02:13:30 +0000 (22:13 -0400)
committerNeil Moore <neil@s-z.org>
Wed, 28 May 2008 02:13:30 +0000 (22:13 -0400)
items/items.itm:
  Rearrange item hierarchy (new base class 'wieldable').

things.py:
  New item attribute 'wielded': either None, or a (Player, slotname) pair.
  New item attribute 'slot' (where the item may be wielded, or None).
    Typically set in the item class; None in the base.
  New methods Item.unwield, Creature.wield/unwield, Item.wieldable.
  New module-level dict of slot abbreviations (for the inventory screen).
  Move inv and Player.pick_up to Creature.
  Override Item.place to unwield the item if neceesary.

roguelike.py:
  New commands 'wield' and 'unwield', with keybindings 'w' and 'W'.
  Show slot abbreviation for wielded items in inventory screen.

items/items.itm
roguelike.py
things.py

index a65d465..9b487d6 100644 (file)
@@ -12,8 +12,14 @@ money {
        material: gold,
 },
 
+wieldable {
+       slot: unspecified
+},
+
 weapon {
+       isa: wieldable,
        ascii: ")",
+       slot: hand,
 },
 
 sword {
@@ -22,10 +28,13 @@ sword {
 },
 
 armor {
+       isa: wieldable,
        ascii: "[",
+       slot: body,
 },
 
 shield {
        isa: armor,
        material: wood,
+       slot: arm,
 },
index fb3d865..1bb5352 100755 (executable)
@@ -87,6 +87,8 @@ class AppUI:
                 'traverse':     self.try_traverse,
                 'save':         self.save,
                 'switch':       lambda: self.switch() and False,
+                'wield':        self.try_wield,
+                'unwield':      self.try_unwield,
                 }
         self.keymap = {
                 curses.KEY_UP:    'north',
@@ -104,6 +106,8 @@ class AppUI:
                 ord('c'):         'close',
                 ord('>'):         'traverse',
                 ord('@'):         'switch',
+                ord('w'):         'wield',
+                ord('W'):         'unwield',
                 }
 
     def message(self, msg=None):
@@ -111,7 +115,7 @@ class AppUI:
         if msg == None:
             msgwin.erase()
         else:
-            msgwin.addnstr(0, 0, msg, self.scrw - 1)
+            msgwin.addnstr(0, 0, msg, self.scrw - 1, ui.Color('White').cp)
         msgwin.refresh()
 
     def get_direction(self):
@@ -149,6 +153,10 @@ class AppUI:
                         w-6)
                 (ascii, attr) = item.render()
                 win.addstr(i+1, w-3, ascii, attr)
+                if item.wielded:
+                    slotabbr = things.slotabbrevs[item.wielded[1]]
+                    win.addstr(i+1, w-2, slotabbr, ui.Color('Cyan').cp)
+
         self.invpanel.show()
         win.refresh()
         while 1:
@@ -172,6 +180,34 @@ class AppUI:
         else:
             it.place(self.location())
             return True
+    
+    def try_wield(self):
+        it = self.draw_inventory()
+        if not it:
+            return False
+        if not it.wieldable():
+            self.message("%s is not wieldable" % (it,))
+            return False
+        if self.player.wield(it):
+            self.message("Wielded %s in %s" % (it,it.wielded[1]))
+            return True
+        else:
+            self.message("Could not wield %s" % (it,))
+            return False
+    
+    def try_unwield(self):
+        it = self.draw_inventory()
+        if not it:
+            return False
+        if not it.wielded:
+            self.message("Not wielding %s" % (it,))
+            return False
+        if self.player.unwield(it):
+            self.message("Unwielded %s" % (it,))
+            return True
+        else:
+            self.message("Could not unwield %s" % (it,))
+            return False
 
     def try_throw(self):
         it = self.draw_inventory()
index 0cefd94..8d1bf5d 100644 (file)
--- a/things.py
+++ b/things.py
@@ -131,14 +131,35 @@ class Thing (object):
             return False
 
 class Item(Thing):
+    wielded = None
+    slot = None
     def is_item(self):
         return True
     def render(self, pic=None):
         return (self.ascii, self.material.attr())
-
+    def wieldable(self):
+        return self.slot is not None
+    def place(self, location):
+        if self.wielded:
+            self.unwield()
+        super(Item, self).place(location)
+    def unwield(self):
+        if self.wielded:
+            # Have the holder unwield it
+            self.wielded[0].unwield(self)
+
+slotabbrevs = { 'hand': 'H', 'arm': 'A', 'body': 'B' }
 class Creature(Thing):
     def __init__(self, location=None):
         Thing.__init__(self, location)
+        self.inv = loc.Inventory(self)
+        self.slots = { 'hand': None, 'arm': None, 'body': None }
+    def holding(self, name):
+        return self.slots[name]
+    def is_wielding(self, item):
+        return item in self.slots
+    def invalidate(self):
+        self.location.invalidate(important = True)
     def vis_radius(self):
         return 5
     def can_see(self, y, x):
@@ -173,22 +194,48 @@ class Creature(Thing):
         return self.try_move(self.location.west())
     def move_east(self):
         return self.try_move(self.location.east())
+    def pick_up(self):
+        it = self.location.top_item()
+        if it:
+            it.try_move(self.inv)
+            return True
+        else:
+            return False
+    def wield(self, item):
+        assert item in self.inv, (
+                "%s is wielding item %s not in inventory" % (self, item))
+        assert item.wieldable(), (
+                "%s trying to wield the unwieldable %s" % (self, item))
+        assert not item.wielded, (
+                "%s trying to wield %s, already wielded by %s"
+                % (self, item, item.wielded))
+        slot = item.slot
+        if self.holding(slot):
+            self.unwield(self.holding(slot))
+        self.slots[slot] = item
+        item.wielded = (self, slot)
+        return True
+
+    def unwield(self, item):
+        assert item in self.inv, (
+                "%s is unwielding item %s not in inventory" % (self, item))
+        assert item.wielded, (
+                "%s trying to unwield already unwielded %s" % (self, item))
+
+        (creat, slot) = item.wielded
+        assert creat is self, "%s unwielding %s's %s" % (self, creat, item)
+        assert self.holding(slot) is item, (
+                "%s unwielding %s from wrong hand %s?" % (self, item, slot))
+
+        item.wielded = None
+        self.slots[slot] = None
+        return True
 
 class Player(Creature):
     def __init__(self, location=None):
         Creature.__init__(self, location)
-        self.inv = loc.Inventory(self)
         self.active = False
-    def invalidate(self):
-        self.location.invalidate(important = True)
     def render(self, pic=None):
         return ("@", ui.Color(('Bright' if self.active else '') + 'Magenta').cp)
     def can_swim(self):
         return random.random() < .5
-    def pick_up(self):
-        it = self.location.top_item()
-        if it:
-            it.try_move(self.inv)
-            return True
-        else:
-            return False