#include <Wire.h>
#include <Keypad.h>
#include <TMRpcm.h>
#include <Adafruit_LEDBackpack.h>
#include <Adafruit_GFX.h>
// LED
int ledPin = 13;
// Keypad
const uint8_t ROWS = 4;
const uint8_t COLS = 3;
char keys[ROWS][COLS] = {
{ '1', '2', '3' },
{ '4', '5', '6' },
{ '7', '8', '9' },
{ 'C', '0', 'S' }
};
uint8_t colPins[COLS] = { 8, 7, 6 }; // Pins connected to C1, C2, C3
uint8_t rowPins[ROWS] = { 12, 11, 10, 9 }; // Pins connected to R1, R2, R3, R4
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// 7-SEG
Adafruit_7segment matrix1 = Adafruit_7segment();
Adafruit_7segment matrix2 = Adafruit_7segment();
// speaker
TMRpcm tmrpcm;
// variables
bool started = false;
char stage = '0';
char key;
char savedKey;
int gamemode = 1; // sets default gamemode to 1
unsigned long countdown = 900000; // sets default countdown time to 15m (in ms)
int defuseTime = 10000; // sets default time to defuse to 10s (in ms)
int plantTime = 10000; // sets default time to plant to 10s (in ms) !Only relevant in gamemode 2!
int code = 1234; // sets default plant code to 1234. !Only relevant in gamemode 1!
bool endOnDefuse = true; // causes the game to end after 1 defusal
int inputNum = 1;
int inputTotal = 0;
bool bombActive = false;
bool gameEnd = false;
KeyState state;
bool displayChanged = false;
unsigned long currentTime;
const int blinkTime = 250;
unsigned long ctdnStartTime;
int timeLeft;
int minsLeft;
int secsLeft;
unsigned long defStartTime;
unsigned long pltStartTime;
unsigned long blinkPreviousTime = 0;
void setup() {
pinMode(ledPin, OUTPUT);
#ifndef __AVR_ATtiny85__
Serial.begin(115200);
#endif
matrix1.begin(0x70);
matrix2.begin(0x71);
tmrpcm.speakerPin = 19;
tone(19, 1000, 100);
}
void loop() {
if (started == false) { // checks if the game has started
started = gamestart();
}
else if (gameEnd == false) {
if (bombActive == false) {
if (gamemode == 1) { // sets the bomb to active if the correct code is entered
keypadInput();
if (inputTotal == code && stage == '6') {
bombActive = true;
Serial.println("Planted");
inputTotal = 0;
ctdnStartTime = millis();
}
}
else {
keypad.setHoldTime(plantTime);
key = getkey();
state = keypad.getState();
if (key != NO_KEY) {
savedKey = key;
}
if (key == 'S') {
pltStartTime = millis();
}
currentTime = millis();
timeLeft = plantTime - (currentTime - pltStartTime);
timeLeft /= 1000;
minsLeft = timeLeft / 1;
secsLeft = timeLeft % 1;
matrix1.writeDigitNum(0, minsLeft / 10);
matrix1.writeDigitNum(1, minsLeft % 10);
matrix1.drawColon(true);
matrix1.writeDigitNum(2, secsLeft / 10);
matrix1.writeDigitNum(3, secsLeft % 10);
matrix1.writeDisplay();
if (savedKey == 'S' && state == HOLD) { // Plants bomb if 'SET' is held
Serial.println("SET");
bombActive = true;
ctdnStartTime = millis();
}
}
}
else {
keypad.setHoldTime(defuseTime);
currentTime = millis();
timeLeft = countdown - (currentTime - ctdnStartTime);
timeLeft /= 1000;
minsLeft = timeLeft / 60;
secsLeft = timeLeft % 60;
matrix2.writeDigitNum(0, (minsLeft - (minsLeft % 10)) / 10);
matrix2.writeDigitNum(1, minsLeft % 10);
matrix2.drawColon(true);
matrix2.writeDigitNum(2, (secsLeft - (secsLeft % 10)) / 10);
matrix2.writeDigitNum(3, secsLeft % 10);
matrix2.writeDisplay();
key = getkey();
state = keypad.getState();
if (key != NO_KEY) {
savedKey = key;
}
if (key == 'C') {
defStartTime = millis();
}
currentTime = millis();
timeLeft = defuseTime - (currentTime - defStartTime);
timeLeft /= 1000;
minsLeft = timeLeft / 1;
secsLeft = timeLeft % 1;
matrix1.writeDigitNum(0, minsLeft / 10);
matrix1.writeDigitNum(1, minsLeft % 10);
matrix1.drawColon(true);
matrix1.writeDigitNum(2, secsLeft / 10);
matrix1.writeDigitNum(3, secsLeft % 10);
matrix1.writeDisplay();
currentTime = millis();
if ((currentTime - blinkPreviousTime) > blinkTime) {
blinkPreviousTime = currentTime;
if (ledPin == HIGH) {
digitalWrite(ledPin, LOW);
}
else {
digitalWrite(ledPin, HIGH);
}
}
if (savedKey == 'C' && state == HOLD) { // Defuses bomb if 'CLR' is held
bombActive = false;
Serial.println("DEFUSED");
digitalWrite(ledPin, LOW);
stage = '0';
if (endOnDefuse == true) {
gameEnd = true;
}
}
if (countdown < (currentTime - ctdnStartTime)) {
gameEnd = true;
bombActive = false;
tmrpcm.play("explosion.wav");
Serial.println("BOOM");
}
}
}
}
char getkey() { // returns a key if one is pressed, and plays a tone
key = keypad.getKey();
bool change = keypad.keyStateChanged();
if ((key != NO_KEY) && (change == true)) {
//tone(19, 1250, 200);
Serial.println(key);
}
return key;
}
void keypadInput () { // returns a number up to 4 digits entered by the user
key = getkey();
if (key != 'C' && key != 'S' && key != NO_KEY) {
switch (inputNum) {
case 1:
inputTotal = key - '0';
inputNum += 1;
break;
case 2 ... 4:
inputTotal *= 10;
inputTotal += key - '0';
inputNum += 1;
break;
}
matrix1.print(inputTotal);
matrix1.writeDisplay();
}
else if (key == 'C') {
inputNum = 1;
matrix1.print(inputTotal);
matrix1.writeDisplay();
}
else if (key == 'S') {
stage = '0';
displayChanged = false;
inputNum = 1;
matrix1.print("SET");
matrix1.writeDisplay();
}
if (started == true && bombActive == false && key == 'S') {
stage = '6';
}
}
void stageChange(String text) {
for (int i = 1; i <= 2; i++) {
matrix1.print(text);
matrix1.writeDisplay();
delay(250);
matrix1.clear();
matrix1.writeDisplay();
delay(250);
}
matrix1.print(text);
matrix1.writeDisplay();
}
bool gamestart() {
bool startheld = false;
keypad.setHoldTime(1000);
switch (stage) {
case '0': // main menu
if (displayChanged == false) {
stageChange("strt");
Serial.println("Main Menu");
displayChanged = true;
}
key = getkey();
state = keypad.getState();
if (key != NO_KEY) {
savedKey = key;
if (savedKey != 'C' && savedKey != 'S' && savedKey != '6' && savedKey != '7' && savedKey != '8' && savedKey != '9') {
stage = key;
displayChanged = false;
}
}
if (savedKey == 'C' && state == HOLD) { // starts the game if the 'SET' button is held
startheld = true;
Serial.println("strt");
stageChange("strt");
}
break;
case '1': // gamemode
if (displayChanged == false) {
stageChange("mode");
Serial.println("Game mode");
displayChanged = true;
}
key = getkey();
switch (key) {
case '1':
gamemode = 1;
stage = '0';
displayChanged = false;
break;
case '2':
gamemode = 2;
stage = '0';
displayChanged = false;
break;
}
break;
case '2': // countdown length (input in mins)
if (displayChanged == false) {
stageChange("ctdn");
Serial.println("Countdown length");
displayChanged = true;
}
inputTotal = countdown / 60000;
keypadInput();
if (key == 'S') {
countdown = inputTotal * 60000;
}
break;
case '3': // time to defuse (input in secs)
if (displayChanged == false) {
stageChange("def.t");
Serial.println("Defusal Time");
displayChanged = true;
}
inputTotal = defuseTime / 1000;
keypadInput();
if (key == 'S') {
defuseTime = inputTotal * 1000;
}
break;
case '4': // code or time to plant (code cannot be less than 1000) (input in secs)
if (gamemode == 1) {
if (displayChanged == false) {
stageChange("code");
Serial.println("Code");
displayChanged = true;
}
inputTotal = code;
keypadInput();
if (key == 'S') {
code = inputTotal;
if (code < 1000) {
code = 1234;
}
}
}
else {
if (displayChanged == false) {
stageChange("plt.t");
Serial.println("Plant Time");
displayChanged = true;
}
inputTotal = plantTime / 1000;
keypadInput();
if (key == 'S') {
plantTime = inputTotal * 1000;
}
}
break;
case '5': // game end on defuse
if (displayChanged == false) {
stageChange("e.o.d");
Serial.println("End on Defuse?");
displayChanged = true;
}
key = getkey();
if (key != NO_KEY) {
if (key == '1') {
endOnDefuse = true;
stage = '0';
displayChanged = false;
stageChange("on");
}
else if (key == '0') {
endOnDefuse = false;
stage = '0';
displayChanged = false;
stageChange("on");
}
}
break;
}
return startheld;
}