// local includes
#include "constants.h"
#include "ems.h"
+#include "helpers.h"
Game::Game()
: spriteSheet(std::nullopt), status("Unknown status"), readyTimer(0.0F),
- prevPos(0), cachedPos(0) {
+ resultsTimer(RESULTS_TIMER_MAX), scoreChangeTimer(SCORE_CHANGE_TIMER_MAX),
+ requestTimer(REQUEST_TIMER_MAX), prevPos(0), cachedPos(0) {
spriteSheet = LoadTexture("resources/rockpaperscissorsSpriteSheet.png");
picked[0] = 0;
const char *currentPlayer, char first_first,
char first_second, char first_third, char second_first,
char second_second, char second_third, bool first_ready,
- bool second_ready, int pos) {
+ bool second_ready, int pos, int matchup_idx) {
+ // TODO DEBUG
+ if (std::strcmp(playerOne, currentPlayer) == 0) {
+ std::clog << "update_state:\n"
+ << " is p1: "
+ << (std::strcmp(playerOne, currentPlayer) == 0 ? "true" : "false")
+ << std::endl
+ << " p1: " << first_first << ", " << first_second << ", "
+ << first_third << "\n p2: " << second_first << ", "
+ << second_second << ", " << second_third << "\nfirst is "
+ << (first_ready ? "ready" : "not ready") << "\nsecond is "
+ << (second_ready ? "ready" : "not ready") << "\npos: " << pos
+ << " matchup_idx: " << matchup_idx << std::endl;
+ std::clog << "flags: " << flags.to_string().substr(32 - 13) << std::endl;
+ }
// TODO handle changing choices from r/p/s to w/l and etc.
if (playerOne) {
this->playerOne = playerOne;
- opponentPicked[0] = second_first;
- opponentPicked[1] = second_second;
- opponentPicked[2] = second_third;
}
if (playerTwo) {
this->playerTwo = playerTwo;
- opponentPicked[0] = first_first;
- opponentPicked[1] = first_second;
- opponentPicked[2] = first_third;
}
+ if (std::strcmp(playerOne, currentPlayer) == 0) {
+ isPlayerOne = true;
+ if (Helpers::isValidChoice(second_first) &&
+ Helpers::isValidChoice(second_second) &&
+ Helpers::isValidChoice(second_third)) {
+ opponentPicked[0] = second_first;
+ opponentPicked[1] = second_second;
+ opponentPicked[2] = second_third;
+ }
+ } else if (std::strcmp(playerTwo, currentPlayer) == 0) {
+ isPlayerOne = false;
+ if (Helpers::isValidChoice(first_first) &&
+ Helpers::isValidChoice(first_second) &&
+ Helpers::isValidChoice(first_third)) {
+ opponentPicked[0] = first_first;
+ opponentPicked[1] = first_second;
+ opponentPicked[2] = first_third;
+ }
+ } else {
+ isPlayerOne = false;
+ }
+
+ if ((!flags.test(10) && first_ready) || (!flags.test(11) && second_ready)) {
+ flags.set(12);
+ }
+ flags.set(10, first_ready);
+ flags.set(11, second_ready);
+
if (std::strcmp(currentPlayer, "undefined") == 0) {
status = "Watching a Game...";
flags.set(2);
cachedPos = pos;
}
- if (flags.test(0) && flags.test(3) && first_ready && second_ready) {
- flags.reset(3);
- flags.set(4);
- } else if (flags.test(0) && flags.test(4) && first_first == 0 &&
- first_second == 0 && first_third == 0 && second_first == 0 &&
- second_second == 0 && second_third == 0) {
+ if (flags.test(0) && flags.test(4) && flags.test(6) && flags.test(7) &&
+ flags.test(8) && first_first == '?' && first_second == '?' &&
+ first_third == '?' && second_first == '?' && second_second == '?' &&
+ second_third == '?') {
+ std::cout << "Resetting for next round" << (isPlayerOne ? " (1) " : " (2) ")
+ << "..." << std::endl;
flags.reset(0);
flags.reset(1);
flags.reset(3);
flags.reset(6);
flags.reset(7);
flags.reset(8);
+ flags.reset(9);
+ flags.reset(10);
+ flags.reset(11);
+ flags.reset(12);
readyTimer = 0;
- resultsTimer = 0;
+ resultsTimer = RESULTS_TIMER_MAX;
picked[0] = 0;
picked[1] = 0;
picked[2] = 0;
+
+ opponentPicked[0] = 0;
+ opponentPicked[1] = 0;
+ opponentPicked[2] = 0;
+
+ call_js_set_ready(false);
+
+ std::clog << "flags: " << flags.to_string().substr(32 - 13) << std::endl;
}
}
return;
}
- readyTimer -= GetFrameTime();
+ const float dt = GetFrameTime();
+
+ readyTimer -= dt;
if (readyTimer <= 0.0F) {
readyTimer = READY_TIMER_MAX;
flags.flip(1);
}
+ if (prevPos != cachedPos) {
+ scoreChangeTimer -= dt;
+ if (scoreChangeTimer <= 0) {
+ scoreChangeTimer = SCORE_CHANGE_TIMER_MAX;
+ prevPos = cachedPos;
+ }
+ }
+
if (IsMouseButtonPressed(0) && !flags.test(0)) {
int triple_single_width = GetScreenWidth() / 3.0F + 0.5F;
if (triple_single_width > ICON_MAX_WIDTH) {
GetTouchY() <= GetScreenHeight() - triple_single_width * 2) {
if (picked[0] != 0 && picked[1] != 0 && picked[2] != 0 &&
!flags.test(0)) {
- call_js_set_ready();
+ call_js_set_ready(true);
flags.set(0);
flags.set(3);
}
status = "Pick Moves!";
}
- if (flags.test(0) && !flags.test(3) && flags.test(4)) {
+ if (flags.test(0) && flags.test(3) && flags.test(10) && flags.test(11)) {
+ char buf[6] = {picked[0], 0, picked[1], 0, picked[2], 0};
+ call_js_set_choices(&buf[0], &buf[2], &buf[4]);
+ flags.reset(3);
+ flags.set(4);
+ } else if (flags.test(0) && !flags.test(3) && flags.test(4)) {
// updates for result animations
if (flags.test(5)) {
flags.reset(5);
+ flags.reset(9);
resultsTimer = RESULTS_TIMER_MAX;
+ } else if (flags.test(9)) {
+ if (!flags.test(8)) {
+ call_js_set_ready(true);
+ flags.reset(9);
+ flags.set(5);
+ }
+ } else {
+ resultsTimer -= dt;
+ if (resultsTimer <= 0) {
+ resultsTimer = RESULTS_TIMER_MAX;
+ if (!flags.test(6)) {
+ flags.set(6);
+ flags.set(9);
+ call_js_set_ready(true);
+ } else if (!flags.test(7)) {
+ flags.set(7);
+ flags.set(9);
+ call_js_set_ready(true);
+ } else if (!flags.test(8)) {
+ flags.set(8);
+ flags.set(9);
+ call_js_set_ready(true);
+ }
+ }
}
+ }
- resultsTimer -= GetFrameTime();
- if (resultsTimer <= 0) {
- resultsTimer = RESULTS_TIMER_MAX;
- if (!flags.test(6)) {
- flags.set(6);
- } else if (!flags.test(7)) {
- flags.set(7);
- } else if (!flags.test(8)) {
- flags.set(8);
- }
+ if (flags.test(12) && flags.test(10) && flags.test(11) &&
+ prevPos == cachedPos && is_choices_set() && is_opponent_choices_set()) {
+ flags.reset(12);
+ call_js_request_update();
+ std::cout << "Requesting update..." << std::endl;
+ }
+
+ requestTimer -= dt;
+ if (requestTimer <= 0.0F) {
+ if (flags.test(10) && flags.test(11)) {
+ call_js_request_update();
+ std::cout << "Requesting update (timer)..." << std::endl;
}
}
}
if (flags.test(2)) {
BeginDrawing();
ClearBackground(BLACK);
- DrawText(status.c_str(), 0, 0, 30, RAYWHITE);
+ draw_score();
+ DrawText(status.c_str(), 0, 20, 30, RAYWHITE);
EndDrawing();
return;
}
}
if (flags.test(0)) {
+ draw_choice(0, picked[0], false, triple_single_width * 2.0F, WHITE);
+ draw_choice(1, picked[1], false, triple_single_width * 2.0F, WHITE);
+ draw_choice(2, picked[2], false, triple_single_width * 2.0F, WHITE);
float ratio = 1.0F - resultsTimer / RESULTS_TIMER_MAX;
+ char otherPicked =
+ Helpers::isValidChoice(opponentPicked[0]) ? opponentPicked[0] : '?';
if (!flags.test(6)) {
if (ratio < 1.0F) {
- draw_choice(0, opponentPicked[0], false, triple_single_width,
+ draw_choice(0, otherPicked, false, triple_single_width,
{255, 255, 255, (unsigned char)(ratio * 255.0F)});
draw_qm(0, false, triple_single_width,
{255, 255, 255, (unsigned char)((1.0F - ratio) * 255.0f)});
} else {
- draw_choice(0, opponentPicked[0], false, triple_single_width);
+ draw_choice(0, otherPicked, false, triple_single_width);
}
} else {
- draw_choice(0, opponentPicked[0], false, triple_single_width);
+ draw_choice(0, otherPicked, false, triple_single_width);
}
+ otherPicked =
+ Helpers::isValidChoice(opponentPicked[1]) ? opponentPicked[1] : '?';
if (!flags.test(7)) {
- if (ratio < 1.0F) {
- draw_choice(0, opponentPicked[1], false, triple_single_width,
+ if (!flags.test(6)) {
+ draw_qm(1, false, triple_single_width, WHITE);
+ } else if (ratio < 1.0F) {
+ draw_choice(1, otherPicked, false, triple_single_width,
{255, 255, 255, (unsigned char)(ratio * 255.0F)});
- draw_qm(0, false, triple_single_width,
+ draw_qm(1, false, triple_single_width,
{255, 255, 255, (unsigned char)((1.0F - ratio) * 255.0f)});
} else {
- draw_choice(0, opponentPicked[1], false, triple_single_width);
+ draw_choice(1, otherPicked, false, triple_single_width);
}
} else {
- draw_choice(0, opponentPicked[1], false, triple_single_width);
+ draw_choice(1, otherPicked, false, triple_single_width);
}
+ otherPicked =
+ Helpers::isValidChoice(opponentPicked[2]) ? opponentPicked[2] : '?';
if (!flags.test(8)) {
- if (ratio < 1.0F) {
- draw_choice(0, opponentPicked[2], false, triple_single_width,
+ if (!flags.test(7)) {
+ draw_qm(2, false, triple_single_width, WHITE);
+ } else if (ratio < 1.0F) {
+ draw_choice(2, otherPicked, false, triple_single_width,
{255, 255, 255, (unsigned char)(ratio * 255.0F)});
- draw_qm(0, false, triple_single_width,
+ draw_qm(2, false, triple_single_width,
{255, 255, 255, (unsigned char)((1.0F - ratio) * 255.0f)});
} else {
- draw_choice(0, opponentPicked[2], false, triple_single_width);
+ draw_choice(2, otherPicked, false, triple_single_width);
}
} else {
- draw_choice(0, opponentPicked[2], false, triple_single_width);
+ draw_choice(2, otherPicked, false, triple_single_width);
}
- } else {
+ } else { // flags.test(0)
unsigned char value = 0;
if (flags.test(1)) {
// fade ready bg to gray
{200, 200, 200, 255});
for (unsigned int i = 0; i < 3; ++i) {
- draw_choice(i, picked[i], true,
- (float)GetScreenHeight() - triple_single_width * 2.0F);
+ if (picked[i] != 0) {
+ draw_choice(i, picked[i], true,
+ (float)GetScreenHeight() - triple_single_width * 2.0F);
+ }
}
DrawRectangle(0, GetScreenHeight() - triple_single_width,
draw_choice(2, 's', true, (float)GetScreenHeight() - triple_single_width);
}
}
- DrawText(status.c_str(), 0, 0, 20, RAYWHITE);
+ draw_score();
+ DrawText(status.c_str(), 0, 20, 20, RAYWHITE);
EndDrawing();
}
default:
// Should never happen.
std::cerr << "WARNING: Invalid choice passed to draw_choice()!"
- << std::endl;
+ " (value is \""
+ << choice << "\" or \"" << (int)choice << "\")" << std::endl;
break;
}
}
switch (idx) {
case 0:
- *x = (GetScreenWidth() - *width * 4.0F) / 2.0F;
+ *x = GetScreenWidth() - *width * 4.0F;
break;
case 1:
- *x = (GetScreenWidth() - *width * 3.0F) / 2.0F;
+ *x = GetScreenWidth() - *width * 3.0F;
break;
case 2:
- *x = (GetScreenWidth() - *width * 2.0F) / 2.0F;
+ *x = GetScreenWidth() - *width * 2.0F;
break;
default:
// Should never happen.
}
}
}
+
+bool Game::is_choices_set() const {
+ return picked[0] != 0 && picked[1] != 0 && picked[2] != 0;
+}
+
+bool Game::is_opponent_choices_set() const {
+ return opponentPicked[0] != 0 && opponentPicked[1] != 0 &&
+ opponentPicked[2] != 0 && opponentPicked[0] != '?' &&
+ opponentPicked[1] != '?' && opponentPicked[2] != '?';
+}
+
+void Game::draw_score() const {
+ char buf[6] = {prevPos < 0 ? '-' : ' ',
+ prevPos < 0 ? (char)('0' - prevPos) : (char)('0' + prevPos),
+ 0,
+ cachedPos < 0 ? '-' : ' ',
+ cachedPos < 0 ? (char)('0' - cachedPos)
+ : (char)('0' + cachedPos),
+ 0};
+ if (prevPos != cachedPos) {
+ float ratio = 1.0F - scoreChangeTimer / SCORE_CHANGE_TIMER_MAX;
+ DrawText(&buf[3], 0, 0, 20,
+ {255, 255, 255, (unsigned char)(ratio * 255.0F)});
+ DrawText(buf, 0, 0, 20,
+ {255, 255, 255, (unsigned char)((1.0F - ratio) * 255.0F)});
+ } else {
+ DrawText(&buf[3], 0, 0, 20, WHITE);
+ }
+}
setup: (players) => ({
player1: players[0],
player2: players[1],
- first_choices: new Array(3).fill(null),
- second_choices: new Array(3).fill(null),
- first_ready: false,
- second_ready: false,
+ first_choices: new Array(3).fill('?'),
+ second_choices: new Array(3).fill('?'),
+ ready: new Array(2).fill(false),
pos: 0,
+ matchup_idx: 0,
}),
actions: {
- set_choices: (first, second, third, { game, playerId }) => {
- if (!game.first_ready || !game.second_ready) {
+ set_choices: ({first, second, third}, { game, playerId }) => {
+ if (!game.ready[0] || !game.ready[1]) {
throw Rune.invalidAction();
}
function is_choices_filled(choices) {
for (let i = 0; i < 3; ++i) {
- if (choices[i] === null) {
+ if (choices[i] === null || choices[i] === '?') {
return false;
}
}
game.second_choices[1] = second;
game.second_choices[2] = third;
}
+ },
+ set_ready: ({ is_ready }, { game, playerId }) => {
+ let is_first = game.player1 === playerId;
+ if (is_first) {
+ game.ready[0] = is_ready;
+ } else {
+ game.ready[1] = is_ready;
+ }
+ },
+ request_update: (unused, {game, playerId}) => {
+ function is_choices_filled(choices) {
+ for (let i = 0; i < 3; ++i) {
+ if (choices[i] === null || choices[i] === '?') {
+ return false;
+ }
+ }
+ return true;
+ }
- if (!is_choices_filled(game.first_choices)
+ if (!game.ready[0]
+ || !game.ready[1]
+ || !is_choices_filled(game.first_choices)
|| !is_choices_filled(game.second_choices)) {
return;
}
// Both sides are ready, iterate through matchups
- let has_remaining = false;
-
- for (let i = 0; i < 3; ++i) {
- // Get next matchup
- if (game.first_choices[i] === 'r'
- || game.first_choices[i] === 'p'
- || game.first_choices[i] === 's') {
- // check if first won the matchup
- if ((game.first_choices[i] === 'r' && game.second_choices[i] === 's')
- || (game.first_choices[i] === 'p' && game.second_choices[i] === 'r')
- || (game.first_choices[i] === 's' && game.second_choices[i] === 'p')) {
- game.first_choices[i] = 'w';
- game.second_choices[i] = 'l';
- game.pos = game.pos + 1;
- }
- // check if second won the matchup
- else if ((game.first_choices[i] === 'r' && game.second_choices[i] === 'p')
- || (game.first_choices[i] === 'p' && game.second_choices[i] === 's')
- || (game.first_choices[i] === 's' && game.second_choices[i] === 'r')) {
- game.first_choices[i] = 'l';
- game.second_choices[i] = 'w';
- game.pos = game.pos - 1;
- }
- // matchup was a draw
- else {
- game.first_choices[i] = 'd';
- game.second_choices[i] = 'd';
- }
- has_remaining = i === 2 ? false : true;
- }
+ // check if first won the matchup
+ if ((game.first_choices[game.matchup_idx] === 'r'
+ && game.second_choices[game.matchup_idx] === 's')
+ || (game.first_choices[game.matchup_idx] === 'p'
+ && game.second_choices[game.matchup_idx] === 'r')
+ || (game.first_choices[game.matchup_idx] === 's'
+ && game.second_choices[game.matchup_idx] === 'p')) {
+ //game.first_choices[game.matchup_idx] = 'w';
+ //game.second_choices[game.matchup_idx] = 'l';
+ game.pos = game.pos + 1;
+ }
+ // check if second won the matchup
+ else if ((game.first_choices[game.matchup_idx] === 'r'
+ && game.second_choices[game.matchup_idx] === 'p')
+ || (game.first_choices[game.matchup_idx] === 'p'
+ && game.second_choices[game.matchup_idx] === 's')
+ || (game.first_choices[game.matchup_idx] === 's'
+ && game.second_choices[game.matchup_idx] === 'r')) {
+ //game.first_choices[game.matchup_idx] = 'l';
+ //game.second_choices[game.matchup_idx] = 'w';
+ game.pos = game.pos - 1;
}
+ // matchup was a draw
+ //else {
+ //game.first_choices[game.matchup_idx] = 'd';
+ //game.second_choices[game.matchup_idx] = 'd';
+ //}
+ game.matchup_idx = game.matchup_idx + 1;
- game.first_ready = false;
- game.second_ready = false;
- if (!has_remaining) {
+ game.ready[0] = false;
+ game.ready[1] = false;
+ if (game.matchup_idx >= 3) {
if (game.pos <= -3) {
// second won
Rune.gameOver();
} else {
// game is still going
for (let i = 0; i < 3; ++i) {
- game.first_choices[i] = null;
- game.second_choices[i] = null;
+ game.first_choices[i] = '?';
+ game.second_choices[i] = '?';
}
+ game.matchup_idx = 0;
}
}
},
- set_ready: (unused, { game, playerId }) => {
- let is_first = game.player1 === playerId;
-
- if (is_first) {
- game.first_ready = true;
- } else {
- game.second_ready = true;
- }
- },
},
})