#include <Wire.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
//#include <LiquidCrystal.h>
/*
Arduino Bomb Pro
created 14,juin, 2026
by Dubs49
*/
LiquidCrystal_I2C lcd(0x27, 16, 2);
//LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
{'1','2','3','a'}
,
{'4','5','6','b'}
,
{'7','8','9','c'}
,
{'*','0','#','d'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
char codeInput[7];
byte time[4];
boolean refresh=true;//1 refresh one time...
char password[7];
int key=-1;
char lastKey;
char var;
boolean passwordEnable=false;
//Buttons for lcd shield
char BT_RIGHT = '4';
char BT_UP = 'a';
char BT_DOWN = 'b';
char BT_LEFT = '6';
char BT_SEL = 'd'; // Ok key
char BT_CANCEL = 'c';
char BT_DEFUSER = 'x'; // not implemented
//leds
const int REDLED = 11;
const int GREENLED = 10;
boolean relayEnable = false;
const int RELAYPIN = 12;
//IS VERY IMPORTANT THAT YOU TEST THIS TIME. BY DEFAULT IS IN 1 SEC. THAT IS NOT TOO MUCH. SO TEST IT!
const int RELAY_TIME = 10000;
//TIME INTS
int GAMEHOURS = 0;
int GAMEMINUTES = 45;
int BOMBMINUTES = 4;
int ACTIVATESECONDS = 5;
byte errorCount = 0;
byte speedFactor = 1;
boolean endGame = false;
boolean sdStatus = false; //search and destroy game enable used in config
boolean doStatus = false; //for DEmolition
boolean start = true;
boolean defusing = false;
boolean cancelando = false;
boolean clikerStatus = false;
int CLICK_TARGET = 50;
int clickCount = 0;
boolean thiefStatus=false;
int GOLD_TARGET=10;
int goldRemaining=10;
int THIEF_TIME = 10;
// SOUND TONES
boolean soundEnable = true;
int tonepin = 13; // Pin 13 for the sound
int alarmTone1 = 700;
int alarmTone2 = 2600;
int activeTone = 1330;
int errorTone = 100;
unsigned long iTime;
unsigned long timeCalcVar;
unsigned long redTime;
unsigned long gameStartTime;
unsigned long greenTime;
unsigned long iZoneTime;
unsigned long penaltyTime = 0; // 10000
byte team=0; // 0 = neutral, 1 = green team, 2 = red team
void setup(){
Wire.begin();
Wire.setClock(400000);
lcd.backlight();
lcd.begin(16, 2); Serial.begin(9600);
lcd.setCursor(2,0);
tone(tonepin,2400,30);
lcd.print("AIRSOFT BOMB");// you can add your team name or someting cool
lcd.setCursor(0,1);
lcd.print("by dubs49 v1.4");// you can add your team name or someting cool
delay(1500); // 👈 AJOUT IMPORTANT
// logo boot systeme
lcd.clear();
lcd.setCursor(0,0);
lcd.print("BOOT SYSTEM");
for(int i = 0; i <= 16; i++){
lcd.setCursor(0,1);
for(int j = 0; j < 16; j++){
if(j < i){
lcd.print("#");
} else {
lcd.print(" ");
}
}
delay(120);
}
delay(500);
lcd.clear();
keypad.setHoldTime(50);
keypad.setDebounceTime(50);
keypad.addEventListener(keypadEvent);
//PinModes
pinMode(GREENLED, OUTPUT);
pinMode(REDLED, OUTPUT);
pinMode(RELAYPIN, OUTPUT);
// CONFIGURE THE BARS OF PROGRESS BAR
byte bar1[8] = {
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
};
byte bar2[8] = {
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
};
byte bar3[8] = {
B11100,
B11100,
B11100,
B11100,
B11100,
B11100,
B11100,
B11100,
};
byte bar4[8] = {
B11110,
B11110,
B11110,
B11110,
B11110,
B11110,
B11110,
B11110,
};
byte bar5[8] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
};
byte up[8] = {
B00000,
B00100,
B01110,
B11111,
B11111,
B00000,
B00000,
};
byte down[8] = {
B00000,
B00000,
B11111,
B11111,
B01110,
B00100,
B00000,
};
lcd.createChar(0,bar1);
lcd.createChar(1,bar2);
lcd.createChar(2,bar3);
lcd.createChar(3,bar4);
lcd.createChar(4,bar5);
lcd.createChar(5,up);
lcd.createChar(6,down);
}
void loop(){
menuPrincipal();
}
void keypadEvent(KeypadEvent key){
switch (keypad.getState()){
case RELEASED:
switch (key){
case 'd': defusing=false;
break;
case 'c': cancelando=false;
break;
}
break;
case HOLD:
switch (key){
case 'd': defusing= true;
break;
case 'c': cancelando=true;
break;
}
break;
}
}
// MENU
char* menu1[]={"Demolition","Domination","Respaw","Thief"};
char* GAME_TIME="Game Time:";
char* BOMB_TIME="Bomb Time:";
char* ZERO_MINUTES="00 minutes";
char* ARM_TIME="Arm Time:";
char* ZERO_SECS="00 seconds";
char* ENABLE_SOUND="Enable Sound?";
char* YES_OR_NOT="A : Yes B : No";
char* ENABLE_RELAYPIN="Enable Relay?";
char* ENABLE_CODE="Enable Code Arm?";
char* GAME_TIME_TOP="GAME TIME";
char* ARMING_BOMB = "ARMING BOMB";
char* ENTER_CODE = "Enter Code";
char* CODE_ERROR = "Code Error!";
char* BOMB_ARMED = "BOMB ARMED";
char* DETONATION_IN = "DETONATION IN";
char* DISARMING = "DISARMING BOMB" ;
char* DISARM = "DISARMING";
char* GAME_OVER = " GAME OVER! ";
char* DEFENDERS_WIN = " DEFENDERS WIN ";
char* SABOTAGE_FAIL= "SABOTAGE FAIL!";
//##################MENUS###############################
void menuPrincipal(){ //MAIN MENU
digitalWrite(GREENLED, LOW);
digitalWrite(REDLED, LOW);
sdStatus=false;
doStatus=false;
cls();
int i=0;
lcd.print(menu1[i]);
lcd.setCursor(15,1);
checkArrows(i,4);
while(1){
var = keypad.waitForKey();
if(var == BT_UP && i>0){
tone(tonepin,2400,30);
i--;
cls();
lcd.print(menu1[i]);
checkArrows(i,4);
delay(50);
}
if(var == BT_DOWN && i<3){
tone(tonepin,2400,30);
i++;
cls();
lcd.print(menu1[i]);
checkArrows(i,3);
delay(50);
}
if(var == BT_SEL){
tone(tonepin,2400,30);
cls();
switch (i){
case 0:
sdStatus=true;
configQuickGame();
startGameCount();
search();
break;
case 1:
doStatus=true;
configQuickGame();
startGameCount();
domination();
break;
case 2:
clikerStatus=true;
configClicker();
startGameCount();
configClicker();
break;
case 3:
thiefStatus = true;
configThief();
startGameCount();
thief();
break;
}
}
}
}
void configQuickGame(){
cls();
//GAME TIME
if(sdStatus || doStatus){
menu1:
cls();
lcd.print(GAME_TIME);
delay(100);
lcd.setCursor(0,1);
lcd.print("00:00 hh:mm");
lcd.cursor();
lcd.blink();
lcd.setCursor(0,1);
byte var2=0;
for(int i=0;i<4;i++){
while(1){
if(i==2 && var2==0){
lcd.print(":");
var2=1;
}
byte varu= getRealNumber();
if(varu !=11){
time[i] = varu;
Serial.print(varu);
lcd.print(varu);
tone(tonepin,2400,30);
break;
}
}
}
lcd.noCursor();
lcd.noBlink();
lcd.setCursor(13,1);
lcd.print("ok?");
while(1){
var = keypad.waitForKey();
if(var == 'd') // Accept
{
tone(tonepin,2400,30);
GAMEMINUTES= ((time[0]*600)+(time[1]*60)+(time[2]*10)+(time[3]));
break;
}
if(var == 'c') // Cancel or Back Button :')
{
tone(tonepin,2400,30);
goto menu1;
}
}
tone(tonepin,2400,30);
cls();
}
//BOMB TIME
if(sdStatus){
menu2:
cls();
lcd.print(BOMB_TIME);
delay(100);
lcd.setCursor(0,1);
lcd.print(ZERO_MINUTES);
lcd.cursor();
lcd.blink();
lcd.setCursor(0,1);
for(int i=0;i<2;i++){
while(1){
byte varu= getRealNumber();
if(varu !=11){
time[i] = varu;
lcd.print(varu);
tone(tonepin,2400,30);
break;
}
}
}
lcd.noCursor();
lcd.noBlink();
lcd.setCursor(13,1);
lcd.print("ok?");
while(1){
var = keypad.waitForKey();
if(var == 'd') //
{
tone(tonepin,2400,30);
BOMBMINUTES= ((time[0]*10)+(time[1]));
break;
}
if(var == 'c') // Cancel or Back Button :')
{
tone(tonepin,2400,30);
goto menu2;
}
}
tone(tonepin,2400,30);
cls();
}
cls();
//ARMING TIME
if(sdStatus || doStatus){
menu3:
cls();
lcd.print(ARM_TIME);
delay(100);
lcd.setCursor(0,1);
lcd.print(ZERO_SECS);
lcd.cursor();
lcd.blink();
lcd.setCursor(0,1);
for(int i=0;i<2;i++){
while(1){
byte varu= getRealNumber();
if(varu !=11){
time[i] = varu;
lcd.print(varu);
tone(tonepin,2400,30);
break;
}
}
}
lcd.noCursor();
lcd.noBlink();
lcd.setCursor(13,1);
lcd.print("ok?");
while(1){
var = keypad.waitForKey();
if(var == 'd') // Accept
{
tone(tonepin,2400,30);
ACTIVATESECONDS= ((time[0]*10)+(time[1]));
break;
}
if(var == 'c') // Cancel or Back Button :')
{
tone(tonepin,2400,30);
goto menu3;
}
}
tone(tonepin,2400,30);
cls();
}
//sound??
if(sdStatus || doStatus){
cls();
lcd.print(ENABLE_SOUND);
lcd.setCursor(0,1);
lcd.print(YES_OR_NOT);
while(1)
{
var = keypad.waitForKey();
if(var == 'a' ){
soundEnable=true;
tone(tonepin,2400,30);
break;
}
if(var == 'b' ){
soundEnable=false;
tone(tonepin,2400,30);
break;
}
}
}
//Activate RELAY at Terrorist game ends??? Boom!
if(sdStatus){
cls();
lcd.print(ENABLE_RELAYPIN);
lcd.setCursor(0,1);
lcd.print(YES_OR_NOT);
while(1)
{
var = keypad.waitForKey();
if(var == 'a' ){
relayEnable=true;
tone(tonepin,2400,30);
break;
}
if(var == 'b' ){
relayEnable=false;
tone(tonepin,2400,30);
break;
}
}
}
//You Want a password enable-disable game?
if(sdStatus){
cls();
lcd.print(ENABLE_CODE);
lcd.setCursor(0,1);
lcd.print(YES_OR_NOT);
while(1)
{
var = keypad.waitForKey();
if(var == 'a' ){
tone(tonepin,2400,30);
setNewPass();
passwordEnable = true;
break;
}
if(var == 'b' ){
tone(tonepin,2400,30);
passwordEnable = false;
break;
}
}
tone(tonepin,2400,30);
}
}
//This fuction compare codeInput[8] and password[8] variables
boolean comparePassword(){
for(int i=0;i<6;i++){
if(codeInput[i]!=password[i])return false;
}
return true;
}
//Set the password variable
void setCode(){
lcd.setCursor(0, 1);
for(int i=0;i<6;i++){
while(1){
var= getNumber();
if(var !='x'){
codeInput[i] = var;
lcd.setCursor(i,1);
lcd.print(var);
delay(50);
lcd.setCursor(i,1);
lcd.print("*");
tone(tonepin,2400,30);
break;
}
}
}
}
void setCodeTime(){
timeCalcVar=millis();
unsigned long lastRefresh = 0;
for(int i=0;i<6;i++){
while(1){
if(ACTIVATESECONDS*1000+timeCalcVar-millis()<=100){
codeInput[i]='x';
break;
}
if(millis() - lastRefresh > 100)
{
lastRefresh = millis();
lcd.setCursor(11,0);
printTimeDom(
ACTIVATESECONDS*1000 + timeCalcVar - millis(),
false
);
}
var= getNumber();
if(var !='x'){
codeInput[i] = var;
lcd.setCursor(i,1);
lcd.print(var);
delay(50);
lcd.setCursor(i,1);
lcd.print("*");
tone(tonepin,2400,30);
break;
}
}
}
}
void setPass(){
lcd.setCursor(0, 1);
for(int i=0;i<6;i++){
while(1){
var= getNumber();
if(var !='x'){
password[i] = var;
lcd.setCursor(i,1);
lcd.print(var);
delay(50);
lcd.setCursor(i,1);
lcd.print("*");
tone(tonepin,2400,30);
break;
}
}
}
}
void setNewPass(){
while(1){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Enter New Pass");
setPass();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Retype Pass");
setCode();
if(comparePassword()){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Password Set OK!");
delay(2000);
break;
}
else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ERROR Dont Match!");
if(soundEnable)tone(tonepin,errorTone,200);
delay(2000);
}
}
}
char getNumber(){
while(1){
var = keypad.getKey();
if (var){//
switch (var) {
case 'a':
return 'x';
break;
case 'b':
return 'x';
break;
case 'c':
return 'x';
break;
case 'd':
return 'x';
break;
case '*':
return 'x';
break;
case '#':
return 'x';
break;
default:
return var;
break;
}
}
return 'x';
}
}
byte getRealNumber(){
while(1){
var = keypad.waitForKey();
if (var){//
switch (var) {
case '1':
return 1;
break;
case '2':
return 2;
break;
case '3':
return 3;
break;
case '4':
return 4;
break;
case '5':
return 5;
break;
case '6':
return 6;
case '7':
return 7;
break;
case '8':
return 8;
break;
case '9':
return 9;
break;
case '0':
return 0;
break;
default:
return 11;
break;
}
}
return 11;
}
}
void drawBar(byte porcent){
static byte oldPercent = 255;
if(oldPercent == porcent)
return;
oldPercent = porcent;
int box=(8*porcent)/10;
lcd.setCursor(0,1);
while(box>=5){
lcd.write(4);
box-=5;
}
switch(box){
case 0: break;
case 1: lcd.write((uint8_t)0); break;
case 2: lcd.write(1); break;
case 3: lcd.write(2); break;
case 4: lcd.write(3); break;
}
}
void cls(){
lcd.clear();
lcd.setCursor(0,0);
}
void printTime(unsigned long minutos, unsigned long aTiempo){
timeCalcVar=minutos-aTiempo/60000;
//Hours
if(timeCalcVar/60==0 && refresh){
lcd.clear();
refresh=false;
//delay(100);
lcd.setCursor(3,1);
Serial.println("!!!!");
}
if(timeCalcVar/60>=1){
if(timeCalcVar/60<10)
{
lcd.setCursor(2,1);
lcd.print("0");
lcd.print(timeCalcVar/60);
}
else
{
lcd.print(timeCalcVar/60);
}
lcd.print(":");
}
//minutes
if(timeCalcVar%60<10)
{
lcd.print("0");
lcd.print(timeCalcVar%60);
}
else
{
lcd.print(timeCalcVar%60);
}
lcd.print(":");
//seconds
timeCalcVar=aTiempo/1000;
if(59-(timeCalcVar%60)<10)
{
lcd.print("0");
lcd.print(59-(timeCalcVar%60));
}
else
{
lcd.print(59-(timeCalcVar%60));
}
lcd.print(":");
lcd.print(999-(millis()%1000));
}
void printTimeDom(unsigned long aTiempo, boolean showMillis){
if((aTiempo/60000)<10)
{
lcd.print("0");
lcd.print(aTiempo/60000);
}
else
{
lcd.print(aTiempo/60000);
}
lcd.print(":");
//seconds
if(((aTiempo/1000)%60)<10)
{
lcd.print("0");
lcd.print((aTiempo/1000)%60);
}
else
{
lcd.print((aTiempo/1000)%60);
}
if(showMillis){
lcd.print(":");
lcd.print(999-millis()%1000);
}
}
void startGameCount(){
gameStartTime = millis();
endGame = false;
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Ready to Begin");
lcd.setCursor(0,1);
lcd.print("Push ANY Button");
keypad.waitForKey();//if you press a button game start
cls();
lcd.setCursor(1,0);
lcd.print("Starting Game");
for(int i = 5; i > 0 ; i--){ // START COUNT GAME INIT
lcd.setCursor(5,1);
tone(tonepin,2000,100);
lcd.print("IN ");
lcd.print(i);
delay(1000);
}
cls();
}
void checkArrows(byte i, byte maxx ){
lcd.setCursor(15,0);
lcd.print(" ");
lcd.setCursor(15,1);
lcd.print(" ");
if(i > 0){
lcd.setCursor(15,0);
lcd.write(5); // flèche haut
}
if(i < maxx){
lcd.setCursor(15,1);
lcd.write(6); // flèche bas
}
}
void activateRelay(){
digitalWrite(RELAYPIN, HIGH);
delay(RELAY_TIME);
digitalWrite(RELAYPIN, LOW);
}
void explodeSplash(){
digitalWrite(REDLED, LOW);
digitalWrite(GREENLED, LOW);
cls();
delay(100);
endGame = false;
lcd.setCursor(1,0);
lcd.print("TERRORISTS WIN");
lcd.setCursor(4,1);
lcd.print("GAME OVER");
for(int i = 200; i>0; i--)// this is the ultra hi definition explosion sound xD
{
tone(tonepin,i);
delay(20);
}
noTone(tonepin);
if(relayEnable){
activateRelay();
}
delay(5000);
cls();
//end code
lcd.print("Play Again?");
lcd.setCursor(0,1);
lcd.print("A : Yes B : No");
while(1)
{
var = keypad.waitForKey();
if(var == 'a' ){
tone(tonepin,2400,30);
if(sdStatus){
startGameCount();
search();
}
}
if(var == 'b' ){
tone(tonepin,2400,30);
menuPrincipal();
break;
}
}
}
void failSplash(){
digitalWrite(REDLED, LOW);
digitalWrite(GREENLED, LOW);
cls();
delay(100);
endGame = false;
lcd.setCursor(1,0);
lcd.print(" TIME OUT");
lcd.setCursor(4,1);
lcd.print("GAME OVER");
for(int i = 200; i>0; i--)// this is the ultra hi definition explosion sound xD
{
tone(tonepin,i);
delay(20);
}
noTone(tonepin);
if(relayEnable){
for(int i = 0; i < 4; i++){
digitalWrite(RELAYPIN, HIGH);
delay(200);
digitalWrite(RELAYPIN, LOW);
delay(500);
}
}
delay(5000);
cls();
//end code
lcd.print("Play Again?");
lcd.setCursor(0,1);
lcd.print("A : Yes B : No");
while(1)
{
var = keypad.waitForKey();
if(var == 'a' ){
tone(tonepin,2400,30);
if(sdStatus){
startGameCount();
search();
}
}
if(var == 'b' ){
tone(tonepin,2400,30);
menuPrincipal();
break;
}
}
}void disarmedSplash(){
endGame = false;
digitalWrite(REDLED, LOW);
digitalWrite(GREENLED, LOW);
if(sdStatus){
lcd.clear();
lcd.setCursor(2,0);
lcd.print("BOMB DISARMED");
lcd.setCursor(3,1);
lcd.print("GOODS WIN");
digitalWrite(GREENLED, HIGH);
delay(5000);
digitalWrite(GREENLED, LOW);
}
//end code
lcd.clear();
lcd.print("Play Again?");
lcd.setCursor(0,1);
lcd.print("A : Yes B : No");
digitalWrite(REDLED, LOW);
digitalWrite(GREENLED, LOW);
while(1)
{
var = keypad.waitForKey();
if(var == 'a' ){
tone(tonepin,2400,30);
if(sdStatus){
startGameCount();
search();
}
}
if(var == 'b' ){
tone(tonepin,2400,30);
menuPrincipal();
break;
}
}
}
void search() {
refresh = true;
cls();
digitalWrite(REDLED, LOW);
digitalWrite(GREENLED, LOW);
//SETUP INITIAL TIME
int minutos = GAMEMINUTES - 1;
unsigned long iTime = millis(); // initialTime in millisec
unsigned long aTime;
//var='o';
//Starting Game Code
while (1) { // this is the important code, is a little messy but works good.
if (millis() - gameStartTime >= GAMEMINUTES * 60000UL) {
failSplash();
}
//If you fail disarm.
if (endGame) {
failSplash();
}
//Code for led blinking
timeCalcVar = (millis() - iTime) % 1000;
if (timeCalcVar >= 0 && timeCalcVar <= 50)digitalWrite(GREENLED, HIGH);
if (timeCalcVar >= 90 && timeCalcVar <= 130)digitalWrite(GREENLED, LOW);
static unsigned long lastLCD = 0;
aTime = millis() - iTime;
if(millis() - lastLCD >= 100)
{
lastLCD = millis();
lcd.setCursor(3,0);
lcd.print(GAME_TIME_TOP);
lcd.setCursor(3,1);
printTime(minutos,aTime);
}
//###########################CHECKINGS##################
//Check If Game End
if (minutos - aTime / 60000 == 0 && 59 - ((aTime / 1000) % 60) == 0)failSplash();
if ('d' == keypad.getKey() && passwordEnable) {
lcd.clear();
lcd.setCursor(2, 0);
lcd.print(ARMING_BOMB);
delay(1000);//a little delay to think in the password
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(ENTER_CODE);
setCodeTime();
if (comparePassword()) {
destroy();
return;
}
lcd.clear();
lcd.setCursor(3, 0);
lcd.print(CODE_ERROR);
if (soundEnable) tone(tonepin, errorTone, 200);
delay(500);
cls();
}
//Check If Is Activating
while (defusing && !passwordEnable)
{
digitalWrite(GREENLED, LOW);
lcd.clear();
lcd.setCursor(2, 0);
lcd.print(ARMING_BOMB);
lcd.setCursor(0, 1);
unsigned int percent = 0;
unsigned long xTime = millis(); //start disabling time
while (defusing)
{
keypad.getKey();
percent = (millis() - xTime) / (ACTIVATESECONDS * 10);
drawBar(percent);
//check if game time runs out during the disabling
aTime = millis() - iTime;
Serial.println(millis()-xTime);
if ((minutos - aTime / 60000 == 0 && 59 - ((aTime / 1000) % 60) == 0) || minutos - aTime / 60000 > 4000000000) {
endGame = true;
}
timeCalcVar = (millis() - xTime) % 1000;
if ( timeCalcVar >= 0 && timeCalcVar <= 40)
{
digitalWrite(REDLED, HIGH);
if (soundEnable)tone(tonepin, alarmTone1, 200);
}
if (timeCalcVar >= 480 && timeCalcVar <= 520)
{
if (soundEnable)tone(tonepin, alarmTone2, 200);
digitalWrite(REDLED, LOW);
}
if (percent >= 100)
{
digitalWrite(GREENLED, LOW);
destroy();// jump to the next gamemode
}
}
cls();
digitalWrite(REDLED, LOW);
}
}
}
void destroy() {
lcd.clear();
lcd.setCursor(3, 0);
lcd.print(BOMB_ARMED);
delay(1000);
int minutos = BOMBMINUTES - 1;
unsigned long iTime = millis();
unsigned long aTime;
// RESET erreurs
errorCount = 0;
speedFactor = 1;
penaltyTime = 0;
unsigned long lastBeep = 0;
unsigned long lastLcdUpdate = 0;
while (1) {
if (endGame) {
explodeSplash();
}
unsigned long realTime = (millis() - iTime) * speedFactor;
aTime = realTime + penaltyTime;
unsigned long tempsBombe = BOMBMINUTES * 60000UL;
if (aTime >= tempsBombe) {
explodeSplash();
}
// BIP synchronisé avec la vitesse
unsigned long interval = 1000UL / speedFactor;
if (soundEnable && millis() - lastBeep >= interval) {
lastBeep = millis();
digitalWrite(REDLED, HIGH);
tone(tonepin, activeTone, 40);
}
if (millis() - lastBeep > 50) {
digitalWrite(REDLED, LOW);
}
// LCD rafraîchi seulement toutes les 100 ms
if (millis() - lastLcdUpdate >= 100) {
lastLcdUpdate = millis();
lcd.setCursor(1, 0);
lcd.print(DETONATION_IN);
lcd.setCursor(3, 1);
printTime(minutos, aTime);
}
// CODE
if ('d' == keypad.getKey() && passwordEnable) {
lcd.clear();
lcd.setCursor(1, 0);
lcd.print(DISARMING);
delay(800);
lcd.clear();
lcd.print(ENTER_CODE);
setCodeTime();
if (comparePassword()) {
disarmedSplash();
}
errorCount++;
if (errorCount == 1) {
penaltyTime += 20000;
lcd.clear();
lcd.print("ERREUR 1");
lcd.setCursor(0,1);
lcd.print("-20 SECONDES");
tone(tonepin, errorTone, 300);
delay(1200);
}
else if (errorCount == 2) {
speedFactor = 6;
lcd.clear();
lcd.print("ERREUR 2");
lcd.setCursor(0,1);
lcd.print("VITESSE x6");
tone(tonepin, 900, 300);
delay(1200);
}
else if (errorCount >= 3) {
lcd.clear();
lcd.print("3 ERREURS !");
lcd.setCursor(0,1);
lcd.print("BOOM !!!");
delay(1000);
explodeSplash();
return;
}
lcd.clear();
lcd.setCursor(3,0);
lcd.print(CODE_ERROR);
delay(500);
cls();
}
// DISARM physique
if (defusing && !passwordEnable) {
lcd.clear();
digitalWrite(REDLED, LOW);
lcd.setCursor(3,0);
lcd.print(DISARM);
unsigned long xTime = millis();
while (defusing) {
keypad.getKey();
timeCalcVar = (millis() - xTime) % 1000;
if (timeCalcVar <= 40) {
digitalWrite(REDLED, HIGH);
if(soundEnable)
tone(tonepin, alarmTone1, 200);
}
if (timeCalcVar >= 480 && timeCalcVar <= 520) {
digitalWrite(REDLED, LOW);
if(soundEnable)
tone(tonepin, alarmTone2, 200);
}
unsigned long percent =
(millis() - xTime) / (ACTIVATESECONDS * 10);
drawBar(percent);
if (percent >= 100) {
digitalWrite(REDLED, LOW);
disarmedSplash();
}
}
cls();
}
}
}
void domination(){
//SETUP INITIAL TIME
int minutos = GAMEMINUTES-1;
boolean showGameTime=true;
unsigned long a;
unsigned long iTime=millis(); // initialTime in millisec
unsigned long aTime;
unsigned long lastLCD = 0;
team=0;
iZoneTime=0;
aTime=0;
redTime=0;
greenTime=0;
int largoTono = 50;
// 0 = neutral, 1 = green team, 2 = red team
a=millis();
//Starting Game Code
while(1) // this is the important code, is a little messy but works good.
{
if(endGame){
gameOver();
}
keypad.getKey();
aTime=millis()- iTime;
//Code for led blinking
timeCalcVar=(millis()- iTime)%1000;
if(timeCalcVar >= 0 && timeCalcVar <= 40)
{
if(team==1)digitalWrite(GREENLED, HIGH);
if(team==2)digitalWrite(REDLED, HIGH);
}
if(timeCalcVar >= 50 && timeCalcVar <= 100)
{
if(team==1)digitalWrite(GREENLED, LOW);
if(team==2)digitalWrite(REDLED, LOW);
}
// Sound!!! same as Destroy
if(timeCalcVar >= 0 && timeCalcVar <= 40 && soundEnable)tone(tonepin,activeTone,largoTono);
if(timeCalcVar >= 245 && timeCalcVar <= 255 && minutos-aTime/60000<2 && soundEnable)tone(tonepin,activeTone,largoTono);
if(timeCalcVar >= 495 && timeCalcVar <= 510 && minutos-aTime/60000<4 && soundEnable)tone(tonepin,activeTone,largoTono);
if(timeCalcVar >= 745 && timeCalcVar <= 760 && minutos-aTime/60000<2 && soundEnable)tone(tonepin,activeTone,largoTono);
//Help to count 3 secs
if(a+2000<millis()){
a=millis();
showGameTime=!showGameTime;
cls();
}
//THE NEXT TO METHODS SHOW "GAME TIME" AND "CONTROLED ZONE TIME" IT SHOWS 2 AND 2 SEC EACH
if(millis() - lastLCD >= 100)
{
lastLCD = millis();
if(showGameTime){
lcd.setCursor(3,0);
lcd.print("GAME TIME");
lcd.setCursor(3,1);
printTime(minutos, aTime);
}
else{
lcd.setCursor(2,0);
if(team == 0) lcd.print("NEUTRAL ZONE ");
if(team == 1) lcd.print(" BLUE ZONE ");
if(team == 2) lcd.print(" RED ZONE ");
if(team > 0){
lcd.setCursor(3,1);
printTimeDom(millis()-iZoneTime,true);
}
}
}
//###########################CHECKINGS##################
//Check If Game End
if(minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0)
{
gameOver();
}
//Check If IS neutral
while((defusing || cancelando) && team > 0)
{
cls();
if(team>0)lcd.print("NEUTRALIZING...");
lcd.setCursor(0,1);
unsigned int percent=0;
unsigned long xTime=millis(); //start disabling time
while(defusing || cancelando)
{
//check if game time runs out during the disabling
aTime= millis()- iTime;
if((minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0) || minutos-aTime/60000>4000000000){
endGame = true;
}
keypad.getKey();
timeCalcVar = (millis()- xTime)%1000;
if( timeCalcVar >= 0 && timeCalcVar <= 20)
{
if(soundEnable)tone(tonepin,alarmTone1,200);
}
if(timeCalcVar >= 480 && timeCalcVar <= 500)
{
if(soundEnable)tone(tonepin,alarmTone2,200);
digitalWrite(REDLED, LOW);
}
unsigned long seconds= millis() - xTime;
percent = (seconds)/(ACTIVATESECONDS*10);
drawBar(percent);
if(percent >= 100)
{
delay(1000);
if(team==1){
greenTime+=millis()-iZoneTime;
iZoneTime=0;
}
if(team==2){
redTime+=millis()-iZoneTime;
iZoneTime=0;
}
team=0;
break;
}
}
cls();
}
//Capturing red
while(defusing && team == 0 )
{
cls();
if(team==0)lcd.print(" CAPTURING ZONE");
lcd.setCursor(0,1);
unsigned int percent=0;
unsigned long xTime=millis(); //start disabling time
while(defusing)
{
keypad.getKey();
//check if game time runs out during the disabling
aTime= millis()- iTime;
if((minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0) || minutos-aTime/60000>4000000000){
endGame = true;
}
timeCalcVar = (millis()- xTime)%1000;
if( timeCalcVar >= 0 && timeCalcVar <= 20)
{
digitalWrite(REDLED, HIGH);
if(soundEnable)tone(tonepin,alarmTone1,200);
}
if(timeCalcVar >= 480 && timeCalcVar <= 500)
{
if(soundEnable)tone(tonepin,alarmTone2,200);
digitalWrite(REDLED, LOW);
}
unsigned long seconds= millis() - xTime;
percent = (seconds)/(ACTIVATESECONDS*10);
drawBar(percent);
if(percent >= 100)
{
digitalWrite(GREENLED, LOW);
team=2;
iZoneTime=millis();
delay(1000);
break;
}
}
cls();
digitalWrite(REDLED, LOW);
}
//getting to green zone
while(cancelando && team == 0 )
{
cls();
if(team==0)lcd.print(" CAPTURING ZONE");
lcd.setCursor(0,1);
unsigned int percent=0;
unsigned long xTime=millis(); //start disabling time
while(cancelando)
{
keypad.getKey();
//check if game time runs out during the disabling
aTime= millis()- iTime;
if((minutos-aTime/60000==0 && 59-((aTime/1000)%60)==0) || minutos-aTime/60000>4000000000){
endGame = true;
}
timeCalcVar = (millis()- xTime)%1000;
if( timeCalcVar >= 0 && timeCalcVar <= 20)
{
digitalWrite(GREENLED, HIGH);
if(soundEnable)tone(tonepin,alarmTone1,200);
}
if(timeCalcVar >= 480 && timeCalcVar <= 500)
{
if(soundEnable)tone(tonepin,alarmTone2,200);
digitalWrite(GREENLED, LOW);
}
unsigned long seconds= millis() - xTime;
percent = (seconds)/(ACTIVATESECONDS*10);
drawBar(percent);
if(percent >= 100)
{
digitalWrite(GREENLED, LOW);
team=1;
iZoneTime=millis();
delay(1000);
break;
}
}
cls();
digitalWrite(GREENLED, LOW);
}
}
}
void gameOver(){
if(team==1)greenTime+=millis()-iZoneTime;
if(team==2)redTime+=millis()-iZoneTime;
digitalWrite(GREENLED, LOW);
digitalWrite(REDLED, LOW);
// 🔴 CLIGNOTEMENT RELAIS 4 FOIS AVANT LES SCORES
for(int i = 0; i < 4; i++){
digitalWrite(RELAYPIN, HIGH);
delay(200);
digitalWrite(RELAYPIN, LOW);
delay(500);
}
while(!defusing){
keypad.getKey();
lcd.clear();
lcd.setCursor(3,0);
lcd.print("TIME OVER!");
lcd.setCursor(0,1);
// check winner
if(greenTime > redTime){
lcd.print(" BLUE TEAM WINS");
digitalWrite(GREENLED, HIGH);
}
else if(redTime > greenTime){
lcd.print(" RED TEAM WINS");
digitalWrite(REDLED, HIGH);
}
else{
lcd.print(" DRAW");
digitalWrite(GREENLED, HIGH);
digitalWrite(REDLED, HIGH);
}
delay(3000);
keypad.getKey();
if(defusing){
keypad.getKey();
break;
}
cls();
lcd.print("Red Time:");
lcd.setCursor(5,1);
printTimeDom(redTime,false);
delay(3000);
keypad.getKey();
if(defusing){
break;
}
cls();
lcd.print("Blue Time:");
lcd.setCursor(5,1);
printTimeDom(greenTime,false);
delay(3000);
keypad.getKey();
if(defusing){
keypad.getKey();
break;
}
}
cls();
delay(100);
lcd.print("Play Again?");
lcd.setCursor(0,1);
lcd.print("A : Yes B : No");
while(1)
{
var = keypad.waitForKey();
if(var == 'a' ){
tone(tonepin,2400,30);
cls();
domination();
break;
}
if(var == 'b' ){
tone(tonepin,2400,30);
menuPrincipal();
break;
}
}
}//################## CLIKER ###############################
void configClicker() {
cls();
lcd.print("NB RESPAWN");
keypad.getKey();
noTone(tonepin);
lcd.setCursor(0,1);
lcd.cursor();
lcd.blink();
int dizaines;
int unites;
char k;
RETRY:
lcd.clear();
lcd.print("NB RESPAWN:");
lcd.setCursor(0,1);
while (true) {
k = keypad.waitForKey();
if (k >= '0' && k <= '9') {
tone(tonepin, 2000, 30);
dizaines = k - '0';
lcd.print(dizaines);
break;
}
}
while (true) {
k = keypad.waitForKey();
if (k >= '0' && k <= '9') {
tone(tonepin, 2000, 30);
unites = k - '0';
lcd.print(unites);
break;
}
}
CLICK_TARGET = dizaines * 10 + unites;
if (CLICK_TARGET < 10) {
lcd.clear();
lcd.print("MIN 10 RESPAWN");
delay(1200);
goto RETRY;
}
lcd.setCursor(0,1);
lcd.print(CLICK_TARGET);
lcd.print(" ");
lcd.setCursor(13,1);
lcd.print("ok?");
while (true) {
char k = keypad.waitForKey();
if (k == 'd') {
tone(tonepin, 2000, 50);
break;
}
if (k == 'c') {
tone(tonepin, 1200, 50);
goto RETRY;
}
}
delay(500);
lcd.noCursor();
lcd.noBlink();
cls();
lcd.print("Relay ON ?");
lcd.setCursor(0,1);
lcd.print("A:Yes B:No");
while (true) {
char k = keypad.waitForKey();
if (k == 'a') {
tone(tonepin, 2000, 50);
relayEnable = true;
break;
}
if (k == 'b') {
tone(tonepin, 1200, 50);
relayEnable = false;
break;
}
}
clickCount = 0;
while (true) {
lcd.setCursor(0,0);
lcd.print("CLICS: ");
lcd.print(clickCount);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print(" ");
char key = keypad.getKey();
if (key == 'd') {
clickCount++;
tone(tonepin, 1800, 50);
// 🔴 LED + message EN MÊME TEMPS
digitalWrite(REDLED, HIGH);
lcd.setCursor(0,1);
lcd.print("+1 RESPAWN");
unsigned long msgStart = millis();
while (millis() - msgStart < 1000) {
lcd.setCursor(0,0);
lcd.print("CLICS: ");
lcd.print(clickCount);
lcd.print(" ");
char k2 = keypad.getKey();
if (k2 == 'd') break;
delay(30);
}
// 🔴 LED OFF après le message
digitalWrite(REDLED, LOW);
lcd.setCursor(0,1);
lcd.print(" ");
if (clickCount >= CLICK_TARGET) {
cls();
lcd.setCursor(1,0);
lcd.print("! GAME OVER !");
lcd.setCursor(2,1);
lcd.print("RESPAWN FINI");
if (soundEnable) {
for (int i = 500; i > 200; i -= 40) {
tone(tonepin, 1200, 100);
delay(i);
}
for (int i = 200; i > 60; i -= 20) {
tone(tonepin, 1800, 80);
delay(i);
}
tone(tonepin, 2500);
delay(1200);
noTone(tonepin);
}
if (relayEnable) {
digitalWrite(RELAYPIN, HIGH);
delay(RELAY_TIME);
digitalWrite(RELAYPIN, LOW);
}
delay(1500);
cls();
lcd.print("REJOUER ?");
lcd.setCursor(0,1);
lcd.print("A:Oui B:Quitter");
while (true) {
char k = keypad.waitForKey();
if (k == 'a') {
tone(tonepin, 2000, 50);
configClicker();
return;
}
if (k == 'b') {
tone(tonepin, 1200, 50);
menuPrincipal();
return;
}
}
}
}
delay(40);
}
}void configThief() {
cls();
lcd.print("NB LINGOTS:");
lcd.setCursor(0,1);
String gold = "";
// ------------------------
// SAISIE DU NOMBRE D'OR
// ------------------------
while(true){
char k = keypad.waitForKey();
if(k >= '0' && k <= '9'){
if(gold.length() < 3){
gold += k;
lcd.print(k);
tone(tonepin, 2000, 30);
}
}
if(k == 'c'){
if(gold.length() > 0){
gold.remove(gold.length() - 1);
lcd.setCursor(gold.length(), 1);
lcd.print(" ");
lcd.setCursor(gold.length(), 1);
tone(tonepin, 1200, 30);
}
}
// ✅ VALIDATION DIRECTE (MODIF ICI)
if(k == 'd'){
tone(tonepin, 2000, 80);
delay(200);
GOLD_TARGET = gold.toInt();
if(GOLD_TARGET < 1) GOLD_TARGET = 1;
break;
}
}
delay(300);
// ------------------------
// TEMPS VOL
// ------------------------
cls();
lcd.print("TEMPS VOL(s)");
lcd.setCursor(0,1);
String t = "";
while(true){
char k = keypad.waitForKey();
if(k >= '0' && k <= '9'){
if(t.length() < 2){
t += k;
lcd.print(k);
tone(tonepin, 2000, 30);
}
}
if(k == 'c'){
tone(tonepin, 1200, 50);
t = "";
cls();
lcd.print("TEMPS VOL(s)");
lcd.setCursor(0,1);
}
if(k == 'd'){
tone(tonepin, 2000, 50);
THIEF_TIME = t.toInt();
if(THIEF_TIME < 1) THIEF_TIME = 1;
break;
}
}
delay(300);
// ------------------------
// RELAIS ON/OFF
// ------------------------
cls();
lcd.print("Relay ON ?");
lcd.setCursor(0,1);
lcd.print("A:Yes B:No");
while(true){
char k = keypad.waitForKey();
if(k == 'a'){
relayEnable = true;
tone(tonepin, 2000, 50);
break;
}
if(k == 'b'){
relayEnable = false;
tone(tonepin, 1200, 50);
break;
}
}
delay(300);
cls();
lcd.print("OK GAME READY");
tone(tonepin, 2000, 100);
delay(1200);
}
void thief(){
goldRemaining = GOLD_TARGET;
unsigned long lastLCD = 0;
unsigned long lastBlink = 0;
bool redState = false;
while(1){
keypad.getKey(); // maintien état defusing
// ======================
// LED attente fluide
// ======================
if(millis() - lastBlink >= 1000){
lastBlink = millis();
redState = !redState;
digitalWrite(REDLED, redState);
}
// ======================
// LCD (rafraîchit lentement = fluide)
// ======================
if(millis() - lastLCD >= 150){
lastLCD = millis();
lcd.setCursor(0,0);
lcd.print("OR RESTANT: ");
lcd.setCursor(0,1);
lcd.print(goldRemaining);
lcd.print(" ");
}
// ======================
// FIN DE PARTIE
// ======================
if(goldRemaining <= 0){
cls();
lcd.setCursor(2,0);
lcd.print("! VICTOIRE !");
lcd.setCursor(1,1);
lcd.print("MISSION SUCCES");
if(soundEnable){
tone(tonepin, 1318, 150);
delay(180);
tone(tonepin, 1567, 150);
delay(180);
tone(tonepin, 1760, 200);
delay(250);
tone(tonepin, 2093, 300);
delay(350);
tone(tonepin, 2637, 500);
delay(600);
noTone(tonepin);
}
if(relayEnable){
digitalWrite(RELAYPIN, HIGH);
delay(RELAY_TIME);
digitalWrite(RELAYPIN, LOW);
}
delay(1500);
cls();
lcd.print("Rejouer ?");
lcd.setCursor(0,1);
lcd.print("A:Oui B:Menu");
while(1){
char k = keypad.waitForKey();
if(k == 'a'){
tone(tonepin, 2000, 50);
configThief();
thief();
return;
}
if(k == 'b'){
tone(tonepin, 1200, 50);
menuPrincipal();
return;
}
}
}
// ======================
// VOL D'OR (OPTIMISÉ)
// ======================
if(defusing){
cls();
lcd.print("RAMASSAGE OR");
unsigned long start = millis();
unsigned long duration = THIEF_TIME * 1000UL;
unsigned long lastBeep = 0;
while(defusing){
keypad.getKey();
// LED rapide EXACTEMENT comme avant
timeCalcVar = millis() % 200;
if(timeCalcVar < 100) digitalWrite(REDLED, HIGH);
else digitalWrite(REDLED, LOW);
// SON EXACT mais mieux cadencé
if(soundEnable){
unsigned long elapsed = millis() - start;
unsigned long interval = map(elapsed, 0, duration, 500, 100);
if(millis() - lastBeep >= interval){
lastBeep = millis();
tone(tonepin, random(1400, 2400), 35);
}
}
// BARRE
unsigned int percent = (millis() - start) * 100 / duration;
drawBar(percent);
if(percent >= 100){
noTone(tonepin);
goldRemaining--;
digitalWrite(REDLED, LOW);
cls();
lcd.print("-1 LINGOT");
digitalWrite(GREENLED, HIGH);
tone(tonepin, 2000, 200);
delay(1000);
digitalWrite(GREENLED, LOW);
delay(200);
break;
}
}
noTone(tonepin);
digitalWrite(REDLED, LOW);
digitalWrite(GREENLED, LOW);
cls();
}
delay(50); // 🔥 IMPORTANT: fluidité globale
}
}