t.position = list(yx)
 cmd_THING_POS.argtypes = 'int:nonneg yx_tuple:nonneg'
 
+def cmd_THING_INVENTORY(game, id_, ids):
+    t = game.world.get_thing(id_)
+    t.inventory = [ids]  # TODO: test whether valid IDs
+cmd_THING_INVENTORY.argtypes = 'int:nonneg, seq:int:nonneg'
+
 def cmd_TERRAIN_LINE(game, y, terrain_line):
     game.world.map_.set_line(y, terrain_line)
 cmd_TERRAIN_LINE.argtypes = 'int:nonneg string'
             write(f, 'THING_TYPE %s %s' % (thing.id_, thing.type_))
             write(f, 'THING_POS %s %s' % (thing.id_,
                                           stringify_yx(thing.position)))
+            write(f, 'THING_INVENTORY %s %s' % (thing.id_,
+                                                ','.join([str(i) for i in
+                                                          thing.inventory])))
             if hasattr(thing, 'task'):
                 task = thing.task
                 if task is not None:
 
-from plomrogue.tasks import Task_WAIT, Task_MOVE
+from plomrogue.tasks import Task_WAIT, Task_MOVE, Task_PICKUP, Task_DROP
 from plomrogue.errors import ArgError
 from plomrogue.commands import (cmd_GEN_WORLD, cmd_GET_GAMESTATE, cmd_MAP,
                                 cmd_MAP, cmd_THING_TYPE, cmd_THING_POS,
     def __init__(self, game_file_name):
         self.io = GameIO(game_file_name, self)
         self.map_type = MapHex
-        self.tasks = {'WAIT': Task_WAIT, 'MOVE': Task_MOVE}
+        self.tasks = {'WAIT': Task_WAIT,
+                      'MOVE': Task_MOVE,
+                      'PICKUP': Task_PICKUP,
+                      'DROP': Task_DROP}
         self.commands = {'GEN_WORLD': cmd_GEN_WORLD,
                          'GET_GAMESTATE': cmd_GET_GAMESTATE,
                          'MAP': cmd_MAP,
                                               stringify_yx(thing.position)))
         player = self.world.get_player()
         self.io.send('PLAYER_POS %s' % (stringify_yx(player.position)))
+        self.io.send('PLAYER_INVENTORY %s' % ','.join([str(i) for i in
+                                                       player.inventory]))
+        for id_ in player.inventory:
+            thing = self.world.get_thing(id_)
+            self.io.send('THING_TYPE %s %s' % (thing.id_, thing.type_))
+            self.io.send('THING_POS %s %s' % (thing.id_,
+                                              stringify_yx(thing.position)))
         self.io.send('GAME_STATE_COMPLETE')
 
     def proceed(self):
 
 
     def get_neighbors(self, pos):
         neighbors = {}
+        pos = tuple(pos)
         if not hasattr(self, 'neighbors_to'):
             self.neighbors_to = {}
         if pos in self.neighbors_to:
 
     def do(self):
         self.thing.position = self.thing.world.map_.move(self.thing.position,
                                                          self.args[0])
+        for id_ in self.thing.inventory:
+            t = self.thing.world.get_thing(id_)
+            t.position[:] = self.thing.position
+
+
+
+class Task_PICKUP(Task):
+    argtypes = 'int:nonneg'
+
+    def check(self):
+        to_pick_up = self.thing.world.get_thing(self.args[0],
+                                                create_unfound=False)
+        if to_pick_up is None:
+            raise GameError('no thing of ID %s to pick up' % self.args[0])
+        if not (self.thing.position == to_pick_up.position or
+                tuple(to_pick_up.position) in
+                self.thing.world.map_.get_neighbors(self.thing.position)):
+            raise GameError('thing of ID %s not in reach to pick up'
+                            % self.args[0])
+
+    def do(self):
+        to_pick_up = self.thing.world.get_thing(self.args[0])
+        self.thing.inventory += [self.args[0]]
+        to_pick_up.in_inventory = True
+
+
+
+class Task_DROP(Task):
+    argtypes = 'int:nonneg'
+
+    def check(self):
+        to_pick_up = self.thing.world.get_thing(self.args[0],
+                                                create_unfound=False)
+        if to_pick_up is None:
+            raise GameError('no thing of ID %s to drop' % self.args[0])
+        if to_pick_up.id_ not in self.thing.inventory:
+            raise GameError('no thing of ID %s to drop in inventory'
+                            % self.args[0])
+
+    def do(self):
+        to_drop = self.thing.world.get_thing(self.args[0])
+        del self.thing.inventory[self.thing.inventory.index(to_drop.id_)]
+        to_drop.in_inventory = False
 
 
 class Thing(ThingBase):
     blocking = False
+    in_inventory = False
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.inventory = []
 
     def proceed(self):
         pass
         stencil = self.get_stencil()
         visible_things = []
         for thing in self.world.things:
-            if stencil[thing.position] == '.':
+            if (not thing.in_inventory) and stencil[thing.position] == '.':
                 visible_things += [thing]
         return visible_things