Complete typed tactical map parity

ober

16cec1d773317008012f778b10adc5416a930de6

diff --git a/templates/original-tactics-parts/TacticalMapView.kt.ss b/templates/original-tactics-parts/TacticalMapView.kt.ss
index c92fcc3..4a15bec 100644
--- a/templates/original-tactics-parts/TacticalMapView.kt.ss
+++ b/templates/original-tactics-parts/TacticalMapView.kt.ss
@@ -76,6 +76,8 @@
         (type ProjectedHelmPose)
         (type ProjectedHelmMove)
         (type ProjectedRangePoint)
+        (type SfcWeaponEffectCue)
+        (type SfcWeaponEffectKind)
 
         (record TacticalPoint
           ((x : Float32)
@@ -109,6 +111,11 @@
         (record TacticalBlockedManeuverBadge
           ((actor : String)
            (text : String)))
+        (record TacticalShipLivery
+          ((hull : Int32)
+           (trim : Int32)
+           (accent : Int32)
+           (stroke : Int32)))
         (record TacticalMapTransform
           ((scale : Float32)
            (origin : TacticalPoint)))
@@ -134,6 +141,8 @@
           (kotlin-member-call compareTo))
         (extern (tmvJsonKeys (json : JSONObject)) : (Iterator String)
           (kotlin-member-call keys))
+        (extern (tmvJsonHas (json : JSONObject) (key : String)) : Bool
+          (kotlin-member-call has))
         (extern (tmvIteratorHasNext (items : (Iterator String))) : Bool
           (kotlin-member-call hasNext))
         (extern (tmvIteratorNext (items : (Iterator String))) : String
@@ -173,6 +182,8 @@
         (extern (tmvColorRed (color : Int32)) : Int32 (kotlin-call Color red))
         (extern (tmvColorGreen (color : Int32)) : Int32 (kotlin-call Color green))
         (extern (tmvColorBlue (color : Int32)) : Int32 (kotlin-call Color blue))
+        (extern (tmvColorTransparent) : Int32
+          (kotlin-value Color TRANSPARENT))
         (extern (tmvPaintColorSet (paint : Paint) (value : Int32)) : Unit
           (kotlin-member-set color))
         (extern (tmvPaintColorGet (paint : Paint)) : Int32
@@ -259,6 +270,9 @@
           (kotlin-member-call arcTo))
         (extern (tmvViewInvalidate (view : TacticalMapView)) : Unit
           (kotlin-member-call invalidate))
+        (extern (tmvViewPostInvalidateOnAnimation
+                  (view : TacticalMapView)) : Unit
+          (kotlin-member-call postInvalidateOnAnimation))
         (extern (tmvViewWidth (view : TacticalMapView)) : Int32
           (kotlin-member-get width))
         (extern (tmvViewHeight (view : TacticalMapView)) : Int32
@@ -376,6 +390,12 @@
           (kotlin-call moveInDirection))
         (extern (tmvCanProjectedTurn (pose : ProjectedHelmPose)) : Bool
           (kotlin-call canProjectedTurn_p))
+        (extern (tmvCanProjectedSideslip (pose : ProjectedHelmPose)) : Bool
+          (kotlin-call canProjectedSideslip))
+        (extern (tmvScheduledProjectedMove
+                  (pose : ProjectedHelmPose)
+                  (maneuver : (Nullable String))) : (Nullable String)
+          (kotlin-call scheduledProjectedHelmManeuver))
         (extern (tmvTurnModeRequiredDistance (mode : String)
                                              (speed : Int32)) : Int32
           (kotlin-call turnModeRequiredDistance))
@@ -390,6 +410,83 @@
         (extern (tmvScaleBy (view : TacticalMapView)
                             (factor : Float32)) : Unit
           (kotlin-member-call scaleBy))
+        (extern (tmvRecentWeaponEffects (events : JSONArray)
+                                        (maximum : Int32))
+          : (List SfcWeaponEffectCue)
+          (kotlin-call SfcWeaponEffects recent))
+        (extern (tmvWeaponEffectSignature
+                  (cues : (List SfcWeaponEffectCue))) : String
+          (kotlin-call SfcWeaponEffects signature))
+        (extern (tmvCueActor (cue : SfcWeaponEffectCue)) : String
+          (kotlin-member-get actor))
+        (extern (tmvCueTarget (cue : SfcWeaponEffectCue)) : String
+          (kotlin-member-get target))
+        (extern (tmvCueKind (cue : SfcWeaponEffectCue)) : SfcWeaponEffectKind
+          (kotlin-member-get kind))
+        (extern (tmvCueLabel (cue : SfcWeaponEffectCue)) : String
+          (kotlin-member-get label))
+        (extern (tmvCueEnveloping (cue : SfcWeaponEffectCue)) : Bool
+          (kotlin-member-get enveloping))
+        (extern (tmvFxPhaser) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PHASER))
+        (extern (tmvFxPhaser1) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PHASER_1))
+        (extern (tmvFxPhaser2) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PHASER_2))
+        (extern (tmvFxPhaser3) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PHASER_3))
+        (extern (tmvFxPhaser4) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PHASER_4))
+        (extern (tmvFxPhaserG) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PHASER_G))
+        (extern (tmvFxPhaserX) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PHASER_X))
+        (extern (tmvFxPhoton) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PHOTON))
+        (extern (tmvFxPhotonOverload) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PHOTON_OVERLOAD))
+        (extern (tmvFxPlasma) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PLASMA))
+        (extern (tmvFxPlasmaBolt) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PLASMA_BOLT))
+        (extern (tmvFxDisruptor) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind DISRUPTOR))
+        (extern (tmvFxDisruptorOverload) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind DISRUPTOR_OVERLOAD))
+        (extern (tmvFxHellbore) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind HELLBORE))
+        (extern (tmvFxFusion) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind FUSION))
+        (extern (tmvFxEsg) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind ESG))
+        (extern (tmvFxTrBeam) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind TR_BEAM))
+        (extern (tmvFxMauler) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind MAULER))
+        (extern (tmvFxPpd) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PPD))
+        (extern (tmvFxDrone) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind DRONE))
+        (extern (tmvFxWeb) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind WEB))
+        (extern (tmvFxTractor) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind TRACTOR))
+        (extern (tmvFxTransporter) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind TRANSPORTER))
+        (extern (tmvFxStasis) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind STASIS))
+        (extern (tmvFxDisplacement) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind DISPLACEMENT))
+        (extern (tmvFxPaPanel) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind PA_PANEL))
+        (extern (tmvFxDisengagement) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind DISENGAGEMENT))
+        (extern (tmvFxMine) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind MINE))
+        (extern (tmvFxBreakdown) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind BREAKDOWN))
+        (extern (tmvFxCloak) : SfcWeaponEffectKind
+          (kotlin-value SfcWeaponEffectKind CLOAK))
 
         (def (tmvMaxInt (left : Int32) (right : Int32)) : Int32
           (if (> left right) left right))
