From e8a289c00f761bb53300d208b1595b08d62969f8 Mon Sep 17 00:00:00 2001
From: Dominic Masters <dominic@domsplace.com>
Date: Sun, 27 Nov 2022 07:55:57 -0800
Subject: [PATCH] Poker winning moment.

---
 src/dawn/poker/CMakeLists.txt                 |   1 +
 src/dawn/poker/Card.cpp                       |   1 -
 src/dawn/poker/Card.hpp                       |  15 ++-
 src/dawn/poker/PokerGame.cpp                  |   2 +-
 src/dawn/poker/PokerPlayer.cpp                |   2 +
 src/dawn/poker/PokerPot.cpp                   | 111 ++++++++++++++++++
 src/dawn/poker/PokerPot.hpp                   |  25 +++-
 src/dawn/poker/PokerWinning.cpp               |  93 +++++++++++++++
 src/dawn/poker/PokerWinning.hpp               |  50 ++++++--
 .../poker/visualnovel/PokerAIBetEvent.hpp     | 104 ++++++++++++++++
 .../visualnovel/PokerNewBettingRoundEvent.hpp |  29 +++++
 .../poker/visualnovel/PokerWinnerEvent.hpp    |  28 +++++
 src/dawnpokergame/CMakeLists.txt              |   3 +-
 src/dawnpokergame/scenes/TestScene.hpp        |   9 +-
 src/dawnpokergame/visualnovel/CMakeLists.txt  |   7 ++
 .../visualnovel/events/CMakeLists.txt         |  10 ++
 .../visualnovel/events/PokerBetLoopEvent.cpp  |  64 ++++++++++
 .../visualnovel/events/PokerBetLoopEvent.hpp  |  29 +----
 .../visualnovel/events/PokerInitialEvent.hpp  |  43 +++++++
 19 files changed, 572 insertions(+), 54 deletions(-)
 create mode 100644 src/dawn/poker/PokerPot.cpp
 create mode 100644 src/dawn/poker/visualnovel/PokerNewBettingRoundEvent.hpp
 create mode 100644 src/dawn/poker/visualnovel/PokerWinnerEvent.hpp
 create mode 100644 src/dawnpokergame/visualnovel/CMakeLists.txt
 create mode 100644 src/dawnpokergame/visualnovel/events/CMakeLists.txt
 create mode 100644 src/dawnpokergame/visualnovel/events/PokerBetLoopEvent.cpp
 create mode 100644 src/dawnpokergame/visualnovel/events/PokerInitialEvent.hpp

diff --git a/src/dawn/poker/CMakeLists.txt b/src/dawn/poker/CMakeLists.txt
index dba2a129..eeb1c912 100644
--- a/src/dawn/poker/CMakeLists.txt
+++ b/src/dawn/poker/CMakeLists.txt
@@ -7,6 +7,7 @@
 target_sources(${DAWN_TARGET_NAME}
   PRIVATE
     Card.cpp
+    PokerPot.cpp
     PokerPlayer.cpp
     PokerGame.cpp
     PokerWinning.cpp
diff --git a/src/dawn/poker/Card.cpp b/src/dawn/poker/Card.cpp
index 7a2f3846..e0e83aef 100644
--- a/src/dawn/poker/Card.cpp
+++ b/src/dawn/poker/Card.cpp
@@ -17,7 +17,6 @@ void Card::fillDeck(std::vector<struct Card> *deck) {
 
 int32_t Card::contains(std::vector<struct Card> *deck, struct Card c) {
   assertNotNull(deck);
-  assertTrue(deck->size() > 0);
 
   auto it = deck->begin();
   while(it != deck->end()) {
diff --git a/src/dawn/poker/Card.hpp b/src/dawn/poker/Card.hpp
index a1209344..956ae6e1 100644
--- a/src/dawn/poker/Card.hpp
+++ b/src/dawn/poker/Card.hpp
@@ -12,7 +12,9 @@ namespace Dawn {
     CARD_CLUBS = 0,
     CARD_DIAMONDS = 1,
     CARD_HEARTS = 2,
-    CARD_SPADES = 3
+    CARD_SPADES = 3,
+
+    CARD_SUIT_INVALUD = 0xFF
   };
 
   enum CardValue {
@@ -28,7 +30,9 @@ namespace Dawn {
     CARD_JACK = 9,
     CARD_QUEEN = 10,
     CARD_KING = 11,
-    CARD_ACE = 12
+    CARD_ACE = 12,
+
+    CARD_VALUE_INVALD = 0xFF
   };
 
   /** Count of cards in each suit */
@@ -106,12 +110,13 @@ namespace Dawn {
       Card(CardSuit suit, CardValue num) :
         cardValue((suit * CARD_COUNT_PER_SUIT) + num)
       {
-        assertTrue(suit < CARD_SUIT_COUNT);
-        assertTrue(num < CARD_COUNT_PER_SUIT);
+        if(suit == CARD_SUIT_INVALUD || num == CARD_VALUE_INVALD) {
+          this->cardValue = 0xFF;
+        }
       }
 
       Card(uint8_t cv) : cardValue(cv) {
-        assertTrue(cv < CARD_DECK_SIZE);
+        // assertTrue(cv < CARD_DECK_SIZE);
       }
 
       /**
diff --git a/src/dawn/poker/PokerGame.cpp b/src/dawn/poker/PokerGame.cpp
index e29aebe4..599bb9b4 100644
--- a/src/dawn/poker/PokerGame.cpp
+++ b/src/dawn/poker/PokerGame.cpp
@@ -107,7 +107,7 @@ void PokerGame::setDealer(uint8_t dealer) {
   for(i = 0; i < this->players.size(); i++) {
     k = (dealer + i) % this->players.size();
     player = this->players[k];
-    if(player->isOut)   ;
+    if(player->isOut) continue;
     if(!foundDealer) {
       this->dealerIndex = k;
       foundDealer = true;
diff --git a/src/dawn/poker/PokerPlayer.cpp b/src/dawn/poker/PokerPlayer.cpp
index cbb4688d..412d2ced 100644
--- a/src/dawn/poker/PokerPlayer.cpp
+++ b/src/dawn/poker/PokerPlayer.cpp
@@ -256,6 +256,8 @@ struct PokerWinning PokerPlayer::getWinning() {
   enum CardSuit suit;
   std::vector<struct Card> pairs;
 
+  winning.player = this;
+
   // Get the full poker hand (should be a 7 card hand, but MAY not be)
   for(i = 0; i < this->pokerGame->community.size(); i++) {
     winning.full.push_back(this->pokerGame->community[i]);
diff --git a/src/dawn/poker/PokerPot.cpp b/src/dawn/poker/PokerPot.cpp
new file mode 100644
index 00000000..92dbf528
--- /dev/null
+++ b/src/dawn/poker/PokerPot.cpp
@@ -0,0 +1,111 @@
+// Copyright (c) 2022 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#include "PokerPot.hpp"
+#include "PokerGame.hpp"
+#include "PokerPlayer.hpp"
+
+using namespace Dawn;
+
+void PokerPotWinning::award() {
+  auto it = this->winners.begin();
+  while(it != this->winners.end()) {
+    if(it == this->winners.begin()) {
+      (*it)->addChips(this->chipsOverflow);
+    } else {
+      (*it)->addChips(this->chipsEach);
+    }
+    ++it;
+  }
+}
+
+struct PokerPotWinning PokerPot::getWinners(PokerGame *game) {
+  struct PokerPotWinning winning;
+
+  winning.pot = this;
+  
+  // Calculate the winnings first.
+  auto it = this->players.begin();
+  while(it != this->players.end()) {
+    auto player = *it;
+
+    if(player->isOut || player->isFolded) {
+      ++it;
+      continue;
+    }
+
+    winning.participants.push_back(player);
+    winning.winnings[player] = player->getWinning();
+    ++it;
+  }
+
+  // Compare participating players
+  auto it2 = winning.participants.begin();
+  while(it2 != winning.participants.end()) {
+    auto playerLeft = *it2;
+    auto winnerLeft = &winning.winnings[playerLeft];
+    bool_t isWinner = true;
+    enum CardValue highNumber = CARD_VALUE_INVALD;
+    enum CardValue number = CARD_VALUE_INVALD;
+    struct Card highCard(0xFF);
+    struct Card card(0xFF);
+
+    auto it3 = winning.participants.begin();
+    while(it3 != winning.participants.end()) {
+      if(it2 == it3) {
+        ++it3;
+        continue;
+      }
+
+      auto playerRight = *it3;
+      auto winnerRight = &winning.winnings[playerRight];
+
+      // Am I the better hand / Is it the better hand?
+      if(winnerLeft->type < winnerRight->type) {
+        ++it3;
+        continue;
+      }
+      if(winnerLeft->type > winnerRight->type) {
+        isWinner = false;
+        break;
+      }
+
+      // Equal, compare hands.
+      card = PokerWinning::compare(winnerLeft, winnerRight);
+      if(card.cardValue == 0xFF) {
+        isWinner = false;
+        break;
+      }
+
+      // Determine high card.
+      number = card.getValue();
+      if(
+        highNumber == CARD_VALUE_INVALD ||
+        number == CARD_ACE ||
+        number > highNumber
+      ) {
+        highCard = card;
+        highNumber = number;
+      }
+      ++it3;
+    }
+
+    if(!isWinner) {
+      ++it2;
+      continue;
+    }
+
+    winnerLeft->kicker = highCard;
+    winning.winners.push_back(playerLeft);
+    ++it2;
+  }
+
+  winning.chipsEach = this->chips / winning.winners.size();
+  winning.chipsOverflow = this->chips - (
+    winning.chipsEach * winning.winners.size()
+  );
+
+  return winning;
+}
\ No newline at end of file
diff --git a/src/dawn/poker/PokerPot.hpp b/src/dawn/poker/PokerPot.hpp
index 07d7da69..881660e8 100644
--- a/src/dawn/poker/PokerPot.hpp
+++ b/src/dawn/poker/PokerPot.hpp
@@ -4,14 +4,31 @@
 // https://opensource.org/licenses/MIT
 
 #pragma once
-#include "dawnlibs.hpp"
+#include "PokerWinning.hpp"
 
 namespace Dawn {
   class PokerPlayer;
+  class PokerGame;
+  struct PokerPot;
+
+  struct PokerPotWinning {
+    public:
+      std::map<PokerPlayer*,struct PokerWinning> winnings;
+      std::vector<PokerPlayer*> winners;
+      std::vector<PokerPlayer*> participants;
+      struct PokerPot *pot;
+      int32_t chipsEach;
+      int32_t chipsOverflow;
+
+      void award();
+  };
   
   struct PokerPot {
-    int32_t chips;
-    int32_t call;
-    std::vector<PokerPlayer*> players;
+    public:
+      int32_t chips;
+      int32_t call;
+      std::vector<PokerPlayer*> players;
+
+      struct PokerPotWinning getWinners(PokerGame *game);
   };
 }
\ No newline at end of file
diff --git a/src/dawn/poker/PokerWinning.cpp b/src/dawn/poker/PokerWinning.cpp
index bf1c02dc..527b356c 100644
--- a/src/dawn/poker/PokerWinning.cpp
+++ b/src/dawn/poker/PokerWinning.cpp
@@ -4,6 +4,7 @@
 // https://opensource.org/licenses/MIT
 
 #include "PokerWinning.hpp"
+#include "PokerPlayer.hpp"
 
 using namespace Dawn;
 
@@ -32,6 +33,98 @@ float_t PokerWinning::getWinningTypeConfidence(enum PokerWinningType type) {
   }
 }
 
+struct Card PokerWinning::compare(
+  struct PokerWinning *left,
+  struct PokerWinning *right
+) {
+  assertNotNull(left);
+  assertNotNull(right);
+
+  uint8_t i;
+  enum CardValue number = CARD_VALUE_INVALD;
+  enum CardValue highNumberLeft = CARD_VALUE_INVALD;
+  enum CardValue highNumberRight = CARD_VALUE_INVALD;
+  struct Card card(0xFF), highCardLeft(0xFF), highCardRight(0xFF);
+  int32_t index;
+  uint8_t countCardsSame;
+
+  countCardsSame = 0;
+
+  for(i = 0; i < left->set.size(); i++) {
+    card = left->set[i];
+    number =  card.getValue();
+    // Quick check
+    if(highNumberLeft != CARD_VALUE_INVALD && number < highNumberLeft) continue;
+
+    // Check if this number is within the other hand or not
+    index = Card::containsNumber(&right->set, number);
+    if(index != -1) {
+      // This number IS within the other hand, let's check that the EXACT card
+      // is a match/isn't a match.
+      index = Card::contains(&right->set, card);
+
+      // Exact card match
+      if(index != -1) {
+        countCardsSame++;
+        continue;
+      }
+      // Not exact card match.. ?
+    }
+
+    if(
+      highNumberLeft == CARD_VALUE_INVALD ||
+      number == CARD_ACE ||
+      highNumberLeft < number
+    ) {
+      highNumberLeft = number;
+      highCardLeft = card;
+    }
+  }
+  
+  for(i = 0; i < right->set.size(); i++) {
+    card = right->set[i];
+    number = card.getValue();
+    if(highNumberRight != CARD_VALUE_INVALD && number < highNumberRight) {
+      continue;
+    }
+    
+    index = Card::containsNumber(&left->set, number);
+    if(index != -1) {
+      index = Card::contains(&left->set, card);
+      if(index != -1) continue;
+    }
+
+    if(
+      highNumberRight == CARD_VALUE_INVALD ||
+      number == CARD_ACE || highNumberRight < number
+    ) {
+      highNumberRight = number;
+      highCardRight = card;
+    }
+  }
+
+
+  if(countCardsSame == left->set.size()) {
+    for(i = 0; i < left->set.size(); i++) {
+      card = left->set[i];
+      number = card.getValue();
+      if(
+        highNumberLeft == CARD_VALUE_INVALD ||
+        number == CARD_ACE ||
+        highNumberLeft < number
+      ) {
+        highNumberLeft = number;
+        highCardLeft = card;
+      }
+    }
+    return highCardLeft;
+  }
+
+  if(highCardLeft.cardValue == CARD_VALUE_INVALD) return 0xFF;
+  if(highNumberLeft < highNumberRight) return 0xFF;
+  return highCardLeft;// Greater or Equal to.
+}
+
 void PokerWinning::fillRemaining() {
   uint8_t i, highest, current;
   struct Card highestCard(0x00);
diff --git a/src/dawn/poker/PokerWinning.hpp b/src/dawn/poker/PokerWinning.hpp
index 021980c3..be71c3db 100644
--- a/src/dawn/poker/PokerWinning.hpp
+++ b/src/dawn/poker/PokerWinning.hpp
@@ -22,6 +22,8 @@
 #define POKER_WINNING_SET_SIZE 5
 
 namespace Dawn {
+  class PokerPlayer;
+
   enum PokerWinningType {
     POKER_WINNING_TYPE_NULL,
     POKER_WINNING_TYPE_ROYAL_FLUSH,
@@ -38,17 +40,47 @@ namespace Dawn {
 
   struct PokerWinning {
     public:
-      enum PokerWinningType type;
-      std::vector<struct Card> full;
-      std::vector<struct Card> set;
-      struct Card kicker;
-      
-      PokerWinning() : kicker(0x00) {
-
-      }
-      
+      /**
+       * Get the confidence of the bet for a given winning type.
+       * 
+       * @param type Winning type type.
+       * @return The confidence.
+       */
       static float_t getWinningTypeConfidence(enum PokerWinningType type);
 
+      /**
+       * Compares two winning sets. The returned card is the kicker if the LEFT
+       * side is the winner. If LEFT is not a winner then 0xFF will be returned.
+       * 
+       * @param left Left winning set.
+       * @param right Right winning set.
+       * @return The kicker card from left's hand or 0xFF if not the winner.
+       */
+      static struct Card compare(
+        struct PokerWinning *left,
+        struct PokerWinning *right
+      );
+
+      /** Winning Type */
+      enum PokerWinningType type;
+      /** The full set of both the dealer and player's hand */
+      std::vector<struct Card> full;
+      /** Holds the winning set */
+      std::vector<struct Card> set;
+      /** If there was a kicker card it will be here */
+      struct Card kicker;
+      /* The player this winning state belongs to */
+      PokerPlayer *player;
+      
+      PokerWinning() : kicker(0xFF) {}
+
+      /**
+       * Fills the remaining cards for a given poker player winning hand.
+       * Essentially this will just take the highest cards and slot them into
+       * the array. This also sorts the cards.
+       * 
+       * @param winning Pointer to the poker winning to fill out.
+       */
       void fillRemaining();
   };
 }
\ No newline at end of file
diff --git a/src/dawn/poker/visualnovel/PokerAIBetEvent.hpp b/src/dawn/poker/visualnovel/PokerAIBetEvent.hpp
index 59b608a7..3fe3201d 100644
--- a/src/dawn/poker/visualnovel/PokerAIBetEvent.hpp
+++ b/src/dawn/poker/visualnovel/PokerAIBetEvent.hpp
@@ -11,6 +11,12 @@
 namespace Dawn {
   class PokerAIBetEvent : public PokerGameEvent {
     protected:
+      IVisualNovelEvent * eventFold = nullptr;
+      IVisualNovelEvent * eventBet = nullptr;
+      IVisualNovelEvent * eventCall = nullptr;
+      IVisualNovelEvent * eventCheck = nullptr;
+      IVisualNovelEvent * eventAllIn = nullptr;
+      
       void onStart(IVisualNovelEvent *previous) override {
         PokerGameEvent::onStart(previous);
         
@@ -19,6 +25,36 @@ namespace Dawn {
         auto player = this->pokerGame->players[better];
         this->turn = player->getAITurn();
         this->turn.action();
+
+        switch(this->turn.type) {
+          case POKER_TURN_TYPE_FOLD:
+            this->then(this->eventFold);
+            this->eventFold = nullptr;
+            break;
+
+          case POKER_TURN_TYPE_BET:
+            this->then(this->eventBet);
+            this->eventBet = nullptr;
+            break;
+          
+          case POKER_TURN_TYPE_CALL:
+            this->then(this->eventCall);
+            this->eventCall = nullptr;
+            break;
+          
+          case POKER_TURN_TYPE_CHECK:
+            this->then(this->eventCheck);
+            this->eventCheck = nullptr;
+            break;
+          
+          case POKER_TURN_TYPE_ALL_IN:
+            this->then(this->eventAllIn);
+            this->eventAllIn = nullptr;
+            break;
+            
+          default:
+            assertUnreachable();
+        }
       }
 
       bool_t onUpdate() override {
@@ -34,5 +70,73 @@ namespace Dawn {
 
       PokerAIBetEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
       }
+      
+      /**
+       * Event that is triggered when the action was a folded event.
+       * 
+       * @param event Event to trigger.
+       */
+      template<class T>
+      T * whenFolded(T *event) {
+        assertNotNull(event);
+        this->eventFold = event;
+        return event;
+      }
+
+      /**
+       * Event that is triggered when the action was a bet event.
+       * 
+       * @param event Event to trigger.
+       */
+      template<class T>
+      T * whenBetting(T *event) {
+        assertNotNull(event);
+        this->eventBet = event;
+        return event;
+      }
+
+      /**
+       * Event that is triggered when the action was a call event.
+       * 
+       * @param event Event to trigger.
+       */
+      template<class T>
+      T * whenCalling(T *event) {
+        assertNotNull(event);
+        this->eventCall = event;
+        return event;
+      }
+
+      /**
+       * Event that is triggered when the action was a check event.
+       * 
+       * @param event Event to trigger.
+       */
+      template<class T>
+      T * whenChecking(T *event) {
+        assertNotNull(event);
+        this->eventCheck = event;
+        return event;
+      }
+
+      /**
+       * Event that is triggered when the action was an all-in event.
+       * 
+       * @param event Event to trigger.
+       */
+      template<class T>
+      T * whenAllIn(T *event) {
+        assertNotNull(event);
+        this->eventAllIn = event;
+        return event;
+      }
+
+      ~PokerAIBetEvent() {
+        if(this->eventFold != nullptr) delete this->eventFold;
+        if(this->eventBet != nullptr) delete this->eventBet;
+        if(this->eventCall != nullptr) delete this->eventCall;
+        if(this->eventCheck != nullptr) delete this->eventCheck;
+        if(this->eventAllIn != nullptr) delete this->eventAllIn;
+      }
   };
 }
\ No newline at end of file
diff --git a/src/dawn/poker/visualnovel/PokerNewBettingRoundEvent.hpp b/src/dawn/poker/visualnovel/PokerNewBettingRoundEvent.hpp
new file mode 100644
index 00000000..00eb289f
--- /dev/null
+++ b/src/dawn/poker/visualnovel/PokerNewBettingRoundEvent.hpp
@@ -0,0 +1,29 @@
+// Copyright (c) 2022 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "PokerGameEvent.hpp"
+
+namespace Dawn {
+  class PokerNewBettingRoundEvent : public PokerGameEvent {
+    protected:
+      void onStart(IVisualNovelEvent *previous) override {
+        PokerGameEvent::onStart(previous);
+        std::cout << "New Betting Round" << std::endl;
+        this->pokerGame->newBettingRound();
+      }
+
+      bool_t onUpdate() override {
+        return false;
+      }
+
+      void onEnd() override {
+      }
+
+    public:
+      PokerNewBettingRoundEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
+      }
+  };
+}
\ No newline at end of file
diff --git a/src/dawn/poker/visualnovel/PokerWinnerEvent.hpp b/src/dawn/poker/visualnovel/PokerWinnerEvent.hpp
new file mode 100644
index 00000000..b727bd71
--- /dev/null
+++ b/src/dawn/poker/visualnovel/PokerWinnerEvent.hpp
@@ -0,0 +1,28 @@
+// Copyright (c) 2022 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "PokerGameEvent.hpp"
+
+namespace Dawn {
+  class PokerWinnerEvent : public PokerGameEvent {
+    protected:
+      void onStart(IVisualNovelEvent *previous) override {
+        PokerGameEvent::onStart(previous);
+        std::cout << "Poker Winning" << std::endl;
+      }
+
+      bool_t onUpdate() override {
+        return false;
+      }
+
+      void onEnd() override {
+      }
+
+    public:
+      PokerWinnerEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
+      }
+  };
+}
\ No newline at end of file
diff --git a/src/dawnpokergame/CMakeLists.txt b/src/dawnpokergame/CMakeLists.txt
index c7841368..ec031fa7 100644
--- a/src/dawnpokergame/CMakeLists.txt
+++ b/src/dawnpokergame/CMakeLists.txt
@@ -17,4 +17,5 @@ target_include_directories(${DAWN_TARGET_NAME}
 
 # Subdirs
 add_subdirectory(game)
-add_subdirectory(ui)
\ No newline at end of file
+add_subdirectory(ui)
+add_subdirectory(visualnovel)
\ No newline at end of file
diff --git a/src/dawnpokergame/scenes/TestScene.hpp b/src/dawnpokergame/scenes/TestScene.hpp
index 77057654..4e979ff6 100644
--- a/src/dawnpokergame/scenes/TestScene.hpp
+++ b/src/dawnpokergame/scenes/TestScene.hpp
@@ -12,6 +12,7 @@
 #include "visualnovel/events/VisualNovelTextboxEvent.hpp"
 #include "poker/PokerGame.hpp"
 #include "visualnovel/events/PokerBetLoopEvent.hpp"
+#include "visualnovel/events/PokerInitialEvent.hpp"
 #include "visualnovel/events/SimpleLoopEvent.hpp"
 
 namespace Dawn {
@@ -47,13 +48,7 @@ namespace Dawn {
           ->setEvent(new VisualNovelTextboxEvent(vnManager, "Starting Game"))
           ->then(new PokerNewGameEvent(vnManager))
           ->then(new VisualNovelTextboxEvent(vnManager, "Game Started"))
-          ->then(new PokerNewRoundEvent(vnManager))
-          ->then(new VisualNovelTextboxEvent(vnManager, "Round Started"))
-          ->then(new PokerTakeBlindsEvent(vnManager))
-          ->then(new VisualNovelTextboxEvent(vnManager, "Blinds Taken"))
-          ->then(new PokerDealEvent(vnManager))
-          ->then(new VisualNovelTextboxEvent(vnManager, "Cards Dealt"))
-          ->then(new PokerBetLoopEvent(vnManager))
+          ->then(new PokerInitialEvent(vnManager))
         ;
 
         return scene;
diff --git a/src/dawnpokergame/visualnovel/CMakeLists.txt b/src/dawnpokergame/visualnovel/CMakeLists.txt
new file mode 100644
index 00000000..a066d91c
--- /dev/null
+++ b/src/dawnpokergame/visualnovel/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Copyright (c) 2022 Dominic Masters
+# 
+# This software is released under the MIT License.
+# https://opensource.org/licenses/MIT
+
+# Subdirs
+add_subdirectory(events)
\ No newline at end of file
diff --git a/src/dawnpokergame/visualnovel/events/CMakeLists.txt b/src/dawnpokergame/visualnovel/events/CMakeLists.txt
new file mode 100644
index 00000000..9b7b0923
--- /dev/null
+++ b/src/dawnpokergame/visualnovel/events/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright (c) 2022 Dominic Masters
+# 
+# This software is released under the MIT License.
+# https://opensource.org/licenses/MIT
+
+# Sources
+target_sources(${DAWN_TARGET_NAME}
+  PRIVATE
+    PokerBetLoopEvent.cpp
+)
\ No newline at end of file
diff --git a/src/dawnpokergame/visualnovel/events/PokerBetLoopEvent.cpp b/src/dawnpokergame/visualnovel/events/PokerBetLoopEvent.cpp
new file mode 100644
index 00000000..9df47411
--- /dev/null
+++ b/src/dawnpokergame/visualnovel/events/PokerBetLoopEvent.cpp
@@ -0,0 +1,64 @@
+// Copyright (c) 2022 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#include "PokerBetLoopEvent.hpp"
+#include "PokerInitialEvent.hpp"
+
+using namespace Dawn;
+
+void PokerBetLoopEvent::onStart(IVisualNovelEvent *prev) {
+  PokerGameEvent::onStart(prev);
+  std::cout << "Bet Loop, bet" << std::endl;
+
+  auto evt2 = new PokerDetermineBetterEvent(this->manager);
+
+  auto betting = this->then(evt2);
+  betting
+    ->whenEveryoneFolded(new VisualNovelTextboxEvent(this->manager, "Everyone Folded"))
+    ->then(new PokerWinnerEvent(this->manager))
+    ->then(new PokerInitialEvent(this->manager))
+  ;
+  betting
+    ->whenBettingFinished(new VisualNovelTextboxEvent(this->manager, "Betting Finished"))
+    ->then(new PokerWinnerEvent(this->manager))
+    ->then(new PokerInitialEvent(this->manager))
+  ;
+  betting
+    ->whenTurn(new PokerTurnEvent(this->manager))
+    ->then(new VisualNovelTextboxEvent(this->manager, "Turn Time"))
+    ->then(new PokerNewBettingRoundEvent(this->manager))
+    ->then(new PokerBetLoopEvent(this->manager))
+  ;
+  betting
+    ->whenHumanBet(new VisualNovelTextboxEvent(this->manager, "Human Bet"))
+    ->then(new PokerBetLoopEvent(this->manager))
+  ;
+
+  // AI Betting
+  auto aiBet = betting
+    ->whenAiBet(new VisualNovelTextboxEvent(this->manager, "AI Bet"))
+    ->then(new PokerAIBetEvent(this->manager))
+  ;
+  aiBet
+    ->whenFolded(new VisualNovelTextboxEvent(this->manager, "Folded"))
+    ->then(new PokerBetLoopEvent(this->manager))
+  ;
+  aiBet
+    ->whenAllIn(new VisualNovelTextboxEvent(this->manager, "All In"))
+    ->then(new PokerBetLoopEvent(this->manager))
+  ;
+  aiBet
+    ->whenBetting(new VisualNovelTextboxEvent(this->manager, "Betting"))
+    ->then(new PokerBetLoopEvent(this->manager))
+  ;
+  aiBet
+    ->whenCalling(new VisualNovelTextboxEvent(this->manager, "Calling"))
+    ->then(new PokerBetLoopEvent(this->manager))
+  ;
+  aiBet
+    ->whenChecking(new VisualNovelTextboxEvent(this->manager, "Checking"))
+    ->then(new PokerBetLoopEvent(this->manager))
+  ;
+}
\ No newline at end of file
diff --git a/src/dawnpokergame/visualnovel/events/PokerBetLoopEvent.hpp b/src/dawnpokergame/visualnovel/events/PokerBetLoopEvent.hpp
index b1d6dc06..4796e5b1 100644
--- a/src/dawnpokergame/visualnovel/events/PokerBetLoopEvent.hpp
+++ b/src/dawnpokergame/visualnovel/events/PokerBetLoopEvent.hpp
@@ -11,38 +11,15 @@
 #include "poker/visualnovel/PokerTurnEvent.hpp"
 #include "poker/visualnovel/PokerDetermineBetterEvent.hpp"
 #include "poker/visualnovel/PokerAIBetEvent.hpp"
+#include "poker/visualnovel/PokerNewBettingRoundEvent.hpp"
+#include "poker/visualnovel/PokerWinnerEvent.hpp"
 
 #define POKER_DEAL_EVENT_CARD_COUNT 2
 
 namespace Dawn {
   class PokerBetLoopEvent : public PokerGameEvent {
     protected:
-      void onStart(IVisualNovelEvent *previous) override {
-        PokerGameEvent::onStart(previous);
-        std::cout << "Bet Loop, bet" << std::endl;
-
-        auto evt2 = new PokerDetermineBetterEvent(this->manager);
-
-        auto betting = this->then(evt2);
-        betting
-          ->whenEveryoneFolded(new VisualNovelTextboxEvent(this->manager, "Everyone Folded"))
-        ;
-        betting
-          ->whenBettingFinished(new VisualNovelTextboxEvent(this->manager, "Betting Finished"))
-        ;
-        betting
-          ->whenTurn(new VisualNovelTextboxEvent(this->manager, "Turn Time"))
-        ;
-        betting
-          ->whenAiBet(new PokerAIBetEvent(this->manager))
-          ->then(new VisualNovelTextboxEvent(this->manager, "AI Bet"))
-          ->then(new PokerBetLoopEvent(this->manager))
-        ;
-        betting
-          ->whenHumanBet(new VisualNovelTextboxEvent(this->manager, "Human Bet"))
-          ->then(new PokerBetLoopEvent(this->manager))
-        ;
-      }
+      void onStart(IVisualNovelEvent *previous) override;
 
       bool_t onUpdate() override {
         return false;
diff --git a/src/dawnpokergame/visualnovel/events/PokerInitialEvent.hpp b/src/dawnpokergame/visualnovel/events/PokerInitialEvent.hpp
new file mode 100644
index 00000000..0c837c36
--- /dev/null
+++ b/src/dawnpokergame/visualnovel/events/PokerInitialEvent.hpp
@@ -0,0 +1,43 @@
+// Copyright (c) 2022 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "poker/visualnovel/PokerNewRoundEvent.hpp"
+#include "poker/visualnovel/PokerDealEvent.hpp"
+#include "poker/visualnovel/PokerTakeBlindsEvent.hpp"
+#include "PokerBetLoopEvent.hpp"
+#include "visualnovel/events/VisualNovelTextboxEvent.hpp"
+
+#define POKER_DEAL_EVENT_CARD_COUNT 2
+
+namespace Dawn {
+  class PokerInitialEvent : public PokerGameEvent {
+    protected:
+      void onStart(IVisualNovelEvent *previous) override {
+        PokerGameEvent::onStart(previous);
+        
+        this
+          ->then(new PokerNewRoundEvent(this->manager))
+          ->then(new VisualNovelTextboxEvent(this->manager, "Round Started"))
+          ->then(new PokerTakeBlindsEvent(this->manager))
+          ->then(new VisualNovelTextboxEvent(this->manager, "Blinds Taken"))
+          ->then(new PokerDealEvent(this->manager))
+          ->then(new VisualNovelTextboxEvent(this->manager, "Cards Dealt"))
+          ->then(new PokerBetLoopEvent(this->manager))
+        ;
+      }
+
+      bool_t onUpdate() override {
+        return false;
+      }
+
+      void onEnd() override {
+      }
+
+    public:
+      PokerInitialEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
+      }
+  };
+}
\ No newline at end of file