chiark / gitweb /
Release 1.1.6.
[rocl] / elite.c
diff --git a/elite.c b/elite.c
index c9a977330451ce8f13de0b35b94a28ffeb255b0a..e6e90f22e5048a43c259736a9d6dbc66ead1a55f 100644 (file)
--- a/elite.c
+++ b/elite.c
@@ -1,46 +1,38 @@
 /* -*-c-*-
- *
- * $Id: elite.c,v 1.1 2003/02/24 01:13:12 mdw Exp $
  *
  * Elite planet data
  *
  * (c) 2003 Mark Wooding
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-/*----- Revision history --------------------------------------------------* 
- *
- * $Log: elite.c,v $
- * Revision 1.1  2003/02/24 01:13:12  mdw
- * Initial import.
- *
- */
-
 /*----- Header files ------------------------------------------------------*/
 
 #include <ctype.h>
+#include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <tcl.h>
 
+
 /*----- Data structures ---------------------------------------------------*/
 
 typedef struct world {
@@ -109,7 +101,7 @@ static void world_us(Tcl_Obj *o)
   o->bytes = p;
   o->length = 12;
   for (i = 0; i < 6; i++, p += 2)
-    sprintf(p, "%02x", w->x[i]);  
+    sprintf(p, "%02x", w->x[i]);
 }
 
 static void world_dir(Tcl_Obj *o, Tcl_Obj *oo)
@@ -321,7 +313,7 @@ static void goatsoup(Tcl_Obj *d, const char *pn, world *w, const char *p)
        p++;
        j = mangle(w);
        goatsoup(d, pn, w, desc[i][(j >= 0x33) + (j >= 0x66) +
-                                  (j >= 0x99) + (j >= 0xcc)]);
+                                  (j >= 0x99) + (j >= 0xcc)]);
        break;
       case '%':
        p++;