@@ -591,6 +688,8 @@
           (var betaImpactShieldDamage : Int32 (int32 0) (modifiers private))
           (var alphaImpactInternalDamage : Int32 (int32 0) (modifiers private))
           (var betaImpactInternalDamage : Int32 (int32 0) (modifiers private))
+          (var weaponEffectStartedAt : Int (int 0) (modifiers private))
+          (var weaponEffectSignature : String "" (modifiers private))
           (val scaleDetector : ScaleGestureDetector
             (tmvMakeScaleDetectorFor context this) (modifiers private))
 
@@ -695,6 +794,28 @@
             (tmvConfigurePaint (new Paint (tmvPaintAntiAliasFlag))
               (tmvColorRgb (int32 245) (int32 185) (int32 60))
               (tmvPaintStyleStroke) (float32 8.0) #f #f) (modifiers private))
+          (val effectBeamPaint : Paint
+            (tmvConfigurePaint (new Paint (tmvPaintAntiAliasFlag))
+              (tmvColorWhite) (tmvPaintStyleStroke) (float32 5.0) #t #t)
+            (modifiers private))
+          (val effectGlowPaint : Paint
+            (tmvConfigurePaint (new Paint (tmvPaintAntiAliasFlag))
+              (tmvColorArgb (int32 90) (int32 255) (int32 255) (int32 255))
+              (tmvPaintStyleStroke) (float32 15.0) #t #t)
+            (modifiers private))
+          (val effectRingPaint : Paint
+            (tmvConfigurePaint (new Paint (tmvPaintAntiAliasFlag))
+              (tmvColorWhite) (tmvPaintStyleStroke) (float32 4.0) #t #t)
+            (modifiers private))
+          (val effectFillPaint : Paint
+            (tmvConfigurePaint (new Paint (tmvPaintAntiAliasFlag))
+              (tmvColorArgb (int32 70) (int32 255) (int32 255) (int32 255))
+              (tmvPaintStyleFill) (float32 0.0) #f #f)
+            (modifiers private))
+          (val effectTextPaint : Paint
+            (tmvConfigureTextPaint (new Paint (tmvPaintAntiAliasFlag))
+              (tmvColorWhite) (float32 15.0) #t #t)
+            (modifiers private))
           (val titlePaint : Paint
             (tmvConfigureTextPaint (new Paint (tmvPaintAntiAliasFlag))
               (tmvColorRgb (int32 28) (int32 35) (int32 48))
@@ -734,6 +855,7 @@
                         (set! tacticalDashboard (nullable-none JSONObject))
                         (finishMovementAnimation)
                         (clearImpactPulse)
+                        (clearWeaponEffectPulse)
                         (resetView))
                       (begin
                         (if (and (not (nullable-null? previousAlpha))
@@ -750,6 +872,7 @@
                                 (finishMovementAnimation))
                             (finishMovementAnimation))
                         (updateImpactPulse nextEvents)
+                        (updateWeaponEffectPulse nextEvents)
                         (tmvViewInvalidate this)))))))
           (def (setTacticalStatus
                  (nextStatus : (Nullable JSONObject))) : Unit
@@ -962,6 +1085,7 @@
                         (shieldFacingIndex
                           (json-object-opt-any battle "beta-shield-facing-hit")))
                       (drawImpactEffects canvas alphaPoint betaPoint)
+                      (drawWeaponEffects canvas alphaPoint betaPoint)
                       (drawBlockedManeuverBadges canvas alphaPoint betaPoint)
                       (drawVolleyBadge canvas battle betaPoint "alpha-volley"
                         "A" alphaPaint (int32 -1))
@@ -1033,6 +1157,49 @@
                           (+ (- (/ drawHeight (float32 2.0))
                                 (* (/ (+ minY maxY) (float32 2.0)) scale))
                              userPanY)))))))))
+          (def (addBattleUnitPoints
+                 (points : (MutableList TacticalPoint))
+                 (raw : (Nullable Any))) : Unit
+            (modifiers private)
+            (if (nullable-null? raw)
+                (begin)
+                (let ((object (tmvAsJsonObject (nullable-get raw)))
+                      (array (tmvAsJsonArray (nullable-get raw))))
+                  (begin
+                    (if (nullable-null? object)
+                        (begin)
+                        (let ((position (json-object-opt-json-object
+                                          (nullable-get object) "position")))
+                          (if (nullable-null? position)
+                              (begin)
+                              (mutable-list-add! points
+                                (tmvRawHexPointInt
+                                  (json-object-opt-int32-default
+                                    (nullable-get position) "q" (int32 0))
+                                  (json-object-opt-int32-default
+                                    (nullable-get position) "r" (int32 0)))))))
+                    (if (nullable-null? array)
+                        (begin)
+                        (addBattleUnitPointsAt points (nullable-get array)
+                          (int32 0)))))))
+          (def (addBattleUnitPointsAt
+                 (points : (MutableList TacticalPoint)) (items : JSONArray)
+                 (index : Int32)) : Unit
+            (modifiers private)
+            (if (>= index (json-array-length items))
+                (begin)
+                (begin
+                  (addBattleUnitPoints points (json-array-opt-any items index))
+                  (addBattleUnitPointsAt points items (+ index (int32 1))))))
+          (def (includeUnit (raw : (Nullable Any))) : Unit
+            (modifiers private)
+            ;; Kept as a named boundary to mirror the authoritative grid
+            ;; collector; map fitting consumes the same heterogeneous data.
+            (addBattleUnitPoints (mutable-list-empty TacticalPoint) raw))
+          (def (toPoint (transform : TacticalMapTransform)
+                        (q : Float32) (r : Float32)) : TacticalPoint
+            (modifiers private)
+            (tmvTransformPoint transform q r))
 
           (def (drawGrid (canvas : Canvas) (transform : TacticalMapTransform)
                          (alphaPosition : JSONObject) (betaPosition : JSONObject)
@@ -1769,6 +1936,7 @@
                   (radius (* (TacticalMapTransform-scale transform) (float32 0.54)))
                   (angle (tmvFacingAngleRadians (TacticalShipPose-facing pose))))
               (begin
+                (drawRaceIdentityHalo canvas center radius ship fill)
                 (drawShieldRing canvas center (* radius (float32 1.35)) ship hitShield)
                 (drawFacingGuide canvas center (* radius (float32 1.9)) angle fill)
                 (drawRaceShipSilhouette canvas center radius angle ship fill)
@@ -1791,8 +1959,11 @@
             (modifiers private)
             (let ((state (tmvCanvasSave canvas))
                   (iconRadius (* radius (float32 1.24)))
-                  (race (shipRaceKey ship)))
+                  (race (shipRaceKey ship))
+                  (oldColor (tmvPaintColorGet fill)))
               (begin
+                (tmvPaintColorSet fill
+                  (TacticalShipLivery-hull (shipLivery race)))
                 (tmvCanvasTranslate canvas (TacticalPoint-x center)
                   (TacticalPoint-y center))
                 (tmvCanvasRotate canvas (float32 (* angle (/ 180.0 (tmvPi)))))
@@ -1818,9 +1989,103 @@
                     (drawIscSilhouette canvas iconRadius fill)
                 (if (tmvStringEquals race "orion")
                     (drawOrionSilhouette canvas iconRadius fill)
-                    (drawGenericSilhouette canvas iconRadius fill))))))))))))
+                (if (or (tmvStringEquals race "maesron")
+                        (or (tmvStringEquals race "koligahr")
+                            (or (tmvStringEquals race "trobrin")
+                                (or (tmvStringEquals race "vari")
+                                    (or (tmvStringEquals race "probr")
+                                        (or (tmvStringEquals race "drex")
+                                            (or (tmvStringEquals race "alunda")
+                                                (or (tmvStringEquals race "loriyill")
+                                                    (or (tmvStringEquals race "iridani")
+                                                        (or (tmvStringEquals race "ymatrian")
+                                                            (or (tmvStringEquals race "worb")
+                                                                (or (tmvStringEquals race "aurora")
+                                                                    (or (tmvStringEquals race "singer")
+                                                                        (or (tmvStringEquals race "ryn")
+                                                                            (or (tmvStringEquals race "qixa")
+                                                                                (tmvStringEquals race "branthodon"))))))))))))))))
+                    (drawOmegaSilhouette canvas iconRadius fill race)
+                    (drawGenericSilhouette canvas iconRadius fill)))))))))))))
+                (tmvPaintColorSet fill oldColor)
                 (tmvCanvasRestoreToCount canvas state))))
 
