@Override
  public void playerJoinedLate(Player player) {
    // put this player onto one of the teams with the fewest survivors
    TeamInfo[] teams = getTeams();
    int[] teamCounts = new int[numTeams.getValue()];
    for (int i = 0; i < teamCounts.length; i++)
      teamCounts[i] = getOnlinePlayers(new PlayerFilter().team(teams[i])).size();

    TeamInfo team = allocatePlayer(player, teamCounts);
    broadcastMessage(
        new PlayerFilter().exclude(player),
        player.getName() + " has joined the " + team.getChatColor() + team.getName());
  }
    @SuppressWarnings("deprecation")
    @Override
    public void populate(World w, Random r, Chunk c) {
      if (dropOffCenter == null) {
        cDropOffX = w.getSpawnLocation().getBlockX() >> 4;
        cDropOffZ = w.getSpawnLocation().getBlockZ() >> 4;
        dropOffCenter =
            new Location(w, cDropOffX * 16 + 7, w.getSeaLevel() + 10, cDropOffZ * 16 + 7);

        cMinX = cDropOffX - 4;
        cMaxX = cDropOffX + 4;
        cMinZ = cDropOffZ - 4;
        cMaxZ = cDropOffZ + 4;
      }

      int cx = c.getX(), cz = c.getZ();
      if (cx < cMinX || cx > cMaxX || cz < cMinZ || cz > cMaxZ) return;

      // create a grassy plain around where the drop off will be, fading to the height of the
      // "underlying" world at the edges
      if (cx == cMinX || cx == cMaxX || cz == cMinZ || cz == cMaxZ) createSlope(c);
      else createFlatSurface(c);

      // generate the central drop-off point itself
      if (c.getX() == cDropOffX && c.getZ() == cDropOffZ) createDropOffPoint(c);

      // generate spawn points for each team
      TeamInfo[] teams = getTeams();
      for (int teamNum = 0; teamNum < numTeams.getValue(); teamNum++) {
        TeamInfo team = teams[teamNum];
        Location spawn = getSpawnLocationForTeam(teamNum);
        if (spawn.getChunk() == c) {
          int spawnX = spawn.getBlockX() & 15,
              spawnY = spawn.getBlockY() - 1,
              spawnZ = spawn.getBlockZ() & 15;

          for (int x = spawnX - 2; x <= spawnX + 2; x++)
            for (int z = spawnZ - 2; z <= spawnZ + 2; z++) {
              Block b = c.getBlock(x, spawnY, z);

              b.setType(Material.WOOL);
              b.setData(team.getDyeColor().getWoolData());
            }
          c.getBlock(spawnX, spawnY, spawnZ).setType(Material.BEDROCK);
        }
      }
    }
  private TeamInfo allocatePlayer(Player player, int[] teamCounts) {
    int teamNum = Helper.getLowestValueIndex(teamCounts);
    TeamInfo team = getTeams()[teamNum];

    setTeam(player, team);
    teamCounts[teamNum]++;
    player.sendMessage(
        "You are on the "
            + team.getChatColor()
            + team.getName()
            + "\n"
            + ChatColor.RESET
            + "Use the /team command to send messages to your team only");

    equipPlayer(player, team);

    return team;
  }
  private void equipPlayer(Player player, TeamInfo team) {
    PlayerInventory inv = player.getInventory();
    Color color = team.getDyeColor().getFireworkColor();

    // give them team-dyed armor, and a sword
    ItemStack armor = new ItemStack(Material.LEATHER_CHESTPLATE);

    LeatherArmorMeta meta = ((LeatherArmorMeta) armor.getItemMeta());
    meta.setColor(color);

    armor.setItemMeta(meta);
    inv.setChestplate(armor);

    armor = new ItemStack(Material.LEATHER_CHESTPLATE);
    armor.setItemMeta(meta);
    inv.setLeggings(armor);

    armor = new ItemStack(Material.LEATHER_BOOTS);
    armor.setItemMeta(meta);
    inv.setBoots(armor);

    inv.addItem(new ItemStack(Material.IRON_SWORD));
  }