2020 has made us feel like our lives have been put on pause. 2020 has felt like a wait. We're waiting to travel again, waiting for the economy to pick up, waiting for a vaccine, waiting for life to return to some semblance of what it used to be.

But what if we don't look at 2020 that way? What if we search for the opportunity inside the obstacle? What if we try to use this uncomfortable and painful year to grow beyond what we believed possible?

X-Team is always trying to find new ways to energize and motivate its developers. We looked 2020 in the eye, decided we weren't going to sit by the sidelines, and developed a battle royale game for the X-Team Slack.

Run to the airdrop for a chance of a legendary weapon

Introducing the Arena

An X-Team Season is a period of three months full of activities designed to energize, inspire, and motivate our developers. Read our review of Season 5 to see what a full Season is like. Our battle royale game – which we call the Arena – is only one part of Season 6, but it's already become a hallmark in the history of X-Team games.

Here's how it works. At the beginning of the game, all X-Teamers start with 100 hp, no items, and no weapons. The game is broken up into rounds. Each round, every X-Teamer presses a button that triggers one of the following commands:

  • /arena-searchforweapons: search the Arena for a weapon
  • /arena-hunt: track down and deal damage to enemy players
  • /arena-hide: hide and avoid all damage from other players
  • /arena-searchforhealth: search for a health pack
  • /arena-revive: heal yourself or revive other players
  • /arena-runtoairdrop: run to an airdrop to get a unique weapon
  • /arena-status: see your hp, inventory, and whether you're visible or not
  • /arena-cheer: cheer on other players as a spectator

These eight commands create a game that's easy to understand, but intricate and really fun to play. There's more to it, too. There's a ring of fire that exposes those in hiding, bosses that slice through opponents like they're butter, and weapons... lots of different weapons.

Watch out for the flamethrower

What's the Tech Behind All This?

At the time of writing, there exists no integration or app that installs a battle royale game on a company's Slack environment. So we had to build everything from scratch. Here's what's underneath the hood. The Arena is separated into three big pieces:

  1. Slack itself. This is our front-end, if you will. It sends requests to an API and prints them so X-Teamers know what's going on as the game progresses.
  2. The Slack Arena app. This is where we tell the Slack API what to expect from us in terms of functions, webhooks, and communication. This is also where we place all our messages, dropdowns, buttons, and how we like to display them. Think of it as Slack CSS.
  3. XHQ API. This is X-Team's back-end API responsible for processing all requests coming from the Slack Arena app. The API is built with NodeJS, HapiJS, and PostgreSQL, as is the game itself, along with a few tweaks here and there.

Here's a code example of our game engine, which runs in a semi-automated fashion, dependent on the actions of the players:

private async processCheers(
    round: ArenaRound,
    actions: ArenaRoundAction[],
    transaction: Transaction
  ) {
    await Promise.all(
      actions.map(async (action) => {
        const player = action._player!;
        await setPlayerPerformanceAction(
          { field: ARENA_PLAYER_PERFORMANCE.CHEERS_GIVEN, value: 1 },
        const { targetPlayerId } = action.actionJSON;
        if (targetPlayerId) {
          const targetPlayer = await findPlayerById(targetPlayerId, false, transaction);
          await publishArenaMessage(
            GameEngineReply.playerCheerSomebody(player, targetPlayer?._user?.slackId!)
          await setPlayerPerformanceAction(
            { field: ARENA_PLAYER_PERFORMANCE.CHEERS_RECEIVED, value: 1 },
        await completeRoundAction(action, transaction);

The most difficult part of building this battle royale game was introducing the ability to roll back a round in case that was needed. Actions and operations are saved inside our database and the game runs like a living instance where each turn is stacked above the previous turn. That makes it hard to roll back a turn and recover all statuses, health, weapons found, weapons used, etc.

We solved this by using JavaScript callbacks and async/await operations that save everything and have our game engine ready to run at the end of each round. So far, although it has its pros and cons, this has worked well during both our tests and the actual events.

We wanted to challenge ourselves. We wanted to see how much further we could push ourselves to energize and motivate our community. The Arena required more programming work than most of our other events, but we wanted it to be the game where we looked 2020 in the eye and said "not today."

Last man standing