+          (def (drawRaceIdentityHalo
+                 (canvas : Canvas) (center : TacticalPoint) (radius : Float32)
+                 (ship : (Nullable JSONObject)) (sidePaint : Paint)) : Unit
+            (modifiers private)
+            (let ((livery (shipLivery (shipRaceKey ship)))
+                  (oldColor (tmvPaintColorGet rangePaint)))
+              (begin
+                (tmvPaintColorSet effectFillPaint
+                  (colorWithAlpha (TacticalShipLivery-hull livery) (int32 72)))
+                (tmvCanvasDrawCircle canvas (TacticalPoint-x center)
+                  (TacticalPoint-y center) (* radius (float32 1.58))
+                  effectFillPaint)
+                (tmvPaintColorSet rangePaint
+                  (colorWithAlpha (TacticalShipLivery-trim livery) (int32 205)))
+                (tmvPaintStrokeWidthSet rangePaint (float32 3.0))
+                (tmvCanvasDrawCircle canvas (TacticalPoint-x center)
+                  (TacticalPoint-y center) (* radius (float32 1.64)) rangePaint)
+                (tmvPaintColorSet rangePaint
+                  (colorWithAlpha (tmvPaintColorGet sidePaint) (int32 185)))
+                (tmvCanvasDrawArc canvas
+                  (new RectF
+                    (- (TacticalPoint-x center) (* radius (float32 1.78)))
+                    (- (TacticalPoint-y center) (* radius (float32 1.78)))
+                    (+ (TacticalPoint-x center) (* radius (float32 1.78)))
+                    (+ (TacticalPoint-y center) (* radius (float32 1.78))))
+                  (float32 -115.0) (float32 70.0) #f rangePaint)
+                (tmvPaintColorSet rangePaint oldColor)
+                (tmvPaintStrokeWidthSet rangePaint (float32 4.0)))))
+          (def (shipOutlineColor (fill : Int32)) : Int32
+            (modifiers private)
+            (let ((brightness
+                    (/ (+ (+ (* (tmvColorRed fill) (int32 299))
+                               (* (tmvColorGreen fill) (int32 587)))
+                            (* (tmvColorBlue fill) (int32 114)))
+                       (int32 1000))))
+              (if (> brightness (int32 150))
+                  (tmvColorRgb (int32 27) (int32 34) (int32 45))
+                  (tmvColorWhite))))
+          (def (shipLivery (race : String)) : TacticalShipLivery
+            (modifiers private)
+            (if (tmvStringEquals race "federation")
+                (make-TacticalShipLivery
+                  (tmvColorRgb (int32 238) (int32 240) (int32 236))
+                  (tmvColorRgb (int32 56) (int32 114) (int32 177))
+                  (tmvColorRgb (int32 190) (int32 54) (int32 48))
+                  (tmvColorTransparent))
+            (if (tmvStringEquals race "klingon")
+                (make-TacticalShipLivery
+                  (tmvColorRgb (int32 82) (int32 96) (int32 91))
+                  (tmvColorRgb (int32 68) (int32 132) (int32 84))
+                  (tmvColorRgb (int32 190) (int32 58) (int32 46))
+                  (tmvColorTransparent))
+            (if (tmvStringEquals race "andromedan")
+                (make-TacticalShipLivery
+                  (tmvColorRgb (int32 64) (int32 126) (int32 76))
+                  (tmvColorRgb (int32 176) (int32 184) (int32 188))
+                  (tmvColorRgb (int32 236) (int32 198) (int32 62))
+                  (tmvColorRgb (int32 24) (int32 35) (int32 28)))
+            (if (tmvStringEquals race "romulan")
+                (make-TacticalShipLivery
+                  (tmvColorRgb (int32 186) (int32 192) (int32 184))
+                  (tmvColorRgb (int32 42) (int32 48) (int32 47))
+                  (tmvColorRgb (int32 173) (int32 42) (int32 42))
+                  (tmvColorTransparent))
+            (if (tmvStringEquals race "kzinti")
+                (make-TacticalShipLivery
+                  (tmvColorRgb (int32 204) (int32 127) (int32 45))
+                  (tmvColorRgb (int32 105) (int32 62) (int32 37))
+                  (tmvColorRgb (int32 239) (int32 196) (int32 78))
+                  (tmvColorTransparent))
+                (make-TacticalShipLivery
+                  (tmvColorRgb (int32 120) (int32 132) (int32 146))
+                  (tmvColorRgb (int32 80) (int32 96) (int32 118))
+                  (tmvColorRgb (int32 208) (int32 145) (int32 58))
+                  (tmvColorTransparent))))))))
+
           (def (drawFilledPath (canvas : Canvas) (path : Path)
                                (fill : Paint)) : Unit
             (modifiers private)
@@ -2045,6 +2310,47 @@
                 (tmvCanvasDrawLine canvas (* r (float32 -0.45)) (float32 0.0)
                   (* r (float32 0.76)) (float32 0.0) detailPaint))))
 
