BattleScriptBattleScriptBattleScriptBattleScript
BrowseUploadDocumentationCompiler / Decompiler

BattleScript

A programming language for creating games and control scripts for the BattleCore laser tag system. Created with love ❤️ by Irrelon Software Limited.

The BattleCore laser tag system is currently in development and you can follow the progress over on our Facebook group.

For business development, media or other queries, please contact us at contact@irrelon.com

Links

  • Browse Scripts
  • Upload Script
  • Documentation
  • Online Compiler

Resources

  • Getting Started
  • API Reference
  • Examples
Terms of ServicePrivacy Policy

© 2026 Irrelon Software Limited. All rights reserved.

Home › Browse › Script Details
← Back to Browse

Slayer Classic

By Rob Evans • 10/5/2025

0

Description

This is a free-for-all "5 lives and out" style game. Last one standing wins!

Tags

slayerbeta

Script Content

include "./protocol_p2p.bst";
include "./protocol_swaptx_ir.bst";
include "./battlecore/audio.bst";
include "./battlecore/fsm.bst";
include "./battlecore/game.bst";
include "./battlecore/lights.bst";
include "./battlecore/player.bst";
include "./battlecore/screens.bst";
include "./battlecore/weapon.bst";

program {
	type "game";
	name "Slayer Classic";
	author "Irrelon Software Limited";
	version "1.0.1";
}

enum StateEnum {
	STARTUP = "STARTUP",
	SETUP = "SETUP",
	HOME = "HOME",
	CREATE_GAME = "CREATE_GAME",
	JOIN_GAME = "JOIN_GAME",
	JOINING_GAME = "JOINING_GAME",
	GAME_LOBBY = "GAME_LOBBY",
	OPTION_SELECT = "OPTION_SELECT",
	SETTINGS = "SETTINGS",
	PAIR_DEVICE = "PAIR_DEVICE",
	IR_LEARNING_MODE = "IR_LEARNING_MODE",
	IN_GAME = "IN_GAME",
	DEBUG = "DEBUG",
}

enum ModuleEnum {
	UNKNOWN = "UNKNOWN", // These are unknown modules, custom peripherals etc
	AUDIO = "AUDIO",
	FSM = "FSM",
	LIGHTS = "LIGHTS",
	NFC = "NFC",
	UI = "UI",
	SERIAL = "SERIAL",
	IR = "IR",
	IMU = "IMU", // Inertial Measurement Unit
	RUMBLE = "RUMBLE",
	GPS = "GPS",
	LORA = "LORA",
    P2P = "P2P",
    WIFI = "WIFI",
    BLE = "BLE",
	INPUT_TRIGGER = "INPUT_TRIGGER",
	INPUT_RELOAD = "INPUT_RELOAD",
	INPUT_AUX = "INPUT_AUX",
}

enum EventEnum {
	// FSM events
	ENTER = "ENTER",
	EXIT = "EXIT",

	// Input events
	UP = "UP",
	DOWN = "DOWN",
	PRESS = "PRESS",

	// WiFi specific events
	LOST = "LOST",
	CONNECTED = "CONNECTED",
	DISCONNECTED = "DISCONNECTED",
	AUTH_FAILED = "AUTH_FAILED",
	AUTH_SUCCEEDED = "AUTH_SUCCEEDED",

	// General events
	IN = "IN",
}

// Disable serial logging
//std::debug.setSerialLogEnabled(false);

// Tell battlecore to create digital inputs on GPIO 0, 48 and 45
//battlecore::input.createDigital(ModuleEnum.INPUT_TRIGGER, 0);
//battlecore::input.createDigital(ModuleEnum.INPUT_RELOAD, 48);
//battlecore::input.createDigital(ModuleEnum.INPUT_AUX, 45);

bool gameIsTeamBased = false;

battlecore::audio.setAudioPack("robot");
battlecore::weapon.setAmmo(5);
battlecore::weapon.setAmmoMax(5);

//every 5000 {
//	std::console.log("[BattleScript] 5 seconds passed");
//}

state StateEnum.STARTUP {
	module ModuleEnum.FSM {
		event EventEnum.ENTER (EventData evt) => {
			std::console.log("[BattleScript] Startup complete, entering HOME state");
			battlecore::fsm.setState(StateEnum.HOME);
		}
	}
}

