#include "web_control.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 void set_active_player(int pn) { state->active_player = pn; state->active_leg = state->legs[pn-1]; scoreboard_set_player_active(pn); if (state->mode == M_PVC && pn == 2) prompt_bot_visit(); else prompt_visit(); } 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); scoreboard_flush_player_info(state->active_player); } EMSCRIPTEN_KEEPALIVE void end_boat_visit(int rem, double avg) { svg_clear_points(); update_player_rem(2, rem); scoreboard_set_player_avg(2, 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) { char pts_str[10]; sprintf(pts_str, "%d", pts); int rem = state->legs[1]->n_visits > 1 ? state->legs[1]->visits[state->legs[1]->n_visits-2].rem : state->legs[1]->start; svg_draw_point(x, y); update_player_rem(2, rem - pts); prompt_set_input(pts_str); prompt_set_msgr(str); free(str); prompt_flush(); scoreboard_flush_player_info(2); // FIXME bot hard-coded as player 2 } 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 (match_is_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(); } } prompt_flush(); scoreboard_flush(); } EMSCRIPTEN_KEEPALIVE void user_visit(int points) { if (!is_points_valid(points, state->active_leg->rem)) { 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) { oi(); return; } if (state->num_darts) { state->num_darts = 0; struct leg *l = state->active_leg; scoreboard_set_player_avg(state->active_player, ((double)(l->start - l->visits[l->n_visits-2].rem) / (l->n_visits - 1))); scoreboard_set_player_active(state->active_player); handle_next(); return; } if (state->mode == M_PVC) { set_active_player(1); } else if (state->mode == M_PVP) { if (match_is_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; memset(v, 0, sizeof(*v)); if (state->mode == M_PVC && state->legs[1]->n_visits > l->n_visits) { struct leg *bl = state->legs[1]; bl->rem += bl->visits[--bl->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) { 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) { 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"); show_player_info(1); update_player_name(1, state->legs[0]->name); update_player_rem(1, state->legs[0]->rem); update_player_avg(1, 0); if (mode != M_P) { show_player_info(2); update_player_name(2, state->legs[1]->name); update_player_rem(2, state->legs[1]->rem); update_player_avg(2, 0); } draw_visits(); handle_next(); } EMSCRIPTEN_KEEPALIVE void end_match() { if (state) free_state(); handle_next(); }