Code Sketch


bixuuu
By: Mhalsakant School
Category: Programming
import javax.swing._
import java.awt._
import java.awt.event._
import java.awt.image.BufferedImage


// ============================================================
// BIXUU 02 - ANIME ENEMIES STORY LAB
// FULL KOJO + SCALA + JAVA SWING/AWT
//
// PASSWORD:
// Bixuu02@anime
//
// IMPORTANT:
// 1. No scala.swing
// 2. No onClick
// 3. No setCharacter
// 4. No CardLayout
// 5. Buttons are created BEFORE listeners
//    so forward-reference error is avoided
// ============================================================


// ============================================================
// DATA
// ============================================================

case class StoryScene(
  stage: String,
  speaker: String,
  text: String
)

case class CharacterInfo(
  name: String,
  role: String,
  powerName: String,
  powers: Array[String],
  personality: String,
  description: String,
  faceStyle: Int,
  accent: Color,
  scenes: Array[StoryScene]
)

case class AnimeInfo(
  name: String,
  subtitle: String,
  description: String,
  accent: Color,
  overview: Array[StoryScene],
  characters: Array[CharacterInfo]
)


// ============================================================
// PASSWORD
// ============================================================

val PASSWORD =
  "Bixuu02@anime"


// ============================================================
// COLORS
// ============================================================

val BG =
  new Color(8, 11, 19)

val PANEL =
  new Color(18, 23, 37)

val PANEL2 =
  new Color(29, 36, 55)

val TEXT =
  new Color(245, 247, 255)

val MUTED =
  new Color(170, 179, 205)

val CYAN =
  new Color(65, 214, 255)

val PURPLE =
  new Color(137, 94, 255)

val PINK =
  new Color(255, 89, 158)

val GREEN =
  new Color(70, 224, 155)

val ORANGE =
  new Color(255, 183, 65)

val RED =
  new Color(242, 78, 90)

val GOLD =
  new Color(248, 210, 82)


// ============================================================
// FONT
// ============================================================

def makeFont(
  size: Int,
  bold: Boolean
): Font = {

  if (bold) {
    new Font(
      "SansSerif",
      Font.BOLD,
      size
    )
  } else {
    new Font(
      "SansSerif",
      Font.PLAIN,
      size
    )
  }
}


// ============================================================
// LABEL
// ============================================================

def makeLabel(
  value: String,
  size: Int,
  color: Color,
  bold: Boolean
): JLabel = {

  val l =
    new JLabel(value)

  l.setFont(
    makeFont(
      size,
      bold
    )
  )

  l.setForeground(color)

  l
}


// ============================================================
// BUTTON
// ============================================================

def makeButton(
  value: String
): JButton = {

  val b =
    new JButton(value)

  b.setFont(
    makeFont(
      13,
      true
    )
  )

  b.setForeground(TEXT)

  b.setBackground(PANEL2)

  b.setFocusPainted(false)

  b.setBorder(
    BorderFactory.createEmptyBorder(
      9,
      13,
      9,
      13
    )
  )

  b
}


// ============================================================
// TEXT AREA
// ============================================================

def makeTextArea(
  value: String,
  size: Int
): JTextArea = {

  val a =
    new JTextArea(value)

  a.setFont(
    makeFont(
      size,
      false
    )
  )

  a.setForeground(TEXT)

  a.setBackground(PANEL)

  a.setCaretColor(TEXT)

  a.setEditable(false)

  a.setLineWrap(true)

  a.setWrapStyleWord(true)

  a.setMargin(
    new Insets(
      18,
      20,
      18,
      20
    )
  )

  a
}


// ============================================================
// FRAME
// ============================================================

val frame =
  new JFrame(
    "BIXUU 02 - ANIME ENEMIES STORY LAB"
  )

frame.setSize(
  1260,
  800
)

frame.setMinimumSize(
  new Dimension(
    920,
    600
  )
)

frame.setDefaultCloseOperation(
  WindowConstants.EXIT_ON_CLOSE
)

frame.setLocationRelativeTo(null)


// ============================================================
// PAGE SWITCH
// ============================================================

def showPage(
  panel: JPanel
): Unit = {

  frame.setContentPane(panel)

  frame.validate()

  frame.repaint()

  frame.setVisible(true)
}


// ============================================================
// HEADER
// ============================================================

def makeHeader(
  section: String
): JPanel = {

  val p =
    new JPanel(
      new BorderLayout()
    )

  p.setBackground(PANEL)

  p.setBorder(
    BorderFactory.createEmptyBorder(
      10,
      15,
      10,
      15
    )
  )

  val left =
    new JPanel(
      new FlowLayout(
        FlowLayout.LEFT,
        12,
        0
      )
    )

  left.setOpaque(false)

  left.add(
    makeLabel(
      "BIX-02",
      24,
      CYAN,
      true
    )
  )

  left.add(
    makeLabel(
      section,
      18,
      TEXT,
      true
    )
  )

  p.add(
    left,
    BorderLayout.WEST
  )

  p.add(
    makeLabel(
      "STORY ENGINE ONLINE",
      12,
      GREEN,
      false
    ),
    BorderLayout.EAST
  )

  p
}


// ============================================================
// ROBOT IMAGE
// ============================================================

def robotImage(
  width: Int,
  height: Int
): BufferedImage = {

  val img =
    new BufferedImage(
      width,
      height,
      BufferedImage.TYPE_INT_ARGB
    )

  val g =
    img.createGraphics()

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

  val cx =
    width / 2

  // background
  g.setColor(BG)

  g.fillRect(
    0,
    0,
    width,
    height
  )

  // glow
  g.setColor(
    new Color(
      18,
      68,
      110
    )
  )

  g.fillOval(
    cx - 110,
    10,
    220,
    220
  )

  // antenna
  g.setColor(CYAN)

  g.setStroke(
    new BasicStroke(5)
  )

  g.drawLine(
    cx,
    62,
    cx,
    30
  )

  g.fillOval(
    cx - 8,
    14,
    16,
    16
  )

  // head
  g.setColor(
    new Color(
      212,
      224,
      237
    )
  )

  g.fillRoundRect(
    cx - 82,
    63,
    164,
    122,
    28,
    28
  )

  // head outline
  g.setColor(
    new Color(
      74,
      97,
      122
    )
  )

  g.drawRoundRect(
    cx - 82,
    63,
    164,
    122,
    28,
    28
  )

  // eyes
  g.setColor(CYAN)

  g.fillOval(
    cx - 52,
    96,
    32,
    40
  )

  g.fillOval(
    cx + 20,
    96,
    32,
    40
  )

  // eye glow
  g.setColor(Color.WHITE)

  g.fillOval(
    cx - 45,
    103,
    7,
    7
  )

  g.fillOval(
    cx + 27,
    103,
    7,
    7
  )

  // mouth
  g.setColor(
    new Color(
      38,
      50,
      64
    )
  )

  g.fillRoundRect(
    cx - 40,
    150,
    80,
    13,
    7,
    7
  )

  // body
  g.setColor(
    new Color(
      190,
      208,
      224
    )
  )

  g.fillRoundRect(
    cx - 75,
    210,
    150,
    101,
    24,
    24
  )

  // chest
  g.setColor(
    new Color(
      15,
      24,
      38
    )
  )

  g.fillRoundRect(
    cx - 44,
    231,
    88,
    43,
    8,
    8
  )

  g.setColor(GREEN)

  g.fillOval(
    cx - 24,
    246,
    9,
    9
  )

  g.fillOval(
    cx - 4,
    246,
    9,
    9
  )

  g.fillOval(
    cx + 16,
    246,
    9,
    9
  )

  // arms
  g.setColor(
    new Color(
      166,
      190,
      208
    )
  )

  g.fillRoundRect(
    cx - 101,
    220,
    24,
    77,
    12,
    12
  )

  g.fillRoundRect(
    cx + 77,
    220,
    24,
    77,
    12,
    12
  )

  // name
  g.setColor(TEXT)

  g.setFont(
    makeFont(
      20,
      true
    )
  )

  val name =
    "BIX-02"

  val fm =
    g.getFontMetrics

  g.drawString(
    name,
    cx -
    fm.stringWidth(name) / 2,
    350
  )

  g.dispose()

  img
}


