diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index f96d927..504c02f 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -10,4 +10,4 @@ add_library(gui
"src/rounded_rect.c"
)
target_include_directories(gui PUBLIC "inc" PRIVATE "privinc")
-target_link_libraries(gui PUBLIC camera gfx input peripheral font)
+target_link_libraries(gui PUBLIC camera gfx input net peripheral font)
diff --git a/src/menu/CMakeLists.txt b/src/menu/CMakeLists.txt
index 940b26b..465250f 100644
--- a/src/menu/CMakeLists.txt
+++ b/src/menu/CMakeLists.txt
@@ -1,6 +1,7 @@
add_library(menu
"src/gamecfg_menu.c"
"src/hostjoin_menu.c"
+ "src/join_menu.c"
"src/menu.c"
"src/main_menu.c"
)
diff --git a/src/menu/privinc/menu_private.h b/src/menu/privinc/menu_private.h
index 0276b20..181825c 100644
--- a/src/menu/privinc/menu_private.h
+++ b/src/menu/privinc/menu_private.h
@@ -24,6 +24,7 @@ int menu_update(struct menu_common *c,
void *arg);
int menu_main(struct menu_common *c);
int menu_hostjoin(struct menu_common *c, bool *back);
+int menu_join(struct menu_common *c);
int menu_gamecfg(struct menu_common *c);
void menu_on_pressed(void *arg);
diff --git a/src/menu/src/hostjoin_menu.c b/src/menu/src/hostjoin_menu.c
index 49d5ec9..9ce93b1 100644
--- a/src/menu/src/hostjoin_menu.c
+++ b/src/menu/src/hostjoin_menu.c
@@ -75,9 +75,16 @@ int menu_hostjoin(struct menu_common *const c, bool *const back)
return -1;
}
- if (host || join)
+ if (host)
+ {
if (menu_gamecfg(c))
return -1;
+ }
+ else if (join)
+ {
+ if (menu_join(c))
+ return -1;
+ }
} while (!*back && !c->p.common.exit);
diff --git a/src/menu/src/join_menu.c b/src/menu/src/join_menu.c
new file mode 100644
index 0000000..40b0f4e
--- /dev/null
+++ b/src/menu/src/join_menu.c
@@ -0,0 +1,262 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct join_menu
+{
+ struct gui_container cnt, bcnt;
+ struct gui_label type_label, address, port, connecting;
+ struct gui_button type_btn, back, connect;
+ struct gui_line_edit address_le, port_le;
+
+ enum
+ {
+ IDLE,
+ CONNECT,
+ CONNECTING,
+ CONNECTED,
+ CONNECT_FAILED
+ } state;
+
+ struct net_socket *socket;
+ size_t domain_i;
+};
+
+static const enum net_domain domains[] =
+{
+ NET_DOMAIN_IPV4,
+ NET_DOMAIN_SERIAL
+};
+
+static void on_connected(void *const arg)
+{
+ struct join_menu *const m = arg;
+
+ if (m->state == IDLE)
+ {
+ m->state = CONNECT;
+ m->connecting.text = "Connecting...";
+ }
+}
+
+static void on_disconnected(void *const arg)
+{
+ struct join_menu *const m = arg;
+
+ m->connecting.text = "Failed to connect";
+ m->state = CONNECT_FAILED;
+ m->socket = NULL;
+}
+
+static int on_connect(struct join_menu *const m)
+{
+ const enum net_domain d = domains[m->domain_i];
+
+ union net_connect c =
+ {
+ .common =
+ {
+ .domain = d,
+ .on_connected = on_connected,
+ .on_disconnected = on_disconnected,
+ .arg = m
+ }
+ };
+
+ switch (d)
+ {
+ case NET_DOMAIN_IPV4:
+ {
+ errno = 0;
+
+ const unsigned long port = strtoul(m->port_le.text, NULL, 0);
+
+ if (errno)
+ return -1;
+
+ c.ipv4.addr = m->address_le.text;
+ c.ipv4.port = port;
+ }
+ break;
+
+ case NET_DOMAIN_SERIAL:
+ break;
+ }
+
+ if (!(m->socket = net_connect(&c)))
+ {
+ fprintf(stderr, "%s: net_connect failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int update(struct menu_common *const c, void *const arg)
+{
+ struct join_menu *const m = arg;
+
+ m->bcnt.common.y = screen_h - 40;
+
+ if (gui_update(&m->cnt.common, &c->p, &c->cam, &c->in)
+ || gui_update(&m->bcnt.common, &c->p, &c->cam, &c->in))
+ return -1;
+
+ if (m->socket && net_update(m->socket))
+ return -1;
+
+ switch (m->state)
+ {
+ case CONNECT:
+ if (on_connect(m))
+ return -1;
+
+ m->state = CONNECTING;
+
+ if (!m->connecting.common.parent)
+ gui_add_child(&m->cnt.common, &m->connecting.common);
+
+ break;
+
+ case CONNECT_FAILED:
+ net_close(m->socket);
+ m->socket = NULL;
+ m->state = IDLE;
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int render(const struct menu_common *const c, void *const arg)
+{
+ const struct join_menu *const m = arg;
+
+ if (gui_render(&m->cnt.common)
+ || gui_render(&m->bcnt.common))
+ return -1;
+
+ return 0;
+}
+
+static void on_type_pressed(void *const arg)
+{
+ struct join_menu *const m = arg;
+
+ if (++m->domain_i >= sizeof domains / sizeof *domains)
+ m->domain_i = 0;
+
+ m->type_btn.u.type1.label.text = net_domain_str(domains[m->domain_i]);
+}
+
+static void on_connect_pressed(void *const arg)
+{
+ struct join_menu *const m = arg;
+
+ m->state = CONNECT;
+}
+
+int menu_join(struct menu_common *const c)
+{
+ int ret = -1;
+ struct join_menu m = {0};
+ bool connect = false;
+ bool back = false;
+
+ gui_container_init(&m.cnt);
+ m.cnt.common.hcentered = true;
+ m.cnt.common.vcentered = true;
+ m.cnt.mode = GUI_CONTAINER_MODE_V;
+ m.cnt.spacing = 2;
+
+ gui_label_init(&m.type_label);
+ m.type_label.common.hcentered = true;
+ m.type_label.text = "Type:";
+ gui_add_child(&m.cnt.common, &m.type_label.common);
+
+ gui_button_init(&m.type_btn, GUI_BUTTON_TYPE_1);
+ m.type_btn.arg = &m;
+ m.type_btn.u.type1.w = 140;
+ m.type_btn.common.hcentered = true;
+ m.type_btn.on_pressed = on_type_pressed;
+ m.type_btn.u.type1.label.text = net_domain_str(*domains);
+ gui_add_child(&m.cnt.common, &m.type_btn.common);
+
+ gui_label_init(&m.address);
+ m.address.common.hcentered = true;
+ m.address.text = "Address:";
+ gui_add_child(&m.cnt.common, &m.address.common);
+
+ char address[sizeof "255.255.255.255"];
+ gui_line_edit_init(&m.address_le, address, sizeof address);
+ m.address_le.w = 140;
+ m.address_le.common.hcentered = true;
+ gui_add_child(&m.cnt.common, &m.address_le.common);
+
+ gui_label_init(&m.port);
+ m.port.common.hcentered = true;
+ m.port.text = "Port:";
+ gui_add_child(&m.cnt.common, &m.port.common);
+
+ char port[sizeof "65535"];
+ gui_line_edit_init(&m.port_le, port, sizeof port);
+ m.port_le.w = 80;
+ m.port_le.common.hcentered = true;
+ gui_add_child(&m.cnt.common, &m.port_le.common);
+
+ gui_label_init(&m.connecting);
+ m.connecting.common.hcentered = true;
+
+ gui_container_init(&m.bcnt);
+ m.bcnt.common.hcentered = true;
+ m.bcnt.mode = GUI_CONTAINER_MODE_H;
+
+ gui_button_init(&m.connect, GUI_BUTTON_TYPE_1);
+ m.connect.u.type1.label.text = "Connect";
+ m.connect.u.type1.w = 140;
+ m.connect.common.vcentered = true;
+ m.connect.on_pressed = on_connect_pressed;
+ m.connect.arg = &m;
+ m.back.common.vcentered = true;
+ gui_add_child(&m.bcnt.common, &m.connect.common);
+
+ gui_button_init(&m.back, GUI_BUTTON_TYPE_1);
+ m.back.u.type1.label.text = "Back";
+ m.back.u.type1.w = 100;
+ m.back.common.vcentered = true;
+ m.back.on_pressed = menu_on_pressed;
+ m.back.arg = &back;
+ m.back.common.vcentered = true;
+ gui_add_child(&m.bcnt.common, &m.back.common);
+
+ while (!back && !c->p.common.exit && !connect)
+ {
+ if (menu_update(c, update, render, &m))
+ goto end;
+ }
+
+ if (connect)
+ {
+
+ }
+
+ ret = 0;
+
+end:
+ gui_deinit(&m.cnt.common, &c->in);
+ return ret;
+}
diff --git a/src/menu/src/settings_menu.c b/src/menu/src/settings_menu.c
new file mode 100644
index 0000000..0e782bd
--- /dev/null
+++ b/src/menu/src/settings_menu.c
@@ -0,0 +1,62 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct menu_settings
+{
+ struct gui_container cnt;
+ struct gui_button back;
+};
+
+static int update(struct menu_common *const c, void *const arg)
+{
+ struct menu_settings *const m = arg;
+
+ if (gui_update(&m->cnt.common, &c->p, &c->cam, &c->in))
+ return -1;
+
+ return 0;
+}
+
+static int render(const struct menu_common *const c, void *const arg)
+{
+ const struct menu_settings *const m = arg;
+
+ if (gui_render(&m->cnt.common))
+ return -1;
+
+ return 0;
+}
+
+int menu_settings(struct menu_common *const c, bool *const back)
+{
+ do
+ {
+ struct menu_settings m;
+
+ gui_container_init(&m.cnt);
+ m.cnt.common.hcentered = true;
+ m.cnt.common.vcentered = true;
+ m.cnt.spacing = 4;
+ m.cnt.mode = GUI_CONTAINER_MODE_V;
+
+ gui_button_init(&m.back, GUI_BUTTON_TYPE_1);
+ m.back.u.type1.label.text = "Back";
+ m.back.common.hcentered = true;
+ m.back.u.type1.w = 140;
+ m.back.arg = back;
+ m.back.on_pressed = menu_on_pressed;
+ gui_add_child(&m.cnt.common, &m.back.common);
+
+ while (!*back && !c->p.common.exit)
+ if (menu_update(c, update, render, &m))
+ return -1;
+
+ } while (!*back && !c->p.common.exit);
+
+ return 0;
+}
diff --git a/src/system/CMakeLists.txt b/src/system/CMakeLists.txt
index 011aee6..4c315b9 100644
--- a/src/system/CMakeLists.txt
+++ b/src/system/CMakeLists.txt
@@ -1,5 +1,5 @@
set(inc "inc")
-set(privdeps gfx sfx)
+set(privdeps gfx sfx net)
if(PS1_BUILD)
set(src "ps1/src/init.c")
diff --git a/src/system/ps1/src/init.c b/src/system/ps1/src/init.c
index 4c30fbd..4ad12c2 100644
--- a/src/system/ps1/src/init.c
+++ b/src/system/ps1/src/init.c
@@ -1,4 +1,5 @@
#include
+#include
#include
#include
#include
@@ -20,13 +21,14 @@ void system_deinit(void)
{
gfx_deinit();
sfx_deinit();
+ net_deinit();
}
int system_init(void)
{
SetVBlankHandler(vblank);
- if (gfx_init() || sfx_init())
+ if (gfx_init() || sfx_init() || net_init())
return -1;
return 0;
diff --git a/src/system/sdl-1.2/src/system.c b/src/system/sdl-1.2/src/system.c
index 24c3e18..bff5e4f 100644
--- a/src/system/sdl-1.2/src/system.c
+++ b/src/system/sdl-1.2/src/system.c
@@ -1,5 +1,6 @@
#include
#include
+#include
#include
#include
#include
@@ -19,6 +20,7 @@ void system_deinit(void)
{
gfx_deinit();
sfx_deinit();
+ net_deinit();
SDL_Quit();
}
@@ -29,7 +31,7 @@ int system_init(void)
fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
goto failure;
}
- else if (gfx_init() || sfx_init())
+ else if (gfx_init() || sfx_init() || net_init())
goto failure;
SDL_WM_SetCaption("rts", NULL);