+          (def (drawOmegaSilhouette
+                 (canvas : Canvas) (r : Float32) (fill : Paint)
+                 (race : String)) : Unit
+            (modifiers private)
+            (let ((core (new Path)))
+              (begin
+                (tmvPathMoveTo core (* r (float32 1.12)) (float32 0.0))
+                (tmvPathLineTo core (* r (float32 0.18)) (* r (float32 -0.30)))
+                (tmvPathLineTo core (* r (float32 -0.90)) (* r (float32 -0.42)))
+                (tmvPathLineTo core (* r (float32 -0.58)) (float32 0.0))
+                (tmvPathLineTo core (* r (float32 -0.90)) (* r (float32 0.42)))
+                (tmvPathLineTo core (* r (float32 0.18)) (* r (float32 0.30)))
+                (tmvPathClose core)
+                (drawFilledPath canvas core fill)
+                (if (or (tmvStringEquals race "iridani")
+                        (tmvStringEquals race "aurora"))
+                    (begin
+                      (tmvCanvasDrawLine canvas (* r (float32 -1.05))
+                        (float32 0.0) (* r (float32 0.62)) (float32 0.0)
+                        detailPaint)
+                      (tmvCanvasDrawCircle canvas (* r (float32 0.82))
+                        (float32 0.0) (* r (float32 0.12)) orangePaint))
+                    (if (or (tmvStringEquals race "alunda")
+                            (or (tmvStringEquals race "singer")
+                                (tmvStringEquals race "ryn")))
+                        (begin
+                          (tmvCanvasDrawOval canvas
+                            (new RectF (* r (float32 -0.62)) (* r (float32 -0.70))
+                              (* r (float32 0.24)) (* r (float32 -0.18))) fill)
+                          (tmvCanvasDrawOval canvas
+                            (new RectF (* r (float32 -0.62)) (* r (float32 0.18))
+                              (* r (float32 0.24)) (* r (float32 0.70))) fill))
+                        (begin
+                          (tmvCanvasDrawLine canvas (* r (float32 -0.62))
+                            (float32 0.0) (* r (float32 0.76)) (float32 0.0)
+                            detailPaint)
+                          (tmvCanvasDrawCircle canvas (* r (float32 -0.28))
+                            (* r (float32 -0.22)) (* r (float32 0.07)) orangePaint)
+                          (tmvCanvasDrawCircle canvas (* r (float32 -0.28))
+                            (* r (float32 0.22)) (* r (float32 0.07)) orangePaint)))))))
+
           (def (drawGenericSilhouette (canvas : Canvas) (r : Float32)
                                       (fill : Paint)) : Unit
             (modifiers private)
@@ -2128,6 +2434,9 @@
                                                 (json-object-opt-string-default
                                                   (nullable-get ship)
                                                   "name" ""))))))))))))))
+                    (let ((omega (omegaRaceKey text)))
+                      (if (not (nullable-null? omega))
+                          (nullable-get omega)
                     (if (or (tmvStringContains text "andromedan")
                             (or (tmvStringContains text "and-")
                                 (tmvStringContains text "andro"))) "andromedan"
@@ -2155,15 +2464,35 @@
                                       "inter-stellar concordium"))) "isc"
                         (if (or (tmvStringContains text "orion")
                                 (tmvStringContains text "ori-")) "orion"
-                            "generic")))))))))))))))
+                            "generic")))))))))))))))))
+          (def (omegaRaceKey (text : String)) : (Nullable String)
+            (modifiers private)
+            (if (tmvStringContains text "maesron") (nullable-some "maesron")
+            (if (tmvStringContains text "koligahr") (nullable-some "koligahr")
+            (if (tmvStringContains text "trobrin") (nullable-some "trobrin")
+            (if (tmvStringContains text "vari") (nullable-some "vari")
+            (if (tmvStringContains text "probr") (nullable-some "probr")
+            (if (tmvStringContains text "drex") (nullable-some "drex")
+            (if (tmvStringContains text "alunda") (nullable-some "alunda")
+            (if (tmvStringContains text "loriyill") (nullable-some "loriyill")
+            (if (tmvStringContains text "iridani") (nullable-some "iridani")
+            (if (tmvStringContains text "ymatrian") (nullable-some "ymatrian")
+            (if (tmvStringContains text "worb") (nullable-some "worb")
+            (if (tmvStringContains text "aurora") (nullable-some "aurora")
+            (if (tmvStringContains text "singer") (nullable-some "singer")
+            (if (tmvStringContains text "ryn") (nullable-some "ryn")
+            (if (tmvStringContains text "qixa") (nullable-some "qixa")
+            (if (tmvStringContains text "branthodon") (nullable-some "branthodon")
+                (nullable-none String))))))))))))))))))
           (def (drawShieldRing (canvas : Canvas) (center : TacticalPoint)
                                (radius : Float32) (ship : (Nullable JSONObject))
                                (hitShield : Int32)) : Unit
             (modifiers private)
-            (let ((panels (paPanelCount ship)) (maximum (paPanelMax ship)))
+            (let ((panels (paPanelCount ship)) (maximum (paPanelMax ship))
+                  (charge (paPanelCharge ship)))
               (if (and (<= (shieldTotal ship #t) (int32 0))
                        (or (> panels (int32 0)) (> maximum (int32 1))))
-                  (drawPaPanelRing canvas center radius panels maximum)
+                  (drawPaPanelRing canvas center radius panels maximum charge)
                   (let ((shields (if (nullable-null? ship)
                                      (nullable-none JSONObject)
                                      (json-object-opt-json-object
@@ -2521,6 +2850,564 @@
               (set! alphaImpactInternalDamage (int32 0))
               (set! betaImpactInternalDamage (int32 0))))
 
+          (def (updateWeaponEffectPulse (rawEvents : JSONArray)) : Unit
+            (modifiers private)
+            (let ((cues (tmvRecentWeaponEffects rawEvents (int32 6))))
+              (let ((signature (tmvWeaponEffectSignature cues)))
+                (if (string-blank? signature)
+                    (begin)
+                    (if (tmvStringEquals signature weaponEffectSignature)
+                        (begin)
+                        (begin
+                          (set! weaponEffectSignature signature)
+                          (set! weaponEffectStartedAt (tmvUptimeMillis))))))))
+          (def (clearWeaponEffectPulse) : Unit
+            (modifiers private)
+            (begin
+              (set! weaponEffectStartedAt (int 0))
+              (set! weaponEffectSignature "")))
+          (def (drawWeaponEffects (canvas : Canvas) (alpha : TacticalPoint)
+                                  (beta : TacticalPoint)) : Unit
+            (modifiers private)
+            (if (= weaponEffectStartedAt (int 0))
+                (begin)
+                (let ((age (- (tmvUptimeMillis) weaponEffectStartedAt)))
+                  (if (> age (int 820))
+                      (clearWeaponEffectPulse)
+                      (let ((cues (tmvRecentWeaponEffects events (int32 6)))
+                            (progress
+                              (tmvClampFloat (/ (float32 age) (float32 820.0))
+                                (float32 0.0) (float32 1.0))))
+                        (begin
+                          (drawWeaponEffectsAt canvas cues alpha beta progress
+                            (int32 0))
+                          (tmvViewPostInvalidateOnAnimation this)))))))
+          (def (drawWeaponEffectsAt
+                 (canvas : Canvas) (cues : (List SfcWeaponEffectCue))
+                 (alpha : TacticalPoint) (beta : TacticalPoint)
+                 (progress : Float32) (index : Int32)) : Unit
+            (modifiers private)
+            (if (or (>= index (list-size cues)) (>= index (int32 6)))
+                (begin)
+                (let ((cue (list-ref cues index)))
+                  (let ((source (pointForSide (tmvCueActor cue) alpha beta))
+                        (target (pointForSide (tmvCueTarget cue) alpha beta)))
+                    (begin
+                      (if (or (nullable-null? source) (nullable-null? target))
+                          (begin)
+                          (drawWeaponEffectCue canvas cue
+                            (nullable-get source) (nullable-get target)
+                            progress index))
+                      (drawWeaponEffectsAt canvas cues alpha beta progress
+                        (+ index (int32 1))))))))
+          (def (drawWeaponEffectCue
+                 (canvas : Canvas) (cue : SfcWeaponEffectCue)
+                 (source : TacticalPoint) (target : TacticalPoint)
+                 (progress : Float32) (index : Int32)) : Unit
+            (modifiers private)
+            (let ((kind (tmvCueKind cue))
+                  (shift (* (- (float32 index) (float32 2.5)) (float32 6.0))))
+              (let ((start (make-TacticalPoint
+                             (TacticalPoint-x source)
+                             (+ (TacticalPoint-y source) shift)))
+                    (end (make-TacticalPoint
+                           (TacticalPoint-x target)
+                           (+ (TacticalPoint-y target) shift))))
+                (begin
+                  (if (equal? kind (tmvFxHellbore))
+                      (drawHellboreEffect canvas start end progress
+                        (tmvCueEnveloping cue))
+                  (if (equal? kind (tmvFxFusion))
+                      (drawFusionCone canvas start end progress)
+                  (if (equal? kind (tmvFxEsg))
+                      (drawEsgEffect canvas start progress)
+                  (if (equal? kind (tmvFxTrBeam))
+                      (drawTwinBeam canvas start end progress
+                        (colorForEffect kind) (float32 7.0))
+                  (if (equal? kind (tmvFxMauler))
+                      (drawMaulerBeam canvas start end progress)
+                  (if (equal? kind (tmvFxPpd))
+                      (drawPpdEffect canvas start end progress)
+                  (if (equal? kind (tmvFxPlasma))
+                      (drawPlasmaEffect canvas start end progress)
+                  (if (equal? kind (tmvFxPlasmaBolt))
+                      (drawPlasmaBoltEffect canvas start end progress)
+                  (if (or (equal? kind (tmvFxPhoton))
+                          (equal? kind (tmvFxPhotonOverload)))
+                      (drawPhotonBolt canvas start end progress
+                        (equal? kind (tmvFxPhotonOverload)))
+                  (if (equal? kind (tmvFxDisruptorOverload))
+                      (drawDisruptorOverloadEffect canvas start end progress)
+                  (if (equal? kind (tmvFxDisruptor))
+                      (drawJaggedBeam canvas start end progress
+                        (colorForEffect kind) (float32 5.0))
+                  (if (equal? kind (tmvFxDrone))
+                      (drawDroneEffect canvas start end progress)
+                  (if (equal? kind (tmvFxWeb))
+                      (drawWebEffect canvas start end progress)
+                  (if (equal? kind (tmvFxTractor))
+                      (drawTractorEffect canvas start end progress)
+                  (if (equal? kind (tmvFxTransporter))
+                      (drawTransporterEffect canvas start end progress)
+                  (if (equal? kind (tmvFxStasis))
+                      (drawStasisEffect canvas start end progress)
+                  (if (equal? kind (tmvFxDisplacement))
+                      (drawDisplacementEffect canvas start end progress)
+                  (if (equal? kind (tmvFxPaPanel))
+                      (drawPaPanelEffect canvas end progress)
+                  (if (equal? kind (tmvFxDisengagement))
+                      (drawDisengagementEffect canvas start end progress)
+                  (if (equal? kind (tmvFxMine))
+                      (drawMineEffect canvas start end progress)
+                  (if (equal? kind (tmvFxBreakdown))
+                      (drawBreakdownEffect canvas start progress)
+                  (if (equal? kind (tmvFxCloak))
+                      (drawCloakEffect canvas start progress)
+                  (if (or (equal? kind (tmvFxPhaser1))
+                          (or (equal? kind (tmvFxPhaser2))
+                              (or (equal? kind (tmvFxPhaser3))
+                                  (or (equal? kind (tmvFxPhaser4))
+                                      (or (equal? kind (tmvFxPhaserG))
+                                          (equal? kind (tmvFxPhaserX)))))))
+                      (drawPhaserEffect canvas start end progress kind)
+                      (drawBeamLine canvas start end progress
+                        (colorForEffect kind) (float32 5.0)))))))))))))))))))))))))
+                  (drawEffectLabel canvas (tmvCueLabel cue) start end
+                    (colorForEffect kind) progress index)))))
+
+          (def (drawBeamLine (canvas : Canvas) (source : TacticalPoint)
+                             (target : TacticalPoint) (progress : Float32)
+                             (color : Int32) (width : Float32)) : Unit
+            (modifiers private)
+            (let ((reach (+ (float32 0.18) (* (float32 0.82) progress))))
+              (let ((x (tmvLerp (TacticalPoint-x source)
+                         (TacticalPoint-x target) reach))
+                    (y (tmvLerp (TacticalPoint-y source)
+                         (TacticalPoint-y target) reach)))
+                (begin
+                  (tmvPaintPathEffectSet effectGlowPaint
+                    (nullable-none DashPathEffect))
+                  (tmvPaintPathEffectSet effectBeamPaint
+                    (nullable-none DashPathEffect))
+                  (tmvPaintColorSet effectGlowPaint
+                    (colorWithAlpha color (tmvClampInt
+                      (int32 (* (- (float32 1.0) progress) (float32 120.0)))
+                      (int32 25) (int32 120))))
+                  (tmvPaintStrokeWidthSet effectGlowPaint
+                    (+ width (float32 12.0)))
+                  (tmvPaintColorSet effectBeamPaint (colorWithAlpha color (int32 235)))
+                  (tmvPaintStrokeWidthSet effectBeamPaint width)
+                  (tmvCanvasDrawLine canvas (TacticalPoint-x source)
+                    (TacticalPoint-y source) x y effectGlowPaint)
+                  (tmvCanvasDrawLine canvas (TacticalPoint-x source)
+                    (TacticalPoint-y source) x y effectBeamPaint)))))
+          (def (drawPhaserEffect
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)
+                 (kind : SfcWeaponEffectKind)) : Unit
+            (modifiers private)
+            (drawBeamLine canvas source target progress (colorForEffect kind)
+              (if (equal? kind (tmvFxPhaser4)) (float32 10.0)
+              (if (equal? kind (tmvFxPhaserG)) (float32 7.0)
+              (if (equal? kind (tmvFxPhaserX)) (float32 8.0)
+              (if (equal? kind (tmvFxPhaser1)) (float32 6.0)
+              (if (equal? kind (tmvFxPhaser2)) (float32 5.0)
+                  (float32 4.0))))))))
+          (def (drawTwinBeam (canvas : Canvas) (source : TacticalPoint)
+                             (target : TacticalPoint) (progress : Float32)
+                             (color : Int32) (width : Float32)) : Unit
+            (modifiers private)
+            (begin
+              (drawBeamLine canvas
+                (make-TacticalPoint (TacticalPoint-x source)
+                  (+ (TacticalPoint-y source) (float32 5.0)))
+                (make-TacticalPoint (TacticalPoint-x target)
+                  (+ (TacticalPoint-y target) (float32 5.0)))
+                progress color width)
+              (drawBeamLine canvas
+                (make-TacticalPoint (TacticalPoint-x source)
+                  (- (TacticalPoint-y source) (float32 5.0)))
+                (make-TacticalPoint (TacticalPoint-x target)
+                  (- (TacticalPoint-y target) (float32 5.0)))
+                progress (tmvColorWhite) (* width (float32 0.55)))))
+          (def (drawJaggedBeam
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)
+                 (color : Int32) (width : Float32)) : Unit
+            (modifiers private)
+            (let ((path (new Path))
+                  (reach (+ (float32 0.2) (* (float32 0.8) progress))))
+              (begin
+                (tmvPathMoveTo path (TacticalPoint-x source)
+                  (TacticalPoint-y source))
+                (drawJaggedBeamSteps path source target progress reach (int32 1))
+                (tmvPaintColorSet effectGlowPaint (colorWithAlpha color (int32 85)))
+                (tmvPaintStrokeWidthSet effectGlowPaint (+ width (float32 10.0)))
+                (tmvPaintColorSet effectBeamPaint (colorWithAlpha color (int32 240)))
+                (tmvPaintStrokeWidthSet effectBeamPaint width)
+                (tmvCanvasDrawPath canvas path effectGlowPaint)
+                (tmvCanvasDrawPath canvas path effectBeamPaint))))
+          (def (drawJaggedBeamSteps
+                 (path : Path) (source : TacticalPoint) (target : TacticalPoint)
+                 (progress : Float32) (reach : Float32) (step : Int32)) : Unit
+            (modifiers private)
+            (if (> step (int32 5))
+                (tmvPathLineTo path
+                  (tmvLerp (TacticalPoint-x source) (TacticalPoint-x target) reach)
+                  (tmvLerp (TacticalPoint-y source) (TacticalPoint-y target) reach))
+                (let ((fraction (* (/ (float32 step) (float32 6.0)) reach))
+                      (wobble (float32 (* (tmvSin
+                        (+ (* (exact->inexact progress) 12.0)
+                           (exact->inexact step))) 9.0))))
+                  (begin
+                    (tmvPathLineTo path
+                      (tmvLerp (TacticalPoint-x source)
+                        (TacticalPoint-x target) fraction)
+                      (+ (tmvLerp (TacticalPoint-y source)
+                           (TacticalPoint-y target) fraction) wobble))
+                    (drawJaggedBeamSteps path source target progress reach
+                      (+ step (int32 1)))))))
+          (def (drawDisruptorOverloadEffect
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)) : Unit
+            (modifiers private)
+            (begin
+              (drawJaggedBeam canvas source target progress
+                (colorForEffect (tmvFxDisruptorOverload)) (float32 8.0))
+              (drawTravelingOrb canvas source target progress
+                (colorForEffect (tmvFxDisruptorOverload)) (float32 17.0))))
+          (def (drawPlasmaEffect (canvas : Canvas) (source : TacticalPoint)
+                                 (target : TacticalPoint)
+                                 (progress : Float32)) : Unit
+            (modifiers private)
+            (begin
+              (drawBeamLine canvas source target progress
+                (colorForEffect (tmvFxPlasma)) (float32 4.0))
+              (drawTravelingOrb canvas source target progress
+                (colorForEffect (tmvFxPlasma)) (float32 22.0))))
+          (def (drawPlasmaBoltEffect
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)) : Unit
+            (modifiers private)
+            (begin
+              (drawBeamLine canvas source target progress
+                (colorForEffect (tmvFxPlasmaBolt)) (float32 6.0))
+              (drawTravelingOrb canvas source target progress
+                (colorForEffect (tmvFxPlasmaBolt)) (float32 27.0))))
+          (def (drawPhotonBolt (canvas : Canvas) (source : TacticalPoint)
+                               (target : TacticalPoint) (progress : Float32)
+                               (overload : Bool)) : Unit
+            (modifiers private)
+            (let ((kind (if overload (tmvFxPhotonOverload) (tmvFxPhoton))))
+              (begin
+                (drawBeamLine canvas source target progress (colorForEffect kind)
+                  (if overload (float32 8.0) (float32 6.0)))
+                (drawTravelingOrb canvas source target progress
+                  (colorForEffect kind)
+                  (if overload (float32 26.0) (float32 20.0))))))
+          (def (drawTravelingOrb
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)
+                 (color : Int32) (radius : Float32)) : Unit
+            (modifiers private)
+            (let ((fraction (tmvClampFloat
+                              (+ (float32 0.12) (* progress (float32 0.88)))
+                              (float32 0.0) (float32 1.0))))
+              (let ((x (tmvLerp (TacticalPoint-x source)
+                         (TacticalPoint-x target) fraction))
+                    (y (tmvLerp (TacticalPoint-y source)
+                         (TacticalPoint-y target) fraction)))
+                (begin
+                  (tmvPaintColorSet effectFillPaint
+                    (colorWithAlpha color (int32 190)))
+                  (tmvPaintColorSet effectRingPaint
+                    (colorWithAlpha (tmvColorWhite) (int32 210)))
+                  (tmvPaintStrokeWidthSet effectRingPaint (float32 3.0))
+                  (tmvCanvasDrawCircle canvas x y (* radius (float32 0.64))
+                    effectFillPaint)
+                  (tmvCanvasDrawCircle canvas x y radius effectRingPaint)))))
+          (def (drawFusionCone (canvas : Canvas) (source : TacticalPoint)
+                               (target : TacticalPoint)
+                               (progress : Float32)) : Unit
+            (modifiers private)
+            (let ((path (new Path))
+                  (tipX (tmvLerp (TacticalPoint-x source)
+                          (TacticalPoint-x target) progress))
+                  (tipY (tmvLerp (TacticalPoint-y source)
+                          (TacticalPoint-y target) progress))
+                  (width (+ (float32 26.0) (* progress (float32 34.0))))
+                  (color (colorForEffect (tmvFxFusion))))
+              (begin
+                (tmvPathMoveTo path (TacticalPoint-x source)
+                  (TacticalPoint-y source))
+                (tmvPathLineTo path tipX (- tipY width))
+                (tmvPathLineTo path tipX (+ tipY width))
+                (tmvPathClose path)
+                (tmvPaintColorSet effectFillPaint (colorWithAlpha color (int32 82)))
+                (tmvPaintColorSet effectRingPaint (colorWithAlpha color (int32 185)))
+                (tmvCanvasDrawPath canvas path effectFillPaint)
+                (tmvCanvasDrawPath canvas path effectRingPaint))))
+          (def (drawHellboreEffect
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)
+                 (enveloping : Bool)) : Unit
+            (modifiers private)
+            (begin
+              (drawTwinBeam canvas source target progress
+                (colorForEffect (tmvFxHellbore))
+                (if enveloping (float32 8.0) (float32 6.0)))
+              (drawEffectRings canvas target progress
+                (colorForEffect (tmvFxHellbore))
+                (if enveloping (int32 4) (int32 2)))))
+          (def (drawEsgEffect (canvas : Canvas) (source : TacticalPoint)
+                              (progress : Float32)) : Unit
+            (modifiers private)
+            (drawEffectRings canvas source progress
+              (colorForEffect (tmvFxEsg)) (int32 4)))
+          (def (drawEffectRings
+                 (canvas : Canvas) (point : TacticalPoint)
+                 (progress : Float32) (color : Int32) (count : Int32)) : Unit
+            (modifiers private)
+            (drawEffectRingsAt canvas point progress color count (int32 0)))
+          (def (drawEffectRingsAt
+                 (canvas : Canvas) (point : TacticalPoint)
+                 (progress : Float32) (color : Int32) (count : Int32)
+                 (step : Int32)) : Unit
+            (modifiers private)
+            (if (>= step count)
+                (begin)
+                (begin
+                  (tmvPaintColorSet effectRingPaint
+                    (colorWithAlpha color (tmvClampInt
+                      (int32 (* (- (float32 1.0) progress)
+                        (- (float32 190.0) (* (float32 step) (float32 25.0)))))
+                      (int32 20) (int32 190))))
+                  (tmvPaintStrokeWidthSet effectRingPaint (float32 4.0))
+                  (tmvCanvasDrawCircle canvas (TacticalPoint-x point)
+                    (TacticalPoint-y point)
+                    (+ (float32 18.0)
+                      (+ (* (float32 step) (float32 15.0))
+                         (* progress (float32 42.0)))) effectRingPaint)
+                  (drawEffectRingsAt canvas point progress color count
+                    (+ step (int32 1))))))
+          (def (drawMaulerBeam (canvas : Canvas) (source : TacticalPoint)
+                               (target : TacticalPoint)
+                               (progress : Float32)) : Unit
+            (modifiers private)
+            (begin
+              (drawBeamLine canvas source target progress
+                (colorForEffect (tmvFxMauler)) (float32 14.0))
+              (drawBeamLine canvas source target progress
+                (tmvColorWhite) (float32 5.0))))
+          (def (drawPpdEffect (canvas : Canvas) (source : TacticalPoint)
+                              (target : TacticalPoint)
+                              (progress : Float32)) : Unit
+            (modifiers private)
+            (begin
+              (drawBeamLine canvas source target progress
+                (colorForEffect (tmvFxPpd)) (float32 4.0))
+              (drawEffectRings canvas target progress
+                (colorForEffect (tmvFxPpd)) (int32 3))))
+          (def (drawDroneEffect (canvas : Canvas) (source : TacticalPoint)
+                                (target : TacticalPoint)
+                                (progress : Float32)) : Unit
+            (modifiers private)
+            (begin
+              (drawJaggedBeam canvas source target progress
+                (colorForEffect (tmvFxDrone)) (float32 4.0))
+              (drawTravelingOrb canvas source target progress
+                (colorForEffect (tmvFxDrone)) (float32 9.0))))
+          (def (drawWebEffect (canvas : Canvas) (source : TacticalPoint)
+                              (target : TacticalPoint)
+                              (progress : Float32)) : Unit
+            (modifiers private)
+            (let ((color (colorForEffect (tmvFxWeb))))
+              (begin
+                (tmvPaintPathEffectSet effectRingPaint
+                  (nullable-some (new DashPathEffect
+                    (float-array (float32 8.0) (float32 8.0))
+                    (* progress (float32 24.0)))))
+                (tmvPaintColorSet effectRingPaint (colorWithAlpha color (int32 190)))
+                (tmvPaintStrokeWidthSet effectRingPaint (float32 5.0))
+                (tmvCanvasDrawLine canvas (TacticalPoint-x source)
+                  (TacticalPoint-y source) (TacticalPoint-x target)
+                  (TacticalPoint-y target) effectRingPaint)
+                (tmvPaintPathEffectSet effectRingPaint
+                  (nullable-none DashPathEffect)))))
+          (def (drawTractorEffect
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)) : Unit
+            (modifiers private)
+            (drawTwinBeam canvas source target progress
+              (colorForEffect (tmvFxTractor)) (float32 6.0)))
+          (def (drawTransporterEffect
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)) : Unit
+            (modifiers private)
+            (let ((mid (make-TacticalPoint
+                         (tmvLerp (TacticalPoint-x source)
+                           (TacticalPoint-x target) (float32 0.5))
+                         (tmvLerp (TacticalPoint-y source)
+                           (TacticalPoint-y target) (float32 0.5)))))
+              (drawEffectRings canvas mid progress
+                (colorForEffect (tmvFxTransporter)) (int32 3))))
+          (def (drawMineEffect (canvas : Canvas) (source : TacticalPoint)
+                               (target : TacticalPoint)
+                               (progress : Float32)) : Unit
+            (modifiers private)
+            (let ((mid (make-TacticalPoint
+                         (tmvLerp (TacticalPoint-x source)
+                           (TacticalPoint-x target) (float32 0.5))
+                         (tmvLerp (TacticalPoint-y source)
+                           (TacticalPoint-y target) (float32 0.5)))))
+              (drawEffectRings canvas mid progress
+                (colorForEffect (tmvFxMine)) (int32 4))))
+          (def (drawBreakdownEffect
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (progress : Float32)) : Unit
+            (modifiers private)
+            (begin
+              (drawEffectRings canvas source progress
+                (colorForEffect (tmvFxBreakdown)) (int32 3))
+              (drawJaggedBeam canvas
+                (make-TacticalPoint (- (TacticalPoint-x source) (float32 34.0))
+                  (- (TacticalPoint-y source) (float32 26.0)))
+                (make-TacticalPoint (+ (TacticalPoint-x source) (float32 34.0))
+                  (+ (TacticalPoint-y source) (float32 26.0)))
+                progress (colorForEffect (tmvFxBreakdown)) (float32 5.0))))
+          (def (drawCloakEffect (canvas : Canvas) (source : TacticalPoint)
+                                (progress : Float32)) : Unit
+            (modifiers private)
+            (let ((color (colorForEffect (tmvFxCloak))))
+              (begin
+                (tmvPaintColorSet effectFillPaint (colorWithAlpha color
+                  (tmvClampInt
+                    (int32 (* (- (float32 1.0) progress) (float32 70.0)))
+                    (int32 12) (int32 70))))
+                (tmvCanvasDrawCircle canvas (TacticalPoint-x source)
+                  (TacticalPoint-y source)
+                  (+ (float32 42.0) (* progress (float32 58.0)))
+                  effectFillPaint))))
+          (def (drawStasisEffect (canvas : Canvas) (source : TacticalPoint)
+                                 (target : TacticalPoint)
+                                 (progress : Float32)) : Unit
+            (modifiers private)
+            (let ((mid (make-TacticalPoint
+                         (tmvLerp (TacticalPoint-x source)
+                           (TacticalPoint-x target) (float32 0.5))
+                         (tmvLerp (TacticalPoint-y source)
+                           (TacticalPoint-y target) (float32 0.5)))))
+              (begin
+                (tmvPaintColorSet effectRingPaint
+                  (colorWithAlpha (colorForEffect (tmvFxStasis)) (int32 190)))
+                (tmvCanvasDrawRoundRect canvas
+                  (new RectF (- (TacticalPoint-x mid) (float32 54.0))
+                    (- (TacticalPoint-y mid) (float32 40.0))
+                    (+ (TacticalPoint-x mid) (float32 54.0))
+                    (+ (TacticalPoint-y mid) (float32 40.0)))
+                  (float32 14.0) (float32 14.0) effectRingPaint))))
+          (def (drawDisplacementEffect
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)) : Unit
+            (modifiers private)
+            (begin
+              (drawCloakEffect canvas source progress)
+              (drawCloakEffect canvas target
+                (tmvClampFloat (+ progress (float32 0.35))
+                  (float32 0.0) (float32 1.0)))
+              (drawBeamLine canvas source target progress
+                (colorForEffect (tmvFxDisplacement)) (float32 5.0))))
+          (def (drawPaPanelEffect (canvas : Canvas) (target : TacticalPoint)
+                                  (progress : Float32)) : Unit
+            (modifiers private)
+            (drawEffectRings canvas target progress
+              (colorForEffect (tmvFxPaPanel)) (int32 4)))
+          (def (drawDisengagementEffect
+                 (canvas : Canvas) (source : TacticalPoint)
+                 (target : TacticalPoint) (progress : Float32)) : Unit
+            (modifiers private)
+            (drawBeamLine canvas source target progress
+              (colorForEffect (tmvFxDisengagement)) (float32 5.0)))
+          (def (drawEffectLabel
+                 (canvas : Canvas) (rawLabel : String)
+                 (source : TacticalPoint) (target : TacticalPoint)
+                 (color : Int32) (progress : Float32) (index : Int32)) : Unit
+            (modifiers private)
+            (let ((text (fitText rawLabel effectTextPaint
+                          (* drawWidth (float32 0.42)))))
+              (if (string-blank? text)
+                  (begin)
+                  (let ((x (tmvLerp (TacticalPoint-x source)
+                             (TacticalPoint-x target) (float32 0.52)))
+                        (y (tmvClampFloat
+                             (- (tmvLerp (TacticalPoint-y source)
+                                  (TacticalPoint-y target) (float32 0.52))
+                                (+ (float32 22.0) (* (float32 index) (float32 2.0))))
+                             (float32 30.0) (- drawHeight (float32 12.0))))
+                        (width (+ (tmvPaintMeasureText effectTextPaint text)
+                                  (float32 18.0))))
+                    (begin
+                      (tmvPaintColorSet effectFillPaint
+                        (tmvColorArgb (int32 220) (int32 15) (int32 21) (int32 34)))
+                      (tmvCanvasDrawRoundRect canvas
+                        (new RectF (- x (/ width (float32 2.0)))
+                          (- y (float32 24.0))
+                          (+ x (/ width (float32 2.0))) (+ y (float32 4.0)))
+                        (float32 10.0) (float32 10.0) effectFillPaint)
+                      (tmvPaintColorSet effectRingPaint
+                        (colorWithAlpha color (int32 210)))
+                      (tmvCanvasDrawRoundRect canvas
+                        (new RectF (- x (/ width (float32 2.0)))
+                          (- y (float32 24.0))
+                          (+ x (/ width (float32 2.0))) (+ y (float32 4.0)))
+                        (float32 10.0) (float32 10.0) effectRingPaint)
+                      (tmvCanvasDrawText canvas text x (- y (float32 4.0))
+                        effectTextPaint))))))