commit e1dc11030e3248648db58de69e027f19b6a8edb3
parent 963ea7493c3dcd6f5ac9ab18c9b913dd62e127aa
Author: hhvn <dev@hhvn.uk>
Date: Sat, 6 Aug 2022 11:50:44 +0200
Saving properly
Diffstat:
M | Makefile | | | 3 | +-- |
M | db/db.c | | | 320 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
M | db/db.h | | | 27 | ++++++++++++++++++++------- |
M | src/main.c | | | 12 | ++++++++---- |
M | src/main.h | | | 4 | ++++ |
M | src/save.c | | | 18 | +++++++++++++----- |
M | src/str.c | | | 27 | +++++++++++++++++++++++++++ |
M | src/struct.h | | | 17 | ++++++++--------- |
M | src/system.c | | | 71 | ++++++++++++++++++++++++++++++++++++++++++----------------------------- |
M | src/ui.c | | | 103 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
10 files changed, 419 insertions(+), 183 deletions(-)
diff --git a/Makefile b/Makefile
@@ -19,8 +19,7 @@ $(BIN): $(OBJ) $(DBLIB)
clean: db-clean
rm -f $(BIN) $(OBJ)
-db: $(DBLIB)
-$(DBLIB):
+db:
@echo $(DBDIR): make $(DBLIB)
@cd $(DBDIR); make CFLAGS="$(CFLAGS)" `basename $(DBLIB)`
db-clean:
diff --git a/db/db.c b/db/db.c
@@ -5,24 +5,34 @@
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
+#include <libgen.h>
#include <sys/stat.h>
#include "db.h"
-typedef struct dbGroup dbGroup;
-typedef struct dbPair dbPair;
+typedef struct DB DB;
+typedef struct Group Group;
+typedef struct Pair Pair;
-struct dbGroup {
+struct DB {
+ DB *prev;
+ char *dir;
+ struct Group *tracked[MAXGROUPS];
+ DB *next;
+};
+
+struct Group {
+ struct DB *db;
char *dir;
char *name;
char *path;
- dbPair *pairs;
+ Pair *pairs;
};
-struct dbPair {
- dbPair *prev;
+struct Pair {
+ Pair *prev;
char *key;
char *val;
- dbPair *next;
+ Pair *next;
};
/* produced only by dirlist()
@@ -34,41 +44,108 @@ struct dbPair {
*
* A possible alternative would be to have a dirlist_backend() function that
* returns the files/dirs in a dir. The frontend would then append the files to
- * its return list, and append the dirs to another list: it keeps calling the
- * backend for each element in this list until none remain. */
+ * its return list, and append the dirs to a dir list: it keeps calling the
+ * backend for each element in the dir list until none remain, and the return
+ * list is filled. */
struct Dirlist {
char *path;
struct Dirlist *next;
};
-static int track(dbGroup *group);
-static int untrack(dbGroup *group);
-static dbGroup *gettracked(char *dir, char *group);
+static int subdir(char *d1, char *d2);
+static DB *getdb(char *db);
+static DB *getdbfor(char *path);
+
+static int track(Group *group);
+static int untrack(Group *group);
+static Group *gettracked(char *dir, char *group);
static int dirlist(struct Dirlist **list, char *dir, int (*filter)(void *data, char *path), void *fdata);
-static dbGroup *dbinitgroup_p(char *dir, char *group);
-static size_t dblistkeys_p(char ***ret, dbGroup *group, int (*filter)(void *data, char *path), void *fdata);
-static dbGroup *dbgetgroup_p(char *dir, char *group, int init);
-static dbPair *dbgetpair_p(dbGroup *group, char *key);
-static int dbset_p(dbPair *pair, char *val);
-static int dbdelgroup_p(dbGroup *group);
-static void dbdelpair_p(dbGroup *group, dbPair *pair);
-static int dbwritegroup_p(dbGroup *group);
-static void dbfreegroup_p(dbGroup *group);
+static Group *initgroup(char *dir, char *group);
+static size_t dblistkeys_p(char ***ret, Group *group, int (*filter)(void *data, char *path), void *fdata);
+static Group *getgroup(char *dir, char *group, int init);
+static Pair *getpair(Group *group, char *key);
+static int dbset_p(Pair *pair, char *val);
+static int dbdelgroup_p(Group *group);
+static void dbdelpair_p(Group *group, Pair *pair);
+static int dbwritegroup_p(Group *group);
+static void dbfreegroup_p(Group *group);
-static dbGroup *tracked[MAXGROUPS] = {NULL};
+static DB *dbs;
+
+/*
+ * DB
+ */
+static int
+subdir(char *d1, char *d2) {
+ if (!d1 || !d2) return 0;
+ if (!((strlen(d1) > strlen(d2) && d1[strlen(d2)] == '/') ||
+ (strlen(d2) > strlen(d1) && d2[strlen(d1)] == '/')))
+ return 0;
+ else if (strncmp(d1, d2, strlen(d1)) == 0 || strncmp(d2, d1, strlen(d2)) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+int
+dbdeclare(char *dir) {
+ DB *db;
+
+ if (!dir) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ db = malloc(sizeof(DB));
+ if (!db) return -1;
+ db->dir = strdup(dir);
+ if (!db->dir) return -1;
+ memset(db->tracked, 0, sizeof(db->tracked));
+
+ if (!dbs) {
+ db->prev = db->next = NULL;
+ dbs = db;
+ } else {
+ db->prev = NULL;
+ db->next = dbs;
+ dbs = db;
+ }
+
+ return 0;
+}
+
+static DB *
+getdb(char *db) {
+ DB *p;
+
+ for (p = dbs; p; p = p->next)
+ if (strcmp(p->dir, db) == 0)
+ return p;
+ return NULL;
+}
+
+static DB *
+getdbfor(char *path) {
+ DB *p;
+
+ for (p = dbs; p; p = p->next)
+ if (strcmp(p->dir, path) == 0 || subdir(p->dir, path))
+ return p;
+ return NULL;
+}
/*
* Tracking loaded groups
*/
static int
-track(dbGroup *group) {
+track(Group *group) {
int i;
if (!group) return -1;
for (i = 0; i < MAXGROUPS; i++) {
- if (!tracked[i]) {
- tracked[i] = group;
+ if (!group->db->tracked[i]) {
+ group->db->tracked[i] = group;
return 0;
}
}
@@ -76,26 +153,30 @@ track(dbGroup *group) {
}
static int
-untrack(dbGroup *group) {
+untrack(Group *group) {
int i;
if (!group) return -1;
for (i = 0; i < MAXGROUPS; i++) {
- if (tracked[i] == group) {
- tracked[i] = NULL;
+ if (group->db->tracked[i] == group) {
+ group->db->tracked[i] = NULL;
return 0;
}
}
return -1;
}
-static dbGroup *
+static Group *
gettracked(char *dir, char *group) {
+ DB *db;
int i;
+
+ if (!(db = getdbfor(dir)))
+ return NULL;
for (i = 0; i < MAXGROUPS; i++)
- if (tracked[i] &&
- strcmp(dir, tracked[i]->dir) == 0 &&
- strcmp(group, tracked[i]->name) == 0)
- return tracked[i];
+ if (db->tracked[i] &&
+ strcmp(dir, db->tracked[i]->dir) == 0 &&
+ strcmp(group, db->tracked[i]->name) == 0)
+ return db->tracked[i];
return NULL;
}
@@ -103,15 +184,15 @@ gettracked(char *dir, char *group) {
* Various struct/data/etc handling
*/
static int
-appendpair(dbPair **pairs, char *key, char *val) {
- dbPair *p, *new;
+appendpair(Pair **pairs, char *key, char *val) {
+ Pair *p, *new;
if (!pairs || !key) {
errno = EINVAL;
return -1;
}
- new = malloc(sizeof(dbPair));
+ new = malloc(sizeof(Pair));
if (!new) return -1; /* ENOMEM */
new->key = strdup(key);
new->val = val ? strdup(val) : NULL;
@@ -185,7 +266,7 @@ dblisteq(char **l1, size_t s1, char **l2, size_t s2) {
}
static void
-freepair(dbPair *pair) {
+freepair(Pair *pair) {
if (pair) {
free(pair->key);
free(pair->val);
@@ -196,9 +277,9 @@ freepair(dbPair *pair) {
/*
* Init
*/
-static dbGroup *
-dbinitgroup_p(char *dir, char *group) {
- dbGroup *ret;
+static Group *
+initgroup(char *dir, char *group) {
+ Group *ret;
if (!dir || !group) {
errno = EINVAL;
@@ -206,9 +287,10 @@ dbinitgroup_p(char *dir, char *group) {
}
if ((ret = gettracked(dir, group)))
return ret;
- ret = malloc(sizeof(dbGroup));
+ ret = malloc(sizeof(Group));
if (!ret) return NULL;
ret->path = malloc(strlen(dir) + strlen(group) + 2);
+ ret->db = getdbfor(dir);
ret->dir = strdup(dir);
ret->name = strdup(group);
ret->pairs = NULL;
@@ -225,12 +307,12 @@ dbinitgroup_p(char *dir, char *group) {
return ret;
}
-static dbGroup *
-dbloadgroup_p(char *dir, char *group) {
+static Group *
+loadgroup(char *dir, char *group) {
char path[PATH_MAX];
char buf[8192];
char *key, *val;
- dbGroup *ret;
+ Group *ret;
FILE *fp;
if (!dir || !group) {
@@ -243,13 +325,16 @@ dbloadgroup_p(char *dir, char *group) {
snprintf(path, sizeof(path), "%s/%s", dir, group);
if (!(fp = fopen(path, "r")))
return NULL; /* errno set by fopen */
- if (!(ret = dbinitgroup_p(dir, group)))
+ if (!(ret = initgroup(dir, group))) {
+ fclose(fp);
return NULL;
+ }
while (fgets(buf, sizeof(buf), fp)) {
buf[strlen(buf) - 1] = '\0'; /* remove \n */
key = strtok_r(buf, "\t", &val);
appendpair(&ret->pairs, key, val);
}
+ fclose(fp);
return ret;
}
@@ -344,10 +429,10 @@ dblistgroups(char ***ret, char *dir) {
}
static size_t
-dblistkeys_p(char ***ret, dbGroup *group, int (*filter)(void *data, char *path), void *fdata) {
+dblistkeys_p(char ***ret, Group *group, int (*filter)(void *data, char *path), void *fdata) {
size_t i = 0;
size_t len;
- dbPair *p;
+ Pair *p;
if (!ret || !group) {
errno = EINVAL;
@@ -372,8 +457,8 @@ dblistkeys_p(char ***ret, dbGroup *group, int (*filter)(void *data, char *path),
size_t
dblistkeys_f(char ***ret, char *dir, char *group, int (*filter)(void *data, char *path), void *fdata) {
- dbGroup *p;
- if (!(p = dbgetgroup_p(dir, group, 0))) {
+ Group *p;
+ if (!(p = getgroup(dir, group, 0))) {
*ret = NULL;
return 0;
}
@@ -388,9 +473,9 @@ dblistkeys(char ***ret, char *dir, char *group) {
/*
* Get
*/
-static dbGroup *
-dbgetgroup_p(char *dir, char *group, int init) {
- dbGroup *p;
+static Group *
+getgroup(char *dir, char *group, int init) {
+ Group *p;
if (!dir || !group) {
errno = EINVAL;
@@ -398,17 +483,17 @@ dbgetgroup_p(char *dir, char *group, int init) {
}
if ((p = gettracked(dir, group)))
return p;
- if ((p = dbloadgroup_p(dir, group)))
+ if ((p = loadgroup(dir, group)))
return p;
if (init)
- return dbinitgroup_p(dir, group);
+ return initgroup(dir, group);
errno = ENOENT;
return NULL;
}
-static dbPair *
-dbgetpair_p(dbGroup *group, char *key) {
- dbPair *p;
+static Pair *
+getpair(Group *group, char *key) {
+ Pair *p;
if (!group || !key) {
errno = EINVAL;
@@ -423,10 +508,10 @@ dbgetpair_p(dbGroup *group, char *key) {
char *
dbget(char *dir, char *group, char *key) {
- dbGroup *gp;
- dbPair *pp;
- if (!(gp = dbgetgroup_p(dir, group, 0)) ||
- !(pp = dbgetpair_p(gp, key)))
+ Group *gp;
+ Pair *pp;
+ if (!(gp = getgroup(dir, group, 0)) ||
+ !(pp = getpair(gp, key)))
return NULL;
return pp->val;
}
@@ -435,7 +520,7 @@ dbget(char *dir, char *group, char *key) {
* Set
*/
static int
-dbset_p(dbPair *pair, char *val) {
+dbset_p(Pair *pair, char *val) {
if (!pair) {
errno = EINVAL;
return -1;
@@ -448,11 +533,11 @@ dbset_p(dbPair *pair, char *val) {
int
dbset(char *dir, char *group, char *key, char *val) {
- dbGroup *gp;
- dbPair *pp;
- if (!(gp = dbgetgroup_p(dir, group, 1)))
+ Group *gp;
+ Pair *pp;
+ if (!(gp = getgroup(dir, group, 1)))
return -1;
- if (!(pp = dbgetpair_p(gp, key)))
+ if (!(pp = getpair(gp, key)))
return appendpair(&gp->pairs, key, val);
return dbset_p(pp, val);
}
@@ -461,7 +546,7 @@ dbset(char *dir, char *group, char *key, char *val) {
* Del
*/
static int
-dbdelgroup_p(dbGroup *group) {
+dbdelgroup_p(Group *group) {
int ret = 0, serrno;
ret = unlink(group->path);
serrno = errno;
@@ -473,14 +558,14 @@ dbdelgroup_p(dbGroup *group) {
int
dbdelgroup(char *dir, char *group) {
- dbGroup *p;
- if (!(p = dbgetgroup_p(dir, group, 0)))
+ Group *p;
+ if (!(p = getgroup(dir, group, 0)))
return -1;
return dbdelgroup_p(p);
}
static void
-dbdelpair_p(dbGroup *group, dbPair *pair) {
+dbdelpair_p(Group *group, Pair *pair) {
if (!pair) return;
if (pair == group->pairs)
group->pairs = pair->next;
@@ -493,10 +578,10 @@ dbdelpair_p(dbGroup *group, dbPair *pair) {
int
dbdelpair(char *dir, char *group, char *key) {
- dbGroup *gp;
- dbPair *pp;
- if (!(gp = dbgetgroup_p(dir, group, 0)) ||
- !(pp = dbgetpair_p(gp, key)))
+ Group *gp;
+ Pair *pp;
+ if (!(gp = getgroup(dir, group, 0)) ||
+ !(pp = getpair(gp, key)))
return -1;
dbdelpair_p(gp, pp);
return 0;
@@ -539,43 +624,63 @@ mkdirp(char *path, mode_t mode) {
}
static int
-dbwritegroup_p(dbGroup *group) {
+dbwritegroup_p(Group *group) {
+ char *dir, *path;
FILE *fp;
- dbPair *p;
+ Pair *p;
+ int serrno;
if (!group || !group->path) {
errno = EINVAL;
return -1;
}
- if (mkdirp(group->dir, 0755) == -1)
- return -1; /* errno set by mkdirp */
+
+ path = strdup(group->path);
+ if (!path) return -1;
+ dir = dirname(path);
+ if (mkdirp(dir, 0755) == -1) {
+ serrno = errno;
+ free(path);
+ errno = serrno;
+ return -1;
+ }
+ free(path);
+
if (!(fp = fopen(group->path, "w")))
- return -1; /* errno set by fopen */
+ return -1;
for (p = group->pairs; p; p = p->next)
fprintf(fp, "%s\t%s\n", p->key, p->val);
+ fclose(fp);
return 0;
}
int
dbwritegroup(char *dir, char *group) {
- dbGroup *p;
- if (!(p = dbgetgroup_p(dir, group, 0)))
+ Group *p;
+ if (!(p = getgroup(dir, group, 0)))
return -1;
return dbwritegroup_p(p);
}
int
-dbwrite(char *dir) {
- int ret = 0, i;
+dbwrite(char *db) {
+ int ret, i;
+ DB *p;
- if (!dir) {
+ if (!db) {
errno = EINVAL;
return -1;
}
- for (i = 0; i < MAXGROUPS; i++)
- if (tracked[i] && strcmp(dir, tracked[i]->dir) == 0)
- if (dbwritegroup_p(tracked[i]) == -1)
+
+ if (!(p = getdb(db))) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ for (i = 0, ret = 0; i < MAXGROUPS; i++)
+ if (p->tracked[i])
+ if (dbwritegroup_p(p->tracked[i]) == -1)
ret = -1;
return ret;
}
@@ -585,17 +690,28 @@ dbwrite(char *dir) {
*/
void
-dbfree(char *dir) {
+dbfree(char *db) {
+ DB *p;
int i;
+ if (!(p = getdb(db)))
+ return;
for (i = 0; i < MAXGROUPS; i++)
- if (tracked[i] && strcmp(dir, tracked[i]->dir) == 0)
- dbfreegroup_p(tracked[i]);
+ if (p->tracked[i])
+ dbfreegroup_p(p->tracked[i]);
+ if (p == dbs)
+ dbs = p->next;
+ if (p->next)
+ p->next->prev = p->prev;
+ if (p->prev)
+ p->prev->next = p->next;
+ free(p->dir);
+ free(p);
}
static void
-dbfreegroup_p(dbGroup *group) {
- dbPair *p, *prev;
+dbfreegroup_p(Group *group) {
+ Pair *p, *prev;
if (group) {
untrack(group);
prev = group->pairs;
@@ -615,16 +731,26 @@ dbfreegroup_p(dbGroup *group) {
void
dbfreegroup(char *dir, char *group) {
- dbGroup *p;
- if ((p = dbgetgroup_p(dir, group, 0)))
+ Group *p;
+ if ((p = getgroup(dir, group, 0)))
dbfreegroup_p(p);
}
void
dbcleanup(void) {
+ DB *p, *prev;
int i;
- for (i = 0; i < MAXGROUPS; i++)
- if (tracked[i])
- dbfreegroup_p(tracked[i]);
+ prev = dbs;
+ p = prev->next;
+ while (prev) {
+ for (i = 0; i < MAXGROUPS; i++)
+ if (prev->tracked[i])
+ dbfreegroup_p(prev->tracked[i]);
+ free(prev->dir);
+ free(prev);
+ prev = p;
+ if (p) p = p->next;
+ }
+ dbs = NULL;
}
diff --git a/db/db.h b/db/db.h
@@ -1,7 +1,20 @@
#include <stddef.h>
-#define MAXGROUPS 256
-#define TODO
+#define MAXGROUPS 256 /* groups in a DB */
+
+/* -----
+ * Declaration
+ */
+
+/* Declare a db to be contained in a dir. Any access to data within this dir
+ * are correlated with it for operations such as dbwrite() and dbfree().
+ *
+ * Declaring a db with a path inside another db will result in weird behaviour.
+ *
+ * Returns 0 on success and -1 on failure. Errors may be:
+ * ENOMEM allocation functions failed
+ */
+int dbdeclare(char *dir);
/* -----
* List functions
@@ -97,26 +110,26 @@ int dbdelpair(char *dir, char *group, char *key);
/* Write a group to file.
* Returns 0 for success or -1 for failure.
- * Errors are that of mkdir(3), fopen(3), or:
+ * Errors are that of mkdir(3), fopen(3), strdup(3), or:
* EINVAL dir or group are NULL
* ENOENT no such group
*/
int dbwritegroup(char *dir, char *group);
-/* Writes all groups in a directory to file.
+/* Writes all groups in a db to file.
* Returns 0 for success or -1 for failure.
* Every write is attempted even if one fails.
* Errors are that of mkdir(3), fopen(3), or:
* EINVAL dir is NULL
*/
-int dbwrite(char *dir);
+int dbwrite(char *db);
/* -----
* Cleanup
*/
-/* Discards and frees the content of groups in a directory. */
-void dbfree(char *dir);
+/* Discards and frees a db. */
+void dbfree(char *db);
/* Discards and frees the content of a group. */
void dbfreegroup(char *dir, char *group);
diff --git a/src/main.c b/src/main.c
@@ -8,13 +8,14 @@ Save *save = NULL;
int
main(void) {
- int w, h;
+ char *system;
+
ui_init();
- Tabs test = {
- 2, 0, {{"Display", 0}, {"Minerals", 0}}
- };
save = save_init(TESTSAVE);
+ system = dbget(save->db.dir, "index", "selsystem");
+ if (!system) system = "Sol"; /* TODO: 1. selsystem, 2. player home, 3. uhh? */
+ save->system = system_load(NULL, system);
while (!WindowShouldClose()) {
ui_clickable_update();
@@ -39,5 +40,8 @@ main(void) {
}
ui_deinit();
+
+ save_write(save);
+ dbcleanup();
return 0;
}
diff --git a/src/main.h b/src/main.h
@@ -18,6 +18,8 @@ char * nstrdup(char *str); /* NULL-safe */
char * strkmdist(float km);
char * strlightdist(float km);
int streq(char *s1, char *s2); /* NULL-safe, no `== 0` required */
+int strprefix(char *str, char *prefix);
+char * strsuffix(char *str, char *suffix);
int strlistpos(char *str, char **list, size_t len);
float strnum(char *str);
@@ -58,6 +60,8 @@ void ui_draw_view_systems(void);
void ui_draw_view_settings(void);
/* system.c */
+int bodytype_enumify(char *name);
+char * bodytype_strify(Body *body);
Vector2 system_vectorize(Polar polar);
Vector2 system_vectorize_around(Vector2 around, Polar polar);
Polar system_polarize(Vector2 vector);
diff --git a/src/save.c b/src/save.c
@@ -9,10 +9,18 @@ save_init(char *dir) {
if (!dir || !(ret = malloc(sizeof(Save))))
return NULL;
- ret->dir = strdup(dir);
- ret->races = smprintf("%s/Races", dir);
- ret->systems = smprintf("%s/Systems", dir);
- ret->fleets = smprintf("%s/Fleets", dir);
- memset(&ret->cache, 0, sizeof(ret->cache));
+ dbdeclare(dir);
+ ret->db.dir = nstrdup(dir);
+ ret->db.races = smprintf("%s/Races", dir);
+ ret->db.systems = smprintf("%s/Systems", dir);
+ ret->db.fleets = smprintf("%s/Fleets", dir);
+ ret->system = NULL;
return ret;
};
+
+void
+save_write(Save *s) {
+ if (s->system && s->system->name)
+ dbset(save->db.dir, "index", "selsystem", s->system->name);
+ dbwrite(s->db.dir);
+}
diff --git a/src/str.c b/src/str.c
@@ -101,6 +101,33 @@ streq(char *s1, char *s2) {
}
int
+strprefix(char *str, char *prefix) {
+ if (str == prefix)
+ return 1;
+ else if (!str || !prefix)
+ return 0;
+ else
+ return strncmp(str, prefix, strlen(prefix)) == 0;
+}
+
+char *
+strsuffix(char *str, char *suffix) {
+ size_t len, slen;
+
+ if (str == suffix)
+ return str;
+ else if (!str || !suffix)
+ return NULL;
+ else if ((len = strlen(str)) < (slen = strlen(suffix)))
+ return NULL;
+
+ if (strcmp(str + len - slen, suffix) == 0)
+ return str + len - slen;
+ else
+ return NULL;
+}
+
+int
strlistpos(char *str, char **list, size_t len) {
int i;
diff --git a/src/struct.h b/src/struct.h
@@ -9,7 +9,7 @@ typedef struct {
/* body->type + body->parent->type == complex type
*
* Ex. for orbiting a star:
- * BODY_PLANET + BODY_STAR == BODY_PLANET
+ * BODY_PLANET + BODY_STAR == BODY_PLANET (still body->type)
*
* Ex. for a moon orbiting a body:
* BODY_MOON + BODY_PLANET is unique
@@ -29,6 +29,7 @@ struct Body {
Body *parent;
Polar polar;
Vector2 vector;
+ Vector2 pxloc; /* used by ui functions */
char *name;
enum BodyType type;
float radius;
@@ -59,15 +60,13 @@ typedef struct {
/* save.c */
typedef struct {
- /* db locator strings.
- * dir the base, everything else is "dir/var" */
- char *dir;
- char *races;
- char *systems;
- char *fleets;
struct {
- System *system;
- } cache;
+ char *dir;
+ char *races;
+ char *systems;
+ char *fleets;
+ } db;
+ System *system;
} Save;
/* ui.c */
diff --git a/src/system.c b/src/system.c
@@ -4,7 +4,7 @@
#include "raylib.h"
#include "main.h"
-char *body_names[BODY_LAST] = {
+char *bodytype_names[BODY_LAST] = {
[BODY_STAR] = "Star",
[BODY_PLANET] = "Planet",
[BODY_DWARF] = "Dwarf planet",
@@ -17,6 +17,30 @@ char *body_names[BODY_LAST] = {
[BODY_COMET + BODY_MOON] = "Comet moon",
};
+int
+bodytype_enumify(char *name) {
+ if (strsuffix(name, "moon") || streq(name, "Moon"))
+ return BODY_MOON;
+ else if (streq(name, "Star"))
+ return BODY_STAR;
+ else if (streq(name, "Planet"))
+ return BODY_PLANET;
+ else if (streq(name, "Dwarf planet"))
+ return BODY_DWARF;
+ else if (streq(name, "Asteroid"))
+ return BODY_ASTEROID;
+ else if (streq(name, "Comet"))
+ return BODY_COMET;
+ else
+ return -1;
+}
+
+char *
+bodytype_strify(Body *body) {
+ return bodytype_names[body->type +
+ body->parent ? body->parent->type : 0];
+}
+
Vector2
system_vectorize(Polar polar) {
return (Vector2) {
@@ -86,7 +110,7 @@ System *
system_init(char *name) {
System *ret = malloc(sizeof(System));
if (!ret) return NULL;
- ret->name = strdup(name);
+ ret->name = nstrdup(name);
ret->bodies = NULL;
ret->bodies_len = 0;
return ret;
@@ -115,7 +139,7 @@ system_load(System *s, char *name) {
if (!s) s = system_init(name);
dir = smprintf("%s/", s->name);
- s->bodies_len = blen = dblistgroups_f(&bname, save->systems, &filter_bodyinsystem, dir);
+ s->bodies_len = blen = dblistgroups_f(&bname, save->db.systems, &filter_bodyinsystem, dir);
if (!bname) return NULL;
bparent = malloc(sizeof(char *) * blen);
s->bodies = malloc(sizeof(Body *) * blen);
@@ -127,35 +151,24 @@ system_load(System *s, char *name) {
for (i = 0; i < blen; i++) {
s->bodies[i] = malloc(sizeof(Body));
s->bodies[i]->name = nstrdup(bname[i] + strlen(dir));
- bparent[i] = dbget(save->systems, bname[i], "parent");
-
- tmp = dbget(save->systems, bname[i], "type");
- if (streq(tmp, "Star"))
- s->bodies[i]->type = BODY_STAR;
- else if (streq(tmp, "Planet"))
- s->bodies[i]->type = BODY_PLANET;
- else if (streq(tmp, "Dwarf planet"))
- s->bodies[i]->type = BODY_DWARF;
- else if (streq(tmp, "Asteroid"))
- s->bodies[i]->type = BODY_ASTEROID;
- else if (streq(tmp, "Comet"))
- s->bodies[i]->type = BODY_COMET;
- else if (streq(tmp, "Moon"))
- s->bodies[i]->type = BODY_MOON;
-
- s->bodies[i]->radius = strnum(dbget(save->systems, bname[i], "radius"));
- s->bodies[i]->mass = strnum(dbget(save->systems, bname[i], "mass"));
- s->bodies[i]->orbdays = strnum(dbget(save->systems, bname[i], "orbdays"));
+ bparent[i] = nstrdup(dbget(save->db.systems, bname[i], "parent"));
+
+ tmp = dbget(save->db.systems, bname[i], "type");
+ s->bodies[i]->type = bodytype_enumify(tmp);
+
+ s->bodies[i]->radius = strnum(dbget(save->db.systems, bname[i], "radius"));
+ s->bodies[i]->mass = strnum(dbget(save->db.systems, bname[i], "mass"));
+ s->bodies[i]->orbdays = strnum(dbget(save->db.systems, bname[i], "orbdays"));
if (s->bodies[i]->type == BODY_COMET) {
/* mindist is on opposite side of parent */
- s->bodies[i]->mindist = 0 - strnum(dbget(save->systems, bname[i], "mindist"));
- s->bodies[i]->maxdist = strnum(dbget(save->systems, bname[i], "maxdist"));
- s->bodies[i]->curdist = strnum(dbget(save->systems, bname[i], "curdist"));
- s->bodies[i]->theta = strnum(dbget(save->systems, bname[i], "theta"));
- s->bodies[i]->inward = strnum(dbget(save->systems, bname[i], "inward"));
+ s->bodies[i]->mindist = 0 - strnum(dbget(save->db.systems, bname[i], "mindist"));
+ s->bodies[i]->maxdist = strnum(dbget(save->db.systems, bname[i], "maxdist"));
+ s->bodies[i]->curdist = strnum(dbget(save->db.systems, bname[i], "curdist"));
+ s->bodies[i]->theta = strnum(dbget(save->db.systems, bname[i], "theta"));
+ s->bodies[i]->inward = strnum(dbget(save->db.systems, bname[i], "inward"));
} else {
- s->bodies[i]->dist = strnum(dbget(save->systems, bname[i], "dist"));
- s->bodies[i]->curtheta = strnum(dbget(save->systems, bname[i], "curtheta"));
+ s->bodies[i]->dist = strnum(dbget(save->db.systems, bname[i], "dist"));
+ s->bodies[i]->curtheta = strnum(dbget(save->db.systems, bname[i], "curtheta"));
}
/* so system_get_polar() knows if it's usable */
diff --git a/src/ui.c b/src/ui.c
@@ -9,6 +9,7 @@
#define WINDOW_TAB_HEIGHT 20
#define TARGET_FPS 60
#define MIN_BODY_DIAM 3
+#define SCREEN_RECT() ((Rect){0, 0, GetScreenWidth(), GetScreenHeight()})
static Font font;
static Clickable clickable[CLICKABLE_MAX];
@@ -32,7 +33,9 @@ void (*view_drawers[UI_VIEW_LAST])(void) = {
};
Tabs view_tabs = {
- UI_VIEW_LAST, 0, {{"Main", 0}, {"Colonies", 0}, {"Fleets", 0}, {"Design", 0},
+ /* Tactical is the terminology used in Aurora, so I decided to use it
+ * in the ui; in the code it's just called 'main' for my fingers' sake */
+ UI_VIEW_LAST, 0, {{"Tactical", 0}, {"Colonies", 0}, {"Fleets", 0}, {"Design", 0},
{"Systems", 0}, {"Settings", 0}}
};
@@ -62,6 +65,7 @@ static struct {
int x, y; /* real y = GetScreenHeight() - y */
int w, h;
} scale;
+ System *system;
} view_main = {
.infobox = {
.tabs = {
@@ -95,6 +99,7 @@ static struct {
.w = 50,
.h = 3,
},
+ .system = NULL,
};
void
@@ -128,6 +133,25 @@ ui_print(int x, int y, Color col, char *fmt, ...) {
free(text);
}
+void
+ui_title(char *fmt, ...) {
+ static char *last = NULL;
+ char *title;
+ va_list ap;
+
+ va_start(ap, fmt);
+ title = vsmprintf(fmt, ap);
+ va_end(ap);
+
+ if (!streq(title, last)) {
+ SetWindowTitle(title);
+ free(last);
+ last = title;
+ } else {
+ free(title);
+ }
+}
+
int
ui_textsize(char *text) {
return MeasureTextEx(font, text, FONT_SIZE, FONT_SIZE/10).x;
@@ -343,14 +367,16 @@ void
ui_handle_view_main(void) {
Vector2 mouse = GetMousePosition();
Vector2 delta = GetMouseDelta();
- float wheel;
+ float wheel = GetMouseWheelMove();
+ float diff;
+ int i;
#define SCROLL_DIVISOR 10
- wheel = GetMouseWheelMove();
- if (wheel < 0)
- view_main.kmperpx += (GetMouseWheelMove() * -1) * (view_main.kmperpx/SCROLL_DIVISOR);
- else if (wheel > 0)
- view_main.kmperpx -= GetMouseWheelMove() * (view_main.kmperpx/SCROLL_DIVISOR);
+ diff = wheel * (view_main.kmperpx/SCROLL_DIVISOR);
+ view_main.kmperpx -= diff;
+ view_main.kmx += (mouse.x - GetScreenWidth() / 2) * diff;
+ view_main.kmy += (mouse.y - GetScreenHeight() / 2) * diff;
+
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
if (view_main.pan) {
view_main.kmx -= delta.x * view_main.kmperpx;
@@ -363,40 +389,53 @@ ui_handle_view_main(void) {
if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT) && !view_main.ruler.held &&
!ui_collides(view_main.infobox.geom, mouse)) {
view_main.ruler.held = 1;
- view_main.ruler.origin = mouse;
+ view_main.ruler.origin = ui_pxtokm(mouse);
} else if (IsMouseButtonUp(MOUSE_BUTTON_RIGHT))
view_main.ruler.held = 0;
+ if (view_main.system != save->system) {
+ view_main.system = save->system;
+
+ ui_title("Tactical: %s", save->system->name);
+ }
+
+
}
void
ui_handle_view_colonies(void) {
-
+ ui_title("Colonies");
}
void
ui_handle_view_fleets(void) {
-
+ ui_title("Fleets");
}
void
ui_handle_view_design(void) {
-
+ ui_title("Design");
}
void
ui_handle_view_systems(void) {
-
+ ui_title("Systems");
}
void
ui_handle_view_settings(void) {
-
+ ui_title("Settings");
}
int
ui_should_draw_body(Body *body, int orbit) {
- if (!orbit && body->type != BODY_COMET && body->dist / view_main.kmperpx < ui_textsize(body->name))
+ if (!orbit && !ui_collides(SCREEN_RECT(), body->pxloc))
+ return 0;
+ if (!orbit && body->type != BODY_STAR &&
+ (body->type == BODY_COMET ? body->maxdist : body->dist) / view_main.kmperpx < ui_textsize(body->name))
+ return 0;
+ if (!orbit && body->parent && body->type != BODY_STAR &&
+ ui_vectordist(body->vector, body->parent->vector) < MIN_BODY_DIAM * view_main.kmperpx)
return 0;
if ((body->type == BODY_DWARF || (body->parent && body->parent->type == BODY_DWARF)) &&
(!orbit || !view_main.infobox.orbit.dwarf.val) &&
@@ -416,7 +455,6 @@ ui_should_draw_body(Body *body, int orbit) {
void
ui_draw_body(Body *body) {
Vector2 parent;
- Vector2 location;
int w;
if (body->parent) {
@@ -426,30 +464,34 @@ ui_draw_body(Body *body) {
parent.y = 0;
}
- location = ui_kmtopx(body->vector);
-
if (ui_should_draw_body(body, 1)) {
if (body->parent && body->type == BODY_COMET)
- DrawLineV(parent, location, COL_ORBIT);
+ DrawLineV(parent, body->pxloc, COL_ORBIT);
else if (body->parent)
- DrawCircleLines(parent.x, parent.y, ui_vectordist(parent, location), COL_ORBIT);
+ DrawCircleLines(parent.x, parent.y,
+ ui_vectordist(parent, body->pxloc),
+ COL_ORBIT);
}
if (body->radius / view_main.kmperpx > MIN_BODY_DIAM)
w = body->radius / view_main.kmperpx;
else
w = MIN_BODY_DIAM;
- DrawCircle(location.x, location.y, MIN_BODY_DIAM, COL_FG);
+ DrawCircle(body->pxloc.x, body->pxloc.y, w, COL_FG);
if (ui_should_draw_body(body, 0))
- ui_print(location.x + 5, location.y + 5, COL_FG, "%s", body->name);
+ ui_print(body->pxloc.x + w + 2, body->pxloc.y + w + 2,
+ COL_FG, "%s", body->name);
}
void
ui_draw_view_main(void) {
Vector2 mouse = GetMousePosition();
Vector2 mousekm = ui_pxtokm(mouse);
- Vector2 v[2];
+ Vector2 ruler;
Vector2 km;
Polar polar;
+ Body *body;
+ float *massa;
+ size_t massi;
float dist;
size_t i;
@@ -460,17 +502,18 @@ ui_draw_view_main(void) {
mousekm.x, mousekm.y);
ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 30, COL_FG, "FPS: %d (target: %d)", GetFPS(), TARGET_FPS);
- /* system bodies */
- if (!save->cache.system)
- save->cache.system = system_load(NULL, "Sol");
- for (i = 0; i < save->cache.system->bodies_len; i++)
- ui_draw_body(save->cache.system->bodies[i]);
+ /* draw system bodies */
+ for (i = 0; i < save->system->bodies_len; i++) {
+ body = save->system->bodies[i];
+ body->pxloc = ui_kmtopx(body->vector);
+ ui_draw_body(body);
+ }
/* ruler */
if (view_main.ruler.held) {
- DrawLineV(view_main.ruler.origin, mouse, COL_INFO);
- km = ui_pxtokm(view_main.ruler.origin);
- dist = ui_vectordist(km, mousekm);
+ ruler = ui_kmtopx(view_main.ruler.origin);
+ DrawLineV(ruler, mouse, COL_INFO);
+ dist = ui_vectordist(view_main.ruler.origin, mousekm);
ui_print(mouse.x + 10, mouse.y - 10, COL_INFO, "%s (%s)", strkmdist(dist), strlightdist(dist));
}