« get me outta code hell

csb-game - Pixelly spin-off of the Command Synergy Battle system used in Final Fantasy XIII
summary refs log tree commit diff
path: root/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'index.js')
-rw-r--r--index.js119
1 files changed, 72 insertions, 47 deletions
diff --git a/index.js b/index.js
index e6aae70..6621c98 100644
--- a/index.js
+++ b/index.js
@@ -201,25 +201,12 @@ class HPBar {
   }
 }
 
-class ActionMenu {
-  constructor() {
+class BaseBattleMenu {
+  constructor({options}) {
     this.canvas = document.createElement('canvas')
 
-    // State
-
-    this.options = [
-      ['Fire', 'Fira', 'Firaga'],
-      ['Blizz', 'Blizza', 'Blizzaga'],
-      ['Aero', 'Aerora', 'Aeroga'],
-      ['Zap', 'Zappa', 'Zappaga'],
-      ['Bio', 'Biora'],
-      ['Stun', 'Stunra', 'Stunga']
-    ]
-
+    this.options = options
     this.currentOptionIndex = 0
-    this.uiLevel = 1 // 1-3 -- which of "fire", "fira", "firaga" is selected.
-
-    // Drawing
 
     // Button height is 9, with a margin of 1 between each plus 1 at the top and bottom.
     const visibleButtonCount = 3
@@ -238,40 +225,33 @@ class ActionMenu {
 
     const len = this.options.length
 
-    let y = 1
+    this.drawY = 1
     for (let i = startIndex; i < endIndex; i++) {
       const option = this.options[i === -1 ? len - 1 : i === len ? 0 : i]
-      const maxLevel = option.length
-      const effectiveLevel = Math.min(maxLevel, this.uiLevel)
-      const text = option[effectiveLevel - 1]
-      const rectW = this.getRectW(effectiveLevel)
-      if (effectiveLevel < maxLevel) {
-        const ghostRectW = this.getRectW(maxLevel)
-        ctx.fillStyle = 'rgba(255, 255, 255, 0.3)'
-        ctx.fillRect(1.5, y + 0.5, ghostRectW, 8)
-        ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)'
-        ctx.strokeRect(1.5, y + 0.5, ghostRectW, 8)
-      }
-      if (i === this.currentOptionIndex) {
-        const mul = Math.sin(Date.now() / 200) * 0.125 + 0.875
-        ctx.fillStyle = `rgb(${mul * 255}, ${mul * 127}, 0)`
-      } else {
-        ctx.fillStyle = 'white'
-      }
-      ctx.fillRect(1, y, rectW, 9)
-      ctx.strokeStyle = 'black'
-      ctx.strokeRect(1.5, y + 0.5, rectW - 1, 8)
-      ctx.textAlign = 'center'
-      ctx.fillStyle = 'black'
-      ctx.font = '5px pixel-font'
-      ctx.fillText(text, 1 + Math.round(rectW / 2), y + 2 + 9 / 2)
-
-      y += 10
+      this.drawOption(option, ctx)
     }
   }
 
-  getRectW(level) {
-    return Math.floor((this.canvas.width - 2) / 3 * level)
+  drawOption(option, ctx) {
+    const rectW = this.getOptionW(option)
+    if (option === this.options[this.currentOptionIndex]) {
+      const mul = Math.sin(Date.now() / 200) * 0.125 + 0.875
+      ctx.fillStyle = `rgb(${mul * 255}, ${mul * 127}, 0)`
+    } else {
+      ctx.fillStyle = 'white'
+    }
+    ctx.fillRect(1, this.drawY, rectW, 9)
+    ctx.strokeStyle = 'black'
+    ctx.strokeRect(1.5, this.drawY + 0.5, rectW - 1, 8)
+    ctx.textAlign = 'center'
+    ctx.fillStyle = 'black'
+    ctx.font = '5px pixel-font'
+    ctx.fillText(option.label, 1 + Math.round(rectW / 2), this.drawY + 2 + 9 / 2)
+    this.drawY += 10
+  }
+
+  getOptionW(option) {
+    return this.canvas.width
   }
 
   downOption() {
@@ -289,6 +269,51 @@ class ActionMenu {
       this.currentOptionIndex = this.options.length - 1
     }
   }
+}
+
+class ActionMenu extends BaseBattleMenu {
+  constructor() {
+    super({options: [
+      ['Fire', 'Fira', 'Firaga'],
+      ['Blizz', 'Blizza', 'Blizzaga'],
+      ['Aero', 'Aerora', 'Aeroga'],
+      ['Zap', 'Zappa', 'Zappaga'],
+      ['Bio', 'Biora'],
+      ['Stun', 'Stunra', 'Stunga']
+    ].map(arr => ({levelTexts: arr}))})
+
+    this.uiLevel = 1 // 1-3 -- which of "fire", "fira", "firaga" is selected.
+  }
+
+  drawOption(option, ctx) {
+    const maxLevel = this.getMaxLevel(option)
+    const effectiveLevel = this.getEffectiveLevel(option)
+    option.label = option.levelTexts[effectiveLevel - 1]
+    if (effectiveLevel < maxLevel) {
+      const ghostRectW = this.getLevelW(maxLevel)
+      ctx.fillStyle = 'rgba(255, 255, 255, 0.3)'
+      ctx.fillRect(1.5, this.drawY + 0.5, ghostRectW, 8)
+      ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)'
+      ctx.strokeRect(1.5, this.drawY + 0.5, ghostRectW, 8)
+    }
+    super.drawOption(option, ctx)
+  }
+
+  getOptionW(option) {
+    return this.getLevelW(this.getEffectiveLevel(option))
+  }
+
+  getEffectiveLevel(option) {
+    return Math.min(option.levelTexts.length, this.uiLevel)
+  }
+
+  getMaxLevel(option) {
+    return option.levelTexts.length
+  }
+
+  getLevelW(level) {
+    return Math.floor((this.canvas.width - 2) / 3 * level)
+  }
 
   increaseLevel() {
     this.uiLevel++
@@ -306,13 +331,13 @@ class ActionMenu {
 
   queueTo(atbBar) {
     const option = this.options[this.currentOptionIndex]
-    const maxLevel = option.length
+    const maxLevel = this.getMaxLevel(option)
     const effectiveLevel = Math.min(maxLevel, this.uiLevel)
     const remainingSpace = atbBar.getRemainingSpace()
 
     if (effectiveLevel <= remainingSpace) {
       atbBar.queuedActions.push({
-        label: option[effectiveLevel - 1],
+        label: option.levelTexts[effectiveLevel - 1],
         size: effectiveLevel
       })
     } else {