cepheid

An Aurora 4X clone
Log | Files | Refs | README

commit e1dc11030e3248648db58de69e027f19b6a8edb3
parent 963ea7493c3dcd6f5ac9ab18c9b913dd62e127aa
Author: hhvn <dev@hhvn.uk>
Date:   Sat,  6 Aug 2022 11:50:44 +0200

Saving properly

Diffstat:
MMakefile | 3+--
Mdb/db.c | 320+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mdb/db.h | 27++++++++++++++++++++-------
Msrc/main.c | 12++++++++----
Msrc/main.h | 4++++
Msrc/save.c | 18+++++++++++++-----
Msrc/str.c | 27+++++++++++++++++++++++++++
Msrc/struct.h | 17++++++++---------
Msrc/system.c | 71++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/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)); }