Code Sketch


Bixuu02 anime card battle naruto
By: Mhalsakant School
Category: Programming

import java.awt._
import java.awt.event._
import javax.swing._
import scala.collection.mutable
import scala.util.Random

object BixuuCardsBattle {

  // =====================================================
  // BIXUU'S ANIME FIGHTING CARDS
  // =====================================================

  case class Ninja(
    name: String,
    power: Int,
    speed: Int,
    defense: Int,
    chakra: Int,
    special: String,
    color: Color
  )

  class PlayerAccount(
    val username: String,
    val password: String
  ) {
    val collectedCards = mutable.ArrayBuffer[String]()
    var wins = 0
    var losses = 0
    var battles = 0
  }

  val random = new Random()

  val accounts =
    mutable.LinkedHashMap[String, PlayerAccount]()

  var currentAccount: PlayerAccount = _

  val ninjas = Vector(
    Ninja("Naruto Uzumaki", 96, 94, 90, 99, "RASENGAN",
      new Color(255, 140, 30)),
    Ninja("Sasuke Uchiha", 97, 96, 88, 98, "CHIDORI",
      new Color(90, 100, 220)),
    Ninja("Sakura Haruno", 86, 80, 94, 78, "SUPER PUNCH",
      new Color(235, 100, 150)),
    Ninja("Kakashi Hatake", 92, 93, 90, 94, "LIGHTNING BLADE",
      new Color(80, 155, 195)),
    Ninja("Itachi Uchiha", 98, 95, 90, 99, "TSUKUYOMI",
      new Color(170, 35, 45)),
    Ninja("Madara Uchiha", 100, 96, 99, 100, "PERFECT SUSANOO",
      new Color(155, 45, 50)),
    Ninja("Obito Uchiha", 97, 92, 96, 98, "KAMUI",
      new Color(100, 75, 160)),
    Ninja("Pain", 96, 88, 94, 98, "ALMIGHTY PUSH",
      new Color(180, 70, 75)),
    Ninja("Minato Namikaze", 95, 100, 87, 96, "FLYING RAJIN",
      new Color(235, 190, 55)),
    Ninja("Gaara", 90, 78, 99, 92, "SAND SHIELD",
      new Color(175, 105, 75)),
    Ninja("Rock Lee", 92, 99, 88, 65, "LOTUS ATTACK",
      new Color(70, 165, 95)),
    Ninja("Shikamaru Nara", 82, 78, 83, 80, "SHADOW POSSESSION",
      new Color(90, 130, 90)),
    Ninja("Jiraiya", 94, 85, 92, 96, "SAGE RASENGAN",
      new Color(200, 95, 45)),
    Ninja("Orochimaru", 93, 90, 94, 97, "SNAKE JUTSU",
      new Color(150, 190, 130)),
    Ninja("Killer Bee", 94, 91, 92, 95, "LARIAT",
      new Color(100, 140, 210)),
    Ninja("Neji Hyuga", 88, 92, 85, 88, "GENTLE FIST",
      new Color(180, 195, 210)),
    Ninja("Tsunade", 94, 79, 98, 90, "HEALING POWER",
      new Color(195, 125, 100)),
    Ninja("Deidara", 91, 92, 80, 91, "EXPLOSIVE ART",
      new Color(190, 175, 115)),
    Ninja("Kisame Hoshigaki", 93, 82, 95, 96, "WATER JUTSU",
      new Color(65, 135, 180)),
    Ninja("Konan", 88, 89, 85, 91, "PAPER JUTSU",
      new Color(130, 155, 205))
  )

  val stats = Vector("POWER", "SPEED", "DEFENSE", "CHAKRA")

  val backgroundColor = new Color(14, 16, 30)
  val panelColor = new Color(27, 30, 49)
  val goldColor = new Color(255, 190, 60)
  val whiteColor = new Color(245, 245, 255)

  var frame: JFrame = _

  var playerCard: Ninja = _
  var enemyCard: Ninja = _

  var playerView: NinjaCardView = _
  var enemyView: NinjaCardView = _