@@ -370,7 +362,7 @@ static int cmd_worldinfo(ClientData cd, Tcl_Interp *ti,
   world ww;
 
   /* --- Check arguments --- */
-  
+
   if (objc != 3)
     return (err(ti, "usage: elite-worldinfo ARR SEED"));
   if ((w = world_get(ti, objv[2])) == 0)
@@ -380,19 +372,20 @@ static int cmd_worldinfo(ClientData cd, Tcl_Interp *ti,
   /* --- Get the basic information --- */
 
   getworldinfo(&wi, w);
+  Tcl_UnsetVar(ti, arr, 0);
   if (!Tcl_SetVar2Ex(ti, arr, "x", Tcl_NewIntObj(wi.x * 4),
                     TCL_LEAVE_ERR_MSG) ||
       !Tcl_SetVar2Ex(ti, arr, "y", Tcl_NewIntObj(wi.y * 2),
                     TCL_LEAVE_ERR_MSG) ||
-      !Tcl_SetVar2Ex(ti, arr, "government", Tcl_NewIntObj(wi.gov), 
+      !Tcl_SetVar2Ex(ti, arr, "government", Tcl_NewIntObj(wi.gov),
                    TCL_LEAVE_ERR_MSG) ||
       !Tcl_SetVar2Ex(ti, arr, "economy", Tcl_NewIntObj(wi.eco),
                     TCL_LEAVE_ERR_MSG) ||
-      !Tcl_SetVar2Ex(ti, arr, "techlevel", Tcl_NewIntObj(wi.tech), 
+      !Tcl_SetVar2Ex(ti, arr, "techlevel", Tcl_NewIntObj(wi.tech),
                    TCL_LEAVE_ERR_MSG) ||
-      !Tcl_SetVar2Ex(ti, arr, "population", Tcl_NewIntObj(wi.pop), 
+      !Tcl_SetVar2Ex(ti, arr, "population", Tcl_NewIntObj(wi.pop),
                    TCL_LEAVE_ERR_MSG) ||
-      !Tcl_SetVar2Ex(ti, arr, "productivity", Tcl_NewIntObj(wi.prod), 
+      !Tcl_SetVar2Ex(ti, arr, "productivity", Tcl_NewIntObj(wi.prod),
                    TCL_LEAVE_ERR_MSG) ||
       !Tcl_SetVar2Ex(ti, arr, "radius", Tcl_NewIntObj(wi.rad),
                     TCL_LEAVE_ERR_MSG) ||
@@ -509,6 +502,7 @@ static int cmd_market(ClientData cd, Tcl_Interp *ti,
     return (TCL_ERROR);
   getworldinfo(&wi, w);
 
+  Tcl_UnsetVar(ti, arr, 0);
   for (i = items; i->name; i++) {
     unsigned pr, qt;
     Tcl_Obj *oo[2];
@@ -704,7 +698,7 @@ static int put_items(Tcl_Interp *ti, /*const*/ char *arr,
       return (-1);
     *p++ = ii;
   }
-  return (0);  
+  return (0);
 }
 
 static struct cmddata cmdtab[] = {
@@ -788,6 +782,7 @@ static int cmd_unpackcmdr(ClientData cd, Tcl_Interp *ti,
 
   /* --- Deconstruct the data --- */
 
+  Tcl_UnsetVar(ti, arr, 0);
   for (c = cmdtab; c->name; c++) {
     if (c->get && c->get(ti, arr, p + c->off, c))
       return (TCL_ERROR);
@@ -822,6 +817,154 @@ static int cmd_packcmdr(ClientData cd, Tcl_Interp *ti,
   return (0);
 }
 
+/*----- Optimizations -----------------------------------------------------*/
+
+/* --- @elite-galaxylist SEED@ --- *
+ *
+ * Returns a SEED/X/Y list for the worlds in galaxy SEED.
+ */
+
+static int cmd_galaxylist(ClientData cd, Tcl_Interp *ti,
+                         int objc, Tcl_Obj *const *objv)
+{
+  world *w, ww;
+  worldinfo wi;
+  int i;
+  Tcl_Obj *o;
+
+  if (objc != 2)
+    return (err(ti, "usage: elite-galaxylist SEED"));
+  if ((w = world_get(ti, objv[1])) == 0)
+    return (TCL_ERROR);
+  ww = *w;
+  o = Tcl_NewListObj(0, 0);
+  for (i = 0; i < 256; i++) {
+    getworldinfo(&wi, &ww);
+    Tcl_ListObjAppendElement(ti, o, world_new(&ww));
+    Tcl_ListObjAppendElement(ti, o, Tcl_NewIntObj(wi.x * 4));
+    Tcl_ListObjAppendElement(ti, o, Tcl_NewIntObj(wi.y * 2));
+    waggle(&ww, &ww); waggle(&ww, &ww); waggle(&ww, &ww); waggle(&ww, &ww);
+  }
+  Tcl_SetObjResult(ti, o);
+  return (TCL_OK);
+}
+
+/* --- @elite-distance X Y XX YY@ --- *
+ *
+ * Returns the distance between two points.
+ */
+
+static int cmd_distance(ClientData cd, Tcl_Interp *ti,
+                       int objc, Tcl_Obj *const *objv)
+{
+  long x, y, xx, yy;
+  long d;
+
+  if (objc != 5)
+    return (err(ti, "usage: elite-distance X Y XX YY"));
+  if (Tcl_GetLongFromObj(ti, objv[1], &x) != TCL_OK ||
+      Tcl_GetLongFromObj(ti, objv[2], &y) != TCL_OK ||
+      Tcl_GetLongFromObj(ti, objv[3], &xx) != TCL_OK ||
+      Tcl_GetLongFromObj(ti, objv[4], &yy) != TCL_OK)
+    return (TCL_ERROR);
+  xx = xx >= x ? xx - x : x - xx; xx >>= 2; xx *= xx;
+  yy = yy >= y ? yy - y : y - yy; yy >>= 2; yy *= yy;
+  d = sqrt(xx + yy); d <<= 2;
+  Tcl_SetObjResult(ti, Tcl_NewLongObj(d));
+  return (TCL_OK);
+}
+
+/* --- @elite-adjacency ADJ LIST [DIST]@ --- *
+ *
+ * Construct an adjacency table from a world list.
+ */
+
+static int cmd_adjacency(ClientData cd, Tcl_Interp *ti,
+                        int objc, Tcl_Obj *const *objv)
+{
+  int oc;
+  Tcl_Obj **ov;
+  size_t i, j;
+  long x, y, xx, yy, d;
+  Tcl_Obj *a;
+  char *s, *ss;
+  Tcl_HashTable done;
+  long dd = 70;
+  int rc = TCL_ERROR;
+  int dummy;
+  Tcl_Obj *o;
+
+  if (objc < 3 || objc > 4)
+    return (err(ti, "usage: elite-adjacency ADJ LIST [DIST]"));
+  a = objv[1];
+  if (Tcl_ListObjGetElements(ti, objv[2], &oc, &ov) != TCL_OK)
+    return (TCL_ERROR);
+  if (oc % 3 != 0)
+    return (err(ti, "world array not a multiple of three in size"));
+  if (objc >= 4 && Tcl_GetLongFromObj(ti, objv[3], &dd) != TCL_OK)
+    return (TCL_ERROR);
+
+  Tcl_InitHashTable(&done, TCL_ONE_WORD_KEYS);
+  Tcl_UnsetVar(ti, Tcl_GetString(a), 0);
+  o = Tcl_NewObj();
+  Tcl_IncrRefCount(o);
+  for (i = 0; i < oc; i += 3) {
+    s = Tcl_GetString(ov[i]);
+    if (Tcl_ObjSetVar2(ti, a, ov[i], o, TCL_LEAVE_ERR_MSG) == 0)
+      goto done;
+  }
+  for (i = 0; i < oc; i += 3) {
+    s = Tcl_GetString(ov[i]);
+    Tcl_CreateHashEntry(&done, s, &dummy);
+    if (Tcl_GetLongFromObj(ti, ov[i + 1], &x) != TCL_OK ||
+       Tcl_GetLongFromObj(ti, ov[i + 2], &y) != TCL_OK)
+      goto done;
+    for (j = 0; j < oc; j += 3) {
+      ss = Tcl_GetString(ov[j]);
+      if (Tcl_FindHashEntry(&done, ss))
+       continue;
+      if (Tcl_GetLongFromObj(ti, ov[j + 1], &xx) != TCL_OK ||
+         Tcl_GetLongFromObj(ti, ov[j + 2], &yy) != TCL_OK)
+       goto done;
+      xx = xx >= x ? xx - x : x - xx; xx >>= 2; xx *= xx;
+      yy = yy >= y ? yy - y : y - yy; yy >>= 2; yy *= yy;
+      d = sqrt(xx + yy); d <<= 2;
+      if (d <= dd) {
+       if (Tcl_ObjSetVar2(ti, a, ov[i], ov[j],
+                          (TCL_APPEND_VALUE |
+                           TCL_LIST_ELEMENT |
+                           TCL_LEAVE_ERR_MSG)) == 0 ||
+           Tcl_ObjSetVar2(ti, a, ov[i], ov[j + 1],
+                          (TCL_APPEND_VALUE |
+                           TCL_LIST_ELEMENT |
+                           TCL_LEAVE_ERR_MSG)) == 0 ||
+           Tcl_ObjSetVar2(ti, a, ov[i], ov[j + 2],
+                          (TCL_APPEND_VALUE |
+                           TCL_LIST_ELEMENT |
+                           TCL_LEAVE_ERR_MSG)) == 0 ||
+           Tcl_ObjSetVar2(ti, a, ov[j], ov[i],
+                          (TCL_APPEND_VALUE |
+                           TCL_LIST_ELEMENT |
+                           TCL_LEAVE_ERR_MSG)) == 0 ||
+           Tcl_ObjSetVar2(ti, a, ov[j], ov[i + 1],
+                          (TCL_APPEND_VALUE |
+                           TCL_LIST_ELEMENT |
+                           TCL_LEAVE_ERR_MSG)) == 0 ||
+           Tcl_ObjSetVar2(ti, a, ov[j], ov[i + 2],
+                          (TCL_APPEND_VALUE |
+                           TCL_LIST_ELEMENT |
+                           TCL_LEAVE_ERR_MSG)) == 0)
+         goto done;
+      }
+    }
+  }
+  rc = TCL_OK;
+
+done:
+  Tcl_DeleteHashTable(&done);
+  return (rc);
+}
+
 /*----- Initialization ----------------------------------------------------*/
 
 int Elite_SafeInit(Tcl_Interp *ti)
@@ -832,10 +975,13 @@ int Elite_SafeInit(Tcl_Interp *ti)
   } cmds[] = {
     { "elite-nextworld",       cmd_nextworld },
     { "elite-nextgalaxy",      cmd_nextgalaxy },
-    { "elite-worldinfo",       cmd_worldinfo },
+    { "elite-worldinfo",       cmd_worldinfo },
     { "elite-market",          cmd_market },
     { "elite-unpackcmdr",      cmd_unpackcmdr },
     { "elite-packcmdr",                cmd_packcmdr },
+    { "elite-distance",                cmd_distance },
+    { "elite-galaxylist",      cmd_galaxylist },
+    { "elite-adjacency",       cmd_adjacency },
     { 0,                       0 }
   };
 
@@ -843,7 +989,7 @@ int Elite_SafeInit(Tcl_Interp *ti)
   for (c = cmds; c->name; c++)
     Tcl_CreateObjCommand(ti, c->name, c->proc, 0, 0);
   Tcl_RegisterObjType(&world_type);
-  if (Tcl_PkgProvide(ti, "elite-bits", "1.0.0"))
+  if (Tcl_PkgProvide(ti, "elite-bits", "1.0.1"))
     return (TCL_ERROR);
   return (TCL_OK);
 }