
Time 30
Every laser tag system behaves in slightly different ways, depending on what the designer thought was important. When we create our laser tag guns, we could start from scratch in terms of game specifications, or choose to make our guns compatible with another system. In this case, we have decided to make our guns compatible with the Miles Tag 2 protocol.
A reference file for the protocol can be found at https://openlasertag.org/download/miles-ii-ir-protocol-pdf/
or can be downloaded here
The Miles Tag protocol covers the following IR signals:
- Shot packet
- Message packed
- Cloning Signal
While there is much to implement, the first step is to add in all the variables, we can then program them to become functional at a later date. The Miles Tag protocol also specifies player names and teams names.
In this tutorial we will:
- Declare all the Miles Tag 2 protocol variables in our program
- Show how to display player names and team names instead of player ID numbers and team ID numbers. We will start to do this through the web interface.
Make an existing copy of the code from the last tutorial, saving it as: NodeMCU_LaserTag_S04
Declaring the Game Variables
The variables are listed in order of the Cloning Data signal. The cloning signal is part of the Miles Tag specifications that deals with how the guns perform in the game. It allows you to easily make changes to the guns to change how they behave in the game.
This code can be cut and pasted into your main program. You will notice the list of variables has significantly increased from your previous version of your program.
These variables go under your teamID and playerID variable.
// Game variables unique to Gun (later to be stored in memory)
int teamID = 4; // 0-4 0 = red, 1 = blue, 2 = yellow, 3 = green, 4 = unspecified
int playerID = 99; // 0-99 Each gun needs a unique player ID
// Game variables in order of Cloning Data (Extra details regarding Cloning data)
int volume = 0x1E; //volume is from 0-30 for the jq6500 module. (this is currently not changed by cloning data signal
int fieldID = 0x00; // 0x00 = A, 0x01 = B
int killLed = 0x3C; // Lill LED timeout in seconds
int soundSet = 0x00; // 0=Military, 1 = Sci-Fi, 2 = Silenced
int SRKDamage = 0x0F; // mapped
int SRKRange = 0x02; // mapped
int flag = 0x00; // FlagView ENABLE = 0x01 FlagRept ENABLE = 0x02 Team Display MILITARY = 0x08 Main Display PLAYER = 0x10
int myGunDamage = 0x05; //Mapped
int magSize = 0x63; // 255=unlimited
int magazines = 0x63; //202= unlimited
int fireSelect = 0x02; // 0=semi-auto, 1=Burst, 2=Full Auto
int burstSize = 0x03; // RESERVED bite, assume used for burst size. Default = 3
int roundsMin = 0x04; // Mapped // 0=250, 1=300, 2=350,..., 12 =800;
int reloadDelay = 0x03; // seconds
int IRPowerMode = 0x01; // (in/out) // 0=indoor, 1=outdoor
int range = 0x06; // Assume 6 is maximum range
int muzFlash = 0x09; // ENABLE = 0x10 Short Range Kill ENABLE = 0x02 Hit Flash ENABLE = 0x08
int respawnHealth = 0x24; // Mapped (life) // 1=1, 2=2,... 20=20, 21=25,..., 36=100 , increments of 5 to 200, increments of 50 to 72=999
int bodyArmourMin = 0x01 ;
int bodyArmourMax = 0x32;
int gameMode1 = 0xB4; //Zombie Mode ENABLE = 0x02 Friendly Fire ENABLE = 0x04 Unlimited Ammo ENABLE = 0x08 Respawn Flash ENABLE = 0x10 Flag Flash ENABLE = 0x20 Game Box RoR ENABLE = 0x40 Game Box Stay ENABLE = 0x80
int gameMode2 = 0x58; // Body Armour ENABLE = 0x02 Zombie Flash ENABLE = 0x08 Near Miss ENABLE = 0x10 Flag End ENABLE = 0x20 Ammo RoR ENABLE = 0x40
int hitDelay = 0; // Seconds
int startDelay = 0; // Seconds (may also be respawn delay)
int bleedOut = 0; // Seconds
int gameLength = 0x0C; // Minutes 0x0C = 12
int zombieLife = 0x3A; // Mapped
int zombieDamage = 8; // Mapped
int bodyArmourHeal = 2; // pts/sec
int medicBoxHealth = 0x32; // raw value
int ammoBoxClips = 0x05; // raw value
int armourBoxPoints = 0x0A; // raw value
int gameOptions = 0x7F; // Weapon RoR ENABLE = 0x08 Zombie Sounds = 0x40 Dual Muzzle ENABLE = 0x80
Adding the player and team names
It is important that each gun refers to the same player name, given a playerID. For this, we will create a function that will allow us to enter in the playerID as a number, and it will return the playerName as a string.
- Create a new tab called MilesTagNames
- Enter the following code
String playerName(int playerID){
switch (playerID){
case 0: return "Eagle"; break;
case 1: return "Joker"; break;
case 2: return "Raven"; break;
case 3: return "Sarge"; break;
case 4: return "Angel"; break;
case 5: return "Cosmo"; break;
case 6: return "Gecko"; break;
case 7: return "Blaze"; break;
case 8: return "Camo"; break;
case 9: return "Fury"; break;
case 10: return "Flash"; break;
case 11: return "Gizmo"; break;
case 12: return "Homer"; break;
case 13: return "Storm"; break;
case 14: return "Habit"; break;
case 15: return "Click"; break;
case 16: return "Ronin"; break;
case 17: return "Lucky"; break;
case 18: return "Radar"; break;
case 19: return "Blade"; break;
case 20: return "Ninja"; break;
case 21: return "Magic"; break;
case 22: return "Gonzo"; break;
case 23: return "Cobra"; break;
case 24: return "Pappy"; break;
case 25: return "Rambo"; break;
case 26: return "Snake"; break;
case 27: return "Audie"; break;
case 28: return "Sting"; break;
case 29: return "Zeena"; break;
case 30: return "Bugsy"; break;
case 31: return "Viper"; break;
case 32: return "Jewel"; break;
case 33: return "Genie"; break;
case 34: return "Logan"; break;
case 35: return "Razor"; break;
case 36: return "Slick"; break;
case 37: return "Venom"; break;
case 38: return "Rocky"; break;
case 39: return "Saber"; break;
case 40: return "Crush"; break;
case 41: return "Titan"; break;
case 42: return "Orbit"; break;
case 43: return "Vixen"; break;
case 44: return "Tank"; break;
case 45: return "Rogue"; break;
case 46: return "Sheik"; break;
case 47: return "Gizmo"; break;
case 48: return "Siren"; break;
case 49: return "Dozer"; break;
case 50: return "Micro"; break;
case 51: return "LgtMG"; break;
case 52: return "HvyMG"; break;
case 53: return "ZOOKA"; break;
case 54: return "ROCKET"; break;
case 55: return "GRNDE"; break;
case 56: return "CLYMR"; break;
case 57: return "MINE"; break;
case 58: return "BOMB"; break;
case 59: return "NUKE"; break;
default: return "Uknown"; break;
}
}
String teamName(int teamID){
switch (teamID){
case 0: return "red"; break;
case 1: return "blue"; break;
case 2: return "yellow"; break;
case 3: return "green"; break;
}
}
The web interface
Instead of using the team number and player number, we now want to display more meaningful information, such as the team colour and the player name.
- Go to the WebActions tab in your Arduino software
- We will be adding two more placeholders. PLACEHOLDER_PlayerName and PLACEHOLDER_TeamName. The return strings will be playerName(playerID) and teamName(teamID) respectfully.
- Your code for the String processor in WebActions should now look like:
String processor(const String& var){
if(var == "PLACEHOLDER_PlayerID"){
return String(playerID);
}
else if(var == "PLACEHOLDER_PlayerName"){
return playerName(playerID);
}
else if(var == "PLACEHOLDER_TeamID"){
return String(teamID);
}
else if(var == "PLACEHOLDER_TeamName"){
return teamName(teamID);
}
return String();
}
- Go to indexPage.h tab in Arduino
- Between the H1 tags, Replace PLACEHOLDER_PlayerID with PLACEHOLDER_PlayerName
<H1> Player: %PLACEHOLDER_PlayerName% Team: %PLACEHOLDER_TeamName% </H1>
Compile and test
Go to sketch –> Export Compiled Binary
Turn your NodeMCU board on and upload the saved binary through the web interface. http://[nodeMCU IP address]/update
You should now see the player name change and team colour change as you modify the variables through the web interface.