// ============================================================
// ROBOT LABEL
// ============================================================

def robotLabel(): JLabel = {

  new JLabel(
    new ImageIcon(
      robotImage(
        250,
        365
      )
    )
  )
}


// ============================================================
// CHARACTER FACE
// ============================================================

def characterFaceImage(
  c: CharacterInfo,
  width: Int,
  height: Int
): BufferedImage = {

  val img =
    new BufferedImage(
      width,
      height,
      BufferedImage.TYPE_INT_ARGB
    )

  val g =
    img.createGraphics()

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

  val cx =
    width / 2

  val top =
    60

  // background
  g.setColor(
    new Color(
      10,
      16,
      28
    )
  )

  g.fillRoundRect(
    5,
    5,
    width - 10,
    height - 10,
    28,
    28
  )

  // border
  g.setColor(
    c.accent
  )

  g.setStroke(
    new BasicStroke(3)
  )

  g.drawRoundRect(
    5,
    5,
    width - 10,
    height - 10,
    28,
    28
  )

  // body
  g.setColor(
    new Color(
      42,
      49,
      67
    )
  )

  g.fillRoundRect(
    cx - 105,
    top + 275,
    210,
    115,
    26,
    26
  )

  // neck
  g.setColor(
    new Color(
      222,
      178,
      151
    )
  )

  g.fillRect(
    cx - 28,
    top + 195,
    56,
    75
  )

  // face
  g.setColor(
    new Color(
      226,
      181,
      154
    )
  )

  g.fillOval(
    cx - 87,
    top,
    174,
    215
  )

  // ears
  g.fillOval(
    cx - 100,
    top + 77,
    28,
    51
  )

  g.fillOval(
    cx + 72,
    top + 77,
    28,
    51
  )

  // hair
  var hairColor =
    new Color(
      27,
      28,
      34
    )

  if (
    c.faceStyle == 2
  ) {

    hairColor =
      new Color(
        54,
        30,
        28
      )
  }

  if (
    c.faceStyle == 4
  ) {

    hairColor =
      new Color(
        49,
        38,
        31
      )
  }

  if (
    c.faceStyle == 5
  ) {

    hairColor =
      new Color(
        48,
        49,
        58
      )
  }

  g.setColor(
    hairColor
  )

  if (
    c.faceStyle == 1
  ) {

    val p =
      new Polygon()

    p.addPoint(
      cx - 99,
      top + 63
    )

    p.addPoint(
      cx - 77,
      top + 3
    )

    p.addPoint(
      cx - 46,
      top + 25
    )

    p.addPoint(
      cx - 12,
      top - 12
    )

    p.addPoint(
      cx + 12,
      top + 18
    )

    p.addPoint(
      cx + 45,
      top - 3
    )

    p.addPoint(
      cx + 76,
      top + 27
    )

    p.addPoint(
      cx + 98,
      top + 6
    )

    p.addPoint(
      cx + 100,
      top + 70
    )

    p.addPoint(
      cx - 100,
      top + 70
    )

    g.fillPolygon(
      p
    )

  } else if (
    c.faceStyle == 2
  ) {

    g.fillRoundRect(
      cx - 97,
      top - 10,
      194,
      161,
      45,
      45
    )

  } else if (
    c.faceStyle == 3
  ) {

    g.fillArc(
      cx - 99,
      top - 10,
      198,
      122,
      0,
      180
    )

  } else if (
    c.faceStyle == 4
  ) {

    g.fillOval(
      cx - 104,
      top - 15,
      208,
      121
    )

  } else {

    val p =
      new Polygon()

    p.addPoint(
      cx - 100,
      top + 56
    )

    p.addPoint(
      cx - 80,
      top + 2
    )

    p.addPoint(
      cx - 46,
      top + 20
    )

    p.addPoint(
      cx - 12,
      top - 9
    )

    p.addPoint(
      cx + 20,
      top + 20
    )

    p.addPoint(
      cx + 58,
      top - 2
    )

    p.addPoint(
      cx + 101,
      top + 48
    )

    p.addPoint(
      cx + 99,
      top + 89
    )

    p.addPoint(
      cx - 100,
      top + 89
    )

    g.fillPolygon(
      p
    )
  }

  // eyebrows
  g.setColor(
    new Color(
      38,
      30,
      30
    )
  )

  g.setStroke(
    new BasicStroke(5)
  )

  g.drawLine(
    cx - 61,
    top + 80,
    cx - 23,
    top + 75
  )

  g.drawLine(
    cx + 23,
    top + 75,
    cx + 61,
    top + 80
  )

  // eyes
  var eyeColor =
    new Color(
      65,
      98,
      188
    )

  if (
    c.faceStyle == 1
  ) {
    eyeColor = CYAN
  }

  if (
    c.faceStyle == 2
  ) {
    eyeColor = RED
  }

  if (
    c.faceStyle == 3
  ) {
    eyeColor = PURPLE
  }

  g.setColor(Color.WHITE)

  g.fillOval(
    cx - 66,
    top + 94,
    46,
    28
  )

  g.fillOval(
    cx + 20,
    top + 94,
    46,
    28
  )

  g.setColor(
    eyeColor
  )

  g.fillOval(
    cx - 55,
    top + 96,
    23,
    24
  )

  g.fillOval(
    cx + 32,
    top + 96,
    23,
    24
  )

  g.setColor(
    new Color(
      15,
      15,
      20
    )
  )

  g.fillOval(
    cx - 48,
    top + 101,
    11,
    17
  )

  g.fillOval(
    cx + 40,
    top + 101,
    11,
    17
  )

  // nose
  g.setColor(
    new Color(
      173,
      118,
      102
    )
  )

  g.setStroke(
    new BasicStroke(3)
  )

  g.drawLine(
    cx,
    top + 118,
    cx - 7,
    top + 149
  )

  g.drawLine(
    cx - 7,
    top + 149,
    cx + 7,
    top + 149
  )

  // mouth
  g.setColor(
    new Color(
      120,
      54,
      65
    )
  )

  g.drawArc(
    cx - 28,
    top + 164,
    56,
    23,
    195,
    150
  )

  // special mark
  if (
    c.name == "SUKUNA"
  ) {

    g.setColor(
      RED
    )

    g.setStroke(
      new BasicStroke(4)
    )

    g.drawLine(
      cx - 70,
      top + 49,
      cx - 31,
      top + 70
    )

    g.drawLine(
      cx + 70,
      top + 49,
      cx + 31,
      top + 70
    )
  }

  // name
  g.setColor(TEXT)

  g.setFont(
    makeFont(
      22,
      true
    )
  )

  val nm =
    c.name

  val fm =
    g.getFontMetrics

  g.drawString(
    nm,
    cx -
    fm.stringWidth(nm) / 2,
    405
  )

  // role
  g.setFont(
    makeFont(
      12,
      false
    )
  )

  g.setColor(MUTED)

  val role =
    c.role

  val fm2 =
    g.getFontMetrics

  g.drawString(
    role,
    cx -
    fm2.stringWidth(role) / 2,
    428
  )

  g.dispose()

  img
}


// ============================================================
// ANIME DATA
// ============================================================

val animeDatabase =
  Array(

    // ========================================================
    // JUJUTSU KAISEN
    // ========================================================

    AnimeInfo(

      "JUJUTSU KAISEN",

      "CURSES / SUPERNATURAL / ACTION",

      "Yuji cha life cursed energy ani supernatural enemies mule completely change hote.",

      PURPLE,

      Array(

        StoryScene(
          "START",
          "BIX-02 ROBOT",
          "Jujutsu Kaisen world loading. Cursed-energy system detected. Story automatically starting."
        ),

        StoryScene(
          "START",
          "NARRATOR",
          "Yuji Itadori ek normal student aahe. Eka strange cursed object mule to hidden supernatural world madhye enter karto."
        ),

        StoryScene(
          "MIDDLE",
          "YUJI",
          "Mi majhya friends na protect karaycha prayatna karnaar. Problem mothi asli tari mi easily give up karnaar nahi."
        ),

        StoryScene(
          "MIDDLE",
          "MEGUMI",
          "Cursed objects ani curses invisible danger create kartat. Situation carefully samjun ghyavi lagte."
        ),

        StoryScene(
          "MIDDLE",
          "BIX-02 ROBOT",
          "Threat level increasing. Training, teamwork ani smart decisions required."
        ),

        StoryScene(
          "ENDING",
          "NARRATOR",
          "Yuji chi journey personal growth sobat increasingly mothya supernatural conflicts kade jate."
        ),

        StoryScene(
          "ENDING",
          "BIX-02 ROBOT",
          "Jujutsu overview complete. Ata character select karun powers ani character story bagha."
        )
      ),

      Array(

        CharacterInfo(
          "SUKUNA",
          "Major Antagonist",
          "CURSED ENERGY",
          Array(
            "Extremely high cursed-energy output",
            "Advanced cursed techniques",
            "Powerful close-range combat",
            "Wide-area attacks",
            "Exceptional battle awareness"
          ),
          "Proud, intimidating and highly confident.",
          "Sukuna is a major supernatural force connected to Yuji's journey.",
          1,
          PINK,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Sukuna profile loaded. Character story starting."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Yuji cursed world madhye enter karto ani ek ancient powerful curse tyachya journey sobat strongly connected hoto."
            ),

            StoryScene(
              "START",
              "YUJI",
              "Mala majhya choices chi responsibility samjun ghyaychi aahe."
            ),

            StoryScene(
              "MIDDLE",
              "SUKUNA",
              "Power la underestimate karne dangerous aahe. Control ani awareness donhi important aahet."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Threat scan: EXTREME."
            ),

            StoryScene(
              "MIDDLE",
              "NARRATOR",
              "Yuji increasingly difficult cursed conflicts madhye jato ani Sukuna chi presence mothi banat jate."
            ),

            StoryScene(
              "MIDDLE",
              "YUJI",
              "Mi easily give up karnaar nahi."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Sukuna cha influence Yuji chya personal journey ani cursed-world conflict var motha effect karto."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Sukuna chapter complete."
            )
          )
        ),

        CharacterInfo(
          "MAHITO",
          "Major Antagonist",
          "SOUL MANIPULATION",
          Array(
            "Soul-based cursed technique",
            "Flexible transformations",
            "Rapid adaptation",
            "Creative cursed-energy use",
            "Psychological pressure"
          ),
          "Curious, unpredictable and manipulative.",
          "Mahito is a dangerous curse interested in human nature and the soul.",
          5,
          PURPLE,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Mahito profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Mahito human emotions ani soul samjun ghenyachi curiosity dakhavto."
            ),

            StoryScene(
              "MIDDLE",
              "MAHITO",
              "People change hotat. Mala transformation samjun ghyaycha aahe."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Technique highly flexible. Prediction difficult."
            ),

            StoryScene(
              "MIDDLE",
              "YUJI",
              "Mala people suffer hotana baghaycha nahi."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Mahito sobatchya encounters mule Yuji la responsibility ani determination samjun ghyavi lagte."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Mahito chapter complete."
            )
          )
        ),

        CharacterInfo(
          "TOJI",
          "Human Combat Specialist",
          "PHYSICAL MASTERY",
          Array(
            "Exceptional physical ability",
            "Fast reflexes",
            "Advanced weapon handling",
            "Stealth",
            "Tactical preparation"
          ),
          "Calm, practical and tactical.",
          "Toji's fighting style focuses heavily on physical skill, equipment and preparation.",
          3,
          CYAN,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Toji profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Jujutsu world madhye ???????? fighter cursed energy var depend ??? ????."
            ),

            StoryScene(
              "MIDDLE",
              "TOJI",
              "Opponent samjun ghya, preparation kara ani timing var focus kara."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Combat efficiency: HIGH."
            ),

            StoryScene(
              "MIDDLE",
              "NARRATOR",
              "Toji cha style speed, weapons ani tactical planning var based aahe."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Tyachi history powerful sorcerers chya world var long-term effect takte."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Toji chapter complete."
            )
          )
        )
      )
    ),


    // ========================================================
    // DEMON SLAYER
    // ========================================================

    AnimeInfo(

      "DEMON SLAYER",

      "DEMONS / SWORDSMEN / DARK FANTASY",

      "Tanjiro chi journey demons ani swordsmanship chya dangerous world madhye ???? ????.",

      RED,

      Array(

        StoryScene(
          "START",
          "BIX-02 ROBOT",
          "Demon Slayer world loading. Demon and swordsman system online."
        ),

        StoryScene(
          "START",
          "NARRATOR",
          "Tanjiro Kamado ek kind ani hardworking boy aahe. Eka tragic event mule tyacha life drastically change hoto."
        ),

        StoryScene(
          "MIDDLE",
          "TANJIRO",
          "Mi Nezuko la protect karnaar. Training ?????? difficult ???? ??? ?? stop ????? ????."
        ),

        StoryScene(
          "MIDDLE",
          "ZENITSU",
          "Mala fear ?????, pan difficult moment la courage dakhvaycha prayatna karto."
        ),

        StoryScene(
          "MIDDLE",
          "INOSUKE",
          "Challenge ??? ki mi ???? ????? ????."
        ),

        StoryScene(
          "ENDING",
          "NARRATOR",
          "Tanjiro chi path increasingly dangerous demons kade jate."
        ),

        StoryScene(
          "ENDING",
          "BIX-02 ROBOT",
          "Demon Slayer overview complete."
        )
      ),

      Array(

        CharacterInfo(
          "MUZAN",
          "Main Demon Antagonist",
          "DEMONIC ABILITIES",
          Array(
            "Exceptional physical strength",
            "Rapid regeneration",
            "Shape changing",
            "Blood-based abilities",
            "Influence over demons"
          ),
          "Controlling, secretive and dangerous.",
          "Muzan demon hierarchy cha central threat aahe.",
          2,
          RED,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Muzan profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Tanjiro chi family tragedy tyala demon world chya hidden side samor ????."
            ),

            StoryScene(
              "START",
              "TANJIRO",
              "Mala Nezuko la protect karaycha aahe ani source samjun ghyaycha aahe."
            ),

            StoryScene(
              "MIDDLE",
              "MUZAN",
              "Survival ani control he major priorities aahet."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Regeneration detected. Threat level VERY HIGH."
            ),

            StoryScene(
              "MIDDLE",
              "NARRATOR",
              "Tanjiro ani Demon Slayers stronger hot jatana increasingly difficult missions face kartat."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Muzan cha threat Tanjiro chya journey cha major target banto."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Muzan chapter complete."
            )
          )
        ),

        CharacterInfo(
          "AKAZA",
          "Upper-Rank Demon",
          "MARTIAL DEMON COMBAT",
          Array(
            "Extreme physical strength",
            "High-speed combat",
            "Regeneration",
            "Battle sensing",
            "Shockwave-style attacks"
          ),
          "Competitive, focused and battle-oriented.",
          "Akaza is an experienced combat-focused demon.",
          1,
          ORANGE,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Akaza profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Some demons ????????? combat skill mule especially dangerous bantat."
            ),

            StoryScene(
              "MIDDLE",
              "AKAZA",
              "Strong opponent samor ??? ki battle interesting hote."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Speed and regeneration both high."
            ),

            StoryScene(
              "MIDDLE",
              "TANJIRO",
              "Mi ?????? training ?? ??????? ??????."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Akaza cha chapter battle, ambition ani memory themes sobat ????? ????."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Akaza chapter complete."
            )
          )
        ),

        CharacterInfo(
          "DOMA",
          "Upper-Rank Demon",
          "ICE-BASED TECHNIQUES",
          Array(
            "Ice creation",
            "Wide-area attacks",
            "Regeneration",
            "Long-range techniques",
            "Battlefield control"
          ),
          "Calm and unusual.",
          "Doma ?? ice-based abilities ???????? powerful demon ???.",
          2,
          CYAN,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Doma profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Powerful demons ?????????? unique techniques ???????."
            ),

            StoryScene(
              "MIDDLE",
              "DOMA",
              "People ????????? emotions hide kartat. Mala observe karayla interesting ?????."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Area-control ability detected."
            ),

            StoryScene(
              "MIDDLE",
              "NARRATOR",
              "Ice-based techniques battlefield environment change ??? ?????."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Doma cha role ???? demon conflicts ??? character histories ???? ????? ????."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Doma chapter complete."
            )
          )
        )
      )
    ),


    // ========================================================
    // ATTACK ON TITAN
    // ========================================================

    AnimeInfo(

      "ATTACK ON TITAN",

      "TITANS / MYSTERY / WAR / FREEDOM",

      "Walls, Titans, hidden history ani freedom cha search ya world cha major part aahe.",

      ORANGE,

      Array(

        StoryScene(
          "START",
          "BIX-02 ROBOT",
          "Titan world loading. Giant wall system detected."
        ),

        StoryScene(
          "START",
          "NARRATOR",
          "Humanity walls chya ?? ????. Outside world ani Titans ????? ???? questions ????."
        ),

        StoryScene(
          "MIDDLE",
          "EREN",
          "Mala truth samjun ghyaycha aahe. Walls chya bahercha world mala pah??cha aahe."
        ),

        StoryScene(
          "MIDDLE",
          "ARMIN",
          "Information analyse karun plan ban??? important aahe."
        ),

        StoryScene(
          "MIDDLE",
          "MIKASA",
          "Mi majhya friends na protect karaycha ??????? ?????."
        ),

        StoryScene(
          "ENDING",
          "NARRATOR",
          "Titans ???? ???? historical mystery ani world conflict ?????? ???."
        ),

        StoryScene(
          "ENDING",
          "BIX-02 ROBOT",
          "Attack on Titan overview complete."
        )
      ),

      Array(

        CharacterInfo(
          "BEAST TITAN",
          "Titan Shifter",
          "TITAN POWER",
          Array(
            "Large Titan form",
            "Exceptional throwing ability",
            "Strong physical power",
            "Strategic battlefield use",
            "Large battlefield presence"
          ),
          "Strategic and analytical.",
          "Beast Titan ?? major battlefield threat ???.",
          4,
          ORANGE,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Beast Titan profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Humanity Titans ????? ??????? ???? ???????? ??????? ????."
            ),

            StoryScene(
              "MIDDLE",
              "BEAST TITAN",
              "Battle only strength ?? depend ????. Timing ani strategy equally important aahet."
            ),

            StoryScene(
              "MIDDLE",
              "ARMIN",
              "Situation analyse karun plan ???? ????? ?????."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Long-range threat detected."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Beast Titan cha role larger war ani Titan mystery sobat strongly connected aahe."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Beast Titan chapter complete."
            )
          )
        ),

        CharacterInfo(
          "REINER",
          "Armored Titan",
          "ARMORED TITAN",
          Array(
            "Heavy armor",
            "High durability",
            "Strong close combat",
            "Battle endurance",
            "Defensive capability"
          ),
          "Determined and conflicted.",
          "Reiner chi story identity ani duty yanchya conflict ????? ?????.",
          5,
          GOLD,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Armored Titan profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Titan warriors normal identities ???? major secrets hide ??? ?????."
            ),

            StoryScene(
              "MIDDLE",
              "REINER",
              "Mission ani personal feelings ???????? balance ????? difficult aahe."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Armor resistance: HIGH."
            ),

            StoryScene(
              "MIDDLE",
              "NARRATOR",
              "Reiner cha personal history larger war sobat increasingly connected hote."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "His chapter shows how a large conflict affects individual people."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Reiner chapter complete."
            )
          )
        ),

        CharacterInfo(
          "ANNIE",
          "Female Titan",
          "MARTIAL ARTS / TITAN FORM",
          Array(
            "Fast movement",
            "Close-range combat",
            "Martial arts",
            "Selective hardening",
            "High combat efficiency"
          ),
          "Reserved, disciplined and focused.",
          "Annie combines human combat training with Titan abilities.",
          3,
          CYAN,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Female Titan profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Annie ?? human combat training Titan form ??????? useful ????."
            ),

            StoryScene(
              "MIDDLE",
              "ANNIE",
              "Every movement la purpose ?????? ???."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Fast close-combat pattern detected."
            ),

            StoryScene(
              "MIDDLE",
              "NARRATOR",
              "Annie chi identity Scouts sathi ???? mystery ????."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Her chapter enemy, identity ani truth ya themes ????? ???? ????."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Annie chapter complete."
            )
          )
        )
      )
    ),


    // ========================================================
    // NARUTO SHIPPUDEN
    // ========================================================

    AnimeInfo(

      "NARUTO SHIPPUDEN",

      "NINJA / WAR / CLANS / FRIENDSHIP",

      "Naruto chi journey friendship, rivalry, war ani peace yanchya madhun ???? ????.",

      CYAN,

      Array(

        StoryScene(
          "START",
          "BIX-02 ROBOT",
          "Shinobi world loading."
        ),

        StoryScene(
          "START",
          "NARRATOR",
          "Naruto cha dream strong shinobi banun respect ?????????? ???."
        ),

        StoryScene(
          "MIDDLE",
          "NARUTO",
          "Mi ??? ?????? ????. Friends ani village sathi mi ???? ?????."
        ),

        StoryScene(
          "MIDDLE",
          "KAKASHI",
          "Teamwork ani trust strong ninja team cha base aahe."
        ),

        StoryScene(
          "MIDDLE",
          "SASUKE",
          "Past cha truth samjun ghenya sathi mala difficult path choose karava lagnaar."
        ),

        StoryScene(
          "ENDING",
          "NARRATOR",
          "Naruto chi journey ?????? war ani peace ???? ?????????????? ???????."
        ),

        StoryScene(
          "ENDING",
          "BIX-02 ROBOT",
          "Naruto overview complete."
        )
      ),

      Array(

        CharacterInfo(
          "MADARA",
          "Legendary Antagonist",
          "SHARINGAN / UCHIHA POWER",
          Array(
            "Sharingan abilities",
            "Powerful fire techniques",
            "Advanced tactics",
            "Exceptional combat",
            "Large-scale war abilities"
          ),
          "Confident and strategic.",
          "Madara shinobi history ???? major figure ???.",
          1,
          PURPLE,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Madara profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Shinobi history rival clans ani repeated conflicts ne ?????? ???."
            ),

            StoryScene(
              "MIDDLE",
              "MADARA",
              "Repeated conflict ????? ??? world ??????????? enormous power ?????? ?????."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Strategic battlefield pattern detected."
            ),

            StoryScene(
              "MIDDLE",
              "NARUTO",
              "Mala fear ?? based peace ???. Trust ani understanding important ????."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Madara cha plan shinobi world ???? largest conflicts ???? ??? conflict ????? ?????."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Madara chapter complete."
            )
          )
        ),

        CharacterInfo(
          "PAIN",
          "Major Antagonist",
          "RINNEGAN / SIX PATHS",
          Array(
            "Rinnegan",
            "Multiple coordinated bodies",
            "Gravity-based techniques",
            "Shared vision",
            "Large-scale attacks"
          ),
          "Serious and philosophical.",
          "Pain cha ????? war, suffering ani peace chya experience ?? ?????? ???.",
          2,
          RED,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Pain profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Pain cha past war ani loss mule deeply affected aahe."
            ),

            StoryScene(
              "MIDDLE",
              "PAIN",
              "People suffering samjun ???????????? conflict repeat ??? ????."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Multi-body combat system active."
            ),

            StoryScene(
              "MIDDLE",
              "NARUTO",
              "Suffering samjun ghen? important aahe, pan fear create karun peace ???? ????."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Pain chapter Naruto chya peace understanding madhye important turning point ????."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Pain chapter complete."
            )
          )
        ),

        CharacterInfo(
          "OBITO",
          "Major Antagonist",
          "SPACE-TIME / SHARINGAN",
          Array(
            "Space-time technique",
            "Sharingan abilities",
            "Stealth",
            "Tactical deception",
            "Advanced combat experience"
          ),
          "Secretive and determined.",
          "Obito chi story personal loss ani large-scale plans yanna connect ????.",
          5,
          CYAN,
          Array(

            StoryScene(
              "START",
              "BIX-02 ROBOT",
              "Masked ninja profile loaded."
            ),

            StoryScene(
              "START",
              "NARRATOR",
              "Obito cha early dream respected shinobi ban?????? ????."
            ),

            StoryScene(
              "MIDDLE",
              "OBITO",
              "Past experiences mule majha world b??????? perspective ?????."
            ),

            StoryScene(
              "MIDDLE",
              "BIX-02 ROBOT",
              "Space-time ability detected."
            ),

            StoryScene(
              "MIDDLE",
              "KAKASHI",
              "Past cha effect future decisions ?? ???? ??? ????."
            ),

            StoryScene(
              "ENDING",
              "NARRATOR",
              "Obito cha chapter loss, friendship, choices ani consequences ????? ?????."
            ),

            StoryScene(
              "ENDING",
              "BIX-02 ROBOT",
              "Obito chapter complete."
            )
          )
        )
      )
    )
  )


// ============================================================
// LOGIN SCREEN
// ============================================================

def loginScreen(): JPanel = {

  val root =
    new JPanel(
      new BorderLayout()
    )

  root.setBackground(BG)

  root.add(
    makeHeader(
      "SECURE LOGIN"
    ),
    BorderLayout.NORTH
  )

  val center =
    new JPanel(
      new GridBagLayout()
    )

  center.setBackground(BG)

  val box =
    new JPanel()

  box.setBackground(PANEL)

  box.setLayout(
    new BoxLayout(
      box,
      BoxLayout.Y_AXIS
    )
  )

  box.setBorder(
    BorderFactory.createCompoundBorder(
      BorderFactory.createLineBorder(
        CYAN,
        2
      ),
      BorderFactory.createEmptyBorder(
        20,
        35,
        20,
        35
      )
    )
  )

  val robot =
    robotLabel()

  robot.setAlignmentX(
    Component.CENTER_ALIGNMENT
  )

  val title =
    makeLabel(
      "BIXUU ANIME ENEMIES",
      25,
      PURPLE,
      true
    )

  title.setAlignmentX(
    Component.CENTER_ALIGNMENT
  )

  val prompt =
    makeLabel(
      "ENTER PASSWORD",
      14,
      MUTED,
      true
    )

  prompt.setAlignmentX(
    Component.CENTER_ALIGNMENT
  )

  val pass =
    new JPasswordField()

  pass.setFont(
    makeFont(
      18,
      true
    )
  )

  pass.setHorizontalAlignment(
    SwingConstants.CENTER
  )

  pass.setMaximumSize(
    new Dimension(
      360,
      43
    )
  )

  val enter =
    makeButton(
      "UNLOCK ANIME STORY LAB"
    )

  enter.setAlignmentX(
    Component.CENTER_ALIGNMENT
  )

  val status =
    makeLabel(
      "Password protected",
      13,
      MUTED,
      false
    )

  status.setAlignmentX(
    Component.CENTER_ALIGNMENT
  )

  box.add(robot)

  box.add(
    title
  )

  box.add(
    Box.createVerticalStrut(
      12
    )
  )

  box.add(
    prompt
  )

  box.add(
    Box.createVerticalStrut(
      8
    )
  )

  box.add(
    pass
  )

  box.add(
    Box.createVerticalStrut(
      14
    )
  )

  box.add(
    enter
  )

  box.add(
    Box.createVerticalStrut(
      8
    )
  )

  box.add(
    status
  )

  center.add(
    box
  )

  root.add(
    center,
    BorderLayout.CENTER
  )

  // ----------------------------------------------------------
  // LOGIN LISTENER
  // ----------------------------------------------------------

  enter.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        val entered =
          new String(
            pass.getPassword
          )

        if (
          entered == PASSWORD
        ) {

          showPage(
            animeLibraryScreen()
          )

        } else {

          status.setText(
            "WRONG PASSWORD"
          )

          status.setForeground(
            RED
          )

          pass.setText("")
        }
      }
    }
  )

  pass.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        enter.doClick()
      }
    }
  )

  root
}


// ============================================================
// ANIME LIBRARY
// ============================================================

def animeLibraryScreen(): JPanel = {

  val root =
    new JPanel(
      new BorderLayout(
        10,
        10
      )
    )

  root.setBackground(BG)

  root.setBorder(
    BorderFactory.createEmptyBorder(
      14,
      14,
      14,
      14
    )
  )

  root.add(
    makeHeader(
      "ANIME ENEMIES LIBRARY"
    ),
    BorderLayout.NORTH
  )

  val intro =
    new JPanel(
      new BorderLayout()
    )

  intro.setBackground(BG)

  intro.add(
    makeLabel(
      "SELECT ANIME",
      25,
      TEXT,
      true
    ),
    BorderLayout.WEST
  )

  intro.add(
    makeLabel(
      "CLICK ONCE = STORY STARTS",
      12,
      GREEN,
      false
    ),
    BorderLayout.EAST
  )

  val cards =
    new JPanel(
      new GridLayout(
        0,
        2,
        14,
        14
      )
    )

  cards.setBackground(BG)

  var i =
    0

  while (
    i < animeDatabase.length
  ) {

    val anime =
      animeDatabase(i)

    val card =
      new JPanel()

    card.setLayout(
      new BoxLayout(
        card,
        BoxLayout.Y_AXIS
      )
    )

    card.setBackground(PANEL)

    card.setBorder(
      BorderFactory.createCompoundBorder(
        BorderFactory.createLineBorder(
          anime.accent,
          2
        ),
        BorderFactory.createEmptyBorder(
          15,
          18,
          15,
          18
        )
      )
    )

    val name =
      makeLabel(
        anime.name,
        22,
        anime.accent,
        true
      )

    name.setAlignmentX(
      Component.CENTER_ALIGNMENT
    )

    val sub =
      makeLabel(
        anime.subtitle,
        12,
        MUTED,
        false
      )

    sub.setAlignmentX(
      Component.CENTER_ALIGNMENT
    )

    val desc =
      makeTextArea(
        anime.description,
        13
      )

    desc.setMaximumSize(
      new Dimension(
        520,
        80
      )
    )

    val open =
      makeButton(
        "OPEN STORY"
      )

    open.setAlignmentX(
      Component.CENTER_ALIGNMENT
    )

    card.add(name)

    card.add(
      Box.createVerticalStrut(
        5
      )
    )

    card.add(sub)

    card.add(
      Box.createVerticalStrut(
        8
      )
    )

    card.add(desc)

    card.add(
      Box.createVerticalStrut(
        8
      )
    )

    card.add(open)

    open.addActionListener(
      new ActionListener {

        def actionPerformed(
          e: ActionEvent
        ): Unit = {

          showPage(
            animeStoryScreen(
              anime
            )
          )
        }
      }
    )

    cards.add(card)

    i += 1
  }

  val scroll =
    new JScrollPane(
      cards
    )

  scroll.setBorder(null)

  scroll.getViewport.setBackground(BG)

  root.add(
    intro,
    BorderLayout.BEFORE_FIRST_LINE
  )

  root.add(
    scroll,
    BorderLayout.CENTER
  )

  val bottom =
    new JPanel(
      new FlowLayout(
        FlowLayout.RIGHT
      )
    )

  bottom.setBackground(BG)

  val lock =
    makeButton(
      "LOCK"
    )

  lock.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        showPage(
          loginScreen()
        )
      }
    }
  )

  bottom.add(lock)

  root.add(
    bottom,
    BorderLayout.SOUTH
  )

  root
}


// ============================================================
// ANIME STORY SCREEN
// ============================================================

def animeStoryScreen(
  anime: AnimeInfo
): JPanel = {

  // ==========================================================
  // STATE
  // ==========================================================

  var overviewMode =
    true

  var sceneIndex =
    0

  var characterIndex =
    0

  var autoPlaying =
    false

  var timer:
    javax.swing.Timer =
    null


  // ==========================================================
  // BUTTONS FIRST
  // ==========================================================
  //
  // IMPORTANT:
  // Every button is created BEFORE any listener below.
  // This prevents Scala forward-reference errors.
  //

  val startButton =
    makeButton(
      "START"
    )

  val previousButton =
    makeButton(
      "< PREVIOUS"
    )

  val nextButton =
    makeButton(
      "NEXT >"
    )

  val autoButton =
    makeButton(
      "AUTO PLAY"
    )

  val fullButton =
    makeButton(
      "READ FULL"
    )

  val overviewButton =
    makeButton(
      "ANIME OVERVIEW"
    )

  val profileButton =
    makeButton(
      "PROFILE"
    )

  val backButton =
    makeButton(
      "ANIME LIST"
    )


  // ==========================================================
  // ROOT
  // ==========================================================

  val root =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  root.setBackground(BG)

  root.setBorder(
    BorderFactory.createEmptyBorder(
      10,
      10,
      10,
      10
    )
  )

  root.add(
    makeHeader(
      anime.name
    ),
    BorderLayout.NORTH
  )


  // ==========================================================
  // CHARACTER LIST
  // ==========================================================

  val left =
    new JPanel(
      new BorderLayout(
        5,
        5
      )
    )

  left.setBackground(PANEL)

  left.setPreferredSize(
    new Dimension(
      235,
      0
    )
  )

  left.setBorder(
    BorderFactory.createEmptyBorder(
      8,
      8,
      8,
      8
    )
  )

  left.add(
    makeLabel(
      "CHARACTERS",
      16,
      anime.accent,
      true
    ),
    BorderLayout.NORTH
  )

  val characterModel =
    new DefaultListModel[String]()

  var ci =
    0

  while (
    ci < anime.characters.length
  ) {

    val c =
      anime.characters(ci)

    characterModel.addElement(
      c.name +
      " - " +
      c.powerName
    )

    ci += 1
  }

  val characterList =
    new JList[String](
      characterModel
    )

  characterList.setFont(
    makeFont(
      11,
      false
    )
  )

  characterList.setForeground(TEXT)

  characterList.setBackground(PANEL2)

  characterList.setSelectionMode(
    ListSelectionModel.SINGLE_SELECTION
  )

  characterList.setSelectedIndex(0)

  left.add(
    new JScrollPane(
      characterList
    ),
    BorderLayout.CENTER
  )

  left.add(
    robotLabel(),
    BorderLayout.SOUTH
  )

  root.add(
    left,
    BorderLayout.WEST
  )


  // ==========================================================
  // CENTER
  // ==========================================================

  val center =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  center.setBackground(BG)


  // ==========================================================
  // FACE HOLDER
  // ==========================================================

  val faceHolder =
    new JPanel(
      new BorderLayout()
    )

  faceHolder.setBackground(BG)

  faceHolder.setPreferredSize(
    new Dimension(
      350,
      460
    )
  )

  def refreshFace(): Unit = {

    faceHolder.removeAll()

    val c =
      anime.characters(
        characterIndex
      )

    val img =
      characterFaceImage(
        c,
        335,
        460
      )

    faceHolder.add(
      new JLabel(
        new ImageIcon(
          img
        )
      ),
      BorderLayout.CENTER
    )

    faceHolder.validate()

    faceHolder.repaint()
  }

  center.add(
    faceHolder,
    BorderLayout.WEST
  )


  // ==========================================================
  // STORY PANEL
  // ==========================================================

  val storyPanel =
    new JPanel(
      new BorderLayout(
        5,
        5
      )
    )

  storyPanel.setBackground(PANEL)


  // ==========================================================
  // STORY HEADER
  // ==========================================================

  val storyHeader =
    new JPanel(
      new BorderLayout()
    )

  storyHeader.setBackground(PANEL)

  storyHeader.setBorder(
    BorderFactory.createEmptyBorder(
      10,
      12,
      10,
      12
    )
  )

  val stageLabel =
    makeLabel(
      "START",
      16,
      GREEN,
      true
    )

  val speakerLabel =
    makeLabel(
      "BIX-02 ROBOT",
      18,
      PINK,
      true
    )

  val counterLabel =
    makeLabel(
      "",
      12,
      MUTED,
      false
    )

  val headerLeft =
    new JPanel()

  headerLeft.setLayout(
    new BoxLayout(
      headerLeft,
      BoxLayout.Y_AXIS
    )
  )

  headerLeft.setBackground(PANEL)

  headerLeft.add(
    stageLabel
  )

  headerLeft.add(
    Box.createVerticalStrut(4)
  )

  headerLeft.add(
    speakerLabel
  )

  storyHeader.add(
    headerLeft,
    BorderLayout.WEST
  )

  storyHeader.add(
    counterLabel,
    BorderLayout.EAST
  )

  storyPanel.add(
    storyHeader,
    BorderLayout.NORTH
  )


  // ==========================================================
  // MAIN STORY TEXT
  // ==========================================================

  val storyText =
    makeTextArea(
      "",
      17
    )

  storyPanel.add(
    new JScrollPane(
      storyText
    ),
    BorderLayout.CENTER
  )


  // ==========================================================
  // TABS
  // ==========================================================

  val tabs =
    new JTabbedPane()

  val profileArea =
    makeTextArea(
      "",
      14
    )

  val powersArea =
    makeTextArea(
      "",
      14
    )

  val fullCharacterArea =
    makeTextArea(
      "",
      14
    )

  val fullAnimeArea =
    makeTextArea(
      "",
      14
    )

  tabs.addTab(
    "PROFILE",
    new JScrollPane(
      profileArea
    )
  )

  tabs.addTab(
    "POWERS",
    new JScrollPane(
      powersArea
    )
  )

  tabs.addTab(
    "FULL CHARACTER",
    new JScrollPane(
      fullCharacterArea
    )
  )

  tabs.addTab(
    "FULL ANIME",
    new JScrollPane(
      fullAnimeArea
    )
  )

  tabs.setPreferredSize(
    new Dimension(
      520,
      220
    )
  )

  storyPanel.add(
    tabs,
    BorderLayout.SOUTH
  )

  center.add(
    storyPanel,
    BorderLayout.CENTER
  )

  root.add(
    center,
    BorderLayout.CENTER
  )


  // ==========================================================
  // FULL CHARACTER TEXT
  // ==========================================================

  def characterFullText(
    c: CharacterInfo
  ): String = {

    val sb =
      new StringBuilder()

    sb.append(
      "FULL CHARACTER STORY\n"
    )

    sb.append(
      "==============================\n\n"
    )

    sb.append(
      "CHARACTER: "
    )

    sb.append(
      c.name
    )

    sb.append(
      "\nROLE: "
    )

    sb.append(
      c.role
    )

    sb.append(
      "\nPOWER: "
    )

    sb.append(
      c.powerName
    )

    sb.append(
      "\n\n"
    )

    var i =
      0

    while (
      i < c.scenes.length
    ) {

      val s =
        c.scenes(i)

      sb.append(
        "SCENE "
      )

      sb.append(
        (i + 1).toString
      )

      sb.append(
        " | "
      )

      sb.append(
        s.stage
      )

      sb.append(
        "\n"
      )

      sb.append(
        "SPEAKER: "
      )

      sb.append(
        s.speaker
      )

      sb.append(
        "\n\n"
      )

      sb.append(
        s.text
      )

      sb.append(
        "\n\n"
      )

      sb.append(
        "----------------------------------------\n\n"
      )

      i += 1
    }

    sb.append(
      "ENDING\n\n"
    )

    sb.append(
      "Character chapter complete."
    )

    sb.toString
  }


  // ==========================================================
  // FULL ANIME TEXT
  // ==========================================================

  def animeFullText(): String = {

    val sb =
      new StringBuilder()

    sb.append(
      anime.name
    )

    sb.append(
      "\n==============================\n\n"
    )

    sb.append(
      anime.description
    )

    sb.append(
      "\n\n"
    )

    sb.append(
      "ANIME STORY\n\n"
    )

    var i =
      0

    while (
      i < anime.overview.length
    ) {

      val s =
        anime.overview(i)

      sb.append(
        "SCENE "
      )

      sb.append(
        (i + 1).toString
      )

      sb.append(
        " | "
      )

      sb.append(
        s.stage
      )

      sb.append(
        "\n"
      )

      sb.append(
        "SPEAKER: "
      )

      sb.append(
        s.speaker
      )

      sb.append(
        "\n\n"
      )

      sb.append(
        s.text
      )

      sb.append(
        "\n\n"
      )

      i += 1
    }

    sb.append(
      "\n==============================\n"
    )

    sb.append(
      "CHARACTER LIST\n"
    )

    sb.append(
      "==============================\n\n"
    )

    var c =
      0

    while (
      c < anime.characters.length
    ) {

      val ch =
        anime.characters(c)

      sb.append(
        ch.name
      )

      sb.append(
        " | "
      )

      sb.append(
        ch.powerName
      )

      sb.append(
        "\n"
      )

      sb.append(
        ch.description
      )

      sb.append(
        "\n\n"
      )

      c += 1
    }

    sb.append(
      "END OF INCLUDED STORY SUMMARY"
    )

    sb.toString
  }


  // ==========================================================
  // UPDATE CHARACTER
  // ==========================================================

  def updateCharacter(): Unit = {

    val c =
      anime.characters(
        characterIndex
      )

    profileArea.setText(
      "CHARACTER PROFILE\n" +
      "==============================\n\n" +
      "NAME\n" +
      c.name +
      "\n\n" +
      "ROLE\n" +
      c.role +
      "\n\n" +
      "MAIN POWER\n" +
      c.powerName +
      "\n\n" +
      "PERSONALITY\n" +
      c.personality +
      "\n\n" +
      "DESCRIPTION\n" +
      c.description
    )

    val powerBuilder =
      new StringBuilder()

    powerBuilder.append(
      "POWER SYSTEM\n"
    )

    powerBuilder.append(
      "==============================\n\n"
    )

    powerBuilder.append(
      c.powerName
    )

    powerBuilder.append(
      "\n\n"
    )

    var p =
      0

    while (
      p < c.powers.length
    ) {

      powerBuilder.append(
        (p + 1).toString
      )

      powerBuilder.append(
        ". "
      )

      powerBuilder.append(
        c.powers(p)
      )

      powerBuilder.append(
        "\n\n"
      )

      p += 1
    }

    powersArea.setText(
      powerBuilder.toString
    )

    fullCharacterArea.setText(
      characterFullText(
        c
      )
    )

    fullAnimeArea.setText(
      animeFullText()
    )

    refreshFace()
  }


  // ==========================================================
  // SHOW OVERVIEW
  // ==========================================================

  def showOverview(): Unit = {

    overviewMode =
      true

    sceneIndex =
      0

    val s =
      anime.overview(0)

    stageLabel.setText(
      "STAGE: " +
      s.stage
    )

    speakerLabel.setText(
      "SPEAKER: " +
      s.speaker
    )

    counterLabel.setText(
      "OVERVIEW 1 / " +
      anime.overview.length
    )

    storyText.setText(
      "BIX-02 ROBOT STORY MODE\n\n" +
      s.text
    )

    storyText.setCaretPosition(0)

    previousButton.setEnabled(false)

    nextButton.setEnabled(
      anime.overview.length > 1
    )

    tabs.setSelectedIndex(3)

    updateCharacter()
  }


  // ==========================================================
  // SHOW CHARACTER STORY
  // ==========================================================

  def showCharacterStory(): Unit = {

    overviewMode =
      false

    val c =
      anime.characters(
        characterIndex
      )

    val s =
      c.scenes(
        sceneIndex
      )

    stageLabel.setText(
      "STAGE: " +
      s.stage
    )

    speakerLabel.setText(
      "SPEAKER: " +
      s.speaker
    )

    counterLabel.setText(
      "SCENE " +
      (sceneIndex + 1) +
      " / " +
      c.scenes.length
    )

    storyText.setText(
      "CHARACTER STORY\n\n" +
      "CHARACTER: " +
      c.name +
      "\n\n" +
      s.text +
      "\n\n" +
      "----------------------------------------\n" +
      "Original / paraphrased story text"
    )

    storyText.setCaretPosition(0)

    previousButton.setEnabled(
      sceneIndex > 0
    )

    nextButton.setEnabled(
      sceneIndex <
      c.scenes.length - 1
    )

    tabs.setSelectedIndex(0)

    updateCharacter()
  }


  // ==========================================================
  // CHARACTER LIST LISTENER
  // ==========================================================

  characterList.addListSelectionListener(
    new javax.swing.event.ListSelectionListener {

      def valueChanged(
        e: javax.swing.event.ListSelectionEvent
      ): Unit = {

        if (
          !e.getValueIsAdjusting &&
          characterList.getSelectedIndex >= 0
        ) {

          if (
            timer != null
          ) {

            timer.stop()

            autoPlaying =
              false

            autoButton.setText(
              "AUTO PLAY"
            )
          }

          characterIndex =
            characterList.getSelectedIndex

          sceneIndex =
            0

          showCharacterStory()
        }
      }
    }
  )


  // ==========================================================
  // START LISTENER
  // ==========================================================

  startButton.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        if (
          timer != null
        ) {

          timer.stop()

          autoPlaying =
            false

          autoButton.setText(
            "AUTO PLAY"
          )
        }

        sceneIndex =
          0

        if (
          overviewMode
        ) {

          showOverview()

        } else {

          showCharacterStory()
        }
      }
    }
  )


  // ==========================================================
  // PREVIOUS LISTENER
  // ==========================================================

  previousButton.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        if (
          overviewMode
        ) {

          if (
            sceneIndex > 0
          ) {

            sceneIndex -= 1

            val s =
              anime.overview(
                sceneIndex
              )

            stageLabel.setText(
              "STAGE: " +
              s.stage
            )

            speakerLabel.setText(
              "SPEAKER: " +
              s.speaker
            )

            counterLabel.setText(
              "OVERVIEW " +
              (sceneIndex + 1) +
              " / " +
              anime.overview.length
            )

            storyText.setText(
              s.text
            )

            storyText.setCaretPosition(0)
          }

          previousButton.setEnabled(
            sceneIndex > 0
          )

          nextButton.setEnabled(
            sceneIndex <
            anime.overview.length - 1
          )

        } else {

          if (
            sceneIndex > 0
          ) {

            sceneIndex -= 1

            showCharacterStory()
          }
        }
      }
    }
  )


  // ==========================================================
  // NEXT LISTENER
  // ==========================================================

  nextButton.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        if (
          overviewMode
        ) {

          if (
            sceneIndex <
            anime.overview.length - 1
          ) {

            sceneIndex += 1

            val s =
              anime.overview(
                sceneIndex
              )

            stageLabel.setText(
              "STAGE: " +
              s.stage
            )

            speakerLabel.setText(
              "SPEAKER: " +
              s.speaker
            )

            counterLabel.setText(
              "OVERVIEW " +
              (sceneIndex + 1) +
              " / " +
              anime.overview.length
            )

            storyText.setText(
              s.text
            )

            storyText.setCaretPosition(0)
          }

          previousButton.setEnabled(
            sceneIndex > 0
          )

          nextButton.setEnabled(
            sceneIndex <
            anime.overview.length - 1
          )

        } else {

          val c =
            anime.characters(
              characterIndex
            )

          if (
            sceneIndex <
            c.scenes.length - 1
          ) {

            sceneIndex += 1

            showCharacterStory()
          }
        }
      }
    }
  )


  // ==========================================================
  // AUTO PLAY LISTENER
  // ==========================================================

  autoButton.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        if (
          autoPlaying
        ) {

          if (
            timer != null
          ) {

            timer.stop()
          }

          autoPlaying =
            false

          autoButton.setText(
            "AUTO PLAY"
          )

        } else {

          autoPlaying =
            true

          autoButton.setText(
            "STOP AUTO"
          )

          timer =
            new javax.swing.Timer(
              3000,
              new ActionListener {

                def actionPerformed(
                  e: ActionEvent
                ): Unit = {

                  if (
                    overviewMode
                  ) {

                    if (
                      sceneIndex <
                      anime.overview.length - 1
                    ) {

                      sceneIndex += 1

                      val s =
                        anime.overview(
                          sceneIndex
                        )

                      stageLabel.setText(
                        "STAGE: " +
                        s.stage
                      )

                      speakerLabel.setText(
                        "SPEAKER: " +
                        s.speaker
                      )

                      counterLabel.setText(
                        "OVERVIEW " +
                        (sceneIndex + 1) +
                        " / " +
                        anime.overview.length
                      )

                      storyText.setText(
                        s.text
                      )

                      storyText.setCaretPosition(0)

                    } else {

                      sceneIndex =
                        0

                      showOverview()
                    }

                  } else {

                    val c =
                      anime.characters(
                        characterIndex
                      )

                    if (
                      sceneIndex <
                      c.scenes.length - 1
                    ) {

                      sceneIndex += 1

                      showCharacterStory()

                    } else {

                      sceneIndex =
                        0

                      showCharacterStory()
                    }
                  }
                }
              }
            )

          timer.setRepeats(true)

          timer.start()
        }
      }
    }
  )


  // ==========================================================
  // FULL STORY LISTENER
  // ==========================================================

  fullButton.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        if (
          overviewMode
        ) {

          tabs.setSelectedIndex(3)

          fullAnimeArea.setText(
            animeFullText()
          )

          fullAnimeArea.setCaretPosition(0)

        } else {

          tabs.setSelectedIndex(2)

          val c =
            anime.characters(
              characterIndex
            )

          fullCharacterArea.setText(
            characterFullText(
              c
            )
          )

          fullCharacterArea.setCaretPosition(0)
        }
      }
    }
  )


  // ==========================================================
  // OVERVIEW LISTENER
  // ==========================================================

  overviewButton.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        if (
          timer != null
        ) {

          timer.stop()

          autoPlaying =
            false

          autoButton.setText(
            "AUTO PLAY"
          )
        }

        showOverview()
      }
    }
  )


  // ==========================================================
  // PROFILE LISTENER
  // ==========================================================

  profileButton.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        overviewMode =
          false

        tabs.setSelectedIndex(0)

        updateCharacter()
      }
    }
  )


  // ==========================================================
  // BACK LISTENER
  // ==========================================================

  backButton.addActionListener(
    new ActionListener {

      def actionPerformed(
        e: ActionEvent
      ): Unit = {

        if (
          timer != null
        ) {

          timer.stop()
        }

        showPage(
          animeLibraryScreen()
        )
      }
    }
  )


  // ==========================================================
  // BOTTOM BAR
  // ==========================================================

  val bottom =
    new JPanel(
      new FlowLayout(
        FlowLayout.CENTER,
        5,
        5
      )
    )

  bottom.setBackground(BG)

  bottom.add(startButton)

  bottom.add(previousButton)

  bottom.add(nextButton)

  bottom.add(autoButton)

  bottom.add(fullButton)

  bottom.add(overviewButton)

  bottom.add(profileButton)

  bottom.add(backButton)

  root.add(
    bottom,
    BorderLayout.SOUTH
  )


  // ==========================================================
  // FIRST SCREEN
  // ==========================================================

  showOverview()

  root
}


// ============================================================
// START
// ============================================================

showPage(
  loginScreen()
)

frame.setVisible(true)