summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client.c149
-rw-r--r--src/server.c49
2 files changed, 144 insertions, 54 deletions
diff --git a/src/client.c b/src/client.c
index 207dc97..964e91f 100644
--- a/src/client.c
+++ b/src/client.c
@@ -30,6 +30,9 @@ typedef struct {
chunk map;
node *map_swap;
vec2 player_pos;
+ char *termbuf_buf;
+ size_t termbuf_size;
+ FILE *termbuf;
} client;
void gfx_alt_buffer(bool enable)
@@ -38,79 +41,129 @@ void gfx_alt_buffer(bool enable)
printf("\e[?1049h\e[?25l");
else
printf("\e[?1049l\e[?25h");
+ fflush(stdout);
}
-void gfx_clear_effects()
+void gfx_clear_effects(client *c)
{
- printf("\e[0m");
+ fprintf(c->termbuf, "\e[0m");
}
-void gfx_set_color(color c, bool bg)
+void gfx_set_color(client *c, color col, bool bg)
{
- printf("\e[%u;2;%u;%u;%um", bg ? 48 : 38, c.r, c.g, c.b);
+ fprintf(c->termbuf, "\e[%u;2;%u;%u;%um", bg ? 48 : 38, col.r, col.g, col.b);
}
-void gfx_clear()
+void gfx_clear(client *c)
{
- printf("\e[2J");
+ fprintf(c->termbuf, "\e[2J");
}
-void gfx_render_node(client *c, vec2 pos, node *n)
+#define C color_from_u32
+#define DISPLAY_BG(X) (node_display) { X, { 0 }, NULL }
+#define DISPLAY(...) (node_display) { __VA_ARGS__ }
+#define DISPLAY_ERR DISPLAY(C(0xff0000), C(0x000000), " ?")
+
+typedef struct {
+ color bg;
+ color fg;
+ char *texture;
+} node_display;
+
+bool gfx_rock_bg(node *n, color *c)
{
- if (!n->present) {
- gfx_set_color(color_from_u32(0x555555), true);
- gfx_set_color(color_from_u32(0xffffff), false);
- printf(" ?");
- return;
+ switch (n->z) {
+ case 1: *c = C(0x595959); return true;
+ case 2: *c = C(0x484848); return true;
+ case 3: *c = C(0x373737); return true;
+ default: return false;
}
+}
- gfx_set_color(n->col, true);
+color gfx_grass_bg(vec2 pos)
+{
+ return C(0x00880d);
+}
- if (vec2_eq(pos, c->player_pos)) {
- printf("🥺");
- return;
- }
+bool gfx_water_wave(vec2 pos)
+{
+ return true;
+}
+
+node_display gfx_render_node(client *c, vec2 pos, node *n)
+{
+ if (!n->present)
+ return DISPLAY(C(0x555555), C(0xffffff), " ?");
- // TODO: persistence
switch (n->type) {
- case N_GRASS: if (rand() % 10 == 0) {
- gfx_set_color(color_from_u32(0x1c571e), false);
- printf(" M");
- return;
- } break;
- case N_WATER: if (rand() % 10 == 0) {
- gfx_set_color(color_from_u32(0x0d79de), false);
- printf(" ~");
- return;
- } break;
- case N_SAND: if (rand() % 15 == 0) {
- gfx_set_color(color_from_u32(0xe3a112), false);
- printf(" ~");
- return;
- } break;
- default: break;
+ case N_VALLEY_FLOWER:
+ case N_MOUNTAIN_FLOWER: {
+ node_display d = {0};
+ if (n->type == N_VALLEY_FLOWER)
+ d.bg = gfx_grass_bg(pos);
+ else if (!gfx_rock_bg(n, &d.bg))
+ return DISPLAY_ERR;
+ switch (n->variant) {
+ case FLOWER_ROSE: d.texture = "🌹"; break;
+ case FLOWER_HIBISCUS: d.texture = "🌺"; break;
+ case FLOWER_SUNFLOWER: d.texture = "🌻"; break;
+ case FLOWER_DANDELION: d.texture = "🌼"; break;
+ case FLOWER_TULIP: d.texture = "🌷"; break;
+ default: return DISPLAY_ERR;
+ }
+ return d;
+ }
+ case N_ROCK: {
+ node_display d = {0};
+ if (!gfx_rock_bg(n, &d.bg))
+ return DISPLAY_ERR;
+ return d;
+ }
+ case N_WATER: return DISPLAY(C(0x00c6ff), C(0x0d79de),
+ n->variant && gfx_water_wave(pos) ? " ~" : NULL);
+ case N_GRASS: return DISPLAY(gfx_grass_bg(pos), C(0x1c571e), n->variant ? " M" : NULL);
+ case N_SAND: return DISPLAY(C(0xded485), C(0xe3a112), n->variant ? " ~" : NULL);
+ case N_NEEDLE_TREE: return DISPLAY_BG(C(0x015100));
+ case N_PATH: return DISPLAY_BG(C(0xa09700));
+ case N_PLANK: return DISPLAY_BG(C(0x5c3b12));
+ case N_BIG_TREE: return DISPLAY_BG(C(0x016300));
+ default: return DISPLAY_ERR;
}
-
- printf(" ");
}
+#undef C
+#undef DISPLAY
+#undef DISPLAY_ERR
void gfx_render(client *c, uint64_t dtime)
{
- gfx_clear();
- printf("\e[H");
- printf("%.*s\n", PSTR(c->server_motd));
+ rewind(c->termbuf);
+ gfx_clear(c);
+ fprintf(c->termbuf, "\e[H");
+ fprintf(c->termbuf, "%.*s\n", PSTR(c->server_motd));
for (size_t i = 0; i < c->players.len; i++)
- printf("%.*s\n", PSTR(c->players.data[i].name));
+ fprintf(c->termbuf, "%.*s\n", PSTR(c->players.data[i].name));
for (size_t y = 0; y < c->map.bounds.size.y; y++) {
for (size_t x = 0; x < c->map.bounds.size.y; x++) {
uvec2 off = UVEC2(x, y);
- vec2 p = vec2_add(c->map.bounds.pos, CVEC2(off));
- gfx_render_node(c, p, chunk_index(c->map, off));
+ vec2 pos = vec2_add(c->map.bounds.pos, CVEC2(off));
+
+ node_display dis = gfx_render_node(c, pos, chunk_index(c->map, off));
+ gfx_set_color(c, dis.bg, true);
+ if (vec2_eq(pos, c->player_pos)) {
+ fprintf(c->termbuf, "🙂");
+ } else if (dis.texture) {
+ gfx_set_color(c, dis.fg, false);
+ fprintf(c->termbuf, "%s", dis.texture);
+ } else {
+ fprintf(c->termbuf, " ");
+ }
}
- gfx_clear_effects();
- printf("\n");
+ gfx_clear_effects(c);
+ fprintf(c->termbuf, "\n");
}
+ fflush(c->termbuf);
+ fwrite(c->termbuf_buf, 1, ftell(c->termbuf), stdout);
fflush(stdout);
}
@@ -135,8 +188,10 @@ void client_exit(client *c, int ret)
peer_free(&c->conn);
tcsetattr(STDIN_FILENO, TCSANOW, &c->oldtio);
+
+ fclose(c->termbuf);
+ free(c->termbuf_buf);
gfx_alt_buffer(false);
- fflush(stdout);
exit(ret);
}
@@ -314,7 +369,7 @@ int main(int argc, char **argv)
str server_name = S("server");
peer_init(&c.conn, socket, &server_name);
- setvbuf(stdout, NULL, _IOFBF, 0);
+ c.termbuf = open_memstream(&c.termbuf_buf, &c.termbuf_size);
gfx_alt_buffer(true);
SEND_PKT(c.conn, SPKT_HI,
@@ -326,7 +381,7 @@ int main(int argc, char **argv)
c.map_swap = malloc(c.map.bounds.size.x * c.map.bounds.size.y * sizeof(node));
ticker t;
- ticker_init(&t, NANOS/60);
+ ticker_init(&t, NANOS/30);
for (;;) {
struct pollfd fds[2];
diff --git a/src/server.c b/src/server.c
index 30b5676..974e396 100644
--- a/src/server.c
+++ b/src/server.c
@@ -14,6 +14,8 @@
#include <errno.h>
#include <poll.h>
#include <png.h>
+#include <perlin.h>
+#include <math.h>
#include "array.h"
#include "content.h"
#include "net.h"
@@ -70,30 +72,63 @@ node *map_node(game *g, vec2 p, int8_t z)
return NULL;
}
+bool silly_noise(vec2 pos, uint32_t grid, double sillyness, int seed)
+{
+ int64_t x = (int64_t) pos.x+INT_MAX+1;
+ int64_t y = (int64_t) pos.y+INT_MAX+1;
+
+ if ((y/grid) % 2 == 0)
+ x += grid/2;
+
+ x += round(noise2d(x/grid, y/grid, 0, seed) * sillyness);
+ y += round(noise2d(y/grid, x/grid, 0, seed) * sillyness);
+
+ return x % grid == 0 && y % grid == 0;
+#undef SMOD
+}
+
void map_load_node(map *m, uvec2 v, color col)
{
uint32_t ucol = color_to_u32(col);
+ vec2 pos = vec2_add(m->chunk.bounds.pos, CVEC2(v));
+
node *n = chunk_index(m->chunk, v);
- n->present = ucol != 0xffffff;
+ *n = (node) { 0 };
+ n->present = ucol != 0xffffff;
if (!n->present)
return;
- n->z = 0;
- n->col = col;
switch (ucol) {
- case 0x00880d: n->type = N_GRASS; break; // TODO: color
+ case 0x00880d: n->type = N_GRASS;
+ n->variant = silly_noise(pos, 3, 1.0, 0);
+ break;
case 0x595959: n->type = N_ROCK; n->z = 1; break;
case 0x484848: n->type = N_ROCK; n->z = 2; break;
case 0x373737: n->type = N_ROCK; n->z = 3; break;
- case 0x00ffe8: n->type = N_MOUNTAIN_FLOWER; break;
+ case 0x00ffe8: n->type = N_MOUNTAIN_FLOWER;
+ n->variant = FLOWER_DANDELION;
+ n->z = 3;
+ break;
+ case 0x001b51: n->type = N_MOUNTAIN_FLOWER;
+ n->variant = FLOWER_DANDELION;
+ n->z = 2;
+ break;
case 0xa09700: n->type = N_PATH; break;
case 0x015100: n->type = N_NEEDLE_TREE; break;
- case 0x00c6ff: n->type = N_WATER; n->z = -1; break;
+ case 0x00c6ff: n->type = N_WATER;
+ n->variant = silly_noise(pos, 3, 0.7, 1);
+ n->z = -1;
+ break;
case 0x5c3b12: n->type = N_PLANK; break;
- case 0xff9de2: n->type = N_VALLEY_FLOWER; break; // TODO: color
+ case 0xff9de2: n->type = N_VALLEY_FLOWER;
+ n->variant = rand() % FLOWER_COUNT;
+ break;
case 0x016300: n->type = N_BIG_TREE; break;
+ case 0xfce84e: n->type = N_SAND;
+ n->variant = silly_noise(pos, 4, 1.0, 1);
+ break;
default:
fprintf(stderr, "invalid color in map %.*s at %"PRIu32" %"PRIu32": %06x\n",
PSTR(m->name), v.x, v.y, ucol);