  var rootPanel: JPanel = _
  var actionPanel: JPanel = _
  var statPanel: JPanel = _
  var messageLabel: JLabel = _
  var scoreLabel: JLabel = _

  var statButtons = Vector.empty[JButton]

  var roundNumber = 1
  var playerSelected = false
  var battleReady = false
  var battleResolved = false

  // =====================================================
  // UI HELPERS
  // =====================================================

  def makeLabel(
    text: String,
    size: Int,
    color: Color
  ): JLabel = {
    val label = new JLabel(text, SwingConstants.CENTER)
    label.setFont(new Font("Arial", Font.BOLD, size))
    label.setForeground(color)
    label
  }

  def makeButton(text: String): JButton = {
    val b = new JButton(text)
    b.setFont(new Font("Arial", Font.BOLD, 14))
    b.setForeground(Color.WHITE)
    b.setBackground(new Color(48, 48, 72))
    b.setFocusPainted(false)
    b.setBorder(
      BorderFactory.createLineBorder(goldColor, 2)
    )
    b.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR))
    b
  }

  def makePanel(layout: LayoutManager): JPanel = {
    val p = new JPanel(layout)
    p.setOpaque(false)
    p
  }

  def setScreen(
    panel: JPanel,
    width: Int,
    height: Int
  ): Unit = {
    frame.setContentPane(panel)
    frame.setSize(width, height)
    frame.setLocationRelativeTo(null)
    frame.revalidate()
    frame.repaint()
    frame.setVisible(true)
  }

  def statValue(ninja: Ninja, stat: String): Int = {
    if (stat == "POWER") ninja.power
    else if (stat == "SPEED") ninja.speed
    else if (stat == "DEFENSE") ninja.defense
    else if (stat == "CHAKRA") ninja.chakra
    else 0
  }

  def makeTitle(text: String): JLabel = {
    val title = makeLabel(text, 27, goldColor)
    title.setBorder(
      BorderFactory.createEmptyBorder(15, 5, 15, 5)
    )
    title
  }

  // =====================================================
  // LOGIN AND CREATE ACCOUNT
  // =====================================================

  def showLogin(): Unit = {
    val page = new JPanel(new BorderLayout(12, 12))
    page.setBackground(backgroundColor)
    page.setBorder(
      BorderFactory.createEmptyBorder(22, 30, 22, 30)
    )

    page.add(
      makeTitle("BIXUU'S ANIME FIGHTING CARDS"),
      BorderLayout.NORTH
    )

    val center = new JPanel(new GridBagLayout())
    center.setOpaque(false)

    val form = new JPanel(new GridLayout(4, 1, 8, 8))
    form.setOpaque(false)
    form.setPreferredSize(new Dimension(350, 230))

    val nameLabel = makeLabel(
      "ENTER YOUR PLAYER NAME",
      15,
      whiteColor
    )

    val nameField = new JTextField()
    nameField.setFont(new Font("Arial", Font.PLAIN, 18))

    val passwordLabel = makeLabel(
      "ENTER PASSWORD",
      15,
      whiteColor
    )

    val passwordField = new JPasswordField()
    passwordField.setFont(new Font("Arial", Font.PLAIN, 18))

    form.add(nameLabel)
    form.add(nameField)
    form.add(passwordLabel)
    form.add(passwordField)

    center.add(form)
    page.add(center, BorderLayout.CENTER)

    val footer = new JPanel(new BorderLayout(8, 8))
    footer.setOpaque(false)

    footer.add(
      makeLabel(
        "Create an account first, or log in to an existing account.",
        12,
        Color.LIGHT_GRAY
      ),
      BorderLayout.NORTH
    )

    val buttons = new JPanel(new GridLayout(1, 2, 10, 10))
    buttons.setOpaque(false)

    val loginButton = makeButton("LOGIN")
    val createButton = makeButton("CREATE ACCOUNT")

    loginButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        val username = nameField.getText.trim
        val password = new String(passwordField.getPassword)

        if (username.isEmpty || password.isEmpty) {
          JOptionPane.showMessageDialog(
            frame,
            "Please enter both name and password.",
            "LOGIN",
            JOptionPane.WARNING_MESSAGE
          )
        } else {
          accounts.get(username) match {
            case Some(account) if account.password == password =>
              currentAccount = account
              showHome()

            case Some(_) =>
              JOptionPane.showMessageDialog(
                frame,
                "Incorrect password.",
                "LOGIN FAILED",
                JOptionPane.ERROR_MESSAGE
              )

            case None =>
              JOptionPane.showMessageDialog(
                frame,
                "Account not found. Please create an account first.",
                "LOGIN FAILED",
                JOptionPane.INFORMATION_MESSAGE
              )
          }
        }
      }
    })

    createButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        val username = nameField.getText.trim
        val password = new String(passwordField.getPassword)

        if (username.isEmpty || password.isEmpty) {
          JOptionPane.showMessageDialog(
            frame,
            "Enter your name and a password first.",
            "CREATE ACCOUNT",
            JOptionPane.WARNING_MESSAGE
          )
        } else if (accounts.contains(username)) {
          JOptionPane.showMessageDialog(
            frame,
            "This username already exists. Please log in.",
            "ACCOUNT EXISTS",
            JOptionPane.INFORMATION_MESSAGE
          )
        } else {
          val account = new PlayerAccount(username, password)
          accounts(username) = account
          currentAccount = account

          JOptionPane.showMessageDialog(
            frame,
            "Account created! Welcome, " + username + "!",
            "WELCOME",
            JOptionPane.INFORMATION_MESSAGE
          )

          showHome()
        }
      }
    })

    buttons.add(loginButton)
    buttons.add(createButton)

    footer.add(buttons, BorderLayout.CENTER)
    page.add(footer, BorderLayout.SOUTH)

    setScreen(page, 800, 620)
  }

  // =====================================================
  // HOME MENU
  // =====================================================

  def showHome(): Unit = {
    val page = new JPanel(new BorderLayout(15, 15))
    page.setBackground(backgroundColor)
    page.setBorder(
      BorderFactory.createEmptyBorder(18, 25, 20, 25)
    )

    page.add(
      makeTitle("BIXUU'S ANIME FIGHTING CARDS"),
      BorderLayout.NORTH
    )

    val center = makePanel(new BorderLayout(10, 10))

    center.add(
      makeLabel(
        "WELCOME, " + currentAccount.username.toUpperCase,
        19,
        Color.WHITE
      ),
      BorderLayout.NORTH
    )

    val menu = new JPanel(new GridLayout(5, 1, 10, 10))
    menu.setOpaque(false)
    menu.setBorder(
      BorderFactory.createEmptyBorder(10, 100, 10, 100)
    )

    val fightingButton = makeButton("NINJA FIGHTING")
    val profileButton = makeButton("MY PROFILE")
    val collectionButton = makeButton("CARD COLLECTION")
    val rulesButton = makeButton("HOW TO PLAY")
    val logoutButton = makeButton("LOG OUT")

    fightingButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        roundNumber = 1
        showBattle()
      }
    })

    profileButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        showProfile()
      }
    })

    collectionButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        showCollection()
      }
    })

    rulesButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        showRules()
      }
    })

    logoutButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        currentAccount = null
        showLogin()
      }
    })

    menu.add(fightingButton)
    menu.add(profileButton)
    menu.add(collectionButton)
    menu.add(rulesButton)
    menu.add(logoutButton)

    center.add(menu, BorderLayout.CENTER)

    page.add(center, BorderLayout.CENTER)

    setScreen(page, 850, 720)
  }

  // =====================================================
  // ANIMATED NINJA CARD
  // =====================================================

  class NinjaCardView(
    val ninja: Ninja,
    val isPlayerCard: Boolean
  ) extends JPanel {

    var revealed = false
    var chosen = false
    var flipScale = 1.0

    setPreferredSize(new Dimension(255, 325))
    setMinimumSize(new Dimension(190, 260))
    setBackground(panelColor)
    setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR))

    addMouseListener(new MouseAdapter {
      override def mouseClicked(e: MouseEvent): Unit = {
        if (
          isPlayerCard &&
          revealed &&
          battleReady &&
          !battleResolved
        ) {
          playerSelected = true
          chosen = true

          messageLabel.setText(
            "YOUR CARD SELECTED! NOW CHOOSE A STAT."
          )

          refreshBattleControls()
          repaint()
        }
      }
    })

    override def paintComponent(graphics: Graphics): Unit = {
      super.paintComponent(graphics)

      val g = graphics.create().asInstanceOf[Graphics2D]

      try {
        g.setRenderingHint(
          RenderingHints.KEY_ANTIALIASING,
          RenderingHints.VALUE_ANTIALIAS_ON
        )

        val w = getWidth
        val h = getHeight

        g.translate(w / 2.0, 0.0)
        g.scale(flipScale, 1.0)
        g.translate(-w / 2.0, 0.0)

        if (!revealed) {
          // CARD BACK

          g.setColor(new Color(64, 35, 110))
          g.fillRoundRect(10, 10, w - 20, h - 20, 24, 24)

          g.setColor(goldColor)
          g.setStroke(new BasicStroke(4))
          g.drawRoundRect(18, 18, w - 36, h - 36, 20, 20)

          g.setColor(Color.WHITE)
          g.setFont(new Font("Arial", Font.BOLD, 48))
          g.drawString("NINJA", w / 2 - 73, h / 2 - 5)

          g.setFont(new Font("Arial", Font.BOLD, 16))
          g.drawString(
            "FLIP CARD",
            w / 2 - 47,
            h / 2 + 37
          )

          g.setFont(new Font("Arial", Font.BOLD, 14))

          val who =
            if (isPlayerCard) "YOUR CARD"
            else "ROBOT CARD"

          g.drawString(who, w / 2 - 45, h - 35)

        } else {
          // CARD FRONT

          g.setColor(ninja.color)
          g.fillRoundRect(10, 10, w - 20, h - 20, 24, 24)

          g.setColor(new Color(18, 20, 34))
          g.fillRoundRect(20, 20, w - 40, h - 40, 18, 18)

          g.setColor(Color.WHITE)
          g.setFont(new Font("Arial", Font.BOLD, 17))

          val nameWidth = g.getFontMetrics.stringWidth(ninja.name)

          g.drawString(
            ninja.name,
            (w - nameWidth) / 2,
            50
          )

          val symbol =
            if (ninja.name.startsWith("Naruto")) "?"
            else if (ninja.name.startsWith("Sasuke")) "?"
            else if (ninja.name.startsWith("Itachi")) "?"
            else if (ninja.name.startsWith("Madara")) "?"
            else if (ninja.name.startsWith("Gaara")) "?"
            else "?"

          g.setColor(ninja.color.brighter())
          g.setFont(new Font("Arial", Font.BOLD, 42))
          g.drawString(symbol, w / 2 - 22, 105)

          g.setColor(Color.WHITE)
          g.setFont(new Font("Arial", Font.BOLD, 14))

          g.drawString("POWER     " + ninja.power, 31, 143)
          g.drawString("SPEED       " + ninja.speed, 31, 171)
          g.drawString("DEFENSE  " + ninja.defense, 31, 199)
          g.drawString("CHAKRA   " + ninja.chakra, 31, 227)

          g.setColor(new Color(255, 220, 120))
          g.setFont(new Font("Arial", Font.BOLD, 12))
          g.drawString(ninja.special, 31, 255)

          g.setFont(new Font("Arial", Font.BOLD, 12))

          if (isPlayerCard && chosen) {
            g.setColor(Color.GREEN)
            g.drawString("SELECTED!", 31, h - 28)
          } else if (isPlayerCard) {
            g.setColor(goldColor)
            g.drawString("TAP TO SELECT", 31, h - 28)
          } else {
            g.setColor(goldColor)
            g.drawString("ROBOT ENEMY", 31, h - 28)
          }

          if (isPlayerCard && chosen) {
            g.setColor(Color.GREEN)
            g.setStroke(new BasicStroke(4))
          } else {
            g.setColor(goldColor)
            g.setStroke(new BasicStroke(2))
          }

          g.drawRoundRect(10, 10, w - 20, h - 20, 24, 24)
        }
      } finally {
        g.dispose()
      }
    }
  }

  // =====================================================
  // FLIP ANIMATION
  // =====================================================

  def flipCard(
    view: NinjaCardView,
    finished: () => Unit
  ): Unit = {

    var step = 0
    var timer: Timer = null

    timer = new Timer(28, new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        step += 1

        if (step <= 5) {
          view.flipScale = 1.0 - step * 0.18
        } else if (step == 6) {
          view.flipScale = 0.10
          view.revealed = true
        } else {
          view.flipScale =
            Math.min(1.0, (step - 5) * 0.20)
        }

        view.repaint()

        if (step >= 11) {
          timer.stop()
          view.flipScale = 1.0
          view.repaint()
          finished()
        }
      }
    })

    timer.start()
  }

  // =====================================================
  // BATTLE SCREEN
  // =====================================================

  def showBattle(): Unit = {
    if (currentAccount == null) {
      showLogin()
      return
    }

    playerSelected = false
    battleReady = false
    battleResolved = false

    playerCard = ninjas(random.nextInt(ninjas.length))

    val enemyOptions = ninjas.filterNot(
      n => n.name == playerCard.name
    )

    enemyCard =
      enemyOptions(random.nextInt(enemyOptions.length))

    rootPanel = new JPanel(new BorderLayout(10, 10))
    rootPanel.setBackground(backgroundColor)
    rootPanel.setBorder(
      BorderFactory.createEmptyBorder(12, 15, 12, 15)
    )

    rootPanel.add(
      makeTitle("NINJA FIGHTING"),
      BorderLayout.NORTH
    )

    // Player and robot card arena

    val arena = new JPanel(new GridLayout(1, 2, 14, 8))
    arena.setOpaque(false)

    val playerBox = new JPanel(new BorderLayout(5, 5))
    playerBox.setOpaque(false)

    playerBox.add(
      makeLabel("YOUR NINJA", 16, Color.WHITE),
      BorderLayout.NORTH
    )

    playerView = new NinjaCardView(playerCard, true)
    playerBox.add(playerView, BorderLayout.CENTER)

    val enemyBox = new JPanel(new BorderLayout(5, 5))
    enemyBox.setOpaque(false)

    enemyBox.add(
      makeLabel("ROBOT ENEMY", 16, Color.WHITE),
      BorderLayout.NORTH
    )

    enemyView = new NinjaCardView(enemyCard, false)
    enemyBox.add(enemyView, BorderLayout.CENTER)

    arena.add(playerBox)
    arena.add(enemyBox)

    rootPanel.add(arena, BorderLayout.CENTER)

    // Battle action panel

    actionPanel = new JPanel(new BorderLayout(7, 7))
    actionPanel.setOpaque(false)

    messageLabel = makeLabel(
      "GET READY... FLIPPING CARDS!",
      15,
      goldColor
    )

    actionPanel.add(messageLabel, BorderLayout.NORTH)

    statPanel = new JPanel(new GridLayout(2, 2, 8, 8))
    statPanel.setOpaque(false)

    statButtons = stats.map { stat =>
      val b = makeButton("CHOOSE " + stat)
      b.setEnabled(false)

      b.addActionListener(new ActionListener {
        override def actionPerformed(e: ActionEvent): Unit = {
          fight(stat)
        }
      })

      statPanel.add(b)
      b
    }

    actionPanel.add(statPanel, BorderLayout.CENTER)

    val bottom = new JPanel(new BorderLayout(5, 5))
    bottom.setOpaque(false)

    scoreLabel = makeLabel(
      "PLAYER: " + currentAccount.username +
      "    WINS: " + currentAccount.wins +
      "    LOSSES: " + currentAccount.losses,
      13,
      Color.WHITE
    )

    bottom.add(scoreLabel, BorderLayout.CENTER)

    val backButton = makeButton("BACK TO HOME")

    backButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        showHome()
      }
    })

    bottom.add(backButton, BorderLayout.SOUTH)

    actionPanel.add(bottom, BorderLayout.SOUTH)

    rootPanel.add(actionPanel, BorderLayout.SOUTH)

    setScreen(rootPanel, 900, 800)

    // Flip player card, then robot card.

    flipCard(playerView, () => {
      flipCard(enemyView, () => {
        battleReady = true

        messageLabel.setText(
          "CARDS REVEALED! TAP YOUR NINJA CARD!"
        )

        refreshBattleControls()
      })
    })
  }

  // =====================================================
  // ENABLE / DISABLE BATTLE CONTROLS
  // =====================================================

  def refreshBattleControls(): Unit = {
    statButtons.foreach { b =>
      b.setEnabled(
        battleReady &&
        playerSelected &&
        !battleResolved
      )
    }

    if (playerView != null) playerView.repaint()
  }

  // =====================================================
  // BATTLE RESULTS AND CARD REWARDS
  // =====================================================

  def fight(stat: String): Unit = {
    if (
      !battleReady ||
      !playerSelected ||
      battleResolved ||
      currentAccount == null
    ) {
      return
    }

    battleResolved = true

    val playerValue = statValue(playerCard, stat)
    val enemyValue = statValue(enemyCard, stat)

    currentAccount.battles += 1

    var outcome = ""
    var rewardMessage = ""

    if (playerValue > enemyValue) {
      currentAccount.wins += 1

      // Winning awards the robot's card.
      currentAccount.collectedCards += enemyCard.name

      outcome = "YOU WIN THE BATTLE!"
      rewardMessage =
        "NEW CARD UNLOCKED: " + enemyCard.name

    } else if (playerValue < enemyValue) {
      currentAccount.losses += 1

      outcome = "ROBOT WINS THIS BATTLE!"
      rewardMessage = "NO CARD REWARD THIS TIME."

    } else {
      outcome = "DRAW! BOTH NINJAS ARE EQUAL!"
      rewardMessage = "TRY ANOTHER BATTLE!"
    }

    messageLabel.setText(
      "<html><center>" + outcome +
      "<br>" + stat + ": " + playerValue +
      " vs " + enemyValue +
      "<br>ROBOT CARD: " + enemyCard.name +
      "</center></html>"
    )

    scoreLabel.setText(
      "WINS: " + currentAccount.wins +
      "    LOSSES: " + currentAccount.losses +
      "    CARDS EARNED: " +
      currentAccount.collectedCards.length
    )

    statButtons.foreach(_.setEnabled(false))

    val resultPanel = new JPanel(new GridLayout(2, 1, 6, 6))
    resultPanel.setOpaque(false)

    val resultLabel = makeLabel(
      rewardMessage,
      16,
      if (playerValue > enemyValue) Color.GREEN
      else if (playerValue < enemyValue) new Color(255, 120, 120)
      else goldColor
    )

    resultPanel.add(resultLabel)

    val nextButton = makeButton("NEXT BATTLE")

    nextButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        roundNumber += 1
        showBattle()
      }
    })

    resultPanel.add(nextButton)

    actionPanel.remove(statPanel)
    actionPanel.add(resultPanel, BorderLayout.CENTER)

    actionPanel.revalidate()
    actionPanel.repaint()

    rootPanel.revalidate()
    rootPanel.repaint()
  }

  // =====================================================
  // CARD COLLECTION
  // =====================================================

  def collectionText: String = {
    if (currentAccount.collectedCards.isEmpty) {
      "Your collection is empty.\n\n" +
      "Win a Ninja Battle to earn the Robot's card!"
    } else {
      val grouped =
        currentAccount.collectedCards.groupBy((name: String) => name)

      val lines = grouped.toSeq.sortBy(_._1).map {
        case (name, copies) =>
          name + "   x" + copies.length
      }

      "YOUR EARNED NINJA CARDS\n\n" +
      lines.mkString("\n") +
      "\n\nTOTAL CARDS: " +
      currentAccount.collectedCards.length +
      "\nUNIQUE NINJAS: " + grouped.size
    }
  }

  def showCollection(): Unit = {
    showTextPage(
      "MY CARD COLLECTION",
      collectionText
    )
  }

  // =====================================================
  // PLAYER PROFILE
  // =====================================================

  def showProfile(): Unit = {
    val a = currentAccount

    val body =
      "PLAYER PROFILE\n\n" +
      "Username: " + a.username + "\n\n" +
      "Battles Played: " + a.battles + "\n" +
      "Battles Won: " + a.wins + "\n" +
      "Battles Lost: " + a.losses + "\n" +
      "Cards Earned: " + a.collectedCards.length +
      "\n\n" +
      "NINJA CARDS EARNED\n\n" +
      collectionText

    showTextPage("MY PROFILE", body)
  }

  // =====================================================
  // RULES
  // =====================================================

  def showRules(): Unit = {
    val rules =
      "BIXUU'S ANIME FIGHTING CARDS\n\n" +
      "1. Create an account or log in.\n\n" +
      "2. Open NINJA FIGHTING.\n\n" +
      "3. Your Ninja card and Robot card flip open.\n\n" +
      "4. Click YOUR NINJA CARD to select it.\n\n" +
      "5. Choose POWER, SPEED, DEFENSE or CHAKRA.\n\n" +
      "6. The selected stats are compared.\n\n" +
      "7. If your stat is higher, YOU WIN!\n\n" +
      "8. Winning adds the Robot's Ninja card to your collection.\n\n" +
      "9. Open MY PROFILE or CARD COLLECTION to see your cards.\n\n" +
      "Note: Character stats are fictional game values."

    showTextPage("HOW TO PLAY", rules)
  }

  // =====================================================
  // GENERAL TEXT PAGE
  // =====================================================

  def showTextPage(
    titleText: String,
    bodyText: String
  ): Unit = {

    val page = new JPanel(new BorderLayout(10, 10))
    page.setBackground(backgroundColor)
    page.setBorder(
      BorderFactory.createEmptyBorder(15, 20, 15, 20)
    )

    page.add(makeTitle(titleText), BorderLayout.NORTH)

    val textArea = new JTextArea(bodyText)
    textArea.setEditable(false)
    textArea.setLineWrap(true)
    textArea.setWrapStyleWord(true)
    textArea.setFont(new Font("Arial", Font.PLAIN, 17))
    textArea.setForeground(whiteColor)
    textArea.setBackground(panelColor)
    textArea.setCaretPosition(0)
    textArea.setBorder(
      BorderFactory.createEmptyBorder(15, 15, 15, 15)
    )

    val scroll = new JScrollPane(textArea)
    scroll.setBorder(
      BorderFactory.createLineBorder(goldColor, 1)
    )

    page.add(scroll, BorderLayout.CENTER)

    val backButton = makeButton("BACK TO HOME")

    backButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        showHome()
      }
    })

    val footer = new JPanel(new FlowLayout(FlowLayout.CENTER))
    footer.setOpaque(false)
    footer.add(backButton)

    page.add(footer, BorderLayout.SOUTH)

    setScreen(page, 800, 700)
  }

  // =====================================================
  // APPLICATION START
  // =====================================================

  def run(): Unit = {
    SwingUtilities.invokeLater(new Runnable {
      override def run(): Unit = {
        frame = new JFrame(
          "Bixuu's Anime Fighting Cards"
        )

        frame.setDefaultCloseOperation(
          WindowConstants.EXIT_ON_CLOSE
        )

        frame.setMinimumSize(new Dimension(700, 650))

        showLogin()
      }
    })
  }
}

// LAUNCH GAME
BixuuCardsBattle.run()