X-Git-Url: https://git.distorted.org.uk/~mdw/rocl/blobdiff_plain/1304202ad2001c85d3eae3a37c51e001794c24c8..4041fdd8af852bf6fb4db0aa6ddd2c8c2f640574:/elite.c diff --git a/elite.c b/elite.c index c9a9773..e6e90f2 100644 --- 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 +#include #include #include #include #include + /*----- 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); }