summaryrefslogtreecommitdiff
path: root/web/web_control.c
diff options
context:
space:
mode:
Diffstat (limited to 'web/web_control.c')
-rw-r--r--web/web_control.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/web/web_control.c b/web/web_control.c
new file mode 100644
index 0000000..b1e20bc
--- /dev/null
+++ b/web/web_control.c
@@ -0,0 +1,257 @@
+#include "web_control.h"
+#include "web_match.h"
+#include "web_opts.h"
+#include "web_prompt.h"
+#include "web_ui.h"
+
+#include "comp.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <emscripten/emscripten.h>
+
+void set_active_player(int pn)
+{
+ state->active_player = pn;
+ state->active_leg = state->legs[pn-1];
+ EM_ASM({setPlayerActive($0)}, pn);
+
+ if (state->mode == M_PVC && pn == 2) {
+ EM_ASM({promptMsgL($0)}, "Bot is throwing…");
+ set_prompt_mode(PM_DARTBOARD);
+ } else {
+ EM_ASM({promptMsgL($0)}, "Enter points:");
+ EM_ASM({setKeyLabel($0, $1)}, "submit", "OK");
+ EM_ASM({setKeyLabel($0, $1)}, "rem", "REMAINING");
+ set_prompt_mode(PM_VISIT);
+ }
+ EM_ASM({promptMsgR($0)}, "");
+}
+
+void toggle_active_player()
+{
+ set_active_player(3 - state->active_player);
+}
+
+EMSCRIPTEN_KEEPALIVE
+void update_user_rem_from_pts(int pts)
+{
+ update_player_rem(state->active_player, state->active_leg->rem - pts);
+}
+
+EMSCRIPTEN_KEEPALIVE
+void end_boat_visit(int rem, double avg)
+{
+ EM_ASM(svgClearPoints());
+ update_player_rem(2, rem);
+ EM_ASM({updatePlayerAvg($0, $1)}, 2, avg);
+ EM_ASM({setPromptInput($0)}, "");
+ EM_ASM({promptMsgR($0)}, "");
+
+ draw_visits();
+ handle_next();
+}
+
+EMSCRIPTEN_KEEPALIVE
+void boat_visit()
+{
+ struct leg *l = state->legs[1];
+ if (state->boat_undone) {
+ --state->boat_undone;
+ l->rem = l->visits[l->n_visits++].rem;
+ } else {
+ comp_visit(l);
+ }
+
+ struct visit *v = l->visits + l->n_visits - 1;
+ double avg = v->rem > 0 ?
+ (double)(l->start - l->rem) / l->n_visits :
+ (double)l->start / (((l->n_visits - 1) * 3) + v->n_darts) * 3;
+
+ if (!delay_ms) {
+ end_boat_visit(l->rem, avg);
+ return;
+ }
+
+ int pts = 0;
+ char str[15] = {0};
+ size_t len_str = 0;
+
+ for (int i = 0; i < v->n_darts; ++i) {
+ pts += segment_points(v->darts[i]);
+ char *seg_name = segment_name(v->darts[i]);
+ len_str += sprintf(str + len_str, i ? "-%s" : "%s", seg_name);
+ free(seg_name);
+
+ struct ccoords c = v->ccoords[i];
+
+ char *tmp = malloc(len_str + 1); // free in draw_boat_throwing
+ memcpy(tmp, str, len_str + 1);
+ EM_ASM({scheduleCCall($0, $1, $2, $3, $4, $5)}, "draw_boat_throwing",
+ delay_ms * (i+1), pts, tmp, c.x, c.y);
+ }
+
+ EM_ASM({scheduleCCall($0, $1, $2, $3)}, "end_boat_visit",
+ delay_ms * (v->n_darts + 1), l->rem, avg);
+}
+
+void handle_next()
+{
+ if (!state) {
+ prompt_select_mode();
+ } else if (is_match_over()) {
+ if (state->num_darts ||
+ (state->mode == M_PVC && state->legs[1]->rem <= 0))
+ prompt_end_match();
+ else
+ prompt_num_darts();
+ } else {
+ if (state->mode == M_P) {
+ set_active_player(1);
+ } else {
+ if (state->active_player)
+ toggle_active_player();
+ else
+ set_active_player(1);
+
+ if (state->mode == M_PVC && state->active_player == 2)
+ boat_visit();
+ }
+ }
+}
+
+EMSCRIPTEN_KEEPALIVE
+void user_visit(int points)
+{
+ if (!is_points_valid(points, state->active_leg->rem)) {
+ EM_ASM(oi());
+ return;
+ }
+
+ struct leg *l = state->active_leg;
+ if (l->n_visits == l->size_visits)
+ leg_grow_visits(l);
+ struct visit *v = l->visits + l->n_visits++;
+ v->points = points;
+ l->rem -= points;
+ v->rem = l->rem;
+ update_player_rem(state->active_player, l->rem);
+
+ if (v->rem > 0)
+ update_player_avg(state->active_player, 0);
+
+ draw_visits();
+ handle_next();
+}
+
+EMSCRIPTEN_KEEPALIVE
+void user_visit_to_rem(int rem)
+{
+ user_visit(state->legs[0]->rem - rem);
+}
+
+EMSCRIPTEN_KEEPALIVE
+void user_undo()
+{
+ if (!state->legs[0]->n_visits) {
+ EM_ASM(oi());
+ return;
+ }
+
+ if (state->num_darts) {
+ state->num_darts = 0;
+ EM_ASM({updatePlayerAvg($0, $1)}, state->active_player,
+ ((double)(state->active_leg->start -
+ state->active_leg->visits[
+ state->active_leg->n_visits-2].rem) /
+ (state->active_leg->n_visits-1)));
+ handle_next();
+ return;
+ }
+
+ if (state->mode == M_PVC) {
+ set_active_player(1);
+ } else if (state->mode == M_PVP) {
+ if (is_match_over())
+ set_active_player(state->active_player);
+ else
+ toggle_active_player();
+ }
+
+ struct leg *l = state->active_leg;
+ struct visit *v = l->visits + --l->n_visits;
+ l->rem += v->points;
+ memcpy(v, 0, sizeof(*v));
+
+ if (state->mode == M_PVC && state->legs[1]->n_visits > l->n_visits) {
+ state->legs[1]->rem +=
+ state->legs[1]->visits[--state->legs[1]->n_visits].points;
+ ++state->boat_undone;
+ }
+
+ update_player_avg(state->active_player, 0);
+ update_player_rem(state->active_player, l->rem);
+ if (state->mode == M_PVC) {
+ update_player_avg(2, 0);
+ update_player_rem(2, state->legs[1]->rem);
+ }
+
+ draw_visits();
+
+ if (state->mode != M_P) // FIXME avoid double toggle?
+ toggle_active_player();
+ handle_next();
+}
+
+EMSCRIPTEN_KEEPALIVE
+void user_num_darts(int n)
+{
+ if (n < 1 || n > 3) {
+ EM_ASM(oi());
+ return;
+ }
+
+ state->num_darts = n;
+ update_player_avg(state->active_player, n);
+
+ handle_next();
+}
+
+EMSCRIPTEN_KEEPALIVE
+void start_match(int mode)
+{
+ if (mode < M_FIRST || mode > M_LAST) {
+ EM_ASM(oi());
+ return;
+ }
+
+ if (state) free_state(); // rematch gets us here
+ state = calloc(1, sizeof(*state));
+ state->mode = mode;
+ state->legs[0] = leg_init(501, mode == M_PVP ? "Player 1" : "User");
+ state->legs[1] = leg_init(501, mode == M_PVC ? "Bot" : "Player 2");
+
+ EM_ASM({showPlayerInfo($0)}, 1);
+ EM_ASM({updatePlayerName($0, $1)}, 1, state->legs[0]->name);
+ update_player_rem(1, state->legs[0]->rem);
+ EM_ASM({updatePlayerAvg($0, $1)}, 1, 0);
+
+ if (mode != M_P) {
+ EM_ASM({showPlayerInfo($0)}, 2);
+ EM_ASM({updatePlayerName($0, $1)}, 2, state->legs[1]->name);
+ update_player_rem(2, state->legs[1]->rem);
+ EM_ASM({updatePlayerAvg($0, $1)}, 2, 0);
+ }
+
+ draw_visits();
+ handle_next();
+}
+
+EMSCRIPTEN_KEEPALIVE
+void end_match()
+{
+ if (state) free_state();
+ handle_next();
+}