From 599f48bd1d9270cf154e885cf276adb05727507a Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Wed, 27 Feb 2019 01:33:20 +0100
Subject: [PATCH] Add inventory / item pickup/drop server-side.

---
 new/plomrogue/commands.py |  8 ++++++++
 new/plomrogue/game.py     | 14 +++++++++++--
 new/plomrogue/mapping.py  |  1 +
 new/plomrogue/tasks.py    | 43 +++++++++++++++++++++++++++++++++++++++
 new/plomrogue/things.py   |  7 ++++++-
 5 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/new/plomrogue/commands.py b/new/plomrogue/commands.py
index 84985f6..280b736 100644
--- a/new/plomrogue/commands.py
+++ b/new/plomrogue/commands.py
@@ -41,6 +41,11 @@ def cmd_THING_POS(game, i, yx):
     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'
@@ -80,6 +85,9 @@ def cmd_SAVE(game):
             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:
diff --git a/new/plomrogue/game.py b/new/plomrogue/game.py
index a5ce474..51bb372 100755
--- a/new/plomrogue/game.py
+++ b/new/plomrogue/game.py
@@ -1,4 +1,4 @@
-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,
@@ -107,7 +107,10 @@ class Game:
     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,
@@ -147,6 +150,13 @@ class Game:
                                               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):
diff --git a/new/plomrogue/mapping.py b/new/plomrogue/mapping.py
index aa76b61..e21def8 100644
--- a/new/plomrogue/mapping.py
+++ b/new/plomrogue/mapping.py
@@ -62,6 +62,7 @@ class Map(MapBase):
 
     def get_neighbors(self, pos):
         neighbors = {}
+        pos = tuple(pos)
         if not hasattr(self, 'neighbors_to'):
             self.neighbors_to = {}
         if pos in self.neighbors_to:
diff --git a/new/plomrogue/tasks.py b/new/plomrogue/tasks.py
index 2625762..58ee46d 100644
--- a/new/plomrogue/tasks.py
+++ b/new/plomrogue/tasks.py
@@ -46,3 +46,46 @@ class Task_MOVE(Task):
     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
diff --git a/new/plomrogue/things.py b/new/plomrogue/things.py
index 243547b..5ef4297 100644
--- a/new/plomrogue/things.py
+++ b/new/plomrogue/things.py
@@ -17,6 +17,11 @@ class ThingBase:
 
 class Thing(ThingBase):
     blocking = False
+    in_inventory = False
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.inventory = []
 
     def proceed(self):
         pass
@@ -140,7 +145,7 @@ class ThingAnimate(Thing):
         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
 
-- 
2.30.2