#include "web_control.h" #include "web_dom.h" #include "web_match.h" #include "web_opts.h" #include "web_prompt.h" #include "web_scoreboard.h" #include "web_svg.h" #include "comp.h" #include #include #include #include #include void set_active_player(int pn) { state->m->active_player = pn; scoreboard_set_player_active(pn); if (match_player_is_comp(pn)) prompt_comp_visit(); else prompt_user_visit(); } void update_user_rem_from_pts(int pts) { int pn = state->m->active_player; update_player_rem(pn, state->m->legs[pn - 1]->rem - pts); scoreboard_flush_player_info(pn); } EMSCRIPTEN_KEEPALIVE void end_boat_visit(int rem, double avg, int match_id) { if (!state || match_id != state->id) return; svg_clear_points(); update_player_rem(state->m->active_player, rem); scoreboard_set_player_avg(state->m->active_player, avg); prompt_set_input(NULL); prompt_set_msgr(NULL); draw_visits(); handle_next(); } EMSCRIPTEN_KEEPALIVE void draw_boat_throwing(int pts, char *str, double x, double y, int match_id) { if (!state || match_id != state->id) return; char pts_str[10]; sprintf(pts_str, "%d", pts); int pn = state->m->active_player; struct leg *l = state->m->legs[pn - 1]; int rem = l->n_visits > 1 ? l->visits[l->n_visits-2].rem : l->start; svg_draw_point(x, y); update_player_rem(pn, rem - pts); prompt_set_input(pts_str); prompt_set_msgr(str); free(str); prompt_flush(); scoreboard_flush_player_info(pn); } static void schedule_boat_visit_draws(struct leg *l, struct visit *v, double avg) { 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]); len_str += sprintf(str + len_str, i ? "-%s" : "%s", segment_name(v->darts[i])); struct ccoords c = v->ccoords[i]; int delay = delay_ms * (i + 1); if (delay_ms >= SVG_THROW_ANIM_MS) delay -= SVG_THROW_ANIM_MS; 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, $6)}, "draw_boat_throwing", delay, pts, tmp, c.x, c.y, state->id); } EM_ASM({scheduleCCall($0, $1, $2, $3, $4)}, "end_boat_visit", delay_ms * (v->n_darts + 1), l->rem, avg, state->id); } void boat_visit() { struct leg *l = state->m->legs[state->m->active_player - 1]; struct visit *v = leg_comp_visit(l, true); 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) schedule_boat_visit_draws(l, v, avg); else end_boat_visit(l->rem, avg, state->id); } void handle_next() { int wp; if (!state) { prompt_main_menu(); } else if ((wp = match_winning_player(state->m))) { if (state->num_darts || match_player_is_comp(wp)) prompt_end_match(); else prompt_num_darts(); } else { if (state->m->active_player) set_active_player(match_next_player(state->m)); else set_active_player(state->m->starting_player); if (match_player_is_comp(state->m->active_player)) boat_visit(); } prompt_flush(); scoreboard_flush(); } void user_visit(int points) { int pn = state->m->active_player; struct leg *l = state->m->legs[pn - 1]; struct visit *v = leg_pts_visit(l, points); if (!v) { oi(); return; } update_player_rem(pn, v->rem); if (v->rem > 0) update_player_avg(pn, 0); draw_visits(); handle_next(); } void user_visit_to_rem(int rem) { user_visit(state->m->legs[state->m->active_player - 1]->rem - rem); } static void undo_active() { int pn = state->m->active_player; struct leg *l = state->m->legs[pn - 1]; leg_undo_visit(l); update_player_avg(pn, 0); update_player_rem(pn, l->rem); state->m->active_player = match_prev_throw_player(state->m); } void user_undo() { if (!match_first_user_has_thrown(state->m)) { oi(); return; } if (state->num_darts) { state->num_darts = 0; int pn = state->m->active_player; struct leg *l = state->m->legs[pn - 1]; scoreboard_set_player_avg(pn, ((double)(l->start - l->visits[l->n_visits-2].rem) / (l->n_visits - 1))); scoreboard_set_player_active(pn); handle_next(); return; } state->m->active_player = match_prev_throw_player(state->m); while (match_player_is_comp(state->m->active_player)) undo_active(); undo_active(); draw_visits(); handle_next(); } void user_num_darts(int n) { if (n < 1 || n > 3) { oi(); return; } state->num_darts = n; update_player_avg(state->m->active_player, n); handle_next(); } void start_match() { match_new(); for (int i = 0; i < match_opts->num_players; ++i) match_add_player(state->m, match_opts->players[i].type, match_opts->players[i].name, match_opts->start_pts); state->m->starting_player = match_opts->throws_first; scoreboard_show_info(state->m->n_players); for (int i = 1; i <= state->m->n_players; ++i) { update_player_name(i, state->m->players[i - 1].name); update_player_rem(i, state->m->legs[i - 1]->rem); update_player_avg(i, 0); } dom_enable_exit_dialogue(true); dom_add_class("#key-exit", "visible"); draw_visits(); handle_next(); } void end_match() { // clean up in case match was ended early svg_clear_points(); prompt_set_input(NULL); scoreboard_set_player_active(0); dom_remove_class("#key-exit", "visible"); dom_enable_exit_dialogue(false); if (state) free_state(); handle_next(); }