top of page

FrankenTimer

King of the Hill Arduino Timer V4

IMG_7693.jpg

New Timer! 

It's time to incorporate what I've learned during the 2023 season of gameplay. This new iteration is called the FrankenTimer.

  1. LiPo's are annoying and so I'm moving to a USB power bank. We ended up killing a couple of LiPo's so I'm just going to move away from them.

  2. 4 Pin LEDs add unnecessary complexity and the 12V LEDs I was using aren't much brighter than the 5V 3 Pin LEDs I'm using now.

  3. Wiring this thing creates a rats nest, it's time to design a 3D printed housing. 

  4. Rotary encoders/ buttons are awesome and make the admin experience so much better. 

  5. The audio sounds are a nice to have and are not necessary for those just starting off. It really should be an upgrade rather than part of the base unit.

​

I want to give a special thanks to the Nerfer DonutCat for showing me how the 3 pin LEDs and rotary encoder/button make things just that much better. I also want to thank Boomstick Mods for letting me test my ideas at our Maryland Nerf Herder games.

 

For those who built the old V3 timer, the updated the code works with either hardware version. Eventually this might not be the case but I will try and maintain cross compatibility as long as possible. However, I recommend upgrading to the rotary encoder as it is really nice for navigation purposes.

​

Introduction 

This is a guide for creating a purpose built timer for playing nerf. This was heavily inspired by Aldoss's YouTube videos with John's timer at Rochester Parkour. 

 

I designed, built and programmed this from scratch. Since I figured it out, I decided to share it with everyone else. I'm currently on version 4. To see V3 click here.

 

Below are the essential building blocks for building an Arduino based timer for king of the hill and other game modes. The programming is already complete, so you just need to buy the parts and assemble it. It will require soldering and other basic modding skills. While it may appear overwhelming, I break it down into manageable steps. This is a guide on how to do the electronics and can be paired with my assembly guide for my 3D printable housing.

 

The timer has all sorts of bells and whistles so it is not the cheapest. Hopefully in the future I can make a version that is less expensive. 

Parts list

Parts List:
Amazon Affiliate Links Included

Total Cost: $100 - $300. Many items are only sold in packs which drive the cost up. 

 

Base Unit

Uncommon Items

$23 - Arduino Mega with Cord (1 each)

$23  - LEDs (16 ft, only need about 4 ft)

$11  - LCD Screen (2 pack, only need 1)

$6   - 220 ohm resistors (100 pack, only need 5)

$9 - Dupont 30 cm Wires (Recommended)

$10 - Red Button (1 each)

$10 - Blue Button (1 each)

$20 - USB Power Bank (2 pack, only need 1)

$15 - USB Connectors (4 pack, only need 2)

$11 - Rotary Encoder (5 pack, only need 1)

$7 - Rocker Switch (5 pack, only need 1)

​

Common Items

$8   - Heat Shrink Tubing (Variety Pack)

$13  - 18 awg Silicone Wire (Black and Red)

$8   - Electrical Wire Twist Caps (Variety pack, only need 4)

​

Upgrade 1 (wiring diagram complete)

$10 - MP3 Controller (2 pack, only need 1)

$8   - Micro SD card

$11  - Aux 3.5mm Cable (6 pack, only need 1)

$? Speaker with Aux Input (For Outdoor use I like to use a Megaphone. This links to a $50 one I use, however, you can rewire a less expensive one to take your Aux Input)

​

​

Upgrade 2 (wiring diagram still pending)

Remote Starter/ Relay Stations: Unfortunately I ran into some reliability issues trying to get the remote starters to work properly. I hope to revisit this soon but as of right now I don't have a good method for starting the timers remotely.

​

Upgrade 3 (wiring diagram still pending)

Large number Display (Recommend for Indoor use ONLY)

$18 ea - 7 segment display X 2

​

Tool List
Creat Layout

Tools List:

  • Arduino Editor Account (Free)

  • Computer

  • Cable to connect Arduino to computer (Should come with the Arduino)

  • Soldering Iron and solder

  • Wire strippers

  • Snips

  • Multimeter

  • 3D Printer (Optional)

  • Wire Crimper (Optional)

Step 1: Create a Layout

I highly recommend figuring out the layout of the electronics prior to doing anything else. If you are using your own housing I suggest going back and looking at my layout advice from V3. My 3D printable housing will solve a lot of the issues of figuring out a layout. 

​

For the Arduino, buttons, LCD screen, rotary encoder, LED signal and MP3 player I used the pre-made DuPont wires since they do not draw much current. For the LEDs and main power I use 18 awg wire since they draw more current. 

The Buttons

Step 2: The Buttons

Buttons Wire V4.png

Warning! I've found the button LED (ie Pin 2 and 4) are not always consistent. Try pulling out the LED and flipping it. For the buttons I cut the DuPont Wires and solder on a short section of the male side to the button to allow me to easily disconnect it from the main body. Start by soldering wires to the button switch terminals. Solder a 220 ohms resistor to the LED terminal then solder the wire to the other end of the resistor. Solder the two negative power terminals together and don’t forget to add the heat shrink tubing.

 

Don't forget to leave enough slack in the wires for assembly and disassemble.  

The LCD Screen

Step 3: The LCD Screen

LCD Wire V4.png

The LCD screen has DuPont connectors which makes it easy to attach and detach wires. 

​

Warning! Don't throw away the LCD screen paperwork, you might need it. I've found not all LCD screens use the same coding, if your LCD screen is not working then you might need to change one line of the code in the program. It's easy to change the code and I will talk about it more in the programming section of the write up. Also adjust the brightness of the screen with a screwdriver by turning the resistor (blue box).

The LEDs

Step 4: The LEDs

IMG_7547.jpg
LED Wire V4_edited.png

Time for the LEDs, which are so much simpler than V3. Soldering to the LED strip is a real pain. You can buy quick solderless connectors, to avoid the hassle if you want but is unnecessary unless you are building a bunch.

 

The signal wire (ie Din) is a cut DuPont wire with the male end still attached. The power and negative power gauge wire depends on the number of LEDs. More LEDs draws more current and requires thicker wire.

 

I use roughly 60 LEDs, each LED requires ~ 60 mA at max load. This means I am pulling approximately 3,600 mA’s through the wire. 18 awg wire ais rated for 14,000 mA’s so a thinner wire could be used if you desire. You could easily replace the 18 awg wire with 20 awg wire. If you add more than 60 LEDs make sure you have the correct gauge wire and note that you might be limited by the number of amps the USB bank can supply. 

 

Solder two 220 ohm resistors to the wire with the male DuPont connector. Then solder that to the center  terminal (I like to have a bit of wire between the resistors and the terminal). I then solder a red 18 awg wire to the +5V terminal and  a black 18 awg wire to the GND terminal.

 

The solder connection to the LED strip is not very strong so add some glue and put heat shrink tubing over the end of the strip. I also zip tie the wires together at this location for added strength.

The MP3 Player

Step 5: The MP3 Player

MP3 Wire V4.png

Similar to the LCD screen the mp3 player has DuPont connectors, so you can just use those. 

​

For the mp3 player  make sure you have access to remove and install the micro SD card and  run the aux cable to your speaker.

The XT-60 Connector

Step 6: Rotary Encoder/ Button

Rotary Encoder V4.png

The rotary encoder/button has 3 terminals on one side (encoder) and 2 terminals on the other side (button). You can just solder Dupont wires to each of these. Note there is also a metal prong on the left and right side as shown in the picture above which are not used and I do not believe have any kind of electrical connection.

PowerSwitch

Step 7: The Power Switch/ Connector

IMG_7546.jpg
IMG_7541.jpg
IMG_7540.jpg
Switch Wire.png

Warning! make sure the battery is disconnected when doing the wiring.

 

Solder two red (positive) 18 awg wires to each of the terminals on the on/off (power) switch. Install the on/off switch in the housing prior to connecting the wires to the other locations. Two wires from one terminal go to the USB connectors (which can just be screwed on), the two wires from the other terminal go to the twist cap junctions TC-2 and TC-3.

 

Connect the the black (negative) 18 awg wires from the USB connectors to twist cap TC-1. Connect a 18 awg wire between TC-1 and TC-4. Next connect the brown/black (GND) wire from the buttons, LCD, rotary encoder, LED to TC-1. Connect the Arduino and mp3 GND wires to TC-4. I run all of the DuPont wires to the twist cap before I cut them so they are nice and neat. 

 

Finally, connect the LED and LCD 5V wires to TC-2 and the Arduino and mp3 5V (VCC) wires to twist cap TC-3. The reason for the extra twist caps is to make assembly easier and to possibly allow for future hardware upgrades.

The Micro SD Card

Step 8: The Micro SD

Warning! If you select all the files and drag and drop them onto the MicroSD card the timer won't be able to read them properly. The order you load the files onto the card matters.

​

Change Log:

2024-06-04 Added "Gained the Lead" sound bits 036 & 037.

​

First make sure that the mp3 files are properly named (i.e. 001, 002, etc). Second, drag and drop each file individually in ascending order onto the card. For example, drop file 001 first, 002 second, 003 third and so forth. It's a bit of a pain but it doesn't take that long.

 -zip file with mp3 sounds

The Arduino Mega
The wiring schematic

Step 9: The Arduino Mega

You might ask why I used an Arduino Mega instead of an Uno or Nano, it's because I wanted the option to upgrade the timer with additional features. Also the difference in price between the Mega and Uno isn't significant. Nano's have enough connections for a basic timer but the code is inefficient so it requires the larger operating memory of a Mega.

 

Attaching the wires to the Arduino is where the DuPont wires come in useful. My connectors did came loose sometimes which is a downside but a little glue or tape could fix that. I'm planning on hot gluing mine in.

Connecting Wires To The Arduino/ Wiring Schematic:

Here is my attempt at a wiring diagram. The entire diagram may be a little intimidating but the above steps break it down into simple steps.

 

You'll notice each step has a simple wiring diagram showing which pin or twist cap (TC) the wire connects too. The full wiring diagram is to help understand the overall big picture.

Wiring Diagram V4.png

Arduino Code:

Change Log:

2024-06-04 Added "Gained the Lead" sound effects. Requires sound bits 036 & 037 be added to the SD card. See SD card section for new sounds.

2024-05-15 Fixed Start Delay and Audio Start timing. Now has a min start delay of 7 seconds when games have a set game length or are using the audio start countdown.

2024-03-18 Fixed Start Delay

 

Updated code to the new admin interface which uses the rotary encoder. I am by no means a programmer so forgive my ignorance/ poor coding etiquette. The code is not the prettiest or efficient but it does function.

 

I don't know how program libraries work or to check the correct ones are downloaded. However, Arduino Editor which is an online website for programing and uploading Arduino code already has the libraries pre installed to make the code run properly. You can sign up for a free account at https://create.arduino.cc/editor

 

In your account create a new sketch and copy/paste the code below into the window. Alternatively, download the .ino file with the button above then import it into your account.

 

Warning! The LEDs are tied to the Arduino so make sure you are plugged into the USB bank whenever the LEDs will be on other wise you could fry the Arduino. The Arduino start up code will not turn on the LEDs until you advance in the menu. 

 

Connect the Arduino to the computer. In the drop down window select the Arduino that you plugged in. Then click upload. You may need to install some drivers to make the software work.

 

Assuming you've wired everything correctly then the LCD, mp3, rotary encoder/button and red/blue buttons should start working. The LEDs will turn on once you advance in the menu, make sure the timer is plugged into the USB power bank before the LEDs turn on.  

​

LCD Screen Issue:

As mentioned, LCD screens don't always work using the same code (even when I use the same link on Amazon). It is because of the I2C address. Hopefully the LCD screen you order has paper work indicating which address to use but if not try these:

​

LiquidCrystal_I2C lcd(0x27, 16, 2);

or

LiquidCrystal_I2C lcd(0x3f, 16, 2); 

​

Both lines of code can't be active. If your LCD screen is not working and you are certain that it is wired correctly then try changing the code. Deactivate one address and activate the other one. Locate the line in the code in the Arduino Editor by hitting ctrl + f and then searching LiquidCrystal.

 

Deactivate a line by adding // at the start of the line. Deactivated lines are grayed out. Conversely, activate a line by removing the //. If the LCD screen is still not working then you might want to check the brightness by rotating the screw in the blue box on the back. 

 

//Arduino Code Posted Date 2024-02-26

 

/*
Please excuse my lack of programming etiquette, I'm not actually a programmer but I do what I can.

​

Currently...

Arduino Code

//Posted Date 2024-02-26

/*
Please excuse my lack of programming ediquette, I'm not actually a programmer
but I do what I can.

Currently I have not gone in and cleaned up the code. There may be many instances 
where comments are not quite accurate as I do a lot of copy and pasting. That 
being said, the code does work.
*/

// Global Variables that change between Arduino Mega and Nano
//---------------------------------------------------------------------------------
 
  //Arduino Mega
    // Define pins for LED Strip
      //Old V3 LED pins
        #define REDPIN 45
        #define GREENPIN 47
        #define BLUEPIN 49
      //New V4 LED pin
        #define LED_PIN 6 
        #define LED_COUNT 42
    //LCD Screen Pins
      //SDA on UNO & Nano is A4. SDA on MEGA it is 20
      //SCL on UNO & Nano is A5. SCL on MEGA it is 21
    //Radio Reciever/Transmitter Code
      #include <SPI.h>
      #include <nRF24L01.h>
      #include <RF24.h>
      int gogogo = 0;
      RF24 radio(48, 46); // CE, CSN
      //const byte addresses[][6] = {"00001", "00002"};
      const byte address[6] = "T0001";
    // Button Pins
      int ledPinRed = 4; // Red Buttton LED Pin
      int ledPinBlue = 2; // Blue Button LED Pin
      int buttonRedpin = 5; // Red Button
      int buttonBluepin = 3; // Blue Button
    // MP3 Player
      #define ARDUINO_RX 8  //should connect to RX of the Serial MP3 Player module
      #define ARDUINO_TX 9  //connect to TX of the module
 
  /*
  //Arduino Nano - Code is too inefficient and takes up too much memory
    // Define pins for LED Strip
      #define REDPIN 2
      #define GREENPIN 3
      #define BLUEPIN 4
    //LCD Screen Pins
      //SDA on UNO & Nano is A4. SDA on MEGA it is 20
      //SCL on UNO & Nano is A5. SCL on MEGA it is 21
    //Radio Reciever/Transmitter Code
      #include <SPI.h>
      #include <nRF24L01.h>
      #include <RF24.h>
      int gogogo = 0;
      RF24 radio(7, 8); // CE, CSN
      const byte address[6] = "T0001";
    // Button Pins
      int ledPinRed = A1; // Red Buttton LED Pin
      int ledPinBlue = A2; // Blue Button LED Pin
      int buttonRedpin = 9; // Red Button
      int buttonBluepin = 10; // Blue Button
    // MP3 Player
      #define ARDUINO_RX 6  //should connect to RX of the Serial MP3 Player module
      #define ARDUINO_TX 5  //connect to TX of the module
    */
//-------------------------------------------------------------------------------------
// End Global Variables that change between Arduino Mega and Nano

//LCD Screen
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27 or 0x3f, 16 column and 2 rows
//LiquidCrystal_I2C lcd(0x3f, 16, 2); // I2C address 0x27 or 0x3f, 16 column and 2 rows
//SDA on UNO is A4 on MEGA it is 20
//SLC on UNO is A5 on MEGA it is 21
String inputLCDText;
int delayLCD = 2500;

//Global Attrition
  int redLifeCount;
  int blueLifeCount;
  int startLifeCount;
  int attritionLifeIndex;
  int attritionLifeSound;
  int attritionLifeSoundModifier;
  int gameAttritionArray[] = {1, 6, 11, 16};

//General Paramemters
  String buttonMode;
  String checkReset;
  int teamHold;
  int holdHillContested;
  String teamInControl;
  //used to help code when it is in standby
    static int BlueFirst = 0;
    static int RedFirst = 0;

struct gameParameters{
   //These are variables for game setup
  String buttonPush;
  String timeX;
  String timeLimit;
  String timePause;
  String timeReset;
  String timeDirection;
  String teamRunDown;
};

gameParameters selectOutput; //database for storing game setup parameters

struct tClock{
   //These are variables for tracking the time
  int m; 
  int k;
  int j;
  int i;
  int mBlue; 
  int kBlue;
  int jBlue;
  int iBlue;
  int mRed; 
  int kRed;
  int jRed;
  int iRed;
  //Remove
  //int mPause; 
  //int kPause;
  //int jPause;
  //int iPause;
  int mHold; 
  int kHold;
  int jHold;
  int iHold;
  int mLimit; 
  int kLimit;
  int jLimit;
  int iLimit;
  String loopExit;
  String Victory;
  String teamRunDown;
 
};

//databases for storing time
tClock teamTime;
tClock timeOutput;

// Record time
struct Scorekeeper{
  int timerName;
  int blueTime;
  int redTime;
  int teamInControl;
};

Scorekeeper Score; // Contains data


//Remove
//byte leds = 0;

// Code for Millis From https://forum.arduino.cc/t/using-millis-for-timing-a-beginners-guide/483573
// this is used to track actual time kept by the Arduino
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 10000;  //the value is a number of milliseconds

unsigned long startSecondMillis;  //some global variables available anywhere in the program
unsigned long currentSecondMillis;
const unsigned long periodSecond = 1000;  //the value is a number of milliseconds

unsigned long gameStartMillis;
unsigned long gameCheckMillis;
unsigned long gameCheckMillisCheck;
unsigned long gameLengthMillis;
unsigned long gameCheckMillis2;
unsigned long gameStartMillis2;

unsigned long xStartMillis;
unsigned long xCheckMillis;
unsigned long xLengthMillis;


// variables for audio count downs and reseting the timer
unsigned long gameRestart = 5000;//amount of milli seconds the two buttons need to be held down to reset the timer
unsigned long gameClockArray[] = {2, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 31000, 61000}; //used in the audio counting
unsigned long gameClockCheck;
int gameClockIndex = 12; // equals the size of array remember the first spot in an array is 0
int gameClockSound = 27; // tells audio count down what mp3 file to start counting from
String gameTimeOver;
String time2Reset;
String playGameStart;
String playGameEnd;
String alarmCheck;

//---------------------------Begin LED Strip Golbal code --------------------------------------------

//Code for 7 segment displays adapted from code written by Limor Fried/Ladyada from Adafruit Industries.
#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"

Adafruit_7segment matrix = Adafruit_7segment();

// 3 Pin LED strip

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

// Declare NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);


//-----------------------End of LED Strip global code -----------------------------

// --------------------- Begin Global Code for MP3 player ----------------------

#include <SoftwareSerial.h>

SoftwareSerial mp3(ARDUINO_TX, ARDUINO_RX);

static int8_t Send_buf[8] = {0}; // Buffer for Send commands.  // BETTER LOCALLY
static uint8_t ansbuf[10] = {0}; // Buffer for the answers.    // BETTER LOCALLY

String mp3Answer;           // Answer from the MP3.

String sanswer(void);
String sbyte2hex(uint8_t b);

/************ Command byte **************************/
#define CMD_NEXT_SONG     0X01  // Play next song.
#define CMD_PREV_SONG     0X02  // Play previous song.
#define CMD_PLAY_W_INDEX  0X03
#define CMD_VOLUME_UP     0X04
#define CMD_VOLUME_DOWN   0X05
#define CMD_SET_VOLUME    0X06

#define CMD_SNG_CYCL_PLAY 0X08  // Single Cycle Play.
#define CMD_SEL_DEV       0X09
#define CMD_SLEEP_MODE    0X0A
#define CMD_WAKE_UP       0X0B
#define CMD_RESET         0X0C
#define CMD_PLAY          0X0D
#define CMD_PAUSE         0X0E
#define CMD_PLAY_FOLDER_FILE 0X0F

#define CMD_STOP_PLAY     0X16  // Stop playing continuously. 
#define CMD_FOLDER_CYCLE  0X17
#define CMD_SHUFFLE_PLAY  0x18 //
#define CMD_SET_SNGL_CYCL 0X19 // Set single cycle.

#define CMD_SET_DAC 0X1A
#define DAC_ON  0X00
#define DAC_OFF 0X01

#define CMD_PLAY_W_VOL    0X22
#define CMD_PLAYING_N     0x4C
#define CMD_QUERY_STATUS      0x42
#define CMD_QUERY_VOLUME      0x43
#define CMD_QUERY_FLDR_TRACKS 0x4e
#define CMD_QUERY_TOT_TRACKS  0x48
#define CMD_QUERY_FLDR_COUNT  0x4f

/************ Opitons **************************/
#define DEV_TF            0X02

/*********************************************************************/
//Remove old Buzzer Code
/*
int numero;      
byte estado;      
byte buzzer = 2;
byte pin = 0;
byte SortNumber = 0;
bool button = 0;
*/

// ------------------------ End of MP3 ---------------------------------

//-------------------------------- Important -------------------------------------
//The order in which you load the sound tracks onto the micro SD card matters
// You should drag each sound track individually onto the micro SD card the order should match the numbering
//------------------------- Micro SD tracks ---------------------------
int kingofthehill = 001;
int gameover = 002;

int hillcontested = 3;
int hillcontrolled = 4;
int hilloccupied = 5;
int oneminutetowin = 6;

int blueteamminutetowin = 7;
int blueteam30secondstowin = 8;

int redteamminutetowin = 9;
int redteam30secondstowin = 10;

int redteamhillcontrolled = 11;
int blueteamhillcontrolled = 12;

int redteamwin = 13;
int blueteamwin = 14;

int stargatealarm = 15;
// 16 - 27 numbers for audio count down
int roundbegins = 28;
int overTimeSound = 29;
//Attrition
int noLivesSound = 30;
int attritionsound = 34;

//----------------------- End of Sound Tracks

//Variables for controlling direction of counting
int timeCheck_1Up = -9;
int timeCheck_2Up = -5; 
int timeReset_1Up = 0;
int timeReset_2Up = 0;
int directionUp = -1;
int timeCheck_1Down = 0;
int timeCheck_2Down = 0; 
int timeReset_1Down = 9;
int timeReset_2Down = 5;
int directionDown = 1;
int timeCheck_1;
int timeCheck_2; 
int timeReset_1;
int timeReset_2;
int directionInput;

String Skip;
String runDownTeamColor;
String overTime;
String overTimeStart;
String variableX;
String checkX;
String gameSelectedMain;


//-------------Global Rotary Encoder --------------------------------

// Define rotary encoder pins
#define ENC_A 19
#define ENC_B 18

unsigned long _lastIncReadTime = micros(); 
unsigned long _lastDecReadTime = micros(); 
int _pauseLength = 25000;
int _fastIncrement = 10;

volatile int RotaryPosition = 0;


const int gameModeSelectionSize= 9;
String gameModeSelection[gameModeSelectionSize]= {"Custom", "Time Keeper", "KoTH", "Rogue One","Attrition","Death Clicks", "Domination","Hold The Hill", "Time Reset"};


//                                  {name, buttonPush, timeX, timeLimit, timePause, timeReset, timeDirection}
String gameParametersArray[9][7]= { {"Custom","-","-","-","-","-", "-"}, 
                                    {"Time Keeper","Tap","No","Yes","No","No", "Up"}, 
                                    {"KoTH","Tap","X","No","No","No", "Down"},
                                    {"Rogue One","Pause","X","Yes","Yes","No", "Down"},
                                    {"Attrition","Pause","No","No","Yes","No", "Down"},
                                    {"Death Clicks","Pause","No","No","Yes","No", "Up"},
                                    {"Domination","Tap","X","Yes","No","No", "Up"}, 
                                    {"Hold The Hill","Continuous","No","Yes","No","No", "Up"},
                                    {"Time Reset","Pause","X","Yes","No","Yes", "Down"}
                                     };


const int YesNoArraySize= 2;
String YesNoArray[YesNoArraySize]= {"Yes", "No"};

const int teamColorArraySize= 2;
String teamColorArray[teamColorArraySize]= {"Red", "Blue"};

const int buttonInteractArraySize= 3;
String buttonInteractArray[buttonInteractArraySize]= {"Tap", "Hold X Seconds", "Continuous Hold"};

const int objectiveArraySize= 5;
String objectiveArray[objectiveArraySize]= {"Both Countdown", "Both Countup", "Both Reset", "Pause/Countdown", "Reset/Countdown"};


byte teamRunDownClock;
int objectiveTime;
int gameLengthTime;
byte gameID;
int startDelayTimeMillis;
int holdXTime;
byte startAudio;
byte endAudio;

byte buttonInteraction;
byte objective;
int objectiveTimeBlue;
byte checkTeamTime;
int objectiveTimeRed;
byte limitGameLength;
byte enableOvertime;
byte timeExit;
String timeDirection;
byte enableRotaryEncoder;
int gameLengthTimeDisplay;
byte setUpGame;
byte turnLEDOff;

 

// -------------------- Start Global Code for Rotary Encoder -----------------------------
volatile boolean TurnDetected;  // need volatile for Interrupts
volatile boolean rotationdirection;  // CW or CCW rotation

const int PinCLK=2;   // Generating interrupts using CLK signal
const int PinDT=3;    // Reading DT signal
const int EncoderButton = 7;    // Reading Push Button switch

//int RotaryPosition=0;    // To store Stepper Motor Position
int RotaryValue;
//int RotaryPosition;    // To store Stepper Motor Position
int PrevPosition;     // Previous Rotary position Value to check accuracy
byte gameExitCheck;
//unsigned long startMillis;  //some global variables available anywhere in the program

 

//------------- End Rotary Encoder ----------------------------------

 


void setup() {
  Serial.begin(9600); // Better to use when debugging with the serial monitor
  //Serial.begin(38400); // needed for mp3 player may cause issues in the serial monitor
  mp3.begin(9600);// initiallze MP3
  sendCommand(0x03, 0, kingofthehill);//Send command to play song 6 
  delay(3000);
  pinMode(REDPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(BLUEPIN, OUTPUT);
  pinMode(ledPinRed, OUTPUT); // identify Red LED Pin as output
  pinMode(ledPinBlue, OUTPUT); // identify Blue LED pin as output
  pinMode(buttonRedpin, INPUT_PULLUP);  // Identify Red button as input
  pinMode(buttonBluepin, INPUT_PULLUP); // Identify Blue button as input
 
  // Set encoder pins and attach interrupts
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);
  pinMode(EncoderButton,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENC_A), read_encoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENC_B), read_encoder, CHANGE);
 
  // Radio Reciever
 
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MIN);

  // set up the LCD's number of columns and rows:
  lcd.init(); // initialize the lcd
  lcd.backlight();
 
  // Print a message to the LCD.
  displayLCD (0, 0, "Hello There!", "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
  digitalWrite(ledPinRed, HIGH); // turn the red LED on
  digitalWrite(ledPinBlue, HIGH); // turn the blue LED on
  delay(delayLCD);
 
  USBCheck ();
 
 
// Set each of the 7 segments to dashes
  matrix.begin(0x70);
  matrix.print(10000, DEC);
  matrix.writeDisplay();
  delay(250);
 
  // Set each of the 7 segments to zero Remove?
  int time_1 = 0; // Left time display
  int time_2 = 0; // Middle left time display
  int time_3 = 0; // Middle right time display
  int time_4 = 0; // Right time display

//Remove ?? not sure where used
    // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  // END of Trinket-specific code.

  buttonCombinedFunc ("Use Rotry Encodr", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
  Serial.println(RotaryValue);
  enableRotaryEncoder = RotaryValue;
  displayLCD (0, 0, "Loading..." , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
 
 
 
  strip.begin();           // INITIALIZE NeoPixel LED strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(255); // Set BRIGHTNESS to max
 
 
  colorLEDChange( 0, 255,   0);    
  delay(1000);
  colorLEDChange( 255, 0,   0); // Red
  delay(1000);
  colorLEDChange( 0, 0,   255); // Blue
  delay(1000);
 
  //Save battery
  turnLEDOff = 1;
    if (enableRotaryEncoder == 1){
      buttonCombinedFunc ("Standby LEDs Off", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
    }
    else{
      rotaryCombinedFunc ("Standby LEDs Off", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
    }
    Serial.println("Turn LEDs Off?");
    Serial.println(RotaryValue);
    turnLEDOff = RotaryValue;

  digitalWrite(ledPinRed, LOW); // turn the red LED on
  digitalWrite(ledPinBlue, LOW); // turn the blue LED on
 
  if (turnLEDOff == 0){
    colorLEDChange( 0, 0,   0); 
  }
  else{
    colorLEDChange( 0, 255,   0); 
  }   

  setUpGame = 0;

 

 


}

void loop() {
 
  if (setUpGame == 0){
    adminSetup();
  }
  //parameterCheck();
 
  //USBCheck ();
  if (turnLEDOff == 0){
    colorLEDChange( 0, 0,   0); 
  }
  else{
    colorLEDChange( 0, 255,   0); 
  }
  teamInControl = "Green";
  delay(1000);


inputLCDText = "Standby Mode";
displayLCD (0, 0, inputLCDText , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
inputLCDText = "Press R 2 Start";
displayLCD (0, 1, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")

//delay(delayLCD);
radio.startListening();

while(2>1){
 
  if (digitalRead(buttonRedpin) == LOW){
    radio.stopListening();
    break; // exit loops
  }

  radio.read(&gogogo, sizeof(gogogo));
  if (gogogo == 1) {
    Serial.println("GameStarted");
    radio.stopListening();
    break; // exit loops
  }
 
  if((startAudio == 1) && (limitGameLength == 1)){
    radio.stopListening();
    displayLCD (0, 0, "Initializing" , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    break; // exit loops
  }
}

colorLEDChange( 255, 0,   0); // Red
teamInControl = "Red";
delay(1000);
colorLEDChange( 0, 0,   255); // Blue
teamInControl = "Blue";
delay(1000);
colorLEDChange( 0, 255,   0);    
teamInControl = "Green";
delay(1000);

if (turnLEDOff == 0){
  colorLEDChange( 0, 0,   0); 
}

if((gameSelectedMain == "Time Keeper") || (gameSelectedMain == "Attrition") || (gameSelectedMain == "Death Clicks")){
  displayLCD (0, 0, "Initializing" , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
 
} else{
  inputLCDText = " Red:" + String(teamTime.mRed) + String(teamTime.kRed) + ":" + String(teamTime.jRed) + String(teamTime.iRed);
  displayLCD (0, 0, inputLCDText , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
  inputLCDText = "Blue:" + String(teamTime.mBlue) + String(teamTime.kBlue) + ":" + String(teamTime.jBlue) + String(teamTime.iBlue);
  displayLCD (0, 1, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
  if(limitGameLength == 0){  
    displayLCD (11, 0, "Game" , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
  }
 
 
  if (buttonMode == "Pause"){
 
    if(runDownTeamColor == "Blue"){
      inputLCDText = " Red:--:-- ";
      displayLCD (0, 0, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    }
    else if (runDownTeamColor == "Red"){
      inputLCDText = "Blue:--:--        ";
      displayLCD (0, 1, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    }
    
  }
}

// Something wierd in the code is messing with the times and it was easier to just adjust it here
if (buttonMode == "Continuous")
{
  teamTime.mBlue = timeOutput.mRed;
  teamTime.kBlue = timeOutput.kRed;
  teamTime.jBlue = timeOutput.jRed;
  teamTime.iBlue = timeOutput.iRed;

  teamTime.mRed = timeOutput.mBlue;
  teamTime.kRed = timeOutput.kBlue;
  teamTime.jRed = timeOutput.jBlue;
  teamTime.iRed = timeOutput.iBlue;
  Skip = "No"; 
}

// ----------------- Start Game Loop -----------------------------------
Serial.println("Gamelength check");
Serial.println(gameLengthMillis);

Serial.println("Gamestart check");
Serial.println(gameStartMillis);
if (startAudio == 0){
  delay(startDelayTimeMillis);
  sendCommand(0x03, 0, roundbegins);//Send command to play song 6
  delay(7000);
}
else{
  delay(startDelayTimeMillis);
}


 
gameStartMillis = millis();

if (gameSelectedMain == "Time Keeper")
{
  inputLCDText = "            Game";
  displayLCD (0, 0, inputLCDText , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
  overTime = "No";
  currentSecondMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started). This is used to check when to increment the 7 segment display.                    
  gameCheckMillis = gameLengthMillis - (currentSecondMillis - gameStartMillis);
  //displayLCD (0, 1, String(gameCheckMillis/1000L) , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
  gameCheckMillisCheck = gameCheckMillis;
  while(2>1){
    if ((digitalRead(buttonRedpin) == LOW) && (digitalRead(buttonBluepin) == LOW)) //Code used to edit the left digit, runs each time the red button gets hit when setting the time
    {
      break; // exit loops
    } else  if (gameTimeOver == "Yes"){
      break; // exit loops
    }
    gameClock();
    gameLengthDisplay ();
    /*
    if(gameCheckMillis < (gameCheckMillisCheck-1000L)){
      displayLCD (0, 1, String(gameCheckMillis/1000L) , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      gameCheckMillisCheck = gameCheckMillis;
    }
    */
  }
  //displayLCD (0, 1, "0" , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
 
}else if ((gameSelectedMain== "Attrition") || (gameSelectedMain== "Death Clicks")) {
  funcAttrition ();
}

else
{
  if ((buttonMode == "Tap") || (buttonMode == "Pause")){
    while(2>1){
        gameLengthDisplay ();
        gameClock();
        if (gameTimeOver == "Yes"){
          break; // exit loops
        }
        if (digitalRead(buttonRedpin) == LOW){  
            funcX(buttonRedpin, "Default");
            if (checkX == "Yes")
            {
              Serial.print("Red");
              Serial.println(" Team Controls the Hill"); //Show which song is playing in serial monitor
              sendCommand(0x03, 0, redteamhillcontrolled);//Send command to play song 6
              colorLEDChange( 255, 0,   0); // Red
              teamInControl = "Red";
              //if ((runDownTeamColor == "Red") || (buttonMode == "Pause")){
              if ((runDownTeamColor == "Red") ){  
                if (enableOvertime == 0){
                  overTime = "Yes"; 
                }
        
              }
              delay(250);
              Skip = "Yes"; 
              if(variableX == "X")
              {
                checkX = "No";
              }
              else
              {
                checkX = "Yes";
              }
              break; // exit loops
              
            }
        }
        if ((digitalRead(buttonBluepin) == LOW)){  
            funcX(buttonBluepin, "Default");
            if (checkX == "Yes")
            {
              Serial.print("Blue");
              Serial.println(" Team Controls the Hill"); //Show which song is playing in serial monitor
              sendCommand(0x03, 0, blueteamhillcontrolled);//Send command to play song 6
              
              colorLEDChange( 0, 0,   255); // Blue
              teamInControl = "Blue";
              //if ((runDownTeamColor == "Blue") || (buttonMode == "Pause")){
              if ((runDownTeamColor == "Blue") ){
                if (enableOvertime == 0){
                  overTime = "Yes"; 
                } 
              }
              delay(250);
              Skip = "No";
              if(variableX == "X")
              {
                checkX = "No";
              }
              else
              {
                checkX = "Yes";
              }
              break; // exit loops
            }
        }
    }
  }
 
  while(2>1){
  teamHold = 0; 
  gameLengthDisplay ();
  gameClock();
 
  theBugger(teamTime.mBlue,teamTime.kBlue,teamTime.jBlue,teamTime.iBlue, "Blue", "Before Loops");
  theBugger(teamTime.mRed,teamTime.kRed,teamTime.jRed,teamTime.iRed, "Red", "Before Loops");
  if(Skip == "No")
  {
  teamTime = funcTimeLoop(teamTime.mBlue,teamTime.kBlue,teamTime.jBlue,teamTime.iBlue,
                      timeCheck_1, timeCheck_2, 
                      timeReset_1, timeReset_2, directionInput, "Red",redteamhillcontrolled,
                      ledPinRed, buttonRedpin, 0, ledPinBlue, teamTime.mRed,teamTime.kRed,teamTime.jRed,teamTime.iRed,buttonBluepin);
  }
  Skip = "No"; 
 
  theBugger(teamTime.mBlue,teamTime.kBlue,teamTime.jBlue,teamTime.iBlue, "Blue", "Between Loops");
  theBugger(teamTime.mRed,teamTime.kRed,teamTime.jRed,teamTime.iRed, "Red", "Between Loops");
 
  if((teamTime.Victory == "Blue") || (gameTimeOver == "Yes")){
      Serial.println("Blue Over");
      break; // exit loops
    }
  gameLengthDisplay ();
  gameClock();
   
  teamTime = funcTimeLoop(teamTime.mRed,teamTime.kRed,teamTime.jRed,teamTime.iRed,
                      timeCheck_1, timeCheck_2, 
                      timeReset_1, timeReset_2, directionInput, "Blue",blueteamhillcontrolled,
                      ledPinBlue, buttonBluepin, 0, ledPinRed,teamTime.mBlue,teamTime.kBlue,teamTime.jBlue,teamTime.iBlue,buttonRedpin);
 
  if((teamTime.Victory == "Red") || (gameTimeOver == "Yes")){
      Serial.println("Red Over");
      break; // exit loops
    } 
  gameLengthDisplay ();
  gameClock();
  if(gameTimeOver == "Yes")
  {
    break; // exit loops
  }
  }
}
// ----------------- End Game Loop -----------------------------------

// ----------------- Start Show Winner -------------------------------------

gameStartMillis = millis();

if(((teamTime.Victory == "Blue") && ((buttonMode == "Tap") || (buttonMode == "Pause"))) || ((teamTime.Victory == "Red") && (buttonMode == "Continuous")) ){
      Serial.println("Game Over Blue Team Wins"); //Show which song is playing in serial monitor
      sendCommand(0x03, 0, gameover);//Send command to play song 6
      delay(1500); // add a delay to allow time for the button to be released
      sendCommand(0x03, 0, blueteamwin);//Send command to play song 6
      delay(2000); // add a delay to allow time for the button to be released
      sendCommand(0x03, 0, stargatealarm);//Send command to play song 6
      Serial.println("Stargate 1");
    
    while(2>1){
      digitalWrite(ledPinBlue, HIGH); // turn the red LED on
      colorLEDChange( 0, 0,   255); // Blue
      delay(250);
      digitalWrite(ledPinBlue, LOW); // turn the blue LED off
      colorLEDChange( 0, 0,   0); // Blank
      delay(250);
      
      gameStartMillis = millis();
      while(2>1){
        if ((digitalRead(buttonRedpin) == LOW) && (digitalRead(buttonBluepin) == LOW)) //Code used to edit the left digit, runs each time the red button gets hit when setting the time
        {
          currentSecondMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started). This is used to check when to increment the 7 segment display.                    
          gameCheckMillis = currentSecondMillis - gameStartMillis;
          if (gameCheckMillis > gameRestart)
          {
            time2Reset = "Yes";
            break; // exit loops
          }
        } 
        else{
          break; // exit loops  
        }
      }
      if(time2Reset == "Yes"){
        time2Reset = "No";
        break; // exit loops 
      }
    }
  }
 
if(((teamTime.Victory == "Red") && ((buttonMode == "Tap") || (buttonMode == "Pause"))) || ((teamTime.Victory == "Blue") && (buttonMode == "Continuous")) ){
      Serial.println("Game Over Red Team Wins"); //Show which song is playing in serial monitor
      sendCommand(0x03, 0, gameover);//Send command to play song 6
      delay(1500); // add a delay to allow time for the button to be released
      sendCommand(0x03, 0, redteamwin);//Send command to play song 6
      delay(2000); // add a delay to allow time for the button to be released
      sendCommand(0x03, 0, stargatealarm);//Send command to play song 6
      Serial.println("Stargate 2");
    
    while(2>1){
      digitalWrite(ledPinRed, HIGH); // turn the red LED on
      colorLEDChange( 255, 0,   0); // Red
      delay(250);
      digitalWrite(ledPinRed, LOW); // turn the blue LED off
      colorLEDChange( 0, 0,   0); // Blank
      delay(250);
      
      gameStartMillis = millis();
      while(2>1){
        if ((digitalRead(buttonRedpin) == LOW) && (digitalRead(buttonBluepin) == LOW)) //Code used to edit the left digit, runs each time the red button gets hit when setting the time
        {
          currentSecondMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started). This is used to check when to increment the 7 segment display.                    
          gameCheckMillis = currentSecondMillis - gameStartMillis;
          if (gameCheckMillis > gameRestart)
          {
            time2Reset = "Yes";
            break; // exit loops
          }
        } 
        else{
          break; // exit loops  
        }
      }
      if(time2Reset == "Yes"){
        time2Reset = "No";
        break; // exit loops 
      }
    }
  }
 
if(gameTimeOver == "Yes") 
{
    //gameLengthMillis = timeOutput.mLimit*600L + timeOutput.kLimit*60L + timeOutput.jLimit*10L + timeOutput.iLimit;
    //gameLengthMillis = gameLengthMillis*1000L;
    radio.stopListening();
    if (teamInControl == "Red"){
        Score.teamInControl = 0;
        /*
        teamTime.mRed = teamTime.m;
        teamTime.kRed = teamTime.k;
        teamTime.jRed= teamTime.j;
        teamTime.iRed = teamTime.i;
        */
      } else 
      if (teamInControl == "Blue"){
        Score.teamInControl = 1;
        /*
        teamTime.mBlue = teamTime.m;
        teamTime.kBlue = teamTime.k;
        teamTime.jBlue = teamTime.j;
        teamTime.iBlue = teamTime.i;
        */
      }
    Score.timerName = 1;
    //Score.blueTime = (teamTime.mBlue*-1)*600L + (long (teamTime.kBlue*-1))*60L + (long (teamTime.jBlue*-1))*10L + (long (teamTime.iBlue*-1));
    //Score.redTime = (long (teamTime.mBlue*-1))*600L + (long (teamTime.kBlue*-1))*60L + (long (teamTime.jBlue*-1))*10L + (long (teamTime.iBlue*-1));
    Score.blueTime = (teamTime.mBlue*600 + teamTime.kBlue*60 + teamTime.jBlue*10 + teamTime.iBlue)*-1;
    Score.redTime = (teamTime.mRed*600 + teamTime.kRed*60 + teamTime.jRed*10 + teamTime.iRed)*-1;
    //Score.timerName = 0;
    //Score.blueTime = 754;
    //Score.redTime =754;
    //Score.teamInControl = 1;
 
    //Score.blueTime = Score.blueTime*2;

  
    Serial.println("Game Over Check Time"); //Show which song is playing in serial monitor
    sendCommand(0x03, 0, stargatealarm);//Send command to play song 6
   while(2>1){
      
      radio.write(&Score, sizeof(Scorekeeper));
      delay(500);
      
      //displayLCD (0, 0, String(Score.timerName), "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      //displayLCD (5, 0, String(Score.blueTime), "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      //displayLCD (0, 1, String(Score.teamInControl), "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      //displayLCD (5, 1, String(Score.redTime), "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      Serial.println(Score.timerName);
      Serial.println(String(Score.blueTime));
      Serial.println(String(Score.redTime));
      Serial.println(Score.teamInControl);
      colorLEDChange( 0, 255,   0);
      
      delay(250);
      if (teamInControl == "Red"){
        colorLEDChange( 255, 0,   0); //
        delay(400);
      } else 
      if (teamInControl == "Blue"){
        colorLEDChange( 0, 0,   255); //
        delay(400);
      } else{
        colorLEDChange( 0, 0,   0); // Blank
        delay(250);
      }
      
      
      gameStartMillis = millis();
      while(2>1){
        if ((digitalRead(buttonRedpin) == LOW) && (digitalRead(buttonBluepin) == LOW)) //Code used to edit the left digit, runs each time the red button gets hit when setting the time
        {
          currentSecondMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started). This is used to check when to increment the 7 segment display.                    
          gameCheckMillis = currentSecondMillis - gameStartMillis;
          if (gameCheckMillis > gameRestart)
          {
            time2Reset = "Yes";
            break; // exit loops
          }
        } 
        else{
          break; // exit loops  
        }
      }
      if(time2Reset == "Yes"){
        time2Reset = "No";
        break; // exit loops 
      }
   }
}
 
//--------------------- Reset variables
  teamTime = timeOutput;
// Set each of the 7 segments to zero
  int time_1 = 0; // Left time display
  int time_2 = 0; // Middle left time display
  int time_3 = 0; // Middle right time display
  int time_4 = 0; // Right time display
  gameClockIndex = 12;
  gameClockSound = 27;
  //Attrition
  redLifeCount = startLifeCount;
  blueLifeCount = startLifeCount;
  attritionLifeIndex = 3 - attritionLifeSoundModifier;
  attritionLifeSound = 33 - attritionLifeSoundModifier;
  alarmCheck = "Yes";

  if(variableX == "X")
  {
    checkX = "No";
  }
  else
  {
    checkX = "Yes";
  }

if(runDownTeamColor == "Red"){
  runDownTeamColor = "Blue";
  teamTime.mBlue = timeOutput.mRed;
  teamTime.kBlue = timeOutput.kRed;
  teamTime.jBlue = timeOutput.jRed;
  teamTime.iBlue = timeOutput.iRed;

  teamTime.mRed = timeOutput.mBlue;
  teamTime.kRed = timeOutput.kBlue;
  teamTime.jRed = timeOutput.jBlue;
  teamTime.iRed = timeOutput.iBlue;
  timeOutput = teamTime;
}
else if(runDownTeamColor == "Blue"){
  runDownTeamColor = "Red";
  teamTime.mBlue = timeOutput.mRed;
  teamTime.kBlue = timeOutput.kRed;
  teamTime.jBlue = timeOutput.jRed;
  teamTime.iBlue = timeOutput.iRed;

  teamTime.mRed = timeOutput.mBlue;
  teamTime.kRed = timeOutput.kBlue;
  teamTime.jRed = timeOutput.jBlue;
  teamTime.iRed = timeOutput.iBlue;
  timeOutput = teamTime;
}
gameTimeOver = "No";
overTime = "No";
overTimeStart = "Yes";
digitalWrite(ledPinBlue, LOW); // turn the blue LED off
digitalWrite(ledPinRed, LOW); // turn the blue LED off

displayLCD (0, 0, "Switch Game Mode" , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
delay(1500);

if (enableRotaryEncoder == 1){
  buttonCombinedFunc ("Switch Game Mode", "Loading...", 1, 1, "list", YesNoArray, YesNoArraySize);
}
else{
  rotaryCombinedFunc ("Switch Game Mode", "Loading...", 1, 1, "list", YesNoArray, YesNoArraySize);
}
Serial.println("Button Interaction");
Serial.println(RotaryValue);
setUpGame = RotaryValue;

//-------------------- End Main Loop
}

 

 

 

 

// ----------Functions -----------------

void globalTransceiver () {
  //Radio Reciever Code
  #include <SPI.h>
  #include <nRF24L01.h>
  #include <RF24.h>
 
  int gogogo = 0;
 
  RF24 radio(48, 46); // CE, CSN
  const byte address[6] = "T0001";
 
  //End Radio Reciever Code
}

void setupTransceiver (){
  // Radio Reciever
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MIN);
}

void startGameTransceiver () {
  radio.read(&gogogo, sizeof(gogogo));
  if (gogogo == 1) {
    Serial.println("GameStarted");
    radio.stopListening();
    //break; // exit loops
  }
}

void gameClock(){
currentSecondMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started). This is used to check when to increment the 7 segment display.                    
  gameCheckMillis = currentSecondMillis - gameStartMillis;
  Serial.println("gameCheckMillis = ");
  Serial.print(gameCheckMillis);
  Serial.println("gameLengthMillis = ");
  Serial.print(gameLengthMillis);
  if (gameCheckMillis > gameLengthMillis)
    {
      if(overTime == "No")
      {
        
        gameTimeOver = "Yes";
        Serial.println("gameTimeOver = Yes");
      }
      else if (overTime == "Yes" && overTimeStart == "Yes") 
      {
        overTimeStart = "No";
        Serial.println("Game is in Over Time");
        sendCommand(0x03, 0, overTimeSound);//Send command to play song 6
      }
    }
 
currentSecondMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started). This is used to check when to increment the 7 segment display.                    
gameCheckMillis = gameLengthMillis - (currentSecondMillis - gameStartMillis);

if ((gameCheckMillis < gameClockArray[gameClockIndex]))
  {
    
    if ((gameClockSound == 15) && (overTime == "No")){
      sendCommand(0x03, 0, stargatealarm);//Send command to play song 6
      Serial.println("Stargate 3");
      Serial.println(overTime);
      gameTimeOver = "Yes";
      Serial.println(gameClockSound);
      Serial.println("Game Time Over");
      
    } 
    else if ((gameClockSound > 15) &&(endAudio == 0)) {
      Serial.println(gameCheckMillis);
      Serial.println(gameClockIndex);
      Serial.println(gameClockSound);
      sendCommand(0x03, 0, gameClockSound);//Send command to play song 6
    }
    
    if (gameClockSound > 15){
      gameClockIndex = gameClockIndex -1;
      gameClockSound = gameClockSound -1;
    }
    
  }
 
}

 

void theBugger(int m, int k, int j, int i, String teamName, String functionName) {
  //display_freeram();
 
  //theBugger(m, k, j, i, teamColor, "funcTimeLoop");
  Serial.print(functionName);
  Serial.print(" ");
  Serial.print(teamName);
  Serial.print(" ");
  Serial.print(m);
  Serial.print(k);
  Serial.print(":");
  Serial.print(j);
  Serial.println(i);
}

void display_freeram() {
  Serial.print(F("- SRAM left: "));
  Serial.println(freeRam());
}

int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0  
    ? (int)&__heap_start : (int) __brkval);  
}


//3 Pin LED strip

void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}


void colorLEDChange( int redSetting, int greenSetting, int blueSetting){
 
  //4 Pin LED Strip
 
  analogWrite(REDPIN, redSetting);
  analogWrite(GREENPIN, greenSetting);
  analogWrite(BLUEPIN, blueSetting);
 
  // 3 Pin LED Strip
  colorWipe(strip.Color(  redSetting, greenSetting,   blueSetting), 0); // Green
 
}

 


// ------------- Start Time Keeper ------------------------------------------------------
void simpleTimerSetup () {
  overTime = "No";
  currentSecondMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started). This is used to check when to increment the 7 segment display.                    
  gameCheckMillis = gameLengthMillis - (currentSecondMillis - gameStartMillis);
  gameCheckMillisCheck = gameCheckMillis;
}

void simpleTimer () {
    gameClock();
    Serial.println("gameCheckMillis2 = ");
    Serial.print(gameCheckMillis);
    Serial.println("gameCheckMillisCheck = ");
    Serial.print(gameCheckMillisCheck);
    if(gameCheckMillis < (gameCheckMillisCheck-1000L)){
      //displayLCD (0, 1, String(gameCheckMillis/1000L) , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      gameCheckMillisCheck = gameCheckMillis;
      
    }
    if((gameTimeOver == "Yes") && (alarmCheck == "Yes")){
      sendCommand(0x03, 0, stargatealarm);
      alarmCheck = "No";
    }
}


// ------------- Attrition -----------------------------

void funcAttrition (){

  if (directionInput == 1)
  { sendCommand(0x03, 0, attritionsound);//Send command to play song 6
  }
  // Setup
  if ((runDownTeamColor == "Red") && (directionInput == 1))
  {
    displayLCD (0, 0, "Red Team Lives" , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    inputLCDText = "Remaining " + String(redLifeCount); 
    displayLCD (0, 1, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    matrix.print(redLifeCount, DEC);
    matrix.drawColon(true);
    matrix.writeDisplay();
  } else if ((runDownTeamColor == "Red") && (directionInput == -1))
  {
    displayLCD (0, 0, "Red Team Number" , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    inputLCDText = "of Deaths " + String(redLifeCount); 
    displayLCD (0, 1, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    matrix.print(redLifeCount, DEC);
    matrix.drawColon(true);
    matrix.writeDisplay();
  }else if ((runDownTeamColor == "Blue") && (directionInput == 1))
  {
    displayLCD (0, 0, "Blue Team Lives" , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    inputLCDText = "Remaining " + String(blueLifeCount); 
    displayLCD (0, 1, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    matrix.print(blueLifeCount, DEC);
    matrix.drawColon(true);
    matrix.writeDisplay();
  } else if ((runDownTeamColor == "Blue") && (directionInput == -1))
  {
    displayLCD (0, 0, "Blue Team Number" , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    inputLCDText = "of Deaths " + String(blueLifeCount); 
    displayLCD (0, 1, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    matrix.print(blueLifeCount, DEC);
    matrix.drawColon(true);
    matrix.writeDisplay();
  }
  if (runDownTeamColor == "Red")
  {
    colorLEDChange( 255, 0,   0); // Red
  }
  else {
    colorLEDChange( 0, 0,  255); // Blue
  }
 
  simpleTimerSetup ();
  // Loop
  while(2>1){
    simpleTimer ();
    if ((runDownTeamColor == "Red") && (digitalRead(buttonRedpin) == LOW))
    {
      redLifeCount = funcLifeCount("Red", directionInput, redLifeCount);
      colorLEDChange( 0, 0,   0); // Red
      delay(250);
      colorLEDChange( 255, 0,   0); // Red
      if ((redLifeCount == 0) && (directionInput == 1)){
        teamInControl = "Red";
        break; // 
      }
    } else if ((runDownTeamColor == "Blue") && (digitalRead(buttonBluepin) == LOW))
    {
      blueLifeCount = funcLifeCount("Blue", directionInput, blueLifeCount);
      colorLEDChange( 0, 0,   0); // Red
      delay(250);
      colorLEDChange( 0, 0,   255); // Red
      if ((blueLifeCount == 0) && (directionInput == 1)){
        teamInControl = "Blue";
        break; // 
      }
    }
    gameStartMillis2 = millis();
      while(2>1){
        if ((digitalRead(buttonRedpin) == LOW) && (digitalRead(buttonBluepin) == LOW)) //Code used to edit the left digit, runs each time the red button gets hit when setting the time
        {
          currentSecondMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started). This is used to check when to increment the 7 segment display.                    
          gameCheckMillis2 = currentSecondMillis - gameStartMillis2;
          if (gameCheckMillis2 > gameRestart)
          {
            time2Reset = "Yes";
            break; // exit loops
          }
        } 
        else{
          break; // exit loops  
        }
      }
      if(time2Reset == "Yes"){
        //time2Reset = "No";
        break; // exit loops 
      }
  }

  gameTimeOver = "Yes"; 
 
}

int funcLifeCount(int teamColor, int direction, int lifeCount){
  int lifeCounter;
  lifeCounter = lifeCount - direction;
  if (direction == 1)
  {
    inputLCDText = "Remaining " + String(lifeCounter); 
    displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    matrix.print(lifeCounter, DEC);
    matrix.drawColon(true);
    matrix.writeDisplay();
    funcAttritionSound(lifeCounter);
    
  } else if (direction == -1)
  {
    inputLCDText = "of Deaths " + String(lifeCounter); 
    displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    matrix.print(lifeCounter, DEC);
    matrix.drawColon(true);
    matrix.writeDisplay();
  }
 
  return lifeCounter;
}

int funcAttritionSound(int lifeCounter){
if ((lifeCounter < gameAttritionArray[attritionLifeIndex]))
  {
    
    if (lifeCounter == 0){
      sendCommand(0x03, 0, noLivesSound);//Send command to play song 6
      delay(1500);
    } 
    else {
      sendCommand(0x03, 0, attritionLifeSound);//Send command to play song 6
    }
    
    
    attritionLifeIndex = attritionLifeIndex -1;
    attritionLifeSound = attritionLifeSound -1;
 
  }
}

// ------------- End Attrition ------------------------
 


// ------------- Timer Loop Functions --------------------------------------------------------

 

 

tClock funcTimeLoop(int time_1, int time_2, int time_3,int time_4, int timeCheck_1, int timeCheck_2, 
                    int timeReset_1, int timeReset_2, int direction, String teamColor,int teamhillcontrolled,
                    int teamPin, int teamButton, int teamReset, int oTeamPin, int em, int ek, int ej, int ei, int oTeamButton)
{
  tClock tInput;
  tInput.loopExit = "No";
  // This is probably very inefficient but these loops are what calculate what to display on the 7 segment digits
  for(int m = time_1; m >= timeCheck_1; m--){ //increments the left digit, m-- is the same as m = m - 1, it essentialy decreases the value of the left digit by 1 each time this loop runs
    for(int k = time_2; k >= timeCheck_1; k--){ //increments the left digit, k-- is the same as k = k - 1, it essentialy decreases the value of the middle left digit by 1 each time this loop runs
      for(int j = time_3; j >= timeCheck_2; j--){ //increments the left digit, j-- is the same as j = j - 1, it essentialy decreases the value of the middle right digit by 1 each time this loop runs
        for(int i = time_4; i >= timeCheck_1; i--) { 
            theBugger(m, k, j, i, teamColor, "funcTimeLoop");
            gameLengthDisplay ();
            
            
            tInput = funcTimeButtonCheck(teamColor, teamhillcontrolled, teamPin, teamButton, teamReset, 
                                          oTeamPin, tInput, direction, m, k, j, i, em, ek, ej, ei,oTeamButton);
            if (tInput.loopExit == "Yes")
                {break; // exit loops
                } 
        } 
        if (tInput.loopExit == "Yes")
            {break; // exit loops
            } 
        time_4 = timeReset_1;  // reset the right digit once it gets to zero
      }
      if (tInput.loopExit == "Yes")
          {break; // exit loops
          } 
      time_3 = timeReset_2; // reset the middle right digit once it gets to zero (note this is 5 because there are only 60 seconds in a minute
    }
    if (tInput.loopExit == "Yes")
       {break; // exit loops
        } 
    time_2 = timeReset_1; // reset the right digit once it gets to zero
  }
  // End of for loop
  return tInput;
}

tClock funcTimeButtonCheck(String teamColor,int teamhillcontrolled, int teamPin, int teamButton, int teamReset, int oTeamPin,tClock tInput, int direction, int m, int k, int j, int i,int em, int ek, int ej, int ei, int oTeamButton )
{
theBugger(m, k, j, i, teamColor, "funcTimeButtonCheck");
if (buttonMode == "Pause")
{
  if (runDownTeamColor == teamColor)
  {
    Serial.println(runDownTeamColor);
    Serial.println(teamColor);
    Serial.println("runDownTeamColor == teamColor");
  }
  else
  {
    Serial.println(runDownTeamColor);
    Serial.println(teamColor);
    Serial.println("runDownTeamColor does not = teamColor");
    Serial.print("gameClockSound = ");
    Serial.println(gameClockSound);
    if (gameClockSound > 15){
      Serial.print("gameClockSoundCheck = ");
      Serial.println(gameClockSound);
      gameClock();
    }
    displayTime (m,k,j,i, direction,teamColor);
  }
}
else
{
  displayTime (m,k,j,i, direction,teamColor);
}

//---------------------------
// Need to DeleteNew Code for calculating score with remote
if (teamInControl == "Red"){
        teamTime.mRed = m;
        teamTime.kRed = k;
        teamTime.jRed = j;
        teamTime.iRed = i;
        
      } else 
      if (teamInControl == "Blue"){
        teamTime.mBlue = m;
        teamTime.kBlue = k;
        teamTime.jBlue = j;
        teamTime.iBlue = i;
      }
//-------------------------------------      
      
startSecondMillis = millis();  // record the current time (actually the number of milliseconds since the program started). This variable is used to check whether 1 second has passed.
currentSecondMillis = millis();  //record the current "time" (actually the number of milliseconds since the program started). This is really just initializing this variable        
// This loop checks to see whether 1 second has passed, so that it knows when to increment the 7 segment display
for(; currentSecondMillis - startSecondMillis < periodSecond;){ // exit the loop once the difference between the current time and the start of the loop is greater than a second
    if (buttonMode == "Continuous")
    {
      tInput = funcCheckButtonHoldContinuous (teamColor,teamhillcontrolled, teamPin, teamButton, teamReset, oTeamPin,tInput, direction, m, k, j, i, em, ek, ej, ei);
    } 
    else  if (buttonMode == "Tap")
    {
      tInput = funcCheckButtonTap (teamColor,teamhillcontrolled, teamPin, teamButton, teamReset, oTeamPin,tInput, direction, m, k, j, i, em, ek, ej, ei,oTeamButton);
    }
    else  if (buttonMode == "Pause")
    {
      tInput = funcCheckButtonTapPause (teamColor,teamhillcontrolled, teamPin, teamButton, teamReset, oTeamPin,tInput, direction, m, k, j, i, em, ek, ej, ei,oTeamButton);
    }
    //Need to add Button Reset capability
    if (tInput.loopExit == "Yes")
       {break; // exit loops
        }                 
    
  gameClock();
  if(gameTimeOver == "Yes")
  {
    tInput.loopExit = "Yes";
    break; // exit loops
  }
 
  }
  return tInput;
}


// -------------- Specific Game Modes ------------------------

tClock funcCheckButtonTap (String teamColor,int teamhillcontrolled, int teamPin, int teamButton, int teamReset, int oTeamPin,tClock tInput, int direction, int m, int k, int j, int i, int em, int ek, int ej, int ei,int oTeamButton)
{
    if ((digitalRead(teamPin) == LOW) && (digitalRead(teamButton) == LOW)) //this code runs when the red LED is off, the red button is pushed and the red button hasn't been pushed twice in a row
        {
          funcX(teamButton, teamColor);
          
          if (checkX == "Yes")
          {
            theBugger(m, k, j, i, teamColor, "funcCheckButtonTap");
            Serial.print(teamColor);
            Serial.println(" Team Controls the Hill"); //Show which song is playing in serial monitor
            sendCommand(0x03, 0, teamhillcontrolled);//Send command to play song 6
            startMillis = millis();  //record what time the button was hit
            digitalWrite(teamPin, HIGH); // turn the red LED on
            digitalWrite(oTeamPin, LOW); // turn the blue LED off
            // Set the color of the NeoPixel LED Strip
            if (teamColor == "Red")
              {
                colorLEDChange( 255, 0,   0); // Red
                teamInControl = "Red";
                // save the blue teams 
                
                tInput.mRed = em;
                tInput.kRed = ek;
                tInput.jRed = ej;
                tInput.iRed = ei;
                
                // save the blue teams 
                if(checkReset == "Yes")
                {
                  tInput.mBlue = timeOutput.mBlue;
                  tInput.kBlue = timeOutput.kBlue;
                  tInput.jBlue = timeOutput.jBlue;
                  tInput.iBlue = timeOutput.iBlue;
                } else{
                  tInput.mBlue = m;
                  tInput.kBlue = k;
                  tInput.jBlue = j;
                  tInput.iBlue = i;
                }
              }
            else
              {
                theBugger(m, k, j, i, teamColor, "funcCheckButtonTap");
                colorLEDChange( 0, 0,   255); // blue
                teamInControl = "Blue";
                // save the red teams time
                
                tInput.mBlue = em;
                tInput.kBlue = ek;
                tInput.jBlue = ej;
                tInput.iBlue = ei;
                
                // save the red teams 
                if(checkReset == "Yes")
                {
                  tInput.mRed = timeOutput.mRed;
                  tInput.kRed = timeOutput.kRed;
                  tInput.jRed = timeOutput.jRed;
                  tInput.iRed = timeOutput.iRed;
                }
                else{
                  tInput.mRed = m;
                  tInput.kRed = k;
                  tInput.jRed = j;
                  tInput.iRed = i;  
                }
              }
            delay(250); // add a delay to allow time for the button to be released  
            tInput.loopExit = "Yes";
            if(variableX == "X")
            {
              checkX = "No";
            }
            else
            {
              checkX = "Yes";
            }
          }
        }
    if(direction == 1)
    {
      if((m+k+j+i == 0) && (teamColor == "Blue")){
        tInput.loopExit = "Yes";
        tInput.Victory = "Red";
      }
      if((m+k+j+i == 0) && (teamColor == "Red")){
        tInput.loopExit = "Yes";
        tInput.Victory = "Blue";
      }
    }
  return tInput;
}

tClock funcCheckButtonHoldContinuous (String teamColor,int teamhillcontrolled, int teamPin, int teamButton, int teamReset, int oTeamPin,tClock tInput, int direction, int m, int k, int j, int i, int em, int ek, int ej, int ei){

    if (digitalRead(teamButton) == LOW && (teamHold == 0)) //this code runs when the red LED is off, the red button is pushed and the red button hasn't been pushed twice in a row
        {
          theBugger(m, k, j, i, teamColor, "funcCheckButtonHoldContinuous 1");
          sendCommand(0x03, 0, teamhillcontrolled);//Send command to play song 6
          startMillis = millis();  //record what time the button was hit
          digitalWrite(teamPin, HIGH); // turn the red LED on
          digitalWrite(oTeamPin, LOW); // turn the blue LED off
          // Set the color of the NeoPixel LED Strip
          if (teamColor == "Red")
            {
              colorLEDChange( 255, 0,   0); // Red
              teamInControl = "Red";
            }
          else
            {
              colorLEDChange( 0, 0,   255); // blue
              teamInControl = "Blue";
            }
          delay(250); // add a delay to allow time for the button to be released 
          teamHold  = 1;
          holdHillContested = 1;
          
        }
    if (digitalRead(teamButton) == HIGH)
          {
            theBugger(m, k, j, i, teamColor, "funcCheckButtonHoldContinuous 2");
            teamHold  = 0;
            colorLEDChange( 0, 255,   0);
            teamInControl = "Green";
            if (holdHillContested == 1)
            {
              sendCommand(0x03, 0, hillcontested);//Send command to play song 6
              holdHillContested = 0;
            }
            tInput.loopExit = "Yes";
            if (teamColor == "Red")
              {
                // save the blue teams time
                theBugger(m, k, j, i, teamColor, "Befor Save Time 1");
                tInput.mBlue = m;
                tInput.kBlue = k;
                tInput.jBlue = j;
                tInput.iBlue = i;
                tInput.mRed = em;
                tInput.kRed = ek;
                tInput.jRed = ej;
                tInput.iRed = ei;
                theBugger(m, k, j, i, teamColor, "After Save Time 1");
                theBugger(tInput.mBlue, tInput.kBlue, tInput.jBlue, tInput.iBlue, teamColor, "After Save Time 2");
              }
            else
              {
                // save the red teams time            
                theBugger(m, k, j, i, teamColor, "Befor Save Time 1");
                tInput.mRed = m;
                tInput.kRed = k;
                tInput.jRed = j;
                tInput.iRed = i;
                theBugger(m, k, j, i, teamColor, "After Save Time 1");
                theBugger(tInput.mBlue, tInput.kBlue, tInput.jBlue, tInput.iBlue, teamColor, "After Save Time 2");
              }
          }
    if(direction == 1)
    {
      if((m+k+j+i == 0) && (teamColor == "Blue")){
        tInput.loopExit = "Yes";
        tInput.Victory = "Red";
      }
      if((m+k+j+i == 0) && (teamColor == "Red")){
        tInput.loopExit = "Yes";
        tInput.Victory = "Blue";
      }
    }
  return tInput;
}
// -------------- End Continuously Hold -----------------------

//--------------- Start Hold X --------------------------------

void funcX(int teamButton, String teamColor)
{
 
  if (variableX == "X")
  {
    holdHillContested = 1;
    xStartMillis = millis();
    while(2>1){
      currentSecondMillis = millis();
      xCheckMillis = currentSecondMillis - xStartMillis;
        if (digitalRead(teamButton) == LOW)
        {
          if (holdHillContested == 1)
            {
              sendCommand(0x03, 0, hillcontested);//Send command to play song 6
              holdHillContested = 0;
              colorLEDChange( 244, 232,   104); // Gold
            }
          
          
          if (xCheckMillis > xLengthMillis)
          {
            checkX = "Yes";
            break; // exit loops
          }
        }
        else
        {
          if (teamColor == "Red")
          {
            sendCommand(0x03, 0, blueteamhillcontrolled);//Send command to play song 6
            colorLEDChange( 0, 0,   255); // blue
            teamInControl = "Blue";
          }
          else if (teamColor == "Blue")
          {
            sendCommand(0x03, 0, redteamhillcontrolled);//Send command to play song 6
            colorLEDChange( 255, 0,   0); // red
            teamInControl = "Red";
          }
          else
          {
            sendCommand(0x03, 0, hillcontested);//Send command to play song 6
            colorLEDChange( 0, 255,   0);
            teamInControl = "Green";
          }
          
          checkX = "No";
          break; // exit loops
        }
      gameLengthDisplay ();  
    }
    
  }
 
}

//--------------- End Hold X ----------------------------------

//--------------- Start Pause Timer ---------------------------------

tClock funcCheckButtonTapPause (String teamColor,int teamhillcontrolled, int teamPin, int teamButton, int teamReset, int oTeamPin,tClock tInput, int direction, int m, int k, int j, int i, int em, int ek, int ej, int ei,int oTeamButton)
{
    if ((digitalRead(teamPin) == LOW) && (digitalRead(teamButton) == LOW)) //this code runs when the red LED is off, the red button is pushed and the red button hasn't been pushed twice in a row
        {
          funcX(teamButton, teamColor);
          
          if (checkX == "Yes")
          {
            theBugger(m, k, j, i, teamColor, "funcCheckButtonTap");
            Serial.print(teamColor);
            Serial.println(" Team Controls the Hill"); //Show which song is playing in serial monitor
            sendCommand(0x03, 0, teamhillcontrolled);//Send command to play song 6
            startMillis = millis();  //record what time the button was hit
            digitalWrite(teamPin, HIGH); // turn the red LED on
            digitalWrite(oTeamPin, LOW); // turn the blue LED off
            // Set the color of the NeoPixel LED Strip
            if (runDownTeamColor == "Red")
            {
              if (teamColor == "Red")
                {
                  colorLEDChange( 255, 0,   0); // Red
                  teamInControl = "Red";
                  // save the blue teams 
                
                  tInput.mRed = em;
                  tInput.kRed = ek;
                  tInput.jRed = ej;
                  tInput.iRed = ei;
                
                  // save the blue teams 
                  tInput.mBlue = 9;
                  tInput.kBlue = 9;
                  tInput.jBlue = 9;
                  tInput.iBlue = 9;
                  if (enableOvertime == 0){
                    overTime = "Yes"; 
                  }
                  
                
                }
              else
                {
                  theBugger(m, k, j, i, teamColor, "funcCheckButtonTap");
                  colorLEDChange( 0, 0,   255); // blue
                  teamInControl = "Blue";
                  // save the red teams time
                
                  tInput.mBlue = em;
                  tInput.kBlue = ek;
                  tInput.jBlue = ej;
                  tInput.iBlue = ei;
                
                  // save the red teams 
                  if(checkReset == "Yes")
                {
                  tInput.mRed = timeOutput.mRed;
                  tInput.kRed = timeOutput.kRed;
                  tInput.jRed = timeOutput.jRed;
                  tInput.iRed = timeOutput.iRed;
                }
                else{
                  tInput.mRed = m;
                  tInput.kRed = k;
                  tInput.jRed = j;
                  tInput.iRed = i;  
                }
                  overTime = "No";
                  
                
                }
            }
            else
            {
              if (teamColor == "Red")
                {
                  colorLEDChange( 255, 0,   0); // Red
                  teamInControl = "Red";
                  // save the blue teams 
                
                  tInput.mRed = em;
                  tInput.kRed = ek;
                  tInput.jRed = ej;
                  tInput.iRed = ei;
                
                  // save the blue teams 
                if(checkReset == "Yes")
                {
                  tInput.mBlue = timeOutput.mBlue;
                  tInput.kBlue = timeOutput.kBlue;
                  tInput.jBlue = timeOutput.jBlue;
                  tInput.iBlue = timeOutput.iBlue;
                } else{
                  tInput.mBlue = m;
                  tInput.kBlue = k;
                  tInput.jBlue = j;
                  tInput.iBlue = i;
                }
                  overTime = "No";
                  
                
                }
              else
                {
                  theBugger(m, k, j, i, teamColor, "funcCheckButtonTap");
                  colorLEDChange( 0, 0,   255); // blue
                  teamInControl = "Blue";
                  // save the red teams time
                
                  tInput.mBlue = em;
                  tInput.kBlue = ek;
                  tInput.jBlue = ej;
                  tInput.iBlue = ei;
                
                  // save the red teams 
                  tInput.mRed = 9;
                  tInput.kRed = 9;
                  tInput.jRed = 9;
                  tInput.iRed = 9;
                  if (enableOvertime == 0){
                    overTime = "Yes"; 
                  }
                  
                
                }
            }
            delay(250); // add a delay to allow time for the button to be released  
            tInput.loopExit = "Yes";
            if(variableX == "X")
            {
              checkX = "No";
            }
            else
            {
              checkX = "Yes";
            }
          }
        }
    if(direction == 1)
    {
      if((m+k+j+i == 0) && (teamColor == "Blue")){
        tInput.loopExit = "Yes";
        tInput.Victory = "Red";
      }
      if((m+k+j+i == 0) && (teamColor == "Red")){
        tInput.loopExit = "Yes";
        tInput.Victory = "Blue";
      }
    }
  return tInput;
}

//--------------- End Pause Timer -----------------------------

// -------------- End Specific Game Modes --------------------

void changeTeamColor(String teamColor, int teamButton, int teamPin, int oTeamPin){
  if (buttonMode == "Continuous") //this code runs when the red LED is off, the red button is pushed and the red button hasn't been pushed twice in a row
        {
          theBugger(9, 9, 9, 9, teamColor, "changeTeamColor");
          digitalWrite(teamPin, HIGH); // turn the red LED on
          digitalWrite(oTeamPin, LOW); // turn the blue LED off
          // Set the color of the NeoPixel LED Strip
          if (teamColor == "Red")
            {
              colorLEDChange( 255, 0,   0); // Red
              teamInControl = "Red";
            }
          else
            {
              colorLEDChange( 0, 0,   255); // blue
              teamInControl = "Blue";
            }
          
        }
}

int displayTime (int m, int k, int j, int i,int direction, String teamColor)
{
  //Tell the 7 segment display what number to display for each digit
  theBugger(m, k, j, i, teamColor, "displayTime");
  int teamColorLCD;
  if (buttonMode == "Continuous")
  {
    if(teamColor == "Red")
    {
      teamColorLCD = 0;
    }
    if(teamColor == "Blue")
    {
      teamColorLCD = 1;
    }
  }
  if ((buttonMode == "Tap") || (buttonMode == "Pause"))
  {
    if(teamColor == "Red")
    {
      teamColorLCD = 1;
    }
    if(teamColor == "Blue")
    {
      teamColorLCD = 0;
    }
  }
  int Clock_show = (m*1000+k*100+j*10+i)*direction;
  matrix.print(Clock_show, DEC);
  matrix.drawColon(true);
  matrix.writeDisplay();
  Serial.print(m*direction); // Left digit
  Serial.print(k*direction); // Middle left digit
  Serial.print(":"); // turn on the colon
  Serial.print(j*direction); // Middle right digit
  Serial.println(i*direction); // Right digit
 
  lcd.setCursor(5, teamColorLCD);//lcd.setCursor(lcdLine1Start, lcdLineNum)
  lcd.print(String(m*direction) + String(k*direction) + ":" + String(j*direction) + String(i*direction));
}

int displayLCD (int digit, int line, String lcdText, String lineClear)
{
  //theBugger(9, 9, 9, 9, "Unknown", "displayLCD");
  if(lineClear == "None")
  {
  }
  else if(lineClear == "First")
  {
    lcd.setCursor(0, 0);//lcd.setCursor(lcdLine1Start, lcdLineNum)
    lcd.print("                ");// clears previous display
  }
  else if(lineClear == "Second")
  {
    lcd.setCursor(0, 1);//lcd.setCursor(lcdLine1Start, lcdLineNum)
    lcd.print("                ");// clears previous display
  }
  else
  {
    lcd.setCursor(0, 0);//lcd.setCursor(lcdLine1Start, lcdLineNum)
    lcd.print("                ");// clears previous display
    lcd.setCursor(0, 1);//lcd.setCursor(lcdLine1Start, lcdLineNum)
    lcd.print("                ");// clears previous display
  }
lcd.setCursor(digit, line);//lcd.setCursor(lcdLine1Start, lcdLineNum)
lcd.print(lcdText);
}

//-------------- End Timer Loop Functions


// --------------------- MP3 Functions ---------------------------------------------
void sendMP3Command(char c) {
  //theBugger(9, 9, 9, 9, "Unknown", "sendMP3Command");
  switch (c) {
    case '?':
    case 'h':
      Serial.println("HELP  ");
      Serial.println(" p = Play");
      Serial.println(" P = Pause");
      Serial.println(" > = Next");
      Serial.println(" < = Previous");
      Serial.println(" s = Stop Play"); 
      Serial.println(" + = Volume UP");
      Serial.println(" - = Volume DOWN");
      Serial.println(" c = Query current file");
      Serial.println(" q = Query status");
      Serial.println(" v = Query volume");
      Serial.println(" x = Query folder count");
      Serial.println(" t = Query total file count");
      Serial.println(" f = Play folder 1.");
      Serial.println(" S = Sleep");
      Serial.println(" W = Wake up");
      Serial.println(" r = Reset");
      break;

    case 'p':
      Serial.println("Play ");
      sendCommand(CMD_PLAY);
      break;

    case 'P':
      Serial.println("Pause");
      sendCommand(CMD_PAUSE);
      break;

    case '>':
      Serial.println("Next");
      sendCommand(CMD_NEXT_SONG);
      sendCommand(CMD_PLAYING_N); // ask for the number of file is playing
      break;

    case '<':
      Serial.println("Previous");
      sendCommand(CMD_PREV_SONG);
      sendCommand(CMD_PLAYING_N); // ask for the number of file is playing
      break;

    case 's':
      Serial.println("Stop Play");
      sendCommand(CMD_STOP_PLAY);
      break;

    case '+':
      Serial.println("Volume Up");
      sendCommand(CMD_VOLUME_UP);
      break;

    case '-':
      Serial.println("Volume Down");
      sendCommand(CMD_VOLUME_DOWN);
      break;

    case 'c':
      Serial.println("Query current file");
      sendCommand(CMD_PLAYING_N);
      break;

    case 'q':
      Serial.println("Query status");
      sendCommand(CMD_QUERY_STATUS);
      break;

    case 'v':
      Serial.println("Query volume");
      sendCommand(CMD_QUERY_VOLUME);
      break;

    case 'x':
      Serial.println("Query folder count");
      sendCommand(CMD_QUERY_FLDR_COUNT);
      break;

    case 't':
      Serial.println("Query total file count");
      sendCommand(CMD_QUERY_TOT_TRACKS);
      break;

    case 'f':
      Serial.println("Playing folder 1");
      sendCommand(CMD_FOLDER_CYCLE, 1, 0);
      break;

    case 'S':
      Serial.println("Sleep");
      sendCommand(CMD_SLEEP_MODE);
      break;

    case 'W':
      Serial.println("Wake up");
      sendCommand(CMD_WAKE_UP);
      break;

    case 'r':
      Serial.println("Reset");
      sendCommand(CMD_RESET);
      break;
  }
}

/********************************************************************************/
/*Function decodeMP3Answer: Decode MP3 answer.                                  */
/*Parameter:-void                                                               */
/*Return: The                                                  */

String decodeMP3Answer() {
  String decodedMP3Answer = "";
  //theBugger(9, 9, 9, 9, "Unknown", "decodeMP3Answer");
  decodedMP3Answer += sanswer();

  switch (ansbuf[3]) {
    case 0x3A:
      decodedMP3Answer += " -> Memory card inserted.";
      break;

    case 0x3D:
      decodedMP3Answer += " -> Completed play num " + String(ansbuf[6], DEC);
      //sendCommand(CMD_NEXT_SONG);
      //sendCommand(CMD_PLAYING_N); // ask for the number of file is playing
      break;

    case 0x40:
      decodedMP3Answer += " -> Error";
      break;

    case 0x41:
      decodedMP3Answer += " -> Data recived correctly. ";
      break;

    case 0x42:
      decodedMP3Answer += " -> Status playing: " + String(ansbuf[6], DEC);
      break;

    case 0x48:
      decodedMP3Answer += " -> File count: " + String(ansbuf[6], DEC);
      break;

    case 0x4C:
      decodedMP3Answer += " -> Playing: " + String(ansbuf[6], DEC);
      break;

    case 0x4E:
      decodedMP3Answer += " -> Folder file count: " + String(ansbuf[6], DEC);
      break;

    case 0x4F:
      decodedMP3Answer += " -> Folder count: " + String(ansbuf[6], DEC);
      break;
  }

  return decodedMP3Answer;
}

/********************************************************************************/
/*Function: Send command to the MP3                                             */
/*Parameter: byte command                                                       */
/*Parameter: byte dat1 parameter for the command                                */
/*Parameter: byte dat2 parameter for the command                                */

void sendCommand(byte command){
  //theBugger(9, 9, 9, 9, "Unknown", "sendCommand");
  sendCommand(command, 0, 0);
}

void sendCommand(byte command, byte dat1, byte dat2){
  //theBugger(9, 9, 9, 9, "Unknown", "sendCommandAgain");
  delay(20);
  Send_buf[0] = 0x7E;    //
  Send_buf[1] = 0xFF;    //
  Send_buf[2] = 0x06;    // Len
  Send_buf[3] = command; //
  Send_buf[4] = 0x01;    // 0x00 NO, 0x01 feedback
  Send_buf[5] = dat1;    // datah
  Send_buf[6] = dat2;    // datal
  Send_buf[7] = 0xEF;    //
  Serial.print("Sending: ");
  for (uint8_t i = 0; i < 8; i++)
  {
    mp3.write(Send_buf[i]) ;
    Serial.print(sbyte2hex(Send_buf[i]));
  }
  Serial.println();
}

 

/********************************************************************************/
/*Function: sbyte2hex. Returns a byte data in HEX format.                       */
/*Parameter:- uint8_t b. Byte to convert to HEX.                                */
/*Return: String                                                                */


String sbyte2hex(uint8_t b)
{
  //theBugger(9, 9, 9, 9, "Unknown", "sbyte2hex");
  String shex;

  shex = "0X";

  if (b < 16) shex += "0";
  shex += String(b, HEX);
  shex += " ";
  return shex;
}


/********************************************************************************/
/*Function: shex2int. Returns a int from an HEX string.                         */
/*Parameter: s. char *s to convert to HEX.                                      */
/*Parameter: n. char *s' length.                                                */
/*Return: int                                                                   */

int shex2int(char *s, int n){
  //theBugger(9, 9, 9, 9, "Unknown", "shex2int");
  int r = 0;
  for (int i=0; i<n; i++){
     if(s[i]>='0' && s[i]<='9'){
      r *= 16; 
      r +=s[i]-'0';
     }else if(s[i]>='A' && s[i]<='F'){
      r *= 16;
      r += (s[i] - 'A') + 10;
     }
  }
  return r;
}


/********************************************************************************/
/*Function: sanswer. Returns a String answer from mp3 UART module.          */
/*Parameter:- uint8_t b. void.                                                  */
/*Return: String. If the answer is well formated answer.                        */

String sanswer(void)
{
  //theBugger(9, 9, 9, 9, "Unknown", "sanswer");
  uint8_t i = 0;
  String mp3answer = "";

  // Get only 10 Bytes
  while (mp3.available() && (i < 10))
  {
    uint8_t b = mp3.read();
    ansbuf[i] = b;
    i++;

    mp3answer += sbyte2hex(b);
  }

  // if the answer format is correct.
  if ((ansbuf[0] == 0x7E) && (ansbuf[9] == 0xEF))
  {
    return mp3answer;
  }

  return "???: " + mp3answer;
}

// ------------------- End MP3 Functions ---------------------------------------------

//--------------------------------- Start Admin Setup -------------------------------------------------

void adminSetup(){
    //--------Code for selecting game mode------------------
    
gameExitCheck = 0;
teamRunDownClock = 3;
enableOvertime = 1;
limitGameLength = 1;

if (turnLEDOff == 0){
    colorLEDChange( 0, 0,   0); 
}
else{
  colorLEDChange( 0, 255,   0); 

  
 
 
  if (enableRotaryEncoder == 1){
    buttonCombinedFunc ("Select Game Mode", "Loading...", 2, 1, "list", gameModeSelection, gameModeSelectionSize);
  }
  else{
  rotaryCombinedFunc ("Select Game Mode", "Loading...", 2, 1, "list", gameModeSelection, gameModeSelectionSize);
  }
  Serial.println(RotaryValue);
  gameID = RotaryValue;
 
  if (RotaryValue == 0){
    gameSelectedMain = gameParametersArray[gameID][0];
    //How do you want to interact with the button
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("Buttn Intraction", "Loading...", 0, 1, "list", buttonInteractArray, buttonInteractArraySize); 
      }
      else{
        rotaryCombinedFunc ("Buttn Intraction", "Loading...", 0, 1, "list", buttonInteractArray, buttonInteractArraySize); 
      }  
        Serial.println("Button Interaction");
        Serial.println(RotaryValue);
        buttonInteraction = RotaryValue;
        //0 = Tap
        //1 = Hold X
        //2 = Continuous
    if ((buttonInteraction == 2)
        )
    {buttonMode = "Continuous";
    }
    else
    {
      buttonMode = "Tap";
    }
    //Victory condition
      if(buttonInteraction == 2){
        if (enableRotaryEncoder == 1){
          buttonCombinedFunc ("Objective", "Loading...", 0, 1, "list", objectiveArray, 2); 
        }
        else{
          rotaryCombinedFunc ("Objective", "Loading...", 0, 1, "list", objectiveArray, 2); 
        }
      }
      else{
        if (enableRotaryEncoder == 1){
          buttonCombinedFunc ("Objective", "Loading...", 0, 1, "list", objectiveArray, objectiveArraySize); 
        }
        else{
          rotaryCombinedFunc ("Objective", "Loading...", 0, 1, "list", objectiveArray, objectiveArraySize); 
        }
      }
      
      Serial.println("Objective");
      Serial.println(RotaryValue);
      objective = RotaryValue;
      //0 = Both Count down time
      //1 = Both Count Up Time
      //2 = Both Reset Run Down
      //3 = One Pause other count down
      //4 = One Reset other count down
    if ((objective == 3) || (objective == 4)
        )
    {buttonMode = "Pause";
    }
    
    if ((objective == 2) ||
        (objective == 4)
        )
    {
      checkReset = "Yes";
    }
    else {
      checkReset = "No";
    }  
      
    //Which team is trying to run down the clock?
      if ((objective == 3) ||
        (objective == 4)
        )
      {
        if (enableRotaryEncoder == 1){
          buttonCombinedFunc ("Team Rndown Clck", "Loading...", 0, 1, "list", teamColorArray, teamColorArraySize); 
        }
        else{
          rotaryCombinedFunc ("Team Rndown Clck", "Loading...", 0, 1, "list", teamColorArray, teamColorArraySize); 
        }
        Serial.println("Team Run Down Clock");
        Serial.println(RotaryValue);
        teamRunDownClock = RotaryValue;
        //0 = Red
        //1 = Blue
      }
        
    // Select the objective time  
    if ((objective != 1)
        )
    { timeDirection = "Down";
      if ((teamRunDownClock != 0)
          )
        {
          if (enableRotaryEncoder == 1){
            buttonCombinedFunc ("Blue Objctv Time", "Loading...", 0, 1, "time", gameModeSelection, gameModeSelectionSize); 
          }
          else{
            rotaryCombinedFunc ("Blue Objctv Time", "Loading...", 180, 1, "time", gameModeSelection, gameModeSelectionSize); 
          }  
          Serial.println("Objective Time");
          Serial.println(RotaryValue);
          objectiveTimeBlue = RotaryValue;
          objectiveTimeRed = RotaryValue;
          checkTeamTime = 1;
        }
    }
    else 
    { 
      timeDirection = "Up";
      objectiveTimeBlue = 0;
      objectiveTimeRed = 0;
    }
    // Are the team times different
    if ((objective == 0) ||
        (objective == 2) 
        )
      {
        if (enableRotaryEncoder == 1){
          buttonCombinedFunc ("Is Red Time Diff", "Loading...", 1, 1, "list", YesNoArray, YesNoArraySize);
        }
        else{
          rotaryCombinedFunc ("Is Red Time Diff", "Loading...", 1, 1, "list", YesNoArray, YesNoArraySize);
        }
        Serial.println("Are team times different?");
        Serial.println(RotaryValue);
        checkTeamTime = RotaryValue;
          //0 = Yes
          //1 = No
      }
    
    
   
    // Select the objective time  
    if ((objective != 1)
        )
    {
      if ((teamRunDownClock == 0) ||
          (checkTeamTime == 0)
          )
        {
          if (enableRotaryEncoder == 1){
            buttonCombinedFunc ("Red Objctv Time", "Loading...", 0, 1, "time", gameModeSelection, gameModeSelectionSize); 
          }
        else{
          rotaryCombinedFunc ("Red Objctv Time", "Loading...", 180, 1, "time", gameModeSelection, gameModeSelectionSize); 
        }
          Serial.println("Objective Time");
          Serial.println(RotaryValue);
          objectiveTimeRed = RotaryValue;
        }
    }
    
  // Set hold button x amount of time  
    if ((buttonInteraction == 1) 
        )
    {
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("Hld Bttn X 2CTRL", "Loading...", 0, 1, "time_ms", gameModeSelection, gameModeSelectionSize); 
      }
      else{
        rotaryCombinedFunc ("Hld Bttn X 2CTRL", "Loading...", 10, 1, "time_ms", gameModeSelection, gameModeSelectionSize); 
      }
      Serial.println("Hold Button X amount of time");
      Serial.println(RotaryValue);
      holdXTime = RotaryValue;
      
      if (holdXTime == 0){
        variableX = "No";
      }
      else{
        variableX = "X";
        xLengthMillis = holdXTime*100L;
      }
    }
 
  if ((objective == 0)
        )
      {
        if (enableRotaryEncoder == 1){
          buttonCombinedFunc ("Limit Gamelength", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
        }
        else{
          rotaryCombinedFunc ("Limit Gamelength", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
        }
        Serial.println("Limit Gamelength?");
        Serial.println(RotaryValue);
        limitGameLength = RotaryValue;
          //0 = Yes
          //1 = No
      }
  // Set the overall game length  
    if ((objective == 1) ||
        (objective == 3) ||
        (objective == 4) ||
        (limitGameLength == 0) 
        )
    {
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("Set Game Length", "Loading...", 0, 0, "time", gameModeSelection, gameModeSelectionSize); 
      }
      else{
        rotaryCombinedFunc ("Set Game Length", "Loading...", 300, 0, "time", gameModeSelection, gameModeSelectionSize); 
      }
      Serial.println("Game Length Time");
      Serial.println(RotaryValue);
      gameLengthTime = RotaryValue;
      limitGameLength = 0;
      //variableCheck1 = gameLengthTime;
    }
    else{
      gameLengthTime = 32000;
    }
  //If victory conditions 3&4
      if ((objective == 3) ||
        (objective == 4)
        )
      {
        if (enableRotaryEncoder == 1){
          buttonCombinedFunc ("Enable Overtime", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
        }
        else{
          rotaryCombinedFunc ("Enable Overtime", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
        }
        Serial.println("Enable Overtime");
        Serial.println(RotaryValue);
        enableOvertime = RotaryValue;
        //Enable Overtime 
          //0 = Yes
          //1 = No
      }
    
  }
 
 
  else if(RotaryValue > gameModeSelectionSize){
    //error
    inputLCDText = String(RotaryValue);
    displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    Serial.println("Error");
    Serial.println(RotaryValue);
    delay(3000);
  }
  // Preprogrammed 
  else{
    Serial.println("You Selected ");
    for (int i = 0; i < 7; i++) {
      Serial.println(gameParametersArray[RotaryValue][i]);
    }
    //{name, buttonPush, timeX, timeLimit, timePause, timeReset, timeDirection}
    
    gameSelectedMain = gameParametersArray[gameID][0];
    buttonMode = gameParametersArray[gameID][1];
    checkReset = gameParametersArray[gameID][5];
    timeDirection = gameParametersArray[gameID][6];
    
    
  // Select which team will be running down the clock
    if ((gameSelectedMain == "Rogue One") ||
        (gameSelectedMain == "Time Reset")
        )
    {
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("Team Rndown Clck", "Loading...", 0, 1, "list", teamColorArray, teamColorArraySize); 
      }
      else{
        rotaryCombinedFunc ("Team Rndown Clck", "Loading...", 0, 1, "list", teamColorArray, teamColorArraySize);
      }
      Serial.println("Team Run Down Clock");
      Serial.println(RotaryValue);
      teamRunDownClock = RotaryValue;
      Serial.println("Enable Overtime");
      enableOvertime = 0;
      Serial.println(enableOvertime);
        
    }
  // Select which team will use this timer to record tags
    if ((gameSelectedMain == "Attrition") ||
        (gameSelectedMain == "Death Clicks")
        )
    {
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("Team Color", "Loading...", 0, 1, "list", teamColorArray, teamColorArraySize); 
      }
      else{
        rotaryCombinedFunc ("Team Color", "Loading...", 0, 1, "list", teamColorArray, teamColorArraySize);
      }
      Serial.println("Team Color");
      Serial.println(RotaryValue);
      teamRunDownClock = RotaryValue;
    }
    
  // Select which team will use this timer to record tags
    if ((gameSelectedMain == "Attrition")
        )
    {
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("How many lives?", "Loading...", 0, 1, "int", teamColorArray, teamColorArraySize);
      }
      else{
        rotaryCombinedFunc ("How many lives?", "Loading...", 15, 1, "int", teamColorArray, teamColorArraySize); 
      }
      Serial.println("Attrition life Counter");
      Serial.println(RotaryValue);
      startLifeCount = RotaryValue;
      redLifeCount = startLifeCount;
      blueLifeCount = startLifeCount;
      if(startLifeCount >15){
        attritionLifeSoundModifier = 0;
      }
      else if(startLifeCount < 10){
        if(startLifeCount > 5){
          attritionLifeSoundModifier = 2;
        }
        else{
          attritionLifeSoundModifier = 3;
        }
      }
      else{
        attritionLifeSoundModifier = 1;
      }
      
    }
  // Select which team will use this timer to record tags
    if ((gameSelectedMain == "Death Clicks")
        )
    {
      Serial.println("Deathclicks life Counter");
      startLifeCount = 0;
      redLifeCount = startLifeCount;
      blueLifeCount = startLifeCount;
      Serial.println(startLifeCount);
      
    }
  // Select the objective time  
    if ((gameSelectedMain == "KoTH") ||
        (gameSelectedMain == "Rogue One") ||
        (gameSelectedMain == "Time Reset")
        )
    {
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("Objective Time", "Loading...", 0, 1, "time", gameModeSelection, gameModeSelectionSize);
      }
      else{
        rotaryCombinedFunc ("Objective Time", "Loading...", 180, 1, "time", gameModeSelection, gameModeSelectionSize); 
      }
      Serial.println("Objective Time");
      Serial.println(RotaryValue);
      objectiveTimeBlue = RotaryValue;
      objectiveTimeRed = RotaryValue;
    }
    else{
      objectiveTimeBlue = 0;
      objectiveTimeRed = 0;
    }
  // Set hold button x amount of time  
    if ((gameParametersArray[gameID][2] == "X")
        )
    {
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("Hld Bttn X 2CTRL", "Loading...", 0, 1, "time_ms", gameModeSelection, gameModeSelectionSize); 
      }
      else{
        rotaryCombinedFunc ("Hld Bttn X 2CTRL", "Loading...", 10, 1, "time_ms", gameModeSelection, gameModeSelectionSize);
      }
      Serial.println("Hold Button X amount of time");
      Serial.println(RotaryValue);
      holdXTime = RotaryValue;
      
      if (holdXTime == 0){
        variableX = "No";
      }
      else{
        variableX = "X";
        xLengthMillis = holdXTime*100L;
      }
      
    }
  // Set the overall game length  
    if ((gameSelectedMain == "Time Keeper") ||
        (gameSelectedMain == "Rogue One") ||
        (gameSelectedMain == "Death Clicks") ||
        (gameSelectedMain == "Domination") ||
        (gameSelectedMain == "Hold The Hill") ||
        (gameSelectedMain == "Time Reset")
        )
    {
      
      if (gameSelectedMain == "Death Clicks"){
        if (enableRotaryEncoder == 1){
          buttonCombinedFunc ("Limit Gamelength", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
        }
        else{
          rotaryCombinedFunc ("Limit Gamelength", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
        }
        Serial.println("Limit Gamelength?");
        Serial.println(RotaryValue);
        limitGameLength = RotaryValue;
          //0 = Yes
          //1 = No
        if(limitGameLength == 0){
          if (enableRotaryEncoder == 1){
            buttonCombinedFunc ("Set Game Length", "Loading...", 0, 0, "time", gameModeSelection, gameModeSelectionSize); 
          }
          else{
            rotaryCombinedFunc ("Set Game Length", "Loading...", 300, 0, "time", gameModeSelection, gameModeSelectionSize);
          }
          Serial.println("Game Length Time");
          Serial.println(RotaryValue);
          gameLengthTime = RotaryValue;
          //variableCheck2 = gameLengthTime;
        }
        else{
          gameLengthTime = 32000;
        }
            
      }
      else{
        if (enableRotaryEncoder == 1){
          buttonCombinedFunc ("Set Game Length", "Loading...", 0, 0, "time", gameModeSelection, gameModeSelectionSize); 
        }
        else{
          rotaryCombinedFunc ("Set Game Length", "Loading...", 300, 0, "time", gameModeSelection, gameModeSelectionSize);
        }
        Serial.println("Game Length Time");
        Serial.println(RotaryValue);
        gameLengthTime = RotaryValue;
        limitGameLength = 0;
        //variableCheck2 = gameLengthTime;
      }
    }
    else{
      gameLengthTime = 32000;
    }
  }
 
 
 

  
 
  // Use Audio to start game
    if (enableRotaryEncoder == 1){
      buttonCombinedFunc ("Use Start Audio", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
    }
    else{
      rotaryCombinedFunc ("Use Start Audio", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
    }
    Serial.println("Use Start Audio");
    Serial.println(RotaryValue);
    startAudio = RotaryValue;
 
 
    
  // Use end game count down
    if (limitGameLength == 0)
    {
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("Use End Countdwn", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
      }
      else{
        rotaryCombinedFunc ("Use End Countdwn", "Loading...", 0, 1, "list", YesNoArray, YesNoArraySize);
      }
      Serial.println("Use End Countdown");
      Serial.println(RotaryValue);
      endAudio = RotaryValue;
    }
 
  // Set start delay
  if ((limitGameLength == 0) || (startAudio == 0))
    {
      if (enableRotaryEncoder == 1){
        buttonCombinedFunc ("Set Start Delay", "Loading...", 0, 1, "time", gameModeSelection, gameModeSelectionSize);
      }
      else{
        rotaryCombinedFunc ("Set Start Delay", "Loading...", 0, 1, "time", gameModeSelection, gameModeSelectionSize); 
      }
      Serial.println("Start Delay Time");
      startDelayTimeMillis = RotaryValue*1000L;
      Serial.println(startDelayTimeMillis);  
    }

  
 
  // check point
  if (teamRunDownClock == 0){
    runDownTeamColor = "Red";
    objectiveTimeBlue = 32000;
  }
  else if (teamRunDownClock == 1){
    runDownTeamColor = "Blue";
    objectiveTimeRed = 32000;
  }
 
  Serial.println("Check1 Length");
  Serial.println(gameLengthTime);
 
 
  gameLengthMillis = gameLengthTime*1000L;
  Serial.println("Check2 Length");
  Serial.println(gameLengthTime);
  Serial.println(gameLengthMillis);
 
  timeOutput.mBlue = FuncCalcDigits (objectiveTimeBlue, 0); 
  timeOutput.kBlue = FuncCalcDigits (objectiveTimeBlue, 1);
  timeOutput.jBlue = FuncCalcDigits (objectiveTimeBlue, 2); 
  timeOutput.iBlue = FuncCalcDigits (objectiveTimeBlue, 3); 
 
  timeOutput.mRed = FuncCalcDigits (objectiveTimeRed, 0); 
  timeOutput.kRed = FuncCalcDigits (objectiveTimeRed, 1);
  timeOutput.jRed = FuncCalcDigits (objectiveTimeRed, 2); 
  timeOutput.iRed = FuncCalcDigits (objectiveTimeRed, 3);
 
  timeOutput.mLimit = FuncCalcDigits (gameLengthTime, 0); 
  timeOutput.kLimit = FuncCalcDigits (gameLengthTime, 1);
  timeOutput.jLimit = FuncCalcDigits (gameLengthTime, 2); 
  timeOutput.iLimit = FuncCalcDigits (gameLengthTime, 3);
 
  teamTime = timeOutput;
 
  // Starting parameters
  gameTimeOver = "No";
  teamInControl = "Green";  
  //playGameStart = "Yes";
  //playGameEnd = "Yes";
  attritionLifeIndex = 3 - attritionLifeSoundModifier;
  attritionLifeSound = 33 - attritionLifeSoundModifier;
  overTime = "No";
  overTimeStart = "Yes";
  alarmCheck = "Yes";
    

 

      
      
      Serial.println("X Time");
      Serial.println(xLengthMillis);
      
      if(variableX == "X")
      {
        checkX = "No";
      }
      else
      {
        checkX = "Yes";
      }

    if(timeDirection == "Down"){
      timeCheck_1 = timeCheck_1Down;
      timeCheck_2 = timeCheck_2Down; 
      timeReset_1 = timeReset_1Down;
      timeReset_2 = timeReset_2Down;
      directionInput = directionDown;
    } 
    else{
      timeCheck_1 = timeCheck_1Up;
      timeCheck_2 = timeCheck_2Up; 
      timeReset_1 = timeReset_1Up;
      timeReset_2 = timeReset_2Up;
      directionInput = directionUp;
    }
    
    
    //--------END Code for selecting game mode------------------
    

    if (limitGameLength == 1)
    {
      displayLCD (0, 0, "Game Length" , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      displayLCD (0, 1, "not set" , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      delay(delayLCD);
    }
    else if ((gameSelectedMain == "Attrition") || (gameSelectedMain == "Death Clicks")){
      
    }
    else{
      displayLCD (0, 0, "GameLengthLimit", "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      inputLCDText = String(timeOutput.mLimit) + String(timeOutput.kLimit) + ":" + String(timeOutput.jLimit) + String(timeOutput.iLimit);
      displayLCD (0, 1, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      delay(delayLCD);
    }
    
    

}

//--------------------------------- End Admin Setup ------------------------------------------------------


int rotaryCombinedFunc (String LCDQuestion, String LCDResponse, int RotaryStart, int turnMultiplier, String typeOut, String listArray[], int sizeArray){
 
  displayLCD (0, 0, LCDQuestion , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
  RotaryPosition= RotaryStart;    // To store Stepper Motor Position
  PrevPosition = RotaryPosition - 1; // Save previous position in variable
 
  if (typeOut == "int")  {
      inputLCDText = String(RotaryPosition);
      displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      Serial.println(RotaryPosition);
    }
  // Cycles through a list
  else if (typeOut == "list") {
    inputLCDText = listArray[RotaryPosition];
    displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    Serial.println(listArray[RotaryPosition]);
    
  }
 
  else if (typeOut == "time") {
    funcTimeCalc (RotaryPosition);
    
  }
 
  while (2>1){ 
    rotaryTurnFunc(RotaryStart, turnMultiplier, typeOut, listArray, sizeArray);
    byte exitCheck = funcEncoderButton(LCDResponse);
    if (exitCheck == 1){
      break;
    }
  }
 
}

int rotaryTurnFunc(int RotaryStart, int turnMultiplier,String typeOut, String listArray[], int sizeArray){ // typeOut is int, list, or time
 
  // Runs if rotation was detected
  if (PrevPosition != RotaryPosition)  {
    PrevPosition = RotaryPosition; // Save previous position in variable
    /*
    if (rotationdirection) {
      RotaryPosition=RotaryPosition+turnMultiplier;} // decrease Position by turnMultiplier
    else {
      RotaryPosition=RotaryPosition-turnMultiplier;} // increase Position by turnMultiplier
    */
    
    //Changes the integer value on the LCD screen
    if (typeOut == "int")  {
      
      if((RotaryPosition < 0)) {
        RotaryPosition = 0;
      }
      
      inputLCDText = String(RotaryPosition);
      displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      Serial.println(RotaryPosition);
    } 
    // Cycles through a list
    else if (typeOut == "list") {
      
      if((RotaryPosition> (sizeArray - 1))) {
        RotaryPosition = 0;
      } else if((RotaryPosition < 0)) {
        RotaryPosition = sizeArray - 1;
      }
      
      inputLCDText = listArray[RotaryPosition];
      displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      Serial.println(listArray[RotaryPosition]);
      PrevPosition = RotaryPosition;
      
      
    }
    
    else if (typeOut == "time") {
      
      if((RotaryPosition < 0)) {
        RotaryPosition = 0;
      }
      
      funcTimeCalc (RotaryPosition);
      
    }
    
    else if (typeOut == "time_ms") {
      
      if((RotaryPosition < 0)) {
        RotaryPosition = 599;
      }
      else if((RotaryPosition > 599)) {
        RotaryPosition = 0;
      }
      
      funcTimeCalcMilli (RotaryPosition);
      
    }
    
    //TurnDetected = false;  // do NOT repeat IF loop until new rotation detected
    
    return RotaryPosition;
    RotaryValue = RotaryPosition;
  }
  RotaryValue = RotaryPosition;
}

//----------------------- Start Rotary Button --------------------------------------------------------------------

byte funcEncoderButton(String LCDResponse){
  byte check = 0;
 
  if ((digitalRead(EncoderButton) == LOW)) { 
    startMillis = millis();
    while ((digitalRead(EncoderButton) == LOW)) { 
      
      if ((millis()-startMillis) > 250) {  // check if button was already pressed
          check = 1;
          displayLCD (0, 0, LCDResponse , "First"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
          Serial.println("Button Pushed");
          delay(1000);
          break;
        }
      }
    
    } 

  return check;
}

 


//----------------------- End Rotary Button -----------------------------------------------------------

// ----------------------Start Calculate Time Functions ------------------------------------------------------

int funcTimeCalc (int timeTotal) {
 
  int fmR = timeTotal % 600;
  int fm = (timeTotal - fmR)/ 600;
 
  int fkR = fmR % 60;
  int fk = (fmR - fkR)/ 60;
 
  int fjR = fkR % 10;
  int fj = (fkR - fjR)/ 10;
 
  int fi = fjR;
 
  clockDisplay(fm, fk, fj, fi,1);
 
}

int funcTimeCalcMilli (int timeTotal) {
 
  int fmR = timeTotal % 100;
  int fm = (timeTotal - fmR)/ 100;
 
  int fkR = fmR % 10;
  int fk = (fmR - fkR)/ 10;
 
  int fj = fkR;
 
  Serial.print(fm); // Left digit
  Serial.print(fk); // Middle left digit
  Serial.print("."); // turn on the colon
  Serial.println(fj); // Middle right digit
 
 
  inputLCDText = String(fm) + String(fk) + "." + String(fj) + " seconds";
  displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
 
 
}

int clockDisplay(int m, int k, int j, int i,int direction){
  //int Clock_show = (m*1000+k*100+j*10+i)*direction;
  //matrix.print(Clock_show, DEC);
  //matrix.drawColon(true);
  //matrix.writeDisplay();
  Serial.print(m*direction); // Left digit
  Serial.print(k*direction); // Middle left digit
  Serial.print(":"); // turn on the colon
  Serial.print(j*direction); // Middle right digit
  Serial.println(i*direction); // Right digit
 
  inputLCDText = String(m*direction) + String(k*direction) + ":" + String(j*direction) + String(i*direction);
  displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
}

// --------------------- End Calculate Time Functions -------------------------------------

//New Encoder
void read_encoder() {
  // Encoder interrupt routine for both pins. Updates counter
  // if they are valid and have rotated a full indent
  //Serial.println("Check 2");
  static uint8_t old_AB = 3;  // Lookup table index
  static int8_t encval = 0;   // Encoder value  
  static const int8_t enc_states[]  = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; // Lookup table

  old_AB <<=2;  // Remember previous state

  if (digitalRead(ENC_A)) old_AB |= 0x02; // Add current state of pin A
  if (digitalRead(ENC_B)) old_AB |= 0x01; // Add current state of pin B
 
  encval += enc_states[( old_AB & 0x0f )];

  // Update counter if encoder has rotated a full indent, that is at least 4 steps
  if( encval > 3 ) {        // Four steps forward
    int changevalue = 1;
    if((micros() - _lastIncReadTime) < _pauseLength) {
      changevalue = _fastIncrement * changevalue; 
    }
    _lastIncReadTime = micros();
    RotaryPosition = RotaryPosition + changevalue;              // Update counter
    encval = 0;
  }
  else if( encval < -3 ) {        // Four steps backward
    int changevalue = -1;
    if((micros() - _lastDecReadTime) < _pauseLength) {
      changevalue = _fastIncrement * changevalue; 
    }
    _lastDecReadTime = micros();
    RotaryPosition = RotaryPosition + changevalue;              // Update counter
    encval = 0;
  }

// ---------------------End Rotary Encoder Functions ---------------------------------------

 

// --------------------- Two Button's Admin Interface --------------------------------------

int buttonCombinedFunc (String LCDQuestion, String LCDResponse, int RotaryStart, int turnMultiplier, String typeOut, String listArray[], int sizeArray){
 
  displayLCD (0, 0, LCDQuestion , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
  RotaryPosition= RotaryStart;    // To store Stepper Motor Position
  PrevPosition = RotaryPosition - 1; // Save previous position in variable
 
  if (typeOut == "int")  {
      inputLCDText = String(RotaryPosition);
      displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      Serial.println(RotaryPosition);
    }
  // Cycles through a list
  else if (typeOut == "list") {
    inputLCDText = listArray[RotaryPosition];
    displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    Serial.println(listArray[RotaryPosition]);
    
  }
 
  else if (typeOut == "time") {
    funcTimeCalc (RotaryPosition);
    
  }
 
  while (2>1){ 
    buttonTurnFunc(RotaryStart, turnMultiplier, typeOut, listArray, sizeArray);
    if ((digitalRead(buttonBluepin) == LOW) || (timeExit == 1)){
      timeExit = 0;
      delay(250);
      Serial.print(" Check 2 Final timeTotal ");
      Serial.println(RotaryValue);
      break;
    }
  }
 
}

int buttonTurnFunc(int RotaryStart, int turnMultiplier,String typeOut, String listArray[], int sizeArray){ // typeOut is int, list, or time
 
  // Runs if rotation was detected
  if (digitalRead(buttonRedpin) == LOW){
    RotaryPosition = RotaryPosition + turnMultiplier;
    delay(150);
  }
 
  if (PrevPosition != RotaryPosition)  {
    PrevPosition = RotaryPosition; // Save previous position in variable
    /*
    if (rotationdirection) {
      RotaryPosition=RotaryPosition+turnMultiplier;} // decrease Position by turnMultiplier
    else {
      RotaryPosition=RotaryPosition-turnMultiplier;} // increase Position by turnMultiplier
    */
    
    //Changes the integer value on the LCD screen
    if (typeOut == "int")  {
      
      if((RotaryPosition < 0)) {
        RotaryPosition = 0;
      }
      
      inputLCDText = String(RotaryPosition);
      displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      Serial.println(RotaryPosition);
    } 
    // Cycles through a list
    else if (typeOut == "list") {
      
      if((RotaryPosition> (sizeArray - 1))) {
        RotaryPosition = 0;
      } else if((RotaryPosition < 0)) {
        RotaryPosition = sizeArray - 1;
      }
      
      inputLCDText = listArray[RotaryPosition];
      displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      Serial.println(listArray[RotaryPosition]);
      PrevPosition = RotaryPosition;
      
      
    }
    
    else if (typeOut == "time") {
      
      if((RotaryPosition < 0)) {
        RotaryPosition = 0;
      }
      
      RotaryPosition = buttonfuncTimeCalc (RotaryPosition);
      RotaryValue = RotaryPosition;
      Serial.print(" Check Final timeTotal ");
      Serial.println(RotaryValue);
      
      
    }
    
    else if (typeOut == "time_ms") {
      
      if((RotaryPosition < 0)) {
        RotaryPosition = 0;
      }
      else if((RotaryPosition > 599)) {
        RotaryPosition = 0;
      }
      
      RotaryPosition = buttonfuncTimeCalcMilli (RotaryPosition);
      RotaryValue = RotaryPosition;
      
    }
    
    //TurnDetected = false;  // do NOT repeat IF loop until new rotation detected
    
    return RotaryPosition;
    RotaryValue = RotaryPosition;
  }
  RotaryValue = RotaryPosition;
}

int buttonfuncTimeCalc (int timeTotal) {
 
  byte digit = 0;
  int digitValue = 0;
  int digitValueAdd = 0;
  byte skip = 0;
 
  int fmR = timeTotal % 600;
  int fm = (timeTotal - fmR)/ 600;
 
  int fkR = fmR % 60;
  int fk = (fmR - fkR)/ 60;
 
  int fjR = fkR % 10;
  int fj = (fkR - fjR)/ 10;
 
  int fi = fjR;
    
  clockDisplay(fm, fk, fj, fi,1); 
 
  while (digit < 4) {
    byte skip = 0;
    while (digit < 4) {
      if (digitalRead(buttonBluepin) == LOW){
        delay(250);
        digit = digit + 1;
        digitValueAdd = 0;
        digitValue = 0;
        skip = 1;
        break;
      }
      if (digitalRead(buttonRedpin) == LOW){
        delay(250);
        digitValue = digitValue + 1;
        Serial.print("digitValue ");
        Serial.println(digitValue);
        break;
      }
      
    }
    
    if(skip == 0){
      if (digitValue > 9){
        if(digit == 0){
          digitValueAdd = -9*600;
          digitValue = 0;
        }
        else if(digit == 1){
          digitValueAdd = -9*60;
          digitValue = 0;
        }
        else if(digit == 3){
          digitValueAdd = -9;
          digitValue = 0;
        }
      }
      else {
        if(digit == 0){
          digitValueAdd = 600;
        }
        else if(digit == 1){
          digitValueAdd = 60;
        }
        else if(digit == 2){
          if (digitValue > 5){
              digitValueAdd = -50;
              digitValue = 0;
          }
          else {
            digitValueAdd = 10;
          }
        }
        else if(digit == 3){
          digitValueAdd = 1;
        }
      }
      
    
    
      timeTotal = timeTotal + digitValueAdd;
      
      Serial.print("timeTotal ");
      Serial.println(timeTotal);
      
      fmR = timeTotal % 600;
      fm = (timeTotal - fmR)/ 600;
      
      fkR = fmR % 60;
      fk = (fmR - fkR)/ 60;
      
      fjR = fkR % 10;
      fj = (fkR - fjR)/ 10;
      
      fi = fjR;
        
      clockDisplay(fm, fk, fj, fi,1);
    }
   }
  timeExit = 1;
 
    Serial.print(" Final timeTotal ");
    Serial.println(timeTotal);
 
  return timeTotal;
  RotaryValue = timeTotal;

  
}

int buttonfuncTimeCalcMilli (int timeTotal) {
  byte digit = 0;
  int digitValue = 0;
  int digitValueAdd = 0;
 
  int fmR = timeTotal % 100;
  int fm = (timeTotal - fmR)/ 100;
 
  int fkR = fmR % 10;
  int fk = (fmR - fkR)/ 10;
 
  int fj = fkR;
 
  Serial.print(fm); // Left digit
  Serial.print(fk); // Middle left digit
  Serial.print("."); // turn on the colon
  Serial.println(fj); // Middle right digit
 
 
  inputLCDText = String(fm) + String(fk) + "." + String(fj) + " seconds";
  displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
 
  while (digit < 4) {
    
    while (digit < 4) {
      if (digitalRead(buttonBluepin) == LOW){
        delay(250);
        digit = 5;
        break;
      }
      if (digitalRead(buttonRedpin) == LOW){
        delay(250);
        timeTotal = timeTotal + 1;
        break;
      }
      
    }
      Serial.print("timeTotal ");
      Serial.println(timeTotal);
      
      fmR = timeTotal % 100;
      fm = (timeTotal - fmR)/ 100;
      
      fkR = fmR % 10;
      fk = (fmR - fkR)/ 10;
      
      fj = fkR;
        
      inputLCDText = String(fm) + String(fk) + "." + String(fj) + " seconds";
      displayLCD (0, 1, inputLCDText , "Second"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
    
  }
  timeExit = 1;
 
    Serial.print(" Final timeTotal ");
    Serial.println(timeTotal);
  RotaryValue = timeTotal;
  return timeTotal;
 
 
}

// Calculate time

byte FuncCalcDigits (int timeTotal, byte digitPlace) {
  byte digitPlaceArray[] = {9,9,9,9};
  int fmR = timeTotal % 600;
  digitPlaceArray[0] = (timeTotal - fmR)/ 600;
 
  int fkR = fmR % 60;
  digitPlaceArray[1] = (fmR - fkR)/ 60;
 
  int fjR = fkR % 10;
  digitPlaceArray[2] = (fkR - fjR)/ 10;
 
  digitPlaceArray[3] = fjR;
 
  return digitPlaceArray[digitPlace];
 
}

void USBCheck (){
 
  int BlueHitStart = 1;
 
  displayLCD (0, 0, "USB plugged in?", "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
  displayLCD (0, 1, "Power switch on?" , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
 
  while(BlueHitStart < 2){
    
 
    if (digitalRead(buttonRedpin) == LOW) 
    {
        displayLCD (0, 0, "Plug in the USB" , "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
        displayLCD (0, 1, "Turn power on" , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
        delay(delayLCD); // add a delay to allow time for the button to be released
        displayLCD (0, 0, "USB plugged in?", "Both"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
        displayLCD (0, 1, "Power switch on?" , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
        delay(250); // add a delay to allow time for the button to be released
      
    }
    
    if (digitalRead(buttonBluepin) == LOW) //when red LED is off and red button is pushed
    {
        BlueHitStart = BlueHitStart + 1;  //incrementally increase the variable to track which digit to edit
        colorLEDChange( 0, 255,   0);
        delay(250); // add a delay to allow time for the button to be released       
    }
  }
}

void parameterCheck(){
Serial.print("gameID ");
Serial.println(gameID);


Serial.print("Button Interaction ");
Serial.println(buttonInteraction);


Serial.print("Objective ");
Serial.println(objective);

Serial.print("checkReset ");
Serial.println(checkReset);

Serial.print("Team Run Down Clock ");
Serial.println(teamRunDownClock);

Serial.print("timeDirection ");
Serial.println(timeDirection);

Serial.print("Are team times different? ");
Serial.println(checkTeamTime);

Serial.print("Objective Time Blue ");
Serial.println(objectiveTimeBlue);

Serial.print("Objective Time Red ");
Serial.println(objectiveTimeRed);

Serial.print("Hold Button X amount of time ");
Serial.println(holdXTime);

Serial.print("variableX ");
Serial.println(variableX);

Serial.print("xLengthMillis ");
Serial.println(xLengthMillis);

Serial.print("Limit Gamelength? ");
Serial.println(limitGameLength);

Serial.print("Game Length Time ");
Serial.println(gameLengthTime);

Serial.print("gameLengthMillis ");
Serial.println(gameLengthMillis);


Serial.print("Enable Overtime ");
Serial.println(enableOvertime);

Serial.print("gameSelectedMain ");
Serial.println(gameSelectedMain);

Serial.print("buttonMode ");
Serial.println(buttonMode);

Serial.print("Start Delay Time ");
Serial.println(startDelayTimeMillis);

Serial.print("Use Start Audio ");
Serial.println(startAudio);

Serial.print("Use End Countdown ");
Serial.println(endAudio);

Serial.print("Blue Time ");
Serial.print(timeOutput.mBlue);
Serial.print(timeOutput.kBlue);
Serial.print(":");
Serial.print(timeOutput.jBlue);
Serial.println(timeOutput.iBlue);

Serial.print("Red Time ");
Serial.print(timeOutput.mRed);
Serial.print(timeOutput.kRed);
Serial.print(":");
Serial.print(timeOutput.jRed);
Serial.println(timeOutput.iRed);

Serial.print("Limit  Time ");
Serial.print(timeOutput.mLimit );
Serial.print(timeOutput.kLimit );
Serial.print(":");
Serial.print(timeOutput.jLimit );
Serial.println(timeOutput.iLimit );

Serial.print("gameTimeOver ");
Serial.println(gameTimeOver);

Serial.print("teamInControl ");
Serial.println(teamInControl);

//Serial.print("playGameStart ");
//Serial.println(playGameStart);

//Serial.print("playGameEnd ");
//Serial.println(playGameEnd);

Serial.print("attritionLifeIndex ");
Serial.println(attritionLifeIndex);

Serial.print("attritionLifeSound ");
Serial.println(attritionLifeSound);

Serial.print("overTime ");
Serial.println(overTime);

Serial.print("overTimeStart ");
Serial.println(overTimeStart);

Serial.print("alarmCheck ");
Serial.println(alarmCheck);

Serial.print("checkX ");
Serial.println(checkX);

Serial.print("timeCheck_1 ");
Serial.println(timeCheck_1);

Serial.print("timeCheck_2 ");
Serial.println(timeCheck_2);

Serial.print("timeReset_1 ");
Serial.println(timeReset_1);

Serial.print("timeReset_2 ");
Serial.println(timeReset_2);

Serial.print("directionInput ");
Serial.println(directionInput);
 
 
}

void gameLengthDisplay (){

  if (limitGameLength == 0)
    {
      currentSecondMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started). This is used to check when to increment the 7 segment display.                    
      gameCheckMillis = gameLengthMillis - (currentSecondMillis - gameStartMillis);
      gameLengthTimeDisplay = gameCheckMillis/1000L;
    
      if (gameLengthTimeDisplay > 0)
      {
        inputLCDText = String(FuncCalcDigits (gameLengthTimeDisplay, 0)) + String(FuncCalcDigits (gameLengthTimeDisplay, 1)) + ":" + String(FuncCalcDigits (gameLengthTimeDisplay, 2)) + String(FuncCalcDigits (gameLengthTimeDisplay, 3));
        displayLCD (11, 1, inputLCDText , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      }
      else{
        displayLCD (11, 1, "00:00" , "None"); // displayLCD (int digit, int line, String lcdText, String "None"/"First"/"Second"/"Both")
      }
      
    }
   
}

Testing timer

Step 10: Testing/ Operating the Timer/
Admin Interface

I use the multimeter continuity function to verify there are no unintended connections.

​

Once your satisfied with your checks, plug in your USB power bank and test it out. The LCD screen will ask you a series of questions. Check out the videos on how to navigate the menu. Sorry for the blurry LCD screen.

​

Setup Videos:

Intro

KoTH

Rogue One

Attrition

Death Clicks

Domination

Hold the Hill

Time Reset

Time Keeper

Custom

Use Buttons instead of Rotary Encoder

Trouble Shooting

Trouble Shooting

If you are having issues make sure you check that the wiring is correct and then carefully read through the section of the component that is not working.

​

You can also join the Facebook group to ask questions.

bottom of page