state StateEnum.IN_GAME {
	module ModuleEnum.FSM {
		event EventEnum.ENTER (EventData evt) => {
	        std::console.log("[BattleScript] Left state: ", evt.oldState);
	        std::console.log("[BattleScript] Entering state: IN_GAME");

	        // Update the display to the IN_GAME screen
	        battlecore::screens.setScreen("IN_GAME");

	        // TODO: This is a placeholder audio track, we need to add a track for the game start
			battlecore::audio.trackStart("02 - game/001 - enemy neutralised.wav");
	    }
	}

	module ModuleEnum.INPUT_TRIGGER {
	    event EventEnum.DOWN (EventData evt) => {
	        std::console.log("[BattleScript] INPUT_TRIGGER DOWN");
	        // Check if the player is currently alive
	        // TODO: This might no longer be required. We could simply define a DEAD and RESPAWNING
	        //      state then apply logic for those states. This is more efficient and also makes
	        //      sense because both those states are going to have different screens displayed.
	        if (!battlecore::player.getIsAlive()) {
	            // Check if the player is already respawning
	            if (battlecore::player.getIsRespawning()) {
	                return;
	            }

	            // Check if player-initiated respawns are allowed
	            if (battlecore::game.getRespawnMode() == 0) {
	                // Player-initiated respawns are allowed, respawn now
	                battlecore::player.respawn();
	            }

				// Since the player is not alive, we don't want
				// to take any other action so return now
	            return;
	        }

	        // Check if we are currently busy (reloading, changing weapon etc)
	        if (battlecore::weapon.getIsBusy()) {
	            std::console.log("[BattleScript] Weapon busy");
	            return;
	        }

			// Check if we have enough ammo
			if (battlecore::weapon.getAmmo() == 0) {
				std::console.log("[BattleScript] No ammo");
				// We don't have enough ammo, so don't fire, play out of ammo sound
				int i = std::math.randomInt(0, 2);

				if (i == 0) {
					battlecore::audio.trackStart("03 - shots/008 - dry shot1.wav");
				} else if (i == 1) {
					battlecore::audio.trackStart("03 - shots/009 - dry shot2.wav");
				} else {
					battlecore::audio.trackStart("03 - shots/010 - dry shot3.wav");
				}

				battlecore::lights.flash(255, 0, 97, 60, 1);
				return;
			}

			// Check if the current weapon is charge-based or shot-based
			if (battlecore::weapon.getIsChargeBased()) {
				// Weapon is charge based, start charging
				battlecore::weapon.setIsCharging(true);
				return;
			}

			// Weapon is not charge-based, fire shot
			battlecore::audio.trackStart("03 - shots/002 - sniper shot1.wav");
			battlecore::lights.sweep(255, 0, 0, 60, 200);
			battlecore::weapon.fire();
			std::console.log("[BattleScript] Firing!");
	    }

	    event EventEnum.UP (EventData evt) => {
	        // If our weapon isn't charge-based, simply return and do nothing
			if (!battlecore::weapon.getIsChargeBased()) {
				return;
			}

			// Stop charging and fire shot
			battlecore::weapon.setIsCharging(false);
			battlecore::audio.trackStart("03 - shots/007 - laser pistol shot5.wav");
	        battlecore::lights.sweep(255, 0, 0, 60, 200);
			battlecore::weapon.fire();
			std::console.log("[BattleScript] Firing!");
	    }
	}

	module ModuleEnum.INPUT_RELOAD {
		// TODO: Support gears of war style reload where timing the reload
		// to the exact bar gives you a power / damage boost on the next shot
	    event EventEnum.DOWN (EventData evt) => {
	        std::console.log("[BattleScript] INPUT_RELOAD DOWN");
	        // Check if we are currently busy (already reloading etc)
	        if (battlecore::weapon.getIsBusy()) {
	            return;
	        }

	        // Check if we are already at full ammo
	        if (battlecore::weapon.getAmmo() == battlecore::weapon.getAmmoMax()) {
	            return;
	        }

			battlecore::weapon.incrementBusyCount(1);

			// Play reload sound
			battlecore::audio.trackStart("04 - reloads/001 - pistol reload1.wav");
			battlecore::lights.sweep(0, 183, 255, 60, 608, false);

			after 608 {
				battlecore::lights.sweep(0, 183, 255, 60, 280, true);
			}

			after battlecore::weapon.getReloadDelayMs() {
				// Reload
	            battlecore::weapon.reload();
	            battlecore::weapon.decrementBusyCount(1);
			}
	    }
	}

	module ModuleEnum.IR {
		event EventEnum.IN (EventData evt) => {
	        // Check if we are playing a team-based game and if the hit came from our own team
	        if (battlecore::game.getIsTeamBased() == true && evt.teamId == battlecore::player.getTeamId()) {
	            return;
	        }

	        // Check if the hit came from our own tagger
	        if (evt.playerId == battlecore::player.getPlayerId()) {
	            return;
	        }

	        // Check if bullet is a damage type
	        if (evt.bulletTypeId == 3) {
	            battlecore::player.takeDamage(evt.hitValue);
	            return;
	        }

			// Check if bullet is a healing type
	        if (evt.bulletTypeId == 4) {
	            battlecore::player.takeHealing(evt.hitValue);
	            return;
	        }
	    }
	}
}

state StateEnum.DEBUG {
	module ModuleEnum.FSM {
		event EventEnum.ENTER (EventData evt) => {
			std::console.log("[BattleScript] Leaving state: ", evt.oldState);
			std::console.log("[BattleScript] Entering state: ", evt.newState);

			battlecore::screens.setScreen("DEBUG");
		}
	}
}

state "_" {
	module "_" {
		event "_" (EventData evt) => {
			std::console.log("[BattleScript] Event fired: ", evt.stateName, evt.moduleName, evt.eventName);
		}
	}
}