Notice the error
We allow the user to enter in up to 99 playerID through the web interface. We should limit this to 50, so we can’t set the gun name to an unknown player, or to a different type of game object. See if you can work this one out yourself. Hint, you will need to change something in the indexPage.h tab.
Christian Content
1 Corinthians 14:6–12 (HCSB) 6 But now, brothers, if I come to you speaking in other languages, how will I benefit you unless I speak to you with a revelation or knowledge or prophecy or teaching? 7 Even inanimate things that produce sounds—whether flute or harp —if they don’t make a distinction in the notes, how will what is played on the flute or harp be recognised? 8 In fact, if the trumpet makes an unclear sound, who will prepare for battle? 9 In the same way, unless you use your tongue for intelligible speech, how will what is spoken be known? For you will be speaking into the air. 10 There are doubtless many different kinds of languages in the world, and all have meaning. 11 Therefore, if I do not know the meaning of the language, I will be a foreigner to the speaker, and the speaker will be a foreigner to me. 12 So also you—since you are zealous for spiritual gifts, seek to excel in building up the church.
A common language where everyone understands each other is great. You can say something, and it can be understood clearly. Language and protocol are very similar. When we talk about the Miles Tag 2 protocol we are talking about a common language that the guns use. It specifies things such as what each number in a shot packet refers to, and things like if the shot signal had a playerID of 10, every gun would understand the player name is “Flash”. If we introduce guns into the game using a different protocol, they cannot understand each other and the game fails. You may be able to shoot, but no one would get any damage, because the IR signals become unintelligible. You might as well just be shooting into the air. Any game goals would become useless, and your guns would become just like a cheap light blaster.
You may feel it is a shame that not all laser tag guns use the same protocol, and that you could just easily add more laser tag guns into the game, regardless of their brand or where you purchased it. At least with our guns they are compatible with the Miles Tag 2 system, and potentially when you learn to program you will be able to reinterpret the code to work with other systems.
The Bible in this passage refers to people that speak different languages. It could be a language like Greek or Japanese, or even the tongues of angels. Regardless of the language spoke, Paul’s point is that in the church, we need people to be able to understand each other, otherwise as in verse 9 – you will be speaking into the air. The Church cannot perform well when we cannot understand each other. For this reason, we need to ensure we are speaking in a way that can be understood.
Churches vary so much, and sometimes even for an experienced churchgoer, entering an unfamiliar church can feel like entering a foreign land. If the practices are not explained well, it can be difficult to know what is happening, or why certain things are being done. Some churches are very good at ensuring everyone understands, while other churches simply assume you should know what is happening, and things can remain a mystery for a long time.
Some good things that churches do to help people understand are:
- Having children’s programs which use simpler language to help children to understand.
- Having before church Bible classes for people who’s 2nd language is English, in this setting people can often get familiar with the passage before the preacher speaks.
- Classes for people investigating the faith, where they can ask clarifying questions.
- Bible studies that allow people to discuss and ask questions about what was said during the Bible Talk on Sunday.
I wonder if there is anyone in your church who could benefit from having someone help them to understand what is being communicated during church. As Paul said – seek to excel in building up the church.
The conclusion to 1 cor 14 is to be eager to prophesy. You may not have the spiritual gift of prophesy, but most Christians can read God’s word, and help others to understand it. In this way we act like prophets who are the mouthpiece of God.
Communication is important. It’s needed for:
- Laser tag guns to communicate with each other for an effective game
- For people at church to be able to communicate with each other in order to have an effective church.