]> git.seodisparate.com - RockPaperScissorsDuel/commitdiff
Refactor logic to be simpler
authorStephen Seo <seo.disparate@gmail.com>
Wed, 18 Jan 2023 05:00:42 +0000 (14:00 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 18 Jan 2023 05:00:42 +0000 (14:00 +0900)
src/3d_renderer.cc
src/3d_renderer.h
src/basic_renderer.cc
src/basic_renderer.h
src/constants.h
src/ems.cc
src/ems.h
src/game_renderer.h
src/main.cc
wasm_build/client.js
wasm_build/logic.js

index beebd4fad60ff1fba4766e916aaa60fa2ffa7fc3..948e8fbe26978d2efa4249390adc2381ff3c0614 100644 (file)
@@ -79,7 +79,6 @@ Renderer3D::Renderer3D()
   flags.set(1);
   flags.set(4);
   flags.set(5);
-  flags.set(14);
 
   qms.at(0).set_model(&qm_model);
   qms.at(0).set_pos({-1.0F, 0.0F, 0.0F});
@@ -114,8 +113,9 @@ void Renderer3D::update_state(const char *playerOne, const char *playerTwo,
                               char first_second, char first_third,
                               char second_first, char second_second,
                               char second_third, bool first_ready,
-                              bool second_ready, int pos, int matchup_idx,
-                              bool gameover, bool matchup_started) {
+                              bool second_ready, bool first_matchup_done,
+                              bool second_matchup_done, int pos,
+                              bool gameover_called, bool matchup_started) {
   if (std::strcmp(playerOne, currentPlayer) == 0) {
     flags.set(2);
     flags.reset(3);
@@ -135,7 +135,6 @@ void Renderer3D::update_state(const char *playerOne, const char *playerTwo,
 
   if (flags.test(2)) {
     std::cout << "got pos: " << pos << std::endl;
-    std::cout << "got matchup_idx: " << matchup_idx << std::endl;
     std::cout << "camera.target.x: " << camera.target.x << std::endl;
     std::cout << "matchup started: " << (matchup_started ? "true" : "false")
               << std::endl;
@@ -146,10 +145,10 @@ void Renderer3D::update_state(const char *playerOne, const char *playerTwo,
   if (!flags.test(13)) {
     received_pos = pos;
   }
-  if (received_matchup_idx != matchup_idx) {
-    flags.reset(7);
-  }
-  received_matchup_idx = matchup_idx;
+  // if (received_matchup_idx != matchup_idx) {
+  //   flags.reset(7);
+  // }
+  // received_matchup_idx = matchup_idx;
 
   if (second_first != '?') {
     if (flags.test(2)) {
@@ -163,8 +162,8 @@ void Renderer3D::update_state(const char *playerOne, const char *playerTwo,
     }
   }
 
-  if (flags.test(11) && first_first == '?' && second_first == '?' &&
-      flags.test(15) && !flags.test(13)) {
+  if ((flags.test(11) || flags.test(3)) && first_first == '?' &&
+      second_first == '?' && flags.test(15) && !flags.test(13)) {
     choices.at(0) = '?';
     choices.at(1) = '?';
     choices.at(2) = '?';
@@ -175,17 +174,18 @@ void Renderer3D::update_state(const char *playerOne, const char *playerTwo,
     flags.reset(8);
     flags.reset(0);
     flags.reset(15);
-    flags.set(14);
+    flags.reset(7);
     overview_timer = OVERVIEW_TIMER_MAX;
     set_random_overview();
-    qms.at(0).set_pos_x(received_pos * 2.0F - 1.0F);
-    qms.at(1).set_pos_x(received_pos * 2.0F + 1.0F);
     camera.target.x = received_pos * 2.0F;
     if (flags.test(2)) {
       std::cerr << "RESET STATE for next round" << std::endl;
     }
   }
 
+  qms.at(0).set_pos_x(received_pos * 2.0F - 1.0F);
+  qms.at(1).set_pos_x(received_pos * 2.0F + 1.0F);
+
   if (flags.test(2)) {
     std::cout << flags.to_string().substr(64 - 16) << std::endl;
   }
@@ -329,6 +329,12 @@ void Renderer3D::update_impl() {
     }
   }
 
+  // if (!flags.test(3) && flags.test(8) &&
+  //     ((flags.test(2) && !flags.test(9)) ||
+  //      (!flags.test(2) && !flags.test(10)))) {
+  //   call_js_set_ready();
+  // }
+
   button_color_timer -= dt;
   if (button_color_timer <= 0.0F) {
     button_color_timer += BUTTON_COLOR_TIME;
@@ -340,149 +346,31 @@ void Renderer3D::update_impl() {
     flags.set(11);
     flags.set(0);
     call_js_set_choices(&buf[0], &buf[2], &buf[4]);
-    call_js_request_update();
   }
 
-  if (flags.test(12)) {
-    if (flags.test(11) && !flags.test(7) && flags.test(13) && anims.is_done()) {
+  if (flags.test(12) || flags.test(3)) {
+    if ((flags.test(11) || flags.test(3)) && !flags.test(7) && flags.test(13) &&
+        anims.is_done()) {
       flags.set(7);
-      flags.reset(14);
       flags.set(15);
 
-      anims.reset_is_done();
-
-      auto newAnim = std::make_unique<AnimConcurrent>(nullptr);
-      newAnim->push_anim(std::make_unique<AnimModelShrink>(
-          &qm_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F}));
-      newAnim->push_anim(std::make_unique<AnimModelShrink>(
-          &qm_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F}));
-      anims.push_anim(std::move(newAnim));
-
-      newAnim = std::make_unique<AnimConcurrent>(nullptr);
-      Model *p1_model = &qm_model;
-      Model *p2_model = &qm_model;
-      switch (choices.at(received_matchup_idx)) {
-        case 'r':
-          if (flags.test(2)) {
-            p1_model = &rock_model;
-          } else {
-            p2_model = &rock_model;
-          }
-          break;
-        case 'p':
-          if (flags.test(2)) {
-            p1_model = &paper_model;
-          } else {
-            p2_model = &paper_model;
-          }
-          break;
-        case 's':
-          if (flags.test(2)) {
-            p1_model = &scissors_model;
-          } else {
-            p2_model = &scissors_model;
-          }
-          break;
-      }
-      switch (opponent_choices.at(received_matchup_idx)) {
-        case 'r':
-          if (flags.test(2)) {
-            p2_model = &rock_model;
-          } else {
-            p1_model = &rock_model;
-          }
-          break;
-        case 'p':
-          if (flags.test(2)) {
-            p2_model = &paper_model;
-          } else {
-            p1_model = &paper_model;
-          }
-          break;
-        case 's':
-          if (flags.test(2)) {
-            p2_model = &scissors_model;
-          } else {
-            p1_model = &scissors_model;
-          }
-          break;
-      }
-      newAnim->push_anim(std::make_unique<AnimModelGrow>(
-          p1_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F}));
-      newAnim->push_anim(std::make_unique<AnimModelGrow>(
-          p2_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F}));
-      anims.push_anim(std::move(newAnim));
-
-      newAnim = std::make_unique<AnimConcurrent>(nullptr);
-
-      const int result = Helpers::a_vs_b(
-          flags.test(2) ? choices.at(received_matchup_idx)
-                        : opponent_choices.at(received_matchup_idx),
-          flags.test(2) ? opponent_choices.at(received_matchup_idx)
-                        : choices.at(received_matchup_idx));
-
-      switch (result) {
-        case -1:
-          newAnim->push_anim(std::make_unique<AnimModelStill>(
-              p1_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F},
-              MODEL_ATTACK_TIME_0 + MODEL_ATTACK_TIME_1 + MODEL_ATTACK_TIME_2));
-          newAnim->push_anim(std::make_unique<AnimModelAttack>(
-              p2_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F}, false));
+      int result = received_pos;
+      for (unsigned int i = 0; i < 3; ++i) {
+        result = setup_anims(i, result);
+        if (result < -3 || result > 3) {
           break;
-        case 1:
-          newAnim->push_anim(std::make_unique<AnimModelAttack>(
-              p1_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F}, true));
-          newAnim->push_anim(std::make_unique<AnimModelStill>(
-              p2_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F},
-              MODEL_ATTACK_TIME_0 + MODEL_ATTACK_TIME_1 + MODEL_ATTACK_TIME_2));
-          break;
-        case 0:
-        default:
-          break;
-      }
-
-      if (result != 0) {
-        anims.push_anim(std::move(newAnim));
+        }
       }
-
-      newAnim = std::make_unique<AnimConcurrent>(nullptr);
-      newAnim->push_anim(std::make_unique<AnimModelShrink>(
-          p1_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F}));
-      newAnim->push_anim(std::make_unique<AnimModelShrink>(
-          p2_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F}));
-
-      using DataT = std::tuple<decltype(flags) *, int *, int>;
-      DataT *data = new DataT{&flags, &received_pos, result};
-      newAnim->set_end_callback(
-          [](void *ud) {
-            auto *d = (std::tuple<decltype(flags) *, int *, int> *)(ud);
-            std::get<0>(*d)->set(14);
-            *std::get<1>(*d) += std::get<2>(*d);
-            delete d;
-          },
-          data);
-
-      anims.push_anim(std::move(newAnim));
-
-      newAnim = std::make_unique<AnimConcurrent>(nullptr);
-      newAnim->push_anim(std::make_unique<AnimModelGrow>(
-          &qm_model, A3F{(result + received_pos) * 2.0F - 1.0F, 0.0F, 0.0F}));
-      newAnim->push_anim(std::make_unique<AnimModelGrow>(
-          &qm_model, A3F{(result + received_pos) * 2.0F + 1.0F, 0.0F, 0.0F}));
-
-      anims.push_anim(std::move(newAnim));
     }
   }
 
   flags.reset(12);
 
   if (flags.test(8) && flags.test(11) && flags.test(7) && anims.is_done()) {
-    flags.set(14);
-    call_js_set_ready();
-    call_js_request_update();
+    call_js_set_matchup_done();
   }
 
-  if (flags.test(14)) {
+  {
     float offset = received_pos * 2.0F - camera.target.x;
     camera.target.x += offset / 4.0F;
   }
@@ -667,3 +555,127 @@ void Renderer3D::set_random_overview() {
 #endif
   }
 }
+
+int Renderer3D::setup_anims(int idx, int score) {
+  anims.reset_is_done();
+
+  auto newAnim = std::make_unique<AnimConcurrent>(nullptr);
+  newAnim->push_anim(std::make_unique<AnimModelShrink>(
+      &qm_model, A3F{score * 2.0F - 1.0F, 0.0F, 0.0F}));
+  newAnim->push_anim(std::make_unique<AnimModelShrink>(
+      &qm_model, A3F{score * 2.0F + 1.0F, 0.0F, 0.0F}));
+  anims.push_anim(std::move(newAnim));
+
+  newAnim = std::make_unique<AnimConcurrent>(nullptr);
+  Model *p1_model = &qm_model;
+  Model *p2_model = &qm_model;
+  switch (choices.at(idx)) {
+    case 'r':
+      if (flags.test(2)) {
+        p1_model = &rock_model;
+      } else {
+        p2_model = &rock_model;
+      }
+      break;
+    case 'p':
+      if (flags.test(2)) {
+        p1_model = &paper_model;
+      } else {
+        p2_model = &paper_model;
+      }
+      break;
+    case 's':
+      if (flags.test(2)) {
+        p1_model = &scissors_model;
+      } else {
+        p2_model = &scissors_model;
+      }
+      break;
+  }
+  switch (opponent_choices.at(idx)) {
+    case 'r':
+      if (flags.test(2)) {
+        p2_model = &rock_model;
+      } else {
+        p1_model = &rock_model;
+      }
+      break;
+    case 'p':
+      if (flags.test(2)) {
+        p2_model = &paper_model;
+      } else {
+        p1_model = &paper_model;
+      }
+      break;
+    case 's':
+      if (flags.test(2)) {
+        p2_model = &scissors_model;
+      } else {
+        p1_model = &scissors_model;
+      }
+      break;
+  }
+  newAnim->push_anim(std::make_unique<AnimModelGrow>(
+      p1_model, A3F{score * 2.0F - 1.0F, 0.0F, 0.0F}));
+  newAnim->push_anim(std::make_unique<AnimModelGrow>(
+      p2_model, A3F{score * 2.0F + 1.0F, 0.0F, 0.0F}));
+  anims.push_anim(std::move(newAnim));
+
+  newAnim = std::make_unique<AnimConcurrent>(nullptr);
+
+  const int result = Helpers::a_vs_b(
+      flags.test(2) ? choices.at(idx) : opponent_choices.at(idx),
+      flags.test(2) ? opponent_choices.at(idx) : choices.at(idx));
+
+  switch (result) {
+    case -1:
+      newAnim->push_anim(std::make_unique<AnimModelStill>(
+          p1_model, A3F{score * 2.0F - 1.0F, 0.0F, 0.0F},
+          MODEL_ATTACK_TIME_0 + MODEL_ATTACK_TIME_1 + MODEL_ATTACK_TIME_2));
+      newAnim->push_anim(std::make_unique<AnimModelAttack>(
+          p2_model, A3F{score * 2.0F + 1.0F, 0.0F, 0.0F}, false));
+      break;
+    case 1:
+      newAnim->push_anim(std::make_unique<AnimModelAttack>(
+          p1_model, A3F{score * 2.0F - 1.0F, 0.0F, 0.0F}, true));
+      newAnim->push_anim(std::make_unique<AnimModelStill>(
+          p2_model, A3F{score * 2.0F + 1.0F, 0.0F, 0.0F},
+          MODEL_ATTACK_TIME_0 + MODEL_ATTACK_TIME_1 + MODEL_ATTACK_TIME_2));
+      break;
+    case 0:
+    default:
+      break;
+  }
+
+  if (result != 0) {
+    anims.push_anim(std::move(newAnim));
+  }
+
+  newAnim = std::make_unique<AnimConcurrent>(nullptr);
+  newAnim->push_anim(std::make_unique<AnimModelShrink>(
+      p1_model, A3F{score * 2.0F - 1.0F, 0.0F, 0.0F}));
+  newAnim->push_anim(std::make_unique<AnimModelShrink>(
+      p2_model, A3F{score * 2.0F + 1.0F, 0.0F, 0.0F}));
+
+  using DataT = std::tuple<int *, int>;
+  DataT *data = new DataT{&received_pos, result};
+  newAnim->set_end_callback(
+      [](void *ud) {
+        auto *d = (DataT *)(ud);
+        *std::get<0>(*d) += std::get<1>(*d);
+        delete d;
+      },
+      data);
+
+  anims.push_anim(std::move(newAnim));
+
+  newAnim = std::make_unique<AnimConcurrent>(nullptr);
+  newAnim->push_anim(std::make_unique<AnimModelGrow>(
+      &qm_model, A3F{(result + score) * 2.0F - 1.0F, 0.0F, 0.0F}));
+  newAnim->push_anim(std::make_unique<AnimModelGrow>(
+      &qm_model, A3F{(result + score) * 2.0F + 1.0F, 0.0F, 0.0F}));
+
+  anims.push_anim(std::move(newAnim));
+
+  return score + result;
+}
index c3e96250ccb913a5bad888fccf9de40a52a3b55b..a0491c6e513a962d2a493f38ea749f1d3976503c 100644 (file)
@@ -25,7 +25,8 @@ class Renderer3D : public GameRenderer {
                     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, int matchup_idx, bool gameover,
+                    bool second_ready, bool first_matchup_done,
+                    bool second_matchup_done, int pos, bool gameover_called,
                     bool matchup_started) override;
 
   void do_update() override;
@@ -38,6 +39,9 @@ class Renderer3D : public GameRenderer {
 
   void set_random_overview();
 
+  // Returns score after round "idx"
+  int setup_anims(int idx, int score);
+
   std::array<QuestionMark, 2> qms;
 
   Camera camera;
@@ -84,7 +88,7 @@ class Renderer3D : public GameRenderer {
    * 11 - choices submitted
    * 12 - update received
    * 13 - matchup started
-   * 14 - do update camera target/pos
+   * 14 - UNUSED
    * 15 - anims was set for matchup
    */
   std::bitset<64> flags;
@@ -93,7 +97,7 @@ class Renderer3D : public GameRenderer {
   float button_color_timer;
 
   int received_pos;
-  int received_matchup_idx;
+  // int received_matchup_idx;
 
   std::array<unsigned char, 3> choices;
   std::array<unsigned char, 3> opponent_choices;
index d2e53955aac5d300fe2375cc562f4d22a22c0872..d9a6ac73c64468318c1f632dfc8e3ea25ca5ce7b 100644 (file)
@@ -38,8 +38,9 @@ void BasicRenderer::update_state(const char *playerOne, const char *playerTwo,
                                  char first_second, char first_third,
                                  char second_first, char second_second,
                                  char second_third, bool first_ready,
-                                 bool second_ready, int pos, int matchup_idx,
-                                 bool gameover, bool matchup_started) {
+                                 bool second_ready, bool first_matchup_done,
+                                 bool second_matchup_done, int pos,
+                                 bool gameover_called, bool matchup_started) {
   // TODO DEBUG
   // if (std::strcmp(playerOne, currentPlayer) == 0) {
   //  std::clog << "update_state:\n"
@@ -124,7 +125,7 @@ void BasicRenderer::update_state(const char *playerOne, const char *playerTwo,
     cachedPos = pos;
   }
 
-  if (gameover) {
+  if (gameover_called) {
     flags.set(14);
   }
 }
@@ -371,7 +372,8 @@ void BasicRenderer::update_impl() {
       prevPos == cachedPos && is_choices_set() && is_opponent_choices_set()) {
     flags.reset(12);
     if (!flags.test(14)) {
-      call_js_request_update();
+      // call_js_request_update();
+      call_js_set_matchup_done();
     }
     // std::cout << "Requesting update..." << std::endl; // TODO DEBUG
   }
@@ -381,7 +383,8 @@ void BasicRenderer::update_impl() {
     requestTimer = REQUEST_TIMER_MAX;
     if (flags.test(10) && flags.test(11)) {
       if (!flags.test(14)) {
-        call_js_request_update();
+        // call_js_request_update();
+        call_js_set_matchup_done();
       }
       // std::cout << "Requesting update (timer)..." << std::endl; // TODO DEBUG
     }
index 31d182e69baa476938c82c9a144cfcb36f371fd0..bd2d21d7ea3752e0310e15f55d93e1a85e556efe 100644 (file)
@@ -21,7 +21,8 @@ class BasicRenderer : public GameRenderer {
                     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, int matchup_idx, bool gameover,
+                    bool second_ready, bool first_matchup_done,
+                    bool second_matchup_done, int pos, bool gameover_called,
                     bool matchup_started) override;
 
   void do_update() override;
index ff91e9d724faa9587dd6344deead893aa5c14da8..b75eb26113e75fb98c83dcfe2d0e412ea385d320 100644 (file)
@@ -77,8 +77,8 @@ constexpr float QM_MAX_Y_OFFSET = 0.3F;
 constexpr float QM_ANGLE_TIMER_MAX = 5.0F;
 constexpr float QM_Y_TIMER_MAX = 3.5F;
 
-constexpr float MODEL_SHRINK_TIME = 1.0F;
-constexpr float MODEL_GROW_TIME = 1.0F;
+constexpr float MODEL_SHRINK_TIME = 0.8F;
+constexpr float MODEL_GROW_TIME = 0.8F;
 
 constexpr float MODEL_ATTACK_TIME_0 = 0.4F;
 constexpr float MODEL_ATTACK_TIME_1 = 0.3F;
index cb9b1fa4fa3a31dd6314a440f965611e97540d54..1d53fc606306592f9a95271c97a2983fdeb4dbad 100644 (file)
@@ -17,6 +17,9 @@ EM_JS(void, js_set_choices,
 
 EM_JS(void, js_request_update, (), { Rune.actions.request_update("unused"); });
 
+EM_JS(void, js_set_matchup_done, (),
+      { Rune.actions.set_matchup_done("unused"); });
+
 EM_JS(int, canvas_get_width, (),
       { return document.getElementById("canvas").clientWidth; });
 
@@ -47,12 +50,22 @@ void call_js_set_choices(const char *first, const char *second,
 #endif
 }
 
-void call_js_request_update() {
+// void call_js_request_update() {
+//#ifdef __EMSCRIPTEN__
+//   js_request_update();
+//#else
+//   std::clog
+//       << "WARNING: emscripten not enabled, cannot call js_request_update()!"
+//       << std::endl;
+//#endif
+// }
+
+void call_js_set_matchup_done() {
 #ifdef __EMSCRIPTEN__
-  js_request_update();
+  js_set_matchup_done();
 #else
   std::clog
-      << "WARNING: emscripten not enabled, cannot call js_request_update()!"
+      << "WARNING: emscripten not enabled, cannot call js_set_matchup_done()!"
       << std::endl;
 #endif
 }
index ecec5487c2636121161a1b439f34df55d3c7d4e9..8deea2892301c04b81041a1fc02c49d6010a068f 100644 (file)
--- a/src/ems.h
+++ b/src/ems.h
@@ -4,7 +4,8 @@
 extern void call_js_set_ready();
 extern void call_js_set_choices(const char *first, const char *second,
                                 const char *third);
-extern void call_js_request_update();
+// extern void call_js_request_update();
+extern void call_js_set_matchup_done();
 extern int call_js_get_canvas_width();
 extern int call_js_get_canvas_height();
 extern float call_js_get_random();
index 385fea88f046326e42511560efb78294bddf97b7..247436d624f9c2bdcbf81ddd23444256947ec3b1 100644 (file)
@@ -11,8 +11,9 @@ class GameRenderer {
                             char first_second, char first_third,
                             char second_first, char second_second,
                             char second_third, bool first_ready,
-                            bool second_ready, int pos, int matchup_idx,
-                            bool gameover, bool matchup_started) = 0;
+                            bool second_ready, bool first_matchup_done,
+                            bool second_matchup_done, int pos,
+                            bool gameover_called, bool matchup_started) = 0;
 
   virtual void do_update() = 0;
 
index c40917a5d6f1cf0205261453f848c316baee348f..b947b9d330eb68bc5bac324c9b43263a9fe00355 100644 (file)
@@ -30,12 +30,14 @@ int EMSCRIPTEN_KEEPALIVE game_visual_update(
     const char *playerOne, const char *playerTwo, 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, int matchup_idx, bool gameover, bool matchup_started) {
+    bool first_matchup_done, bool second_matchup_done, int pos,
+    bool gameover_called, bool matchup_started) {
   ((GameRenderer *)global_game_ptr)
       ->update_state(playerOne, playerTwo, currentPlayer, first_first,
                      first_second, first_third, second_first, second_second,
-                     second_third, first_ready, second_ready, pos, matchup_idx,
-                     gameover, matchup_started);
+                     second_third, first_ready, second_ready,
+                     first_matchup_done, second_matchup_done, pos,
+                     gameover_called, matchup_started);
   return 0;
 }
 
index e48f78a37b9a2308389263c95f1340a4c42138d4..071512b4835139fcfd13cb719137b6bc64151b11 100644 (file)
@@ -1,6 +1,6 @@
 Rune.initClient({
     visualUpdate: ({ newGame, yourPlayerId}) => {
-        const { player1, player2, first_choices, second_choices, ready, pos, matchup_idx, gameover, matchup_started } = newGame;
+        const { player1, player2, first_choices, second_choices, ready, matchup_done, pos, gameover, gameover_called, matchup_started } = newGame;
 
         function is_choices_filled(choices) {
             for (let i = 0; i < 3; ++i) {
@@ -18,7 +18,8 @@ Rune.initClient({
                     'number', 'number', 'number',
                     'number', 'number', 'number',
                     'boolean', 'boolean',
-                    'number', 'number', 'boolean', 'boolean'],
+                    'boolean', 'boolean',
+                    'number', 'boolean', 'boolean'],
                 [player1, player2,
                     yourPlayerId === undefined ? 'undefined' : yourPlayerId,
                     first_choices[0].charCodeAt(0),
@@ -28,7 +29,8 @@ Rune.initClient({
                     second_choices[1].charCodeAt(0),
                     second_choices[2].charCodeAt(0),
                     ready[0], ready[1],
-                    pos, matchup_idx, gameover, matchup_started]);
+                    matchup_done[0], matchup_done[1],
+                    pos, gameover_called, matchup_started]);
         } else {
             Module.ccall('game_visual_update',
                 'number',
@@ -36,7 +38,8 @@ Rune.initClient({
                     'number', 'number', 'number',
                     'number', 'number', 'number',
                     'boolean', 'boolean',
-                    'number', 'number', 'boolean', 'boolean'],
+                    'boolean', 'boolean',
+                    'number', 'boolean', 'boolean'],
                 [player1, player2,
                     yourPlayerId === undefined ? 'undefined' : yourPlayerId,
                     '?'.charCodeAt(0),
@@ -46,7 +49,8 @@ Rune.initClient({
                     '?'.charCodeAt(0),
                     '?'.charCodeAt(0),
                     ready[0], ready[1],
-                    pos, matchup_idx, gameover, matchup_started]);
+                    matchup_done[0], matchup_done[1],
+                    pos, gameover_called, matchup_started]);
         }
     },
 });
index 8e821d6271314c3c193c0b6331f4ef05847d6954..24c8cfba21dde32d1ebc7bd5536b0ec6edd588d3 100644 (file)
@@ -7,9 +7,10 @@ Rune.initLogic({
         first_choices: new Array(3).fill('?'),
         second_choices: new Array(3).fill('?'),
         ready: new Array(2).fill(false),
+        matchup_done: new Array(2).fill(false),
         pos: 0,
-        matchup_idx: 0,
         gameover: false,
+        gameover_called: false,
         matchup_started: false,
     }),
     actions: {
@@ -54,8 +55,69 @@ Rune.initLogic({
                 game.second_choices[1] = second;
                 game.second_choices[2] = third;
             }
+
+            function check_matchup(a, b) {
+                if (a == 'r') {
+                    if (b == 'r') {
+                        return 0;
+                    } else if (b == 'p') {
+                        return -1;
+                    } else if (b == 's') {
+                        return 1;
+                    } else {
+                        return 0;
+                    }
+                } else if (a == 'p') {
+                    if (b == 'r') {
+                        return 1;
+                    } else if (b == 'p') {
+                        return 0;
+                    } else if (b == 's') {
+                        return -1;
+                    } else {
+                        return 0;
+                    }
+                } else if (a == 's') {
+                    if (b == 'r') {
+                        return -1;
+                    } else if (b == 'p') {
+                        return 1;
+                    } else if (b == 's') {
+                        return 0;
+                    } else {
+                        return 0;
+                    }
+                } else {
+                    return 0;
+                }
+            }
+
+            if (is_choices_filled(game.first_choices) && is_choices_filled(game.second_choices)) {
+                game.matchup_started = true;
+                for (let i = 0; i < 3; ++i) {
+                    let result = check_matchup(game.first_choices[i], game.second_choices[i]);
+                    if (result > 0) {
+                        game.pos += 1;
+                    } else if (result < 0) {
+                        game.pos -= 1;
+                    }
+
+                    if (game.pos < -3 || game.pos > 3) {
+                        game.gameover = true;
+                        break;
+                    }
+                }
+
+                if (game.pos <= -3 || game.pos >= 3) {
+                    game.gameover = true;
+                }
+            }
         },
         set_ready: (unused, { game, playerId }) => {
+            if (game.matchup_started) {
+                throw Rune.invalidAction();
+            }
+
             let is_first = game.player1 === playerId;
 
             if (is_first) {
@@ -64,71 +126,32 @@ Rune.initLogic({
                 game.ready[1] = true;
             }
         },
-        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 (!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
-            if (!game.matchup_started) {
-                game.matchup_started = true;
-                game.ready[0] = false;
-                game.ready[1] = false;
-                return;
-            }
+        set_matchup_done: (unused, { game, playerId }) => {
+            let is_first = game.player1 === playerId;
 
-            // 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.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.pos = game.pos - 1;
+            if (is_first) {
+                game.matchup_done[0] = true;
+            } else {
+                game.matchup_done[1] = true;
             }
-            game.matchup_idx = game.matchup_idx + 1;
 
-            game.ready[0] = false;
-            game.ready[1] = false;
-            if (game.matchup_idx >= 3) {
-                if (game.pos <= -3) {
-                    // second won
-                    Rune.gameOver();
-                    game.gameover = true;
-                } else if (game.pos >= 3) {
-                    // first won
+            if (game.matchup_done[0] && game.matchup_done[1]) {
+                game.matchup_started = false;
+                if (game.gameover) {
+                    game.gameover_called = true;
                     Rune.gameOver();
-                    game.gameover = true;
-                } else {
-                    // game is still going
-                    for (let i = 0; i < 3; ++i) {
-                        game.first_choices[i] = '?';
-                        game.second_choices[i] = '?';
-                    }
-                    game.matchup_idx = 0;
                 }
-                game.matchup_started = false;
+
+                game.ready[0] = false;
+                game.ready[1] = false;
+                game.matchup_done[0] = false;
+                game.matchup_done[1] = false;
+                game.first_choices[0] = '?';
+                game.first_choices[1] = '?';
+                game.first_choices[2] = '?';
+                game.second_choices[0] = '?';
+                game.second_choices[1] = '?';
+                game.second_choices[2] = '?';
             }
         },
     },