From b745286c163a4a50789e0620eeac0555a940954c Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Thu, 5 Mar 2015 14:44:26 +0100
Subject: [PATCH] Server/py: Add map navigation infrastructure / API to
 libplomrogue.c.

---
 libplomrogue.c      | 127 +++++++++++++++++++++++++++++++++++++++++++-
 plomrogue-server.py |  18 ++++---
 2 files changed, 136 insertions(+), 9 deletions(-)

diff --git a/libplomrogue.c b/libplomrogue.c
index c6f5724..eb108c4 100644
--- a/libplomrogue.c
+++ b/libplomrogue.c
@@ -1,4 +1,20 @@
-#include <stdint.h> /* uint16_t, uint32_t */
+#include <stdint.h> /* uint8_t, uint16_t, uint32_t, INT8_MIN, INT8_MAX */
+
+
+
+/* Coordinate for maps of max. 256x256 cells. */
+struct yx_uint8
+{
+    uint8_t y;
+    uint8_t x;
+};
+
+/* Storage for map_length, set by set_maplength(). */
+static uint16_t maplength = 0;
+extern void set_maplength(uint16_t maplength_input)
+{
+    maplength = maplength_input;
+}
 
 
 
@@ -7,6 +23,115 @@ static uint32_t seed = 0;
 
 
 
+/* Helper to mv_yx_in_dir_legal(). Move "yx" into hex direction "d". */
+static void mv_yx_in_dir(char d, struct yx_uint8 * yx)
+{
+    if      (d == 'e')
+    {
+        yx->x = yx->x + (yx->y % 2);
+        yx->y--;
+    }
+    else if (d == 'd')
+    {
+        yx->x++;
+    }
+    else if (d == 'c')
+    {
+        yx->x = yx->x + (yx->y % 2);
+        yx->y++;
+    }
+    else if (d == 'x')
+    {
+        yx->x = yx->x - !(yx->y % 2);
+        yx->y++;
+    }
+    else if (d == 's')
+    {
+        yx->x--;
+    }
+    else if (d == 'w')
+    {
+        yx->x = yx->x - !(yx->y % 2);
+        yx->y--;
+    }
+}
+
+
+
+/* Move "yx" into hex direction "dir". Available hex directions are: 'e'
+ * (north-east), 'd' (east), 'c' (south-east), 'x' (south-west), 's' (west), 'w'
+ * (north-west). Returns 1 if the move was legal, 0 if not, and -1 when internal
+ * wrapping limits were exceeded.
+ *
+ * A move is legal if "yx" ends up within the the map and the original wrap
+ * space. The latter is left to a neighbor wrap space if "yx" moves beyond the
+ * minimal (0) or maximal (UINT8_MAX) column or row of possible map space – in
+ * which case "yx".y or "yx".x will snap to the respective opposite side. The
+ * current wrapping state is kept between successive calls until a "yx" of NULL
+ * is passed, in which case the function does nothing but zero the wrap state.
+ * Successive wrapping may move "yx" several wrap spaces into either direction,
+ * or return it into the original wrap space.
+ */
+static int8_t mv_yx_in_dir_legal(char dir, struct yx_uint8 * yx)
+{
+    static int8_t wrap_west_east   = 0;
+    static int8_t wrap_north_south = 0;
+    if (!yx)
+    {
+        wrap_west_east = wrap_north_south = 0;
+        return 0;
+    }
+    if (   INT8_MIN == wrap_west_east || INT8_MIN == wrap_north_south
+        || INT8_MAX == wrap_west_east || INT8_MAX == wrap_north_south)
+    {
+        return -1;
+    }
+    struct yx_uint8 original = *yx;
+    mv_yx_in_dir(dir, yx);
+    if      (('e' == dir || 'd' == dir || 'c' == dir) && yx->x < original.x)
+    {
+        wrap_west_east++;
+    }
+    else if (('x' == dir || 's' == dir || 'w' == dir) && yx->x > original.x)
+    {
+        wrap_west_east--;
+    }
+    if      (('w' == dir || 'e' == dir)               && yx->y > original.y)
+    {
+        wrap_north_south--;
+    }
+    else if (('x' == dir || 'c' == dir)               && yx->y < original.y)
+    {
+        wrap_north_south++;
+    }
+    if (   !wrap_west_east && !wrap_north_south
+        && yx->x < maplength && yx->y < maplength)
+    {
+        return 1;
+    }
+    return 0;
+}
+
+
+
+/* Wrapper around mv_yx_in_dir_legal() that stores the new coordinate in the
+ * globals res_y, res_x.
+ */
+uint8_t res_y = 0;
+uint8_t res_x = 0;
+extern uint8_t mv_yx_in_dir_legal_wrap(char dir, uint8_t y, uint8_t x)
+{
+    struct yx_uint8 yx;
+    yx.y = y;
+    yx.x = x;
+    uint8_t result = mv_yx_in_dir_legal(dir, &yx);
+    res_y = yx.y;
+    res_x = yx.x;
+    return result;
+}
+
+
+
 /* With set_seed set, set seed global to seed_input. In any case, return it. */
 extern uint32_t seed_rrand(uint8_t set_seed, uint32_t seed_input)
 {
diff --git a/plomrogue-server.py b/plomrogue-server.py
index 1751544..3234c4a 100755
--- a/plomrogue-server.py
+++ b/plomrogue-server.py
@@ -32,6 +32,10 @@ def prep_library():
     libpr.seed_rrand.restype = ctypes.c_uint32
     libpr.rrand.argtypes = []
     libpr.rrand.restype = ctypes.c_uint16
+    libpr.set_maplength.argtypes = [ctypes.c_uint16]
+    libpr.mv_yx_in_dir_legal_wrap.argtypes = [ctypes.c_char, ctypes.c_uint8,
+                                              ctypes.c_uint8]
+    libpr.mv_yx_in_dir_legal_wrap.restype = ctypes.c_uint8
     return libpr
 
 
@@ -740,8 +744,6 @@ def play_commander(action, args=False):
         if None != val:
             world_db["Things"][0]["T_ARGUMENT"] = val
             set_command()
-        else:
-            print("Ignoring: Argument must be integer >= 0 <=255.")
 
     def set_command_and_argument_movestring(str_arg):
         dirs = {"east": "d", "south-east": "c", "south-west": "x",
@@ -765,8 +767,6 @@ def command_seedrandomness(seed_string):
     val = integer_test(seed_string, 0, 4294967295)
     if None != val:
         rand.seed = val
-    else:
-        print("Ignoring: Value must be integer >= 0, <= 4294967295.")
 
 
 def command_seedmap(seed_string):
@@ -810,7 +810,6 @@ def command_makeworld(seed_string):
 
     val = integer_test(seed_string, 0, 4294967295)
     if None == val:
-        print("Ignoring: Value must be integer >= 0, <= 4294967295.")
         return
     rand.seed = val
     world_db["SEED_MAP"] = val
@@ -851,9 +850,12 @@ def command_makeworld(seed_string):
 
 def command_maplength(maplength_string):
     """Redefine map length. Invalidate map, therefore lose all things on it."""
-    set_world_inactive()
-    world_db["Things"] = {}
-    setter(None, "MAP_LENGTH", 1, 256)(maplength_string)
+    val = integer_test(val_string, 1, 256)
+    if None != val:
+        world_db["MAP_LENGTH"] = val
+        set_world_inactive()
+        world_db["Things"] = {}
+        libpr.set_maplength = val
 
 
 def command_worldactive(worldactive_string):
-- 
2.30.2