diff options
Diffstat (limited to 'web/web_control.c')
-rw-r--r-- | web/web_control.c | 257 |
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(); +} |