#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// have to hold buttons down to claim points or time
// Initialize the LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Define button pins
const int buttonPins[3] = {8, 9, 10}; // Red, Blue, Yellow buttons
// Define LED pins
const int ledPins[3] = {11, 12, 13}; // Red, Blue, Yellow LEDs
// Define buzzer pin
const int buzzerPin = A1;
// Define relay pins
const int relayPins[3] = {2, 3, 4}; // Relay pins for Red, Blue, Yellow teams
// Point settings
int points[3] = {0, 0, 0}; // Starting points for Red, Blue, Yellow
unsigned long buttonPressStartTime[3] = {0}; // Record the start time of button presses
unsigned long lastPointsAdditionTime[3] = {0}; // Record the last time points were added
unsigned long timers[3] = {90, 90, 90}; // Starting time in seconds for Red, Blue, Yellow
bool menuNeedsRefresh = true; // Declare and initialize the menuNeedsRefresh variable
enum MenuState {
MENU,
RED_MODE,
BLUE_MODE,
YELLOW_MODE // New game mode
};
MenuState menuState = MENU;
// Variables to track zone ownership
bool zoneCaptured[3] = {false}; // Red, Blue, Yellow
// Forward declaration of calculateIncrement function
int calculateIncrement(unsigned long duration);
// Function prototypes
void displayMenu();
void displayTimers();
void displayPoints();
void handleMenu();
void runRedMode();
void runBlueMode();
void runYellowMode();
void displayZoneControl();
void setup() {
lcd.init(); // Initialize the LCD
lcd.backlight(); // Turn on the backlight
for (int i = 0; i < 3; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
pinMode(ledPins[i], OUTPUT);
}
pinMode(buzzerPin, OUTPUT);
for (int i = 0; i < 3; i++) {
pinMode(relayPins[i], OUTPUT);
digitalWrite(relayPins[i], LOW); // Initialize relays to be off
}
displayMenu(); // Display initial menu
}
void loop() {
switch (menuState) {
case MENU:
handleMenu();
break;
case RED_MODE:
runRedMode();
break;
case BLUE_MODE:
runBlueMode();
break;
case YELLOW_MODE: // Added case for Yellow mode
runYellowMode();
break;
default:
break;
}
}
void handleMenu() {
if (menuNeedsRefresh) {
lcd.clear();
lcd.print("Red = Points Game");
lcd.setCursor(0, 1);
lcd.print("Blue = Timer Game");
lcd.setCursor(0, 2);
lcd.print("Yellow = Zone Game"); // Added line for yellow game mode
menuNeedsRefresh = false;
}
if (digitalRead(buttonPins[0]) == LOW) { // Red button is pressed
menuState = RED_MODE;
displayPoints();
menuNeedsRefresh = true; // Set menuNeedsRefresh to true after menu display
} else if (digitalRead(buttonPins[1]) == LOW) { // Blue button is pressed
menuState = BLUE_MODE;
displayTimers(); // Display the timer
menuNeedsRefresh = true; // Set menuNeedsRefresh to true after menu display
} else if (digitalRead(buttonPins[2]) == LOW) { // Yellow button is pressed
menuState = YELLOW_MODE;
displayZoneControl(); // Display zone control status
menuNeedsRefresh = true; // Set menuNeedsRefresh to true after menu display
}
}
void runRedMode() {
// Code for Red button mode
for (int i = 0; i < 3; i++) {
if (digitalRead(buttonPins[i]) == LOW) { // Button is pressed
if (buttonPressStartTime[i] == 0) { // If button was not previously pressed
buttonPressStartTime[i] = millis(); // Record the start time of button press
} else {
unsigned long duration = millis() - buttonPressStartTime[i]; // Calculate the duration of button press
if (duration >= 1000) { // If button is held down for at least 10 seconds
if (millis() - lastPointsAdditionTime[i] >= 1000) { // Add points only if 10 seconds have passed since the last addition
int increment = calculateIncrement(duration); // Calculate points to add
points[i] += increment;
lastPointsAdditionTime[i] = millis(); // Record the time points were added
// Beep the buzzer
tone(buzzerPin, 1000, 100);
// Blink the LED
digitalWrite(ledPins[i], HIGH);
delay(100);
digitalWrite(ledPins[i], LOW);
displayPoints(); // Update display
delay(100); // Debounce delay
}
}
}
} else {
buttonPressStartTime[i] = 0; // Reset button press start time if button is released
}
}
}
void runBlueMode() {
// Code for Blue button mode
unsigned long lastMillis = millis();
bool gameActive = true;
bool gameOverDisplayed = false; // Flag to track if game over message has been displayed
lcd.clear(); // Clear the LCD before displaying the timer
while (gameActive) {
unsigned long currentMillis = millis();
if (currentMillis - lastMillis >= 1000) { // Update every second
lastMillis = currentMillis;
for (int i = 0; i < 3; i++) {
if (digitalRead(buttonPins[i]) == LOW && timers[i] > 0) { // Button is pressed
timers[i]--;
// Beep for every 3rd second
if (timers[i] % 3 == 0) {
tone(buzzerPin, 1000, 100); // Beep
}
// Check for game over
if (timers[i] == 0) {
gameActive = false; // Stop game
tone(buzzerPin, 500, 500); // Game over tone
digitalWrite(ledPins[i], HIGH); // Illuminate winning team's LED
digitalWrite(relayPins[i], HIGH); // Activate winning team's relay
lcd.clear();
lcd.setCursor(3, 0);
lcd.print(i == 0 ? "Red" : i == 1 ? "Blue" : "Yellow");
lcd.print(" Team Zone");
lcd.setCursor(4, 2);
lcd.print("You can now");
lcd.setCursor(4, 3);
lcd.print("respawn Here");
gameOverDisplayed = true;
break; // Exit the for loop
}
}
}
if (gameActive) displayTimers(); // Update display if game is still active
}
}
// Keep displaying the result until device is reset
while (gameOverDisplayed) {
// Do nothing
}
}
void runYellowMode() {
const unsigned long captureDuration = 10000; // 30 seconds for zone capture
const unsigned long buzzerInterval = 1000; // Buzzer activation interval (1 second)
unsigned long lastBuzzerTime = 0; // Track the last time the buzzer was activated
bool buttonPressed[3] = {false}; // Track button presses for each team
unsigned long buttonPressStartTime[3] = {0}; // Track start time for each team
while (true) {
bool anyButtonPressed = false; // Flag to track if any button is pressed
for (int i = 0; i < 3; i++) {
if (digitalRead(buttonPins[i]) == LOW) { // Button is pressed
anyButtonPressed = true; // Set flag to true if any button is pressed
if (!buttonPressed[i]) { // Start timing when button is pressed for the first time
buttonPressed[i] = true;
buttonPressStartTime[i] = millis();
lcd.clear();
lcd.print(" Capturing Zone");
} else {
unsigned long elapsedTime = millis() - buttonPressStartTime[i];
if (elapsedTime < captureDuration) { // Update progress bar if still within capture duration
int progress = map(elapsedTime, 0, captureDuration, 0, 18); // Map time to progress bar length (18 characters)
lcd.setCursor(0, 1 + i);
lcd.print("[");
for (int j = 0; j < progress; ++j) {
lcd.print("=");
}
for (int j = progress; j < 18; ++j) { // Adjusted to fit 18 characters
lcd.print(" ");
}
lcd.print("]");
// Activate buzzer every second during capture
unsigned long currentTime = millis();
if (currentTime - lastBuzzerTime >= buzzerInterval) {
tone(buzzerPin, 1000); // Activate buzzer at 1000 Hz
lastBuzzerTime = currentTime;
}
} else { // Zone captured if capture duration reached
// Reset all zone ownerships
for (int j = 0; j < 3; j++) {
zoneCaptured[j] = false;
}
zoneCaptured[i] = true; // Set the capturing team's zone ownership
lcd.clear();
lcd.print(i == 0 ? "Red Team" : i == 1 ? "Blue Team" : "Yellow Team");
lcd.setCursor(0, 1);
lcd.print("Zone Captured!");
delay(2000); // Display the message for 2 seconds
// Reset button press start time and clear progress bar
buttonPressed[i] = false;
buttonPressStartTime[i] = 0;
lcd.setCursor(0, 1 + i);
lcd.print(" "); // Clear progress bar
}
}
} else { // Button is released
if (buttonPressed[i]) { // Check if the button was previously pressed
// Revert zone status
zoneCaptured[i] = false;
lcd.clear();
lcd.print(i == 0 ? "Red Team" : i == 1 ? "Blue Team" : "Yellow Team");
lcd.setCursor(0, 1);
lcd.print("Zone Status Reverted");
delay(1000); // Display the message for 2 seconds
// Reset button press start time and clear progress bar
buttonPressed[i] = false;
buttonPressStartTime[i] = 0;
lcd.setCursor(0, 1 + i);
lcd.print(" "); // Clear progress bar
}
}
}
// If no button is pressed, show zone status as "Neutral Zone"
if (!anyButtonPressed) {
bool zoneOwned = false;
for (int i = 0; i < 3; i++) {
if (zoneCaptured[i]) {
lcd.clear();
lcd.print(i == 0 ? "Red Team" : i == 1 ? "Blue Team" : "Yellow Team");
lcd.setCursor(0, 1);
lcd.print("Owns the Zone");
zoneOwned = true;
// Blink LED and beep buzzer for the team that owns the zone
digitalWrite(ledPins[i], HIGH);
tone(buzzerPin, 1000); // Beep buzzer at 1000 Hz
delay(500); // Keep LED and buzzer on for 0.5 seconds
digitalWrite(ledPins[i], LOW);
noTone(buzzerPin); // Stop buzzer
delay(500); // Keep LED and buzzer off for 0.5 seconds
break;
}
}
// If no team owns the zone, turn off all LEDs
if (!zoneOwned) {
for (int i = 0; i < 3; i++) {
digitalWrite(ledPins[i], LOW);
}
lcd.clear();
lcd.print("Neutral Zone");
}
delay(1000); // Display the message for 2 seconds
}
}
}
void displayPoints() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Red: ");
lcd.print(points[0]);
lcd.setCursor(0, 1);
lcd.print("Blue: ");
lcd.print(points[1]);
lcd.setCursor(0, 2);
lcd.print("Yellow: ");
lcd.print(points[2]);
lcd.setCursor(1, 3);
lcd.print("HOLD COLOUR BUTTON");
}
void displayMenu() {
lcd.clear();
lcd.print("Press Red for Points");
lcd.setCursor(0, 1);
lcd.print("Press Blue for Timer");
lcd.setCursor(0, 2);
lcd.print("Press Yellow for Zone");
}
void displayTimers() {
for (int i = 0; i < 3; i++) {
lcd.setCursor(0, i);
lcd.print(i == 0 ? "Red: " : i == 1 ? "Blue: " : "Yellow: ");
int minutes = timers[i] / 60;
int seconds = timers[i] % 60;
if (minutes < 10) lcd.print("0");
lcd.print(minutes);
lcd.print(":");
if (seconds < 10) lcd.print("0");
lcd.print(seconds);
lcd.setCursor(1, 3);
lcd.print("HOLD COLOUR BUTTON");
}
}
void displayZoneControl() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Zone Control");
lcd.setCursor(0, 1);
lcd.print("Red: ");
lcd.print(zoneCaptured[0] ? "Captured" : "Not Captured");
lcd.setCursor(0, 2);
lcd.print("Blue: ");
lcd.print(zoneCaptured[1] ? "Captured" : "Not Captured");
lcd.setCursor(0, 3);
lcd.print("Yellow: ");
lcd.print(zoneCaptured[2] ? "Captured" : "Not Captured");
}
int calculateIncrement(unsigned long duration) {
if (duration >= 61000) {
return 10; // 15 points for every 10 seconds if held for more than 1 minute
} else if (duration >= 31000) {
return 5; // 10 points for every 10 seconds if held for 30 seconds or more
} else {
return 1; // 5 points for every 10 seconds
}
}