//----------------------------------------------------------------//
//------------------Included Files/Libraries----------------------//
//----------------------------------------------------------------//
#include <LiquidCrystal_I2C.h>
//----------------------------------------------------------------//
//--------------------Constant Definitions------------------------//
//----------------------------------------------------------------//
#if defined(ARDUINO) && ARDUINO >= 100
#define write(args) write(args);
#else
#define write(args) print(args, BYTE);
#endif
#define _DEBUG_MODE true
#define _WELCOME_SCREEN_DELAY_MS 200
#define _LEDS_FLASH_TIME_MS 500
#define _BUZZER_DURATION_MS 35
#define _BUZZER_FREQUENCY_HZ 1000
#if _DEBUG_MODE
#define debug(x) Serial.print(x)
#define debugln(x) Serial.println(x)
#else
#define debug(x)
#define debugln(x)
#endif
const uint32_t PROGMEM _GAME_TIME_MAX_TIME = (int32_t)(99) * (int32_t)(60 * 60) + (int32_t)(59 * 60) + (int32_t)(59); // HOURS * 60 * 60 + MINUTES * 60 + SECONDS [Total Unit = SECONDS]
const uint32_t PROGMEM _GAME_TIME_MIN_TIME = (int32_t)(00) * (int32_t)(60 * 60) + (int32_t)(01 * 60) + (int32_t)(00); // HOURS * 60 * 60 + MINUTES * 60 + SECONDS [Total Unit = SECONDS]
//----------------------------------------------------------------//
//--------------------Pins Definitions----------------------------//
//----------------------------------------------------------------//
#define BUZZER 3
#define RED_LED 4
#define GREEN_LED 5
#define BLUE_LED 6
#define RED_BUTTON 7
#define GREEN_BUTTON 8
#define UP_BUTTON 9
#define DOWN_BUTTON 10
#define RIGHT_BUTTON 11
#define LEFT_BUTTON 12
uint8_t WIRES_PINS[4] = {A3, A2, A1, A0};
//----------------------------------------------------------------//
//------------------Variables Declarations------------------------//
//----------------------------------------------------------------//
LiquidCrystal_I2C LCD(0x27, 20, 4); // set the LCD address to 0x27 for a 20 chars and 4 line display
uint8_t zero_bar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t one_bar[8] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 };
uint8_t two_bar[8] = { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 };
uint8_t three_bar[8] = { 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C };
uint8_t four_bar[8] = { 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E };
uint8_t full_bar[8] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
volatile bool red_button_last_state = false;
volatile bool red_button_pressed = false;
volatile uint32_t red_button_start_press_time = 0;
volatile uint32_t red_button_current_press_time = 0;
volatile bool green_button_last_state = false;
volatile bool green_button_pressed = false;
volatile uint32_t green_button_start_press_time = 0;
volatile uint32_t green_button_current_press_time = 0;
bool up_button_last_state = false;
bool up_button_pressed = false;
bool down_button_last_state = false;
bool down_button_pressed = false;
bool right_button_last_state = false;
bool right_button_pressed = false;
bool left_button_last_state = false;
bool left_button_pressed = false;
bool domination_wires_last_state = false;
bool change_in_screen = true;
uint32_t game_time_total = (uint32_t)(00) * (uint32_t)(60 * 60) + (uint32_t)(0 * 60) + (uint32_t)(10); // HOURS * 60 * 60 + MINUTES * 60 + SECONDS [Total Unit = SECONDS]
uint32_t activation_time_total = (uint32_t)(00) * (uint32_t)(60 * 60) + (uint32_t)(0 * 60) + (uint32_t)(05); // HOURS * 60 * 60 + MINUTES * 60 + SECONDS [Total Unit = SECONDS]
uint32_t defusing_time_total = (uint32_t)(00) * (uint32_t)(60 * 60) + (uint32_t)(0 * 60) + (uint32_t)(05); // HOURS * 60 * 60 + MINUTES * 60 + SECONDS [Total Unit = SECONDS]
uint32_t bomb_set_time_total = (uint32_t)(00) * (uint32_t)(60 * 60) + (uint32_t)(0 * 60) + (uint32_t)(05); // HOURS * 60 * 60 + MINUTES * 60 + SECONDS [Total Unit = SECONDS]
uint32_t start_timer_total = (uint32_t)(00) * (uint32_t)(60 * 60) + (uint32_t)(0 * 60) + (uint32_t)(02); // HOURS * 60 * 60 + MINUTES * 60 + SECONDS [Total Unit = SECONDS]
uint32_t capture_time_total = (uint32_t)(00) * (uint32_t)(60 * 60) + (uint32_t)(0 * 60) + (uint32_t)(05); // HOURS * 60 * 60 + MINUTES * 60 + SECONDS [Total Unit = SECONDS]
uint32_t acquire_time_total = (uint32_t)(00) * (uint32_t)(60 * 60) + (uint32_t)(0 * 60) + (uint32_t)(05); // HOURS * 60 * 60 + MINUTES * 60 + SECONDS [Total Unit = SECONDS]
uint32_t red_team_time_total = 0;
uint32_t green_team_time_total = 0;
uint8_t bomb_wires_wire_to_cut = 3;
/* Menu Mapping
Level 1: Game Type
Page 1: Bomb Buttons
Configuration 1-1: Game Time
Configuration 1-2: Activation Time
Configuration 1-3: Defusing Time
Configuration 1-4: Bomb Time
Configuration 1-5: Start Timer
Page 2: Bomb Wires
Configuration 2-1: Game Time
Configuration 2-2: Activation Time
Configuration 2-3: Wire to Cut
Configuration 2-4: Bomb Set Time
Configuration 2-5: Start Timer
Page 3: Domination
Configuration 3-1: Game Time
Configuration 3-2: Capture Time
Configuration 3-3: Accquire Time
Configuration 3-4: Start Timer
Page 4: Fast Bomb
Configuration 4-1: Activation Time
Configuration 4-2: Defusing Time
Configuration 4-3: Bomb Set Time
Level 2: Settings
Page 1: Backlight
Configuration 1-1: ON OFF
Page 2: Brightness
Configuration 2-1: 0% 25% 50% 75% 100%
Page 3: LCD Effects
Page 4: Sound Effects
Page 5: External Output
Configuration 5-1: Start Warning
Configuration 5-2: Game Warning
Configuration 5-3: Gameover Warning
Page 6: Vibration
*/
enum Program_States {
IN_SELECT_GAME_TYPE_PAGE,
IN_GAME_CONF,
IN_GAME,
IN_SETTINGS_PAGE,
IN_SETTINGS_CONF
};
enum Game_Type {
BOMB_BUTTONS,
BOMB_WIRES,
DOMINATION,
FAST_BOMB,
};
enum All_Game_States {
HAS_NOT_STARTED_YET,
STARTED,
SETTING_BOMB,
DETONATION_IN,
DEFUSING_BOMB,
GAME_OVER_TIME,
GAME_OVER_EXPLODED,
GAME_OVER_DEFUSED,
GAME_OVER_DRAW,
GAME_OVER_RED,
GAME_OVER_GREEN,
RED_ACQUIRING,
RED_CAPTURING,
GREEN_ACQUIRING,
GREEN_CAPTURING,
};
enum Game_Pages // Levels
{
GAME_TYPE_PAGE_START,
BOMB_BUTTONS_PAGE,
BOMB_WIRES_PAGE,
DOMINATION_PAGE,
FAST_BOMB_PAGE,
GAME_TYPE_PAGE_END
};
enum Settings_Pages // Levels
{
SETTINGS_PAGE_START,
BACKLIGHT,
BRIGHTNESS,
LCD_EFFECTS,
SOUND_EFFECTS,
EXTERNAL_OUTPUT,
VIBRATION,
SETTINGS_PAGE_END,
};
enum Game_Type_Configurations // Configurations
{
GAME_TYPE_CONF_START,
BOMB_BUTTONS_CONF_START,
BOMB_BUTTONS_GAME_TIME,
BOMB_BUTTONS_ACTIVATION_TIME,
BOMB_BUTTONS_DEFUSING_TIME,
BOMB_BUTTONS_BOMB_SET_TIME,
BOMB_BUTTONS_START_TIMER,
BOMB_BUTTONS_CONF_END,
BOMB_WIRES_CONF_START,
BOMB_WIRES_GAME_TIME,
BOMB_WIRES_ACTIVATION_TIME,
BOMB_WIRES_WIRE_TO_CUT,
BOMB_WIRES_BOMB_SET_TIME,
BOMB_WIRES_START_TIMER,
BOMB_WIRES_CONF_END,
DOMINATION_CONF_START,
DOMINATION_GAME_TIME,
DOMINATION_CAPTURE_TIME,
DOMINATION_ACQUIRE_TIME,
DOMINATION_START_TIMER,
DOMINATION_CONF_END,
FAST_BOMB_CONF_START,
FAST_BOMB_ACTIVATION_TIME,
FAST_BOMB_DEFUSING_TIME,
FAST_BOMB_BOMB_SET_TIME,
FAST_BOMB_CONF_END,
GAME_TYPE_CONF_END
};
enum Settings_Configurations // Configurations
{
SETTINGS_CONF_START,
BACKLIGHT_CONF_START,
BACKLIGHT_CONF_END,
BRIGHTNESS_CONF_START,
BRIGHTNESS_CONF_END,
SETTINGS_CONF_END
};
enum Cursor_Position {
CURSOR_POSITION_START,
HOURS, // 8
MINUTES, // 11
SECONDS, // 14
CURSOR_POSITION_END,
WIRE, // 10
};
enum Cut_Wire {
NO_WIRE_CUT,
WRONG_WIRE_CUT,
RIGHT_WIRE_CUT,
};
uint8_t current_menu_page = GAME_TYPE_PAGE_START + 1;
uint8_t last_menu_page;
uint8_t current_program_state = IN_SELECT_GAME_TYPE_PAGE;
uint8_t current_game_type_conf;
uint8_t cursor_position = CURSOR_POSITION_START + 1;
bool red_acquired = false;
bool red_captured = false;
bool green_acquired = false;
bool green_captured = false;
bool can_start_bomb_wires = false;
int8_t flag_with_who = 0; // -1 ==> with red, 0 ==> no one, +1 ==> with green
uint8_t chosen_game_type;
uint8_t chosen_game_state;
uint32_t chosen_game_start_time;
uint32_t chosen_game_elapsed_time;
uint32_t countdown_time;
uint8_t current_progress_bar = 0;
uint8_t previous_progress_bar = 0;
uint32_t last_millis;
uint32_t one_minute_millis;
//----------------------------------------------------------------//
//------------------Functions Definitions-------------------------//
//----------------------------------------------------------------//
void initializationSequence(void);
void welcomeScreen(void);
bool isButtonPressed(uint8_t button_pin, bool *last_state);
bool isColorButtonPressed_andGetPressTime(uint8_t button_pin, volatile bool *last_state, volatile uint32_t *start_press_time, volatile uint32_t *current_press_time);
void handleTimings(void);
void handleMenu(void);
void printTiming(uint32_t *total_time);
void printScores(void);
void printProgressBar(uint8_t *current_progress, uint8_t *previous_progress, uint8_t col);
void Increase(int32_t *time_total, int32_t time_max, uint8_t *timestamp);
void Decrease(int32_t *time_total, int32_t time_min, uint8_t *timestamp);
void adjustOtherTimings(void);
//----------------------------------------------------------------//
//-----------------------Main Routine-----------------------------//
//----------------------------------------------------------------//
void setup() {
Serial.begin(9600); // Initialize Serial Monitor
delay(500); // Wait for Serial Monitor to Start
debugln(F("Program Started!"));
debugln(F("Debug Mode On!"));
initializationSequence();
adjustOtherTimings();
welcomeScreen();
}
void loop() {
// Section 1: Inputs
// Handle Inputs (Push Buttons)
red_button_pressed = isColorButtonPressed_andGetPressTime(RED_BUTTON, &red_button_last_state, &red_button_start_press_time, &red_button_current_press_time);
green_button_pressed = isColorButtonPressed_andGetPressTime(GREEN_BUTTON, &green_button_last_state, &green_button_start_press_time, &green_button_current_press_time);
up_button_pressed = isButtonPressed(UP_BUTTON, &up_button_last_state);
down_button_pressed = isButtonPressed(DOWN_BUTTON, &down_button_last_state);
right_button_pressed = isButtonPressed(RIGHT_BUTTON, &right_button_last_state);
left_button_pressed = isButtonPressed(LEFT_BUTTON, &left_button_last_state);
can_start_bomb_wires = canStartDomination();
// Section 2: Processing
// processRedButton();
if (red_button_pressed) {
change_in_screen = true;
tone(BUZZER, _BUZZER_FREQUENCY_HZ, _BUZZER_DURATION_MS);
switch (current_program_state) {
case IN_SELECT_GAME_TYPE_PAGE: // Then we will do nothing.
break;
case IN_GAME_CONF: // Then either go to previous conf, or return to the main screen.
if (current_game_type_conf - 1 == BOMB_BUTTONS_CONF_START || current_game_type_conf - 1 == BOMB_WIRES_CONF_START || current_game_type_conf - 1 == DOMINATION_CONF_START || current_game_type_conf - 1 == FAST_BOMB_CONF_START) {
// Return to the main screen
current_program_state = IN_SELECT_GAME_TYPE_PAGE;
} else {
// Go to previous conf
current_game_type_conf--;
// Set cursor accordingly
if (current_game_type_conf == BOMB_WIRES_WIRE_TO_CUT) {
cursor_position = WIRE;
} else {
cursor_position = CURSOR_POSITION_START + 1;
}
}
break;
case IN_GAME: // Later
switch (chosen_game_type) {
case BOMB_BUTTONS:
switch (chosen_game_state) {
case HAS_NOT_STARTED_YET:
break;
case STARTED:
break;
case SETTING_BOMB:
break;
case DETONATION_IN:
chosen_game_state = DEFUSING_BOMB;
previous_progress_bar = 0;
current_progress_bar = 0;
last_millis = millis();
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
break;
case DEFUSING_BOMB:
break;
case GAME_OVER_TIME:
break;
case GAME_OVER_EXPLODED:
break;
case GAME_OVER_DEFUSED:
break;
}
break;
case BOMB_WIRES:
break;
case DOMINATION:
switch (chosen_game_state)
{
case STARTED:
if (flag_with_who == -1) // Red team has flag
{
// Do nothing
}
else if (flag_with_who == 0) // No one has flag
{
chosen_game_state = RED_CAPTURING;
previous_progress_bar = 0;
current_progress_bar = 0;
last_millis = millis();
one_minute_millis = millis();
digitalWrite(BLUE_LED, LOW);
digitalWrite(RED_LED, HIGH);
}
else // Green has flag
{
chosen_game_state = RED_ACQUIRING;
previous_progress_bar = 0;
current_progress_bar = 0;
last_millis = millis();
one_minute_millis = millis();
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, HIGH);
}
break;
}
break;
case FAST_BOMB:
switch (chosen_game_state) {
case HAS_NOT_STARTED_YET:
break;
case STARTED:
break;
case SETTING_BOMB:
break;
case DETONATION_IN:
chosen_game_state = DEFUSING_BOMB;
previous_progress_bar = 0;
current_progress_bar = 0;
last_millis = millis();
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
break;
case DEFUSING_BOMB:
break;
case GAME_OVER_EXPLODED:
break;
case GAME_OVER_DEFUSED:
break;
}
break;
}
break;
case IN_SETTINGS_PAGE:
break;
case IN_SETTINGS_CONF: // Later
break;
}
}
// processGreenButton();
if (green_button_pressed) {
change_in_screen = true;
tone(BUZZER, _BUZZER_FREQUENCY_HZ, _BUZZER_DURATION_MS);
switch (current_program_state) {
case IN_SELECT_GAME_TYPE_PAGE: // Then we will enter configurations menu.
current_program_state = IN_GAME_CONF;
last_menu_page = current_menu_page;
cursor_position = CURSOR_POSITION_START + 1;
switch (current_menu_page) {
case BOMB_BUTTONS_PAGE:
current_game_type_conf = BOMB_BUTTONS_CONF_START + 1;
break;
case BOMB_WIRES_PAGE:
current_game_type_conf = BOMB_WIRES_CONF_START + 1;
break;
case DOMINATION_PAGE:
current_game_type_conf = DOMINATION_CONF_START + 1;
break;
case FAST_BOMB_PAGE:
current_game_type_conf = FAST_BOMB_CONF_START + 1;
game_time_total = 90;
adjustOtherTimings();
break;
}
break;
case IN_GAME_CONF: // Then either go to next conf, or start the game.
if (current_game_type_conf + 1 == BOMB_BUTTONS_CONF_END) {
current_program_state = IN_GAME;
chosen_game_type = BOMB_BUTTONS;
chosen_game_state = HAS_NOT_STARTED_YET;
countdown_time = start_timer_total;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
} else if (current_game_type_conf + 1 == BOMB_WIRES_CONF_END) {
if (can_start_bomb_wires)
{
current_program_state = IN_GAME;
chosen_game_type = BOMB_WIRES;
chosen_game_state = HAS_NOT_STARTED_YET;
countdown_time = start_timer_total;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
}
} else if (current_game_type_conf + 1 == DOMINATION_CONF_END) {
current_program_state = IN_GAME;
chosen_game_type = DOMINATION;
chosen_game_state = HAS_NOT_STARTED_YET;
countdown_time = start_timer_total;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
} else if (current_game_type_conf + 1 == FAST_BOMB_CONF_END) {
current_program_state = IN_GAME;
chosen_game_type = FAST_BOMB;
chosen_game_state = STARTED;
last_millis = millis();
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
} else {
// Go to next conf
current_game_type_conf++;
// Set cursor accordingly
if (current_game_type_conf == BOMB_WIRES_WIRE_TO_CUT) {
cursor_position = WIRE;
} else {
cursor_position = CURSOR_POSITION_START + 1;
}
}
break;
case IN_GAME:
switch (chosen_game_type) {
case BOMB_BUTTONS:
switch (chosen_game_state) {
case HAS_NOT_STARTED_YET:
break;
case STARTED:
chosen_game_state = SETTING_BOMB;
previous_progress_bar = 0;
current_progress_bar = 0;
last_millis = millis();
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, HIGH);
break;
case SETTING_BOMB:
break;
case DETONATION_IN:
break;
case DEFUSING_BOMB:
break;
case GAME_OVER_TIME:
break;
case GAME_OVER_EXPLODED:
break;
case GAME_OVER_DEFUSED:
break;
}
break;
case BOMB_WIRES:
switch (chosen_game_state)
{
case STARTED:
chosen_game_state = SETTING_BOMB;
previous_progress_bar = 0;
current_progress_bar = 0;
last_millis = millis();
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, HIGH);
break;
}
break;
case DOMINATION:
switch (chosen_game_state)
{
case STARTED:
if (flag_with_who == -1) // Red team has flag
{
chosen_game_state = GREEN_ACQUIRING;
previous_progress_bar = 0;
current_progress_bar = 0;
last_millis = millis();
one_minute_millis = millis();
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
}
else if (flag_with_who == 0) // No one has flag
{
chosen_game_state = GREEN_CAPTURING;
previous_progress_bar = 0;
current_progress_bar = 0;
last_millis = millis();
one_minute_millis = millis();
digitalWrite(BLUE_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
}
else // Green has flag
{
// Do nothing to game state
}
break;
}
break;
case FAST_BOMB:
switch (chosen_game_state) {
case STARTED:
chosen_game_state = SETTING_BOMB;
previous_progress_bar = 0;
current_progress_bar = 0;
last_millis = millis();
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, HIGH);
break;
case SETTING_BOMB:
break;
case DETONATION_IN:
break;
case DEFUSING_BOMB:
break;
}
break;
}
break;
case IN_SETTINGS_PAGE:
break;
case IN_SETTINGS_CONF: // Later
break;
}
}
// processUpButton();
if (up_button_pressed) {
change_in_screen = true;
tone(BUZZER, _BUZZER_FREQUENCY_HZ, _BUZZER_DURATION_MS);
switch (current_program_state) {
case IN_SELECT_GAME_TYPE_PAGE: // Do nothing
break;
case IN_GAME_CONF:
switch (current_game_type_conf) {
case BOMB_BUTTONS_GAME_TIME:
case BOMB_WIRES_GAME_TIME:
case DOMINATION_GAME_TIME:
Increase(&game_time_total, _GAME_TIME_MAX_TIME, &cursor_position);
break;
case BOMB_BUTTONS_ACTIVATION_TIME:
case BOMB_WIRES_ACTIVATION_TIME:
case FAST_BOMB_ACTIVATION_TIME:
Increase(&activation_time_total, game_time_total, &cursor_position);
break;
case BOMB_BUTTONS_DEFUSING_TIME:
case FAST_BOMB_DEFUSING_TIME:
Increase(&defusing_time_total, game_time_total, &cursor_position);
break;
case BOMB_BUTTONS_BOMB_SET_TIME:
case BOMB_WIRES_BOMB_SET_TIME:
case FAST_BOMB_BOMB_SET_TIME:
Increase(&bomb_set_time_total, game_time_total, &cursor_position);
break;
break;
case BOMB_BUTTONS_START_TIMER:
case BOMB_WIRES_START_TIMER:
case DOMINATION_START_TIMER:
Increase(&start_timer_total, game_time_total, &cursor_position);
break;
case BOMB_WIRES_WIRE_TO_CUT:
if (bomb_wires_wire_to_cut < 4) {
bomb_wires_wire_to_cut++;
}
break;
case DOMINATION_CAPTURE_TIME:
Increase(&capture_time_total, game_time_total, &cursor_position);
break;
case DOMINATION_ACQUIRE_TIME:
Increase(&acquire_time_total, game_time_total, &cursor_position);
break;
}
break;
case IN_GAME: // Later
break;
case IN_SETTINGS_PAGE: // Do nothing
break;
case IN_SETTINGS_CONF: // Later
break;
}
}
// processDownButton();
if (down_button_pressed) {
change_in_screen = true;
tone(BUZZER, _BUZZER_FREQUENCY_HZ, _BUZZER_DURATION_MS);
switch (current_program_state) {
case IN_SELECT_GAME_TYPE_PAGE: // Do nothing
break;
case IN_GAME_CONF:
switch (current_game_type_conf) {
case BOMB_BUTTONS_GAME_TIME:
case BOMB_WIRES_GAME_TIME:
case DOMINATION_GAME_TIME:
Decrease(&game_time_total, _GAME_TIME_MIN_TIME, &cursor_position);
adjustOtherTimings();
break;
case BOMB_BUTTONS_ACTIVATION_TIME:
case BOMB_WIRES_ACTIVATION_TIME:
case FAST_BOMB_ACTIVATION_TIME:
Decrease(&activation_time_total, 0, &cursor_position);
break;
case BOMB_BUTTONS_DEFUSING_TIME:
case FAST_BOMB_DEFUSING_TIME:
Decrease(&defusing_time_total, 0, &cursor_position);
break;
case BOMB_BUTTONS_BOMB_SET_TIME:
case BOMB_WIRES_BOMB_SET_TIME:
case FAST_BOMB_BOMB_SET_TIME:
Decrease(&bomb_set_time_total, 0, &cursor_position);
break;
case BOMB_BUTTONS_START_TIMER:
case BOMB_WIRES_START_TIMER:
case DOMINATION_START_TIMER:
Decrease(&start_timer_total, 0, &cursor_position);
break;
case BOMB_WIRES_WIRE_TO_CUT:
if (bomb_wires_wire_to_cut > 1) {
bomb_wires_wire_to_cut--;
}
break;
case DOMINATION_CAPTURE_TIME:
Decrease(&capture_time_total, 0, &cursor_position);
break;
case DOMINATION_ACQUIRE_TIME:
Decrease(&acquire_time_total, 0, &cursor_position);
break;
}
break;
case IN_GAME: // Later
break;
case IN_SETTINGS_PAGE: // Do nothing
break;
case IN_SETTINGS_CONF: // Later
break;
}
}
// processRightButton();
if (right_button_pressed) {
change_in_screen = true;
tone(BUZZER, _BUZZER_FREQUENCY_HZ, _BUZZER_DURATION_MS);
switch (current_program_state) {
case IN_SELECT_GAME_TYPE_PAGE:
if (++current_menu_page == GAME_TYPE_PAGE_END) {
current_menu_page = GAME_TYPE_PAGE_START + 1;
current_program_state = IN_SELECT_GAME_TYPE_PAGE;
// current_menu_page = SETTINGS_PAGE_START + 1;
// current_program_state = IN_SETTINGS_PAGE;
}
break;
case IN_GAME_CONF:
switch (current_game_type_conf) {
case BOMB_WIRES_WIRE_TO_CUT: // Do nothing, we have no other places to go with the cursor.
cursor_position = WIRE;
break;
default: // Move to next position (hours to minutes, minutes to seconds, seconds to seconds)
if (++cursor_position == CURSOR_POSITION_END) {
cursor_position = CURSOR_POSITION_END - 1;
}
break;
}
break;
case IN_GAME: // Later
break;
case IN_SETTINGS_PAGE:
if (++current_menu_page == SETTINGS_PAGE_END) {
current_menu_page = GAME_TYPE_PAGE_START + 1;
current_program_state = IN_SELECT_GAME_TYPE_PAGE;
}
break;
case IN_SETTINGS_CONF: // Later
break;
}
}
// processLeftButton();
if (left_button_pressed) {
change_in_screen = true;
tone(BUZZER, _BUZZER_FREQUENCY_HZ, _BUZZER_DURATION_MS);
switch (current_program_state) {
case IN_SELECT_GAME_TYPE_PAGE:
if (--current_menu_page == GAME_TYPE_PAGE_START) {
current_menu_page = GAME_TYPE_PAGE_END - 1;
current_program_state = IN_SELECT_GAME_TYPE_PAGE;
// current_menu_page = SETTINGS_PAGE_END - 1;
// current_program_state = IN_SETTINGS_PAGE;
}
break;
case IN_GAME_CONF:
switch (current_game_type_conf) {
case BOMB_WIRES_WIRE_TO_CUT: // Do nothing, we have no other places to go with the cursor.
cursor_position = WIRE;
break;
default: // Move to previous position (hours to hours , minutes to hours , seconds to minutes )
if (--cursor_position == CURSOR_POSITION_START) {
cursor_position = CURSOR_POSITION_START + 1;
}
break;
}
break;
case IN_GAME: // Later
break;
case IN_SETTINGS_PAGE:
if (--current_menu_page == SETTINGS_PAGE_START) {
current_menu_page = GAME_TYPE_PAGE_END - 1;
current_program_state = IN_SELECT_GAME_TYPE_PAGE;
}
break;
case IN_SETTINGS_CONF: // Later
break;
}
}
// Handle Timings
handleTimings();
// Section 3: Outputs
// Handle Menu
handleMenu();
}
void initializationSequence(void) {
digitalWrite(BUZZER, LOW);
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, LOW);
pinMode(BUZZER, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);
pinMode(RED_BUTTON, INPUT);
pinMode(GREEN_BUTTON, INPUT);
pinMode(UP_BUTTON, INPUT);
pinMode(DOWN_BUTTON, INPUT);
pinMode(RIGHT_BUTTON, INPUT);
pinMode(LEFT_BUTTON, INPUT);
for (uint8_t i = 0; i < 4; i++)
{
pinMode(WIRES_PINS[i], INPUT_PULLUP);
}
LCD.backlight(); // Turn on backlight
LCD.init(); // Initialize the LCD
LCD.createChar(0, zero_bar);
LCD.createChar(1, one_bar);
LCD.createChar(2, two_bar);
LCD.createChar(3, three_bar);
LCD.createChar(4, four_bar);
LCD.createChar(5, full_bar);
LCD.home(); // Save settings
return;
}
void welcomeScreen(void) {
LCD.setCursor(0, 0); // Set cursor to Column 1, Row 1
LCD.print(" Airsoft Bomb ");
LCD.setCursor(0, 1); // Set cursor to Column 1, Row 2
LCD.print(" fremontairsoft.com ");
delay(_WELCOME_SCREEN_DELAY_MS);
return;
}
bool isButtonPressed(uint8_t button_pin, bool *last_state) {
bool current_state = digitalRead(button_pin);
if (current_state == HIGH && *(last_state) == LOW) // Was not pressed, now pressed [this takes action only on rising edge]
{
(*last_state) = current_state;
return true;
}
(*last_state) = current_state;
return false;
}
bool isColorButtonPressed_andGetPressTime(uint8_t button_pin, volatile bool *last_state, volatile uint32_t *start_press_time, volatile uint32_t *current_press_time) {
bool current_state = digitalRead(button_pin);
if (current_state == HIGH && *(last_state) == LOW) // Was not pressed, now pressed [this takes action only on rising edge]
{
(*last_state) = current_state;
(*start_press_time) = millis();
(*current_press_time) = millis();
return true;
} else if (current_state == HIGH && *(last_state) == HIGH) // Was pressed, still pressed. [this updates press time only and does not take action]
{
(*last_state) = current_state;
(*current_press_time) = millis();
return false;
} else if (current_state == LOW && *(last_state) == HIGH) // Was pressed, now not pressed. [this resets all times and does not take action]
{
(*last_state) = current_state;
(*start_press_time) = 0;
(*current_press_time) = 0;
return false;
} else if (current_state == LOW && *(last_state) == LOW) // Was not pressed, still not pressed. [this resets all times and does not take action]
{
(*last_state) = current_state;
(*start_press_time) = 0;
(*current_press_time) = 0;
return false;
}
}
bool canStartDomination(void)
{
bool current_state = digitalRead(WIRES_PINS[0]) &&
digitalRead(WIRES_PINS[1]) &&
digitalRead(WIRES_PINS[2]) &&
digitalRead(WIRES_PINS[3]);
if (current_state == LOW && domination_wires_last_state == LOW)
{
domination_wires_last_state = current_state;
return false;
}
else if (current_state == LOW && domination_wires_last_state == HIGH)
{
domination_wires_last_state = current_state;
change_in_screen = true;
return false;
}
else if (current_state == HIGH && domination_wires_last_state == LOW)
{
domination_wires_last_state = current_state;
change_in_screen = true;
return true;
}
else
{
domination_wires_last_state = current_state;
return true;
}
}
void handleTimings(void) {
switch (current_program_state) {
case IN_GAME:
chosen_game_elapsed_time = (millis() - chosen_game_start_time) / 1000;
change_in_screen = true;
switch (chosen_game_type) {
case BOMB_BUTTONS:
switch (chosen_game_state) {
case HAS_NOT_STARTED_YET:
if (chosen_game_elapsed_time < start_timer_total)
{
countdown_time = start_timer_total - chosen_game_elapsed_time;
if (millis() - last_millis >= 1000)
{
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
}
}
else
{
chosen_game_state = STARTED;
countdown_time = game_time_total;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, LOW);
}
break;
case STARTED:
if (chosen_game_elapsed_time < game_time_total) {
countdown_time = game_time_total - chosen_game_elapsed_time;
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS) {
last_millis = millis();
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
}
} else {
chosen_game_state = GAME_OVER_TIME;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(GREEN_LED, LOW);
}
break;
case SETTING_BOMB:
if (green_button_start_press_time == 0) {
chosen_game_state = STARTED;
last_millis = millis();
digitalWrite(GREEN_LED, HIGH);
digitalWrite(BLUE_LED, LOW);
} else {
if (current_progress_bar == 100) {
chosen_game_state = DETONATION_IN;
countdown_time = bomb_set_time_total;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(BLUE_LED, LOW);
digitalWrite(RED_LED, HIGH);
}
previous_progress_bar = current_progress_bar;
current_progress_bar = map((green_button_current_press_time - green_button_start_press_time) / 1000, 0, activation_time_total, 0, 100);
current_progress_bar = constrain(current_progress_bar, 0, 100);
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS) {
last_millis = millis();
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
}
}
break;
case DETONATION_IN:
if (chosen_game_elapsed_time < bomb_set_time_total) {
countdown_time = bomb_set_time_total - chosen_game_elapsed_time;
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS) {
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
}
} else {
chosen_game_state = GAME_OVER_EXPLODED;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(RED_LED, LOW);
}
break;
case DEFUSING_BOMB:
if (red_button_start_press_time == 0) {
chosen_game_state = DETONATION_IN;
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, LOW);
} else {
if (current_progress_bar == 100) {
chosen_game_state = GAME_OVER_DEFUSED;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(GREEN_LED, LOW);
}
previous_progress_bar = current_progress_bar;
current_progress_bar = map((red_button_current_press_time - red_button_start_press_time) / 1000, 0, defusing_time_total, 0, 100);
current_progress_bar = constrain(current_progress_bar, 0, 100);
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS) {
last_millis = millis();
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
}
}
break;
}
break;
case BOMB_WIRES:
switch (chosen_game_state)
{
case HAS_NOT_STARTED_YET:
if (chosen_game_elapsed_time < start_timer_total)
{
countdown_time = start_timer_total - chosen_game_elapsed_time;
if (millis() - last_millis >= 1000)
{
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
}
}
else
{
chosen_game_state = STARTED;
countdown_time = game_time_total;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, LOW);
}
break;
case STARTED:
if (chosen_game_elapsed_time < game_time_total) {
countdown_time = game_time_total - chosen_game_elapsed_time;
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS) {
last_millis = millis();
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
}
}
else
{
chosen_game_state = GAME_OVER_TIME;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(GREEN_LED, LOW);
}
break;
case SETTING_BOMB:
if (green_button_start_press_time == 0) {
chosen_game_state = STARTED;
last_millis = millis();
digitalWrite(GREEN_LED, HIGH);
digitalWrite(BLUE_LED, LOW);
} else {
if (current_progress_bar == 100) {
chosen_game_state = DETONATION_IN;
countdown_time = bomb_set_time_total;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(BLUE_LED, LOW);
digitalWrite(RED_LED, HIGH);
}
previous_progress_bar = current_progress_bar;
current_progress_bar = map((green_button_current_press_time - green_button_start_press_time) / 1000, 0, activation_time_total, 0, 100);
current_progress_bar = constrain(current_progress_bar, 0, 100);
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS) {
last_millis = millis();
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
}
}
break;
case DETONATION_IN:
if (chosen_game_elapsed_time < bomb_set_time_total) {
countdown_time = bomb_set_time_total - chosen_game_elapsed_time;
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS) {
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
}
switch (cutWire())
{
case NO_WIRE_CUT: // do nothing
break;
case WRONG_WIRE_CUT:
// Game over exploded
chosen_game_state = GAME_OVER_EXPLODED;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(RED_LED, LOW);
break;
case RIGHT_WIRE_CUT:
// Game over defused
chosen_game_state = GAME_OVER_DEFUSED;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(RED_LED, LOW);
break;
}
}
else
{
chosen_game_state = GAME_OVER_EXPLODED;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(RED_LED, LOW);
}
break;
}
break;
case DOMINATION:
switch (chosen_game_state)
{
case HAS_NOT_STARTED_YET:
if (chosen_game_elapsed_time < start_timer_total)
{
countdown_time = start_timer_total - chosen_game_elapsed_time;
if (millis() - last_millis >= 1000)
{
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
}
}
else
{
chosen_game_state = STARTED;
countdown_time = game_time_total;
chosen_game_start_time = millis();
last_millis = millis();
one_minute_millis = millis();
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, LOW);
}
break;
case STARTED:
if (chosen_game_elapsed_time < game_time_total)
{
countdown_time = game_time_total - chosen_game_elapsed_time;
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS)
{
last_millis = millis();
if (flag_with_who == -1) // Red team has flag
{
digitalWrite(RED_LED, !digitalRead(RED_LED));
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, LOW);
}
else if (flag_with_who == 0) // No one has flag
{
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
}
else // Green has flag
{
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
digitalWrite(BLUE_LED, LOW);
}
}
if (millis() - one_minute_millis >= 1000) // One second has passed.
{
one_minute_millis = millis();
if (flag_with_who == -1) // Red team has flag
{
red_team_time_total++;
}
else if (flag_with_who == 1) // Green has flag
{
green_team_time_total++;
}
}
}
else
{
if (red_team_time_total == green_team_time_total)
{
chosen_game_state = GAME_OVER_DRAW;
}
else if (red_team_time_total > green_team_time_total)
{
chosen_game_state = GAME_OVER_RED;
}
else
{
chosen_game_state = GAME_OVER_GREEN;
}
digitalWrite(BLUE_LED, LOW);
}
break;
case GREEN_ACQUIRING:
if (green_button_start_press_time == 0)
{
chosen_game_state = STARTED;
flag_with_who = -1; // Return flag to red team
last_millis = millis();
one_minute_millis = millis();
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, HIGH);
}
else
{
if (current_progress_bar == 100)
{
chosen_game_state = STARTED;
flag_with_who = 0; // Now flag is neutral
last_millis = millis();
one_minute_millis = millis();
digitalWrite(RED_LED, LOW);
digitalWrite(BLUE_LED, HIGH);
}
previous_progress_bar = current_progress_bar;
current_progress_bar = map((green_button_current_press_time - green_button_start_press_time) / 1000, 0, acquire_time_total, 0, 100);
current_progress_bar = constrain(current_progress_bar, 0, 100);
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS)
{
last_millis = millis();
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
}
}
break;
case GREEN_CAPTURING:
if (green_button_start_press_time == 0)
{
chosen_game_state = STARTED;
flag_with_who = 0; // Return flag to neutral
last_millis = millis();
one_minute_millis = millis();
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, HIGH);
}
else
{
if (current_progress_bar == 100)
{
chosen_game_state = STARTED;
flag_with_who = 1; // Now flag is with green team
last_millis = millis();
one_minute_millis = millis();
digitalWrite(BLUE_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
}
previous_progress_bar = current_progress_bar;
current_progress_bar = map((green_button_current_press_time - green_button_start_press_time) / 1000, 0, capture_time_total, 0, 100);
current_progress_bar = constrain(current_progress_bar, 0, 100);
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS)
{
last_millis = millis();
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
}
}
break;
case RED_ACQUIRING:
if (red_button_start_press_time == 0)
{
chosen_game_state = STARTED;
flag_with_who = 1; // Return flag to green team
last_millis = millis();
one_minute_millis = millis();
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
}
else
{
if (current_progress_bar == 100)
{
chosen_game_state = STARTED;
flag_with_who = 0; // Now flag is neutral
last_millis = millis();
one_minute_millis = millis();
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, HIGH);
}
previous_progress_bar = current_progress_bar;
current_progress_bar = map((red_button_current_press_time - red_button_start_press_time) / 1000, 0, acquire_time_total, 0, 100);
current_progress_bar = constrain(current_progress_bar, 0, 100);
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS)
{
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
}
}
break;
case RED_CAPTURING:
if (red_button_start_press_time == 0)
{
chosen_game_state = STARTED;
flag_with_who = 0; // Return flag to neutral
last_millis = millis();
one_minute_millis = millis();
digitalWrite(RED_LED, LOW);
digitalWrite(BLUE_LED, HIGH);
}
else
{
if (current_progress_bar == 100)
{
chosen_game_state = STARTED;
flag_with_who = -1; // Now flag is with red team
last_millis = millis();
one_minute_millis = millis();
digitalWrite(BLUE_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
}
previous_progress_bar = current_progress_bar;
current_progress_bar = map((red_button_current_press_time - red_button_start_press_time) / 1000, 0, capture_time_total, 0, 100);
current_progress_bar = constrain(current_progress_bar, 0, 100);
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS)
{
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
}
}
break;
}
break;
case FAST_BOMB:
switch (chosen_game_state) {
case STARTED:
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS) {
last_millis = millis();
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
}
break;
case SETTING_BOMB:
if (green_button_start_press_time == 0) {
chosen_game_state = STARTED;
last_millis = millis();
digitalWrite(GREEN_LED, HIGH);
digitalWrite(BLUE_LED, LOW);
}
else
{
if (current_progress_bar == 100)
{
chosen_game_state = DETONATION_IN;
countdown_time = bomb_set_time_total;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(BLUE_LED, LOW);
digitalWrite(RED_LED, HIGH);
}
previous_progress_bar = current_progress_bar;
current_progress_bar = map((green_button_current_press_time - green_button_start_press_time) / 1000, 0, activation_time_total, 0, 100);
current_progress_bar = constrain(current_progress_bar, 0, 100);
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS)
{
last_millis = millis();
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED));
}
}
break;
case DETONATION_IN:
if (chosen_game_elapsed_time < bomb_set_time_total)
{
countdown_time = bomb_set_time_total - chosen_game_elapsed_time;
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS)
{
last_millis = millis();
digitalWrite(RED_LED, !digitalRead(RED_LED));
}
}
else
{
chosen_game_state = GAME_OVER_EXPLODED;
last_millis = millis();
digitalWrite(RED_LED, LOW);
}
break;
case DEFUSING_BOMB:
if (red_button_start_press_time == 0) {
chosen_game_state = DETONATION_IN;
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, LOW);
} else {
if (current_progress_bar == 100) {
chosen_game_state = GAME_OVER_DEFUSED;
chosen_game_start_time = millis();
last_millis = millis();
digitalWrite(GREEN_LED, LOW);
}
previous_progress_bar = current_progress_bar;
current_progress_bar = map((red_button_current_press_time - red_button_start_press_time) / 1000, 0, defusing_time_total, 0, 100);
current_progress_bar = constrain(current_progress_bar, 0, 100);
if (millis() - last_millis >= _LEDS_FLASH_TIME_MS) {
last_millis = millis();
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED));
}
}
break;
}
break;
}
break;
}
return;
}
void handleMenu(void) {
if (!change_in_screen) {
return;
}
change_in_screen = false;
LCD.noBlink();
LCD.setCursor(0, 0); // Set cursor to Column 1, Row 1
switch (current_program_state) {
case IN_SELECT_GAME_TYPE_PAGE: // Show "Select Game Type"
LCD.print(" Select Game Type ");
LCD.setCursor(0, 1); // Set cursor to Column 1, Row 2
switch (current_menu_page) {
case BOMB_BUTTONS_PAGE:
LCD.print("< Bomb Buttons >");
break;
case BOMB_WIRES_PAGE:
LCD.print("< Bomb Wires >");
break;
case DOMINATION_PAGE:
LCD.print("< Domination >");
break;
case FAST_BOMB_PAGE:
LCD.print("< Fast Bomb >");
break;
}
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" ");
LCD.setCursor(0, 3); // Set cursor to Column 1, Row 4
LCD.print(" ");
break;
case IN_GAME_CONF:
switch (last_menu_page) {
case BOMB_BUTTONS_PAGE:
LCD.print(" Bomb Buttons ");
break;
case BOMB_WIRES_PAGE:
LCD.print(" Bomb Wires ");
LCD.setCursor(0, 3); // Set cursor to Column 1, Row 4
if (can_start_bomb_wires == false)
{
LCD.print("Reset Wires Switches");
}
else
{
LCD.print(" ");
}
break;
case DOMINATION_PAGE:
LCD.print(" Domination ");
break;
case FAST_BOMB_PAGE:
LCD.print(" Fast Bomb ");
break;
}
LCD.setCursor(0, 1); // Set cursor to Column 1, Row 2
switch (current_game_type_conf) {
case BOMB_BUTTONS_GAME_TIME:
case BOMB_WIRES_GAME_TIME:
case DOMINATION_GAME_TIME:
LCD.print("< Game Time: >");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&game_time_total);
break;
case BOMB_BUTTONS_ACTIVATION_TIME:
case BOMB_WIRES_ACTIVATION_TIME:
case FAST_BOMB_ACTIVATION_TIME:
LCD.print("< Activation Time: >");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&activation_time_total);
break;
case BOMB_BUTTONS_DEFUSING_TIME:
case FAST_BOMB_DEFUSING_TIME:
LCD.print("< Defuse Time: >");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&defusing_time_total);
break;
case BOMB_BUTTONS_BOMB_SET_TIME:
case BOMB_WIRES_BOMB_SET_TIME:
case FAST_BOMB_BOMB_SET_TIME:
LCD.print("< Bomb Set Time: >");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&bomb_set_time_total);
break;
case BOMB_BUTTONS_START_TIMER:
case BOMB_WIRES_START_TIMER:
case DOMINATION_START_TIMER:
LCD.print("< Start Timer: >");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&start_timer_total);
break;
case BOMB_WIRES_WIRE_TO_CUT:
LCD.print("< Wire to Cut: >");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" ");
LCD.print(bomb_wires_wire_to_cut);
LCD.print(" ");
break;
case DOMINATION_CAPTURE_TIME:
LCD.print("< Capture Time >");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&capture_time_total);
break;
case DOMINATION_ACQUIRE_TIME:
LCD.print("< Acquire Time >");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&acquire_time_total);
break;
}
switch (cursor_position) {
case HOURS:
LCD.setCursor(7, 2);
break;
case MINUTES:
LCD.setCursor(10, 2);
break;
case SECONDS:
LCD.setCursor(13, 2);
break;
case WIRE:
LCD.setCursor(9, 2);
break;
}
LCD.blink();
break;
case IN_GAME:
LCD.setCursor(0, 1); // Set cursor to Column 1, Row 2
switch (chosen_game_type) {
case BOMB_BUTTONS:
switch (chosen_game_state)
{
case HAS_NOT_STARTED_YET:
LCD.print(" Game Starts In ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&countdown_time);
break;
case STARTED:
LCD.print(" Remaining Time ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&countdown_time);
break;
case SETTING_BOMB:
LCD.print(" Setting Bomb ");
printProgressBar(¤t_progress_bar, &previous_progress_bar, 2);
break;
case DETONATION_IN:
LCD.print(" Detonation In: ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&countdown_time);
break;
case DEFUSING_BOMB:
LCD.print(" Defusing Bomb: ");
printProgressBar(¤t_progress_bar, &previous_progress_bar, 2);
break;
case GAME_OVER_TIME:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Time Up! ");
break;
case GAME_OVER_EXPLODED:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Exploded ");
break;
case GAME_OVER_DEFUSED:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Defused! ");
break;
}
break;
case BOMB_WIRES:
switch (chosen_game_state)
{
case HAS_NOT_STARTED_YET:
LCD.print(" Game Starts In ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&countdown_time);
break;
case STARTED:
LCD.print(" Remaining Time ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&countdown_time);
break;
case SETTING_BOMB:
LCD.print(" Setting Bomb ");
printProgressBar(¤t_progress_bar, &previous_progress_bar, 2);
break;
case DETONATION_IN:
LCD.print(" Detonation In: ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&countdown_time);
break;
case GAME_OVER_TIME:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Time Up! ");
break;
case GAME_OVER_EXPLODED:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Exploded ");
break;
case GAME_OVER_DEFUSED:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Defused! ");
break;
}
break;
case DOMINATION:
switch (chosen_game_state)
{
case HAS_NOT_STARTED_YET:
LCD.print(" Game Starts In ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&countdown_time);
break;
case STARTED:
LCD.print(" Remaining Time ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&countdown_time);
LCD.setCursor(0, 3); // Set cursor to Column 1, Row 4
printScores();
break;
case GREEN_ACQUIRING:
LCD.print(" Green! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Acquiring! ");
LCD.setCursor(0, 3); // Set cursor to Column 1, Row 4
printProgressBar(¤t_progress_bar, &previous_progress_bar, 3);
break;
case GREEN_CAPTURING:
LCD.print(" Green! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Capturing! ");
LCD.setCursor(0, 3); // Set cursor to Column 1, Row 4
printProgressBar(¤t_progress_bar, &previous_progress_bar, 3);
break;
case RED_ACQUIRING:
LCD.print(" Red! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Acquiring! ");
LCD.setCursor(0, 3); // Set cursor to Column 1, Row 4
printProgressBar(¤t_progress_bar, &previous_progress_bar, 3);
break;
case RED_CAPTURING:
LCD.print(" Red! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Capturing! ");
LCD.setCursor(0, 3); // Set cursor to Column 1, Row 4
printProgressBar(¤t_progress_bar, &previous_progress_bar, 3);
break;
case GAME_OVER_DRAW:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Draw ");
break;
case GAME_OVER_RED:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Red Team Wins! ");
break;
case GAME_OVER_GREEN:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Green Team Wins! ");
break;
}
break;
case FAST_BOMB:
switch (chosen_game_state)
{
case STARTED:
LCD.print(" Awaiting Bomb ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Activation ");
break;
case SETTING_BOMB:
LCD.print(" Setting Bomb ");
printProgressBar(¤t_progress_bar, &previous_progress_bar, 2);
break;
case DETONATION_IN:
LCD.print(" Detonation In: ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
printTiming(&countdown_time);
break;
case DEFUSING_BOMB:
LCD.print(" Defusing Bomb: ");
printProgressBar(¤t_progress_bar, &previous_progress_bar, 2);
break;
case GAME_OVER_EXPLODED:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Exploded ");
break;
case GAME_OVER_DEFUSED:
LCD.print(" Game Over! ");
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" Defused! ");
break;
}
break;
}
break;
case IN_SETTINGS_PAGE:
LCD.print(" Settings ");
LCD.setCursor(0, 1); // Set cursor to Column 1, Row 2
switch (current_menu_page) {
case BACKLIGHT:
LCD.print("< Back-light >");
break;
case BRIGHTNESS:
LCD.print("< Brightness >");
break;
case LCD_EFFECTS:
LCD.print("< LCD FX >");
break;
case SOUND_EFFECTS:
LCD.print("< Sound FX >");
break;
case EXTERNAL_OUTPUT:
LCD.print("< Ext. Output >");
break;
case VIBRATION:
LCD.print("< Vibration >");
break;
}
LCD.setCursor(0, 2); // Set cursor to Column 1, Row 3
LCD.print(" ");
LCD.setCursor(0, 3); // Set cursor to Column 1, Row 4
LCD.print(" ");
break;
case IN_SETTINGS_CONF:
break;
}
return;
}
uint8_t cutWire(void)
{
for (uint8_t i = 0; i < 4; i++)
{
if (i == (bomb_wires_wire_to_cut - 1) )
{
continue;
}
if (digitalRead(WIRES_PINS[i]) == LOW)
{
return WRONG_WIRE_CUT;
}
}
if (digitalRead(WIRES_PINS[bomb_wires_wire_to_cut - 1]) == LOW)
{
return RIGHT_WIRE_CUT;
}
return NO_WIRE_CUT;
}
void printTiming(uint32_t *total_time) {
//char temporaryBuffer[20];
uint8_t hours = (*total_time) / 60 / 60;
uint8_t minutes = (*total_time) / 60 % 60;
uint8_t seconds = (*total_time) % 60;
//sprintf(temporaryBuffer, " %d%d:%d%d:%d%d ", hours / 10, hours % 10, minutes / 10, minutes % 10, seconds / 10, seconds % 10);
//LCD.print(temporaryBuffer);
LCD.print(" ");
LCD.print(hours / 10); LCD.print(hours % 10); LCD.print(":");
LCD.print(minutes / 10); LCD.print(minutes % 10); LCD.print(":");
LCD.print(seconds / 10); LCD.print(seconds % 10);
LCD.print(" ");
return;
}
void printScores(void)
{
uint8_t red_hours = red_team_time_total / 60 / 60;
uint8_t red_minutes = red_team_time_total / 60 % 60;
uint8_t red_seconds = red_team_time_total % 60;
uint8_t green_hours = green_team_time_total / 60 / 60;
uint8_t green_minutes = green_team_time_total / 60 % 60;
uint8_t green_seconds = green_team_time_total % 60;
LCD.print(" ");
LCD.print(red_hours / 10); LCD.print(red_hours % 10);
LCD.print(":");
LCD.print(red_minutes / 10); LCD.print(red_minutes % 10);
LCD.print(":");
LCD.print(red_seconds / 10); LCD.print(red_seconds % 10);
LCD.print(" ");
LCD.print(green_hours / 10); LCD.print(green_hours % 10);
LCD.print(":");
LCD.print(green_minutes / 10); LCD.print(green_minutes % 10);
LCD.print(":");
LCD.print(green_seconds / 10); LCD.print(green_seconds % 10);
LCD.print(" ");
return;
}
void printProgressBar(uint8_t *current_progress, uint8_t *previous_progress, uint8_t col) {
if (*previous_progress == 0) {
LCD.setCursor(0, col);
LCD.print(" ");
}
if (*current_progress == *previous_progress) {
return;
}
LCD.setCursor(*(previous_progress) / 5, 2);
for (uint8_t i = 0; i < (*(current_progress) / 5) - (*(previous_progress) / 5); i++) {
for (uint8_t j = (*(previous_progress) % 5); j <= 5; j++) {
LCD.setCursor((*(previous_progress) / 5) + i, col);
LCD.write(j);
}
}
LCD.write(*(current_progress) % 5);
return;
}
void Increase(uint32_t *time_total, uint32_t time_max, uint8_t *timestamp) {
switch (*timestamp) {
case HOURS:
if (int32_t(*time_total) + int32_t(3600) <= int32_t(time_max) )
{
*(time_total) = *(time_total) + 3600;
}
break;
case MINUTES:
{
if (int32_t(*time_total) + int32_t(60) <= int32_t(time_max) )
{
*(time_total) = *(time_total) + 60;
}
}
break;
case SECONDS:
{
if (int32_t(*time_total) + int32_t(1) <= int32_t(time_max) )
{
*(time_total) = *(time_total) + 1;
}
}
break;
}
return;
}
void Decrease(uint32_t *time_total, uint32_t time_min, uint8_t *timestamp) {
switch (*timestamp) {
case HOURS:
{
if (int32_t(*time_total) - int32_t(3600) >= int32_t(time_min) ) {
*(time_total) = *(time_total) - 3600;
}
}
break;
case MINUTES:
{
if (int32_t(*time_total) - int32_t(60) >= int32_t(time_min) ) {
*(time_total) = *(time_total) - 60;
}
}
break;
case SECONDS:
{
if (int32_t(*time_total) - int32_t(1) >= int32_t(time_min) ) {
*(time_total) = *(time_total) - 1;
}
}
break;
}
return;
}
void adjustOtherTimings(void) {
if (activation_time_total > game_time_total) {
activation_time_total = game_time_total / 60;
}
if (defusing_time_total > game_time_total) {
defusing_time_total = game_time_total / 60;
}
if (bomb_set_time_total > game_time_total) {
bomb_set_time_total = game_time_total / 60;
}
if (start_timer_total > game_time_total) {
start_timer_total = game_time_total / 30;
}
if (capture_time_total > game_time_total) {
capture_time_total = game_time_total / 60;
}
if (acquire_time_total > game_time_total) {
acquire_time_total = game_time_total / 60;
}
return;
}