Complete typed tactics status views
ober
5b130d74a1e361bdb8fee34ee5c3c5e3c9a0e88a
--- a/templates/original-tactics-parts/BridgeHudView.kt.ss +++ b/templates/original-tactics-parts/BridgeHudView.kt.ss @@ -112,6 +112,14 @@ (extern (bhvStringReplace (text : String) (old : String) (replacement : String)) : String (kotlin-member-call replace)) + (extern (bhvStringUppercase (text : String)) : String + (kotlin-member-call uppercase)) + (extern (bhvStringStartsWith (text : String) (prefix : String)) : Bool + (kotlin-member-call startsWith)) + (extern (bhvStringContains (text : String) (part : String)) : Bool + (kotlin-member-call contains)) + (extern (bhvJsonHas (json : JSONObject) (key : String)) : Bool + (kotlin-member-call has)) (extern (bhvCurrentBattleRange (battle : (Nullable JSONObject))) : String (kotlin-call currentBattleRange)) (extern (bhvShipDisplayLabel (ship : (Nullable JSONObject)) @@ -498,7 +506,22 @@ (- (bhvRectWidth rect) (float32 16.0)) "ARMED" (counterTotal (bhvNullableAnyField ship "armed-weapons")) (bhvMaxInt (int32 1) - (counterTotal (bhvNullableAnyField ship "weapons"))))))))))) + (bhvMaxInt + (counterTotal (bhvNullableAnyField ship "weapons")) + (weaponInstalledTotal + (bhvNullableArrayField statusShip "weapon-status"))))) + (let ((weaponText + (weaponFamilySummary + (bhvNullableArrayField statusShip "weapon-status")))) + (if (string-blank? weaponText) + (begin) + (begin + (bhvPaintTextAlignSet smallPaint (bhvPaintAlignLeft)) + (bhvCanvasDrawText canvas + (fitText (string-append "WPN " weaponText) smallPaint + (- (bhvRectWidth rect) (float32 16.0))) + (+ (bhvRectLeft rect) (float32 8.0)) + (+ barY (float32 99.0)) smallPaint))))))))))) (def (drawCenterBlock (canvas : Canvas) (rect : RectF) (current : JSONObject) (battle : JSONObject) @@ -508,7 +531,12 @@ (bhvCanvasDrawRoundRect canvas rect (float32 8.0) (float32 8.0) panelAltPaint) (bhvCanvasDrawRoundRect canvas rect (float32 8.0) (float32 8.0) borderPaint) (let ((compact (< (bhvRectHeight rect) (float32 72.0))) - (orders (json-object-opt-json-object current "orders"))) + (orders (json-object-opt-json-object current "orders")) + (phaseText + (phaseSlotSummary + (bhvNullableArrayField + (bhvNullableObjectField dashboard "impulse-activity") + "stage-slots")))) (let ((fireImpulse (bhvAnyText (bhvNullableAnyField orders "fire-impulse") "-")) (seekers @@ -541,9 +569,17 @@ labelPaint (- (bhvRectWidth rect) (float32 14.0))) (bhvRectCenterX rect) (+ (bhvRectTop rect) (float32 38.0)) labelPaint)) - (let ((y (+ (bhvRectTop rect) (float32 49.0)))) + (var ((y (+ (bhvRectTop rect) (float32 49.0)))) (begin (bhvPaintTextAlignSet smallPaint (bhvPaintAlignCenter)) + (if (string-blank? phaseText) + (begin) + (begin + (bhvCanvasDrawText canvas + (fitText phaseText smallPaint + (- (bhvRectWidth rect) (float32 14.0))) + (bhvRectCenterX rect) y smallPaint) + (set! y (+ y (float32 18.0))))) (bhvCanvasDrawText canvas (fitText (string-append @@ -720,6 +756,106 @@ ignored)))))) (begin)))))))))) + (def (phaseSlotSummary (slots : (Nullable JSONArray))) : String + (modifiers private) + (if (nullable-null? slots) "" + (phaseSlotSummaryAt (nullable-get slots) (int32 0) (int32 0) ""))) + (def (phaseSlotSummaryAt (slots : JSONArray) (index : Int32) + (count : Int32) (out : String)) : String + (modifiers private) + (if (or (>= index (json-array-length slots)) (>= count (int32 3))) out + (let ((slot (json-array-opt-json-object slots index))) + (if (or (nullable-null? slot) + (not (json-object-opt-bool-default + (nullable-get slot) "implemented?" #f))) + (phaseSlotSummaryAt slots (+ index (int32 1)) count out) + (let ((raw (json-object-opt-string-default + (nullable-get slot) "action" + (json-object-opt-string-default + (nullable-get slot) "engine-hook" "")))) + (let ((action + (bhvStringReplace + (bhvStringReplace + (bhvStringReplace raw "Launch " "Ln ") + "Fire Weapons" "Fire") + "Announce " ""))) + (if (string-blank? action) + (phaseSlotSummaryAt slots (+ index (int32 1)) count out) + (phaseSlotSummaryAt slots (+ index (int32 1)) (+ count (int32 1)) + (string-append out + (string-append (if (> count (int32 0)) " | " "") action)))))))))) + + (def (weaponInstalledTotal (weapons : (Nullable JSONArray))) : Int32 + (modifiers private) + (if (nullable-null? weapons) (int32 0) + (for/fold ((total (int32 0))) + ((index (in-range (int32 0) (json-array-length (nullable-get weapons))))) + (+ total + (bhvMaxInt (int32 0) + (bhvNullableIntField + (json-array-opt-json-object (nullable-get weapons) index) + "installed" (int32 0))))))) + + (def (weaponFamilySummary (weapons : (Nullable JSONArray))) : String + (modifiers private) + (if (nullable-null? weapons) "" + (weaponFamilySummaryAt (nullable-get weapons) (int32 0) (int32 0) ""))) + (def (weaponFamilySummaryAt (weapons : JSONArray) (index : Int32) + (count : Int32) (out : String)) : String + (modifiers private) + (if (or (>= index (json-array-length weapons)) (>= count (int32 3))) out + (let ((weapon (json-array-opt-json-object weapons index))) + (if (nullable-null? weapon) + (weaponFamilySummaryAt weapons (+ index (int32 1)) count out) + (let ((installed (bhvNullableIntField weapon "installed" (int32 0))) + (armed (bhvNullableIntField weapon "armed" (int32 0))) + (fireable (bhvNullableIntField weapon "fireable" (int32 0))) + (inArc (bhvNullableIntField weapon "fireable-in-arc" (int32 0))) + (cooldown (bhvNullableIntField weapon "cooldown" (int32 0)))) + (if (<= (+ installed (+ armed (+ fireable cooldown))) (int32 0)) + (weaponFamilySummaryAt weapons (+ index (int32 1)) count out) + (weaponFamilySummaryAt weapons (+ index (int32 1)) (+ count (int32 1)) + (string-append out + (string-append (if (> count (int32 0)) " " "") + (string-append + (shortWeaponKind + (json-object-opt-string-default + (nullable-get weapon) "kind" "")) + (string-append " " + (string-append (int32->string fireable) + (string-append "/" + (string-append (int32->string armed) + (string-append "/" + (string-append (int32->string installed) + (string-append + (if (and (> fireable (int32 0)) (< inArc fireable)) + (string-append " a" (int32->string inArc)) "") + (if (> cooldown (int32 0)) + (string-append " cd" (int32->string cooldown)) "")))))))))))))))))) + + (def (shortWeaponKind (kind : String)) : String + (modifiers private) + (if (equal? kind "photon") "PHT" + (if (equal? kind "disruptor") "DIS" + (if (equal? kind "hellbore") "HB" + (if (equal? kind "fusion") "FUS" + (if (equal? kind "tr-beam") "TR" + (if (equal? kind "phaser") "PH" + (if (bhvStringStartsWith kind "phaser-") + (bhvStringUppercase (bhvStringReplace kind "phaser-" "PH-")) + (if (equal? kind "drone") "DRN" + (if (bhvStringStartsWith kind "plasma-") + (bhvStringUppercase (bhvStringReplace kind "plasma-" "PL-")) + (bhvStringUppercase + (bhvStringReplace kind "drone-" "D-")))))))))))) + + (def (weaponSortBucket (kind : String)) : Int32 + (modifiers private) + (if (bhvStringStartsWith kind "phaser") (int32 2) + (if (or (bhvStringContains kind "drone") + (bhvStringContains kind "plasma")) + (int32 1) (int32 0)))) + (def (shipName (ship : (Nullable JSONObject)) (statusShip : (Nullable JSONObject))) : String (modifiers private) @@ -745,6 +881,44 @@ (bhvNumberValue counter) (counterArrayTotal (nullable-get array) (int32 0)))) (objectTotal (nullable-some (nullable-get obj))))))) + (def (numberValue (value : (Nullable Any))) : Int32 + (modifiers private) + (bhvNumberValue value)) + (def (forEachCounterPair + (counter : (Nullable Any)) + (action : (-> String (Nullable Any) Unit))) : Unit + (modifiers private) + (if (nullable-null? counter) (begin) + (let ((object (bhvAsJsonObject (nullable-get counter))) + (array (bhvAsJsonArray (nullable-get counter)))) + (if (not (nullable-null? object)) + (let ((pair (json-object-opt-json-array + (nullable-get object) "$pair"))) + (if (nullable-null? pair) + (forEachCounterObjectKeys (nullable-get object) + (bhvJsonKeys (nullable-get object)) action) + (invoke action + (json-array-opt-string (nullable-get pair) (int32 0)) + (json-array-opt-any (nullable-get pair) (int32 1))))) + (if (nullable-null? array) (begin) + (forEachCounterArray (nullable-get array) (int32 0) action)))))) + (def (forEachCounterObjectKeys + (object : JSONObject) (keys : (Iterator String)) + (action : (-> String (Nullable Any) Unit))) : Unit + (modifiers private) + (if (not (bhvIteratorHasNext keys)) (begin) + (let ((key (bhvIteratorNext keys))) + (begin + (invoke action key (json-object-opt-any object key)) + (forEachCounterObjectKeys object keys action))))) + (def (forEachCounterArray + (array : JSONArray) (index : Int32) + (action : (-> String (Nullable Any) Unit))) : Unit + (modifiers private) + (if (>= index (json-array-length array)) (begin) + (begin + (forEachCounterPair (json-array-opt-any array index) action) + (forEachCounterArray array (+ index (int32 1)) action)))) (def (objectTotal (obj : (Nullable JSONObject))) : Int32 (modifiers private) (if (nullable-null? obj) @@ -804,10 +978,35 @@ (def (paPanelCount (ship : (Nullable JSONObject)) (statusShip : (Nullable JSONObject))) : Int32 (modifiers private) - (let ((shipCount (counterValue (bhvNullableAnyField ship "boxes") "52"))) - (if (> shipCount (int32 0)) - shipCount - (counterValue (bhvNullableAnyField statusShip "boxes") "52")))) + (let ((carrier (if (nullable-null? ship) statusShip ship))) + (if (and (not (nullable-null? carrier)) + (bhvJsonHas (nullable-get carrier) "pa-panels")) + (bhvMaxInt (int32 0) + (bhvNumberValue (bhvNullableAnyField carrier "pa-panels"))) + (bhvMaxInt (int32 0) + (- (paPanelBoxCount ship statusShip) + (paPanelCharge ship statusShip)))))) + (def (paPanelBoxCount (ship : (Nullable JSONObject)) + (statusShip : (Nullable JSONObject))) : Int32 + (modifiers private) + (let ((carrier (if (nullable-null? ship) statusShip ship))) + (let ((boxes (bhvNumberValue (bhvNullableAnyField carrier "pa-panel-boxes"))) + (maximum (bhvNumberValue (bhvNullableAnyField carrier "pa-panel-max"))) + (shipBoxes (counterValue (bhvNullableAnyField ship "boxes") "52"))) + (if (> boxes (int32 0)) boxes + (if (> maximum (int32 0)) maximum + (if (> shipBoxes (int32 0)) shipBoxes + (counterValue (bhvNullableAnyField statusShip "boxes") "52"))))))) + (def (paPanelCharge (ship : (Nullable JSONObject)) + (statusShip : (Nullable JSONObject))) : Int32 + (modifiers private) + (let ((carrier (if (nullable-null? ship) statusShip ship))) + (let ((charge (bhvMaxInt (int32 0) + (bhvNumberValue + (bhvNullableAnyField carrier "pa-panel-charge")))) + (maximum (bhvMaxInt (int32 1) + (paPanelBoxCount ship statusShip)))) + (if (> charge maximum) maximum charge)))) (def (paPanelMax (ship : (Nullable JSONObject)) (statusShip : (Nullable JSONObject))) : Int32 (modifiers private) @@ -815,7 +1014,7 @@ (counterValue (bhvNullableAnyField ship "destroyed-boxes") "52"))) (bhvMaxInt (int32 1) - (+ (paPanelCount ship statusShip) + (+ (paPanelBoxCount ship statusShip) (if (> destroyed (int32 0)) destroyed (counterValue @@ -834,9 +1033,11 @@ (let ((panels (paPanelCount ship statusShip)) (maximum (paPanelMax ship statusShip))) (if (or (> panels (int32 0)) (> maximum (int32 1))) - (string-append - (string-append "PA " (int32->string panels)) - (string-append "/" (int32->string maximum))) + (string-append "PA chg " + (string-append (int32->string (paPanelCharge ship statusShip)) + (string-append "/" + (string-append (int32->string maximum) + (string-append " av " (int32->string panels)))))) "SH 0"))))) (def (shieldFacingIndex (value : (Nullable Any))) : Int32 (modifiers private) @@ -912,10 +1113,30 @@ (- (json-array-length raw) (int32 1))))) (if (nullable-null? event) "Recent event" - (bhvStringReplace - (json-object-opt-string-default - (nullable-get event) "type" "event") - "-" " "))))) + (let ((payload + (json-object-opt-json-object + (nullable-get event) "payload"))) + (string-append + (bhvStringReplace + (json-object-opt-string-default + (nullable-get event) "type" "event") + "-" " ") + (if (and (not (nullable-null? payload)) + (bhvJsonHas (nullable-get payload) "damage")) + (string-append " dmg " + (bhvAnyText + (bhvNullableAnyField payload "damage") "")) + (if (and (not (nullable-null? payload)) + (bhvJsonHas (nullable-get payload) "winner")) + (string-append " winner " + (bhvAnyText + (bhvNullableAnyField payload "winner") "")) + (if (and (not (nullable-null? payload)) + (bhvJsonHas (nullable-get payload) "range")) + (string-append " range " + (bhvAnyText + (bhvNullableAnyField payload "range") "")) + ""))))))))) (def (fitText (text : String) (paint : Paint) (maxWidth : Float32)) : String (modifiers private) --- a/templates/original-tactics-parts/Sfc2IntelView.kt.ss +++ b/templates/original-tactics-parts/Sfc2IntelView.kt.ss @@ -17,7 +17,7 @@ (export Sfc2IntelView) (type Context) (type Canvas) (type Paint) (type Align) (type Style) (type RectF) (type View) (type Resources) (type DisplayMetrics) - (type JSONArray) (type JSONObject) (type Int32) (type Float32) + (type JSONArray) (type JSONObject) (type Int32) (type Float32) (type Any) (type Number) (extern (sivPaintFlag) : Int32 (kotlin-value Paint ANTI_ALIAS_FLAG)) (extern (sivFill) : Style (kotlin-value Paint Style FILL)) (extern (sivStroke) : Style (kotlin-value Paint Style STROKE)) @@ -37,6 +37,8 @@ (kotlin-member-set isFakeBoldText)) (extern (sivPaintAlignSet (paint : Paint) (value : Align)) : Unit (kotlin-member-set textAlign)) + (extern (sivPaintMeasure (paint : Paint) (text : String)) : Float32 + (kotlin-member-call measureText)) (extern (sivInvalidate (view : Sfc2IntelView)) : Unit (kotlin-member-call invalidate)) (extern (sivSuperDraw (canvas : Canvas)) : Unit @@ -64,12 +66,18 @@ (x : Float32) (y : Float32) (paint : Paint)) : Unit (kotlin-member-call drawText)) + (extern (sivDrawCircle (canvas : Canvas) (x : Float32) (y : Float32) + (radius : Float32) (paint : Paint)) : Unit + (kotlin-member-call drawCircle)) (extern (sivRectLeft (rect : RectF)) : Float32 (kotlin-member-get left)) (extern (sivRectTop (rect : RectF)) : Float32 (kotlin-member-get top)) (extern (sivRectRight (rect : RectF)) : Float32 (kotlin-member-get right)) + (extern (sivRectBottom (rect : RectF)) : Float32 (kotlin-member-get bottom)) + (extern (sivRectWidth (rect : RectF)) : Float32 (kotlin-member-call width)) + (extern (sivRectHeight (rect : RectF)) : Float32 (kotlin-member-call height)) (extern (sivJsonObject (object : JSONObject) (key : String)) : (Nullable JSONObject) (kotlin-member-call optJSONObject)) @@ -79,6 +87,39 @@ (extern (sivJsonBoolean (object : JSONObject) (key : String) (fallback : Bool)) : Bool (kotlin-member-call optBoolean)) + (extern (sivJsonArray (object : JSONObject) (key : String)) : (Nullable JSONArray) + (kotlin-member-call optJSONArray)) + (extern (sivJsonAny (object : JSONObject) (key : String)) : (Nullable Any) + (kotlin-member-call opt)) + (extern (sivJsonString (object : JSONObject) (key : String) + (fallback : String)) : String + (kotlin-member-call optString)) + (extern (sivJsonHas (object : JSONObject) (key : String)) : Bool + (kotlin-member-call has)) + (extern (sivArrayLength (array : JSONArray)) : Int32 (kotlin-member-call length)) + (extern (sivArrayObject (array : JSONArray) (index : Int32)) : (Nullable JSONObject) + (kotlin-member-call optJSONObject)) + (extern (sivArrayAny (array : JSONArray) (index : Int32)) : (Nullable Any) + (kotlin-member-call opt)) + (extern (sivArrayPut (array : JSONArray) (value : JSONObject)) : JSONArray + (kotlin-member-call put)) + (extern (sivMutableObjectAddAt (items : (MutableList JSONObject)) + (index : Int32) (value : JSONObject)) : Unit + (kotlin-member-call add)) + (extern (sivFloatInt (value : Float32)) : Int32 (kotlin-member-call toInt)) + (extern (sivAsNumber (value : Any)) : (Nullable Number) (kotlin-safe-cast Number)) + (extern (sivAsObject (value : Any)) : (Nullable JSONObject) (kotlin-safe-cast JSONObject)) + (extern (sivAsString (value : Any)) : (Nullable String) (kotlin-safe-cast String)) + (extern (sivNumberInt (value : Number)) : Int32 (kotlin-member-call toInt)) + (extern (sivAnyText (value : Any)) : String (kotlin-member-call toString)) + (extern (sivKeys (object : JSONObject)) : (Iterator String) (kotlin-member-call keys)) + (extern (sivHasNext (iterator : (Iterator String))) : Bool (kotlin-member-call hasNext)) + (extern (sivNext (iterator : (Iterator String))) : String (kotlin-member-call next)) + (extern (sivReplace (text : String) (old : String) (replacement : String)) : String + (kotlin-member-call replace)) + (extern (sivUppercase (text : String)) : String (kotlin-member-call uppercase)) + (extern (sivDropLast (text : String) (count : Int32)) : String + (kotlin-member-call dropLast)) (extern (sivShipTechnicalLabel (actor : (Nullable JSONObject)) (fallback : String)) : String (kotlin-call shipTechnicalLabel)) @@ -100,6 +141,10 @@ (def (sivDensity (view : Sfc2IntelView)) : Float32 (let ((value (sivDensityValue (sivMetrics (sivResources view))))) (if (< value (float32 1.0)) (float32 1.0) value))) + (def (sivMaxInt (a : Int32) (b : Int32)) : Int32 (if (> a b) a b)) + (def (sivObjectInt (object : (Nullable JSONObject)) (key : String)) : Int32 + (if (nullable-null? object) (int32 0) + (sivJsonInt (nullable-get object) key (int32 0)))) (class Sfc2IntelView ((context : Context)) (extends View context) (var statusReport : (Nullable JSONObject) (nullable-none JSONObject) @@ -125,6 +170,18 @@ (val betaPaint : Paint (sivPaint (sivRgb (int32 205) (int32 82) (int32 66)) (sivFill)) (modifiers private)) + (val gridPaint : Paint + (sivPaint (sivRgb (int32 42) (int32 55) (int32 73)) (sivFill)) + (modifiers private)) + (val readyPaint : Paint + (sivPaint (sivRgb (int32 76) (int32 177) (int32 112)) (sivFill)) + (modifiers private)) + (val warningPaint : Paint + (sivPaint (sivRgb (int32 222) (int32 158) (int32 68)) (sivFill)) + (modifiers private)) + (val blockedPaint : Paint + (sivPaint (sivRgb (int32 191) (int32 71) (int32 64)) (sivFill)) + (modifiers private)) (val titlePaint : Paint (sivTextPaint (sivWhite) (float32 25.0) #t) (modifiers private)) (val labelPaint : Paint @@ -200,16 +257,31 @@ (+ (/ drawHeight (float32 2.0)) (float32 20.0)) smallPaint))) (def (drawHeader (canvas : Canvas) (status : JSONObject)) : Unit (modifiers private) - (begin + (let ((counts (sivJsonObject status "counts"))) + (begin (sivPaintAlignSet titlePaint (sivLeft)) (sivDrawText canvas "SFC2 INTEL" (float32 12.0) (float32 27.0) titlePaint) - (sivPaintAlignSet smallPaint (sivRight)) + (sivPaintAlignSet smallPaint (sivCenter)) (sivDrawText canvas (string-append "T" (string-append (int32->string (sivJsonInt status "turn" (int32 0))) (string-append "." - (int32->string (sivJsonInt status "impulse" (int32 0)))))) - (- drawWidth (float32 12.0)) (float32 25.0) smallPaint))) + (string-append (int32->string (sivJsonInt status "impulse" (int32 0))) + (string-append " R" + (if (nullable-null? (sivJsonAny status "range")) "-" + (sivAnyText (nullable-get (sivJsonAny status "range"))))))))) + (/ drawWidth (float32 2.0)) (float32 25.0) smallPaint) + (sivPaintAlignSet smallPaint (sivRight)) + (sivDrawText canvas + (string-append "S:" + (string-append (int32->string (sivObjectInt counts "active-seeking")) + (string-append " U:" + (string-append (int32->string (sivObjectInt counts "active-small-units")) + (string-append " W:" + (string-append (int32->string (sivObjectInt counts "active-webs")) + (string-append " M:" + (int32->string (sivObjectInt counts "active-mines"))))))))) + (- drawWidth (float32 12.0)) (float32 25.0) smallPaint)))) (def (drawActorIntel (canvas : Canvas) (rect : RectF) (side : String) (actor : (Nullable JSONObject)) @@ -226,17 +298,270 @@ (sivPaintAlignSet labelPaint (sivLeft)) (sivDrawText canvas side (+ (sivRectLeft rect) (float32 8.0)) - (+ (sivRectTop rect) (float32 20.0)) labelPaint) - (sivPaintAlignSet smallPaint (sivLeft)) + (+ (sivRectTop rect) (float32 18.0)) labelPaint) + (sivPaintAlignSet dimPaint (sivRight)) (sivDrawText canvas - (if (or (nullable-null? actor) - (not (sivJsonBoolean (nullable-get actor) "ship-present?" #f))) - "No ship report" - (sivShipDisplayLabel (nullable-get actor))) - (+ (sivRectLeft rect) (float32 8.0)) - (+ (sivRectTop rect) (float32 52.0)) smallPaint) + (fitText (sivShipTechnicalLabel actor "-") dimPaint + (* (sivRectWidth rect) (float32 0.48))) + (- (sivRectRight rect) (float32 8.0)) + (+ (sivRectTop rect) (float32 18.0)) dimPaint) + (if (or (nullable-null? actor) + (not (sivJsonBoolean (nullable-get actor) "ship-present?" #f))) + (begin + (sivPaintAlignSet smallPaint (sivLeft)) + (sivDrawText canvas "No ship report" + (+ (sivRectLeft rect) (float32 8.0)) + (+ (sivRectTop rect) (float32 53.0)) smallPaint) + (drawTruth canvas rect truth (+ (sivRectTop rect) (float32 82.0)))) + (let ((ship (nullable-get actor))) + (var ((y (+ (sivRectTop rect) (float32 49.0)))) + (begin + (sivPaintAlignSet smallPaint (sivLeft)) + (sivDrawText canvas + (fitText (sivShipDisplayLabel ship) smallPaint + (- (sivRectWidth rect) (float32 16.0))) + (+ (sivRectLeft rect) (float32 8.0)) y smallPaint) + (set! y (+ y (float32 18.0))) + (set! y (drawVitals canvas rect ship y)) + (drawWeaponHeader canvas rect y) + (set! y (+ y (float32 18.0))) + (let ((weapons (sortedWeapons + (let ((raw (sivJsonArray ship "weapon-status"))) + (if (nullable-null? raw) (new JSONArray) (nullable-get raw)))))) + (begin + (if (> (sivArrayLength weapons) (int32 0)) + (let ((maxRows + (sivMaxInt (int32 1) + (sivFloatInt (/ (- (- (sivRectBottom rect) (float32 61.0)) + (+ y (float32 42.0))) + (float32 18.0)))))) + (begin + (drawWeaponRows canvas rect y weapons (int32 0) + (if (> maxRows (int32 5)) (int32 5) maxRows)) + (set! y (+ y (* (float32 + (if (> (sivArrayLength weapons) maxRows) maxRows + (sivArrayLength weapons))) (float32 18.0)))))) + (begin + (sivPaintAlignSet dimPaint (sivLeft)) + (sivDrawText canvas "No weapon status" + (+ (sivRectLeft rect) (float32 8.0)) y dimPaint))) + (set! y (+ y (float32 21.0))))) + (set! y (drawSpecialSystems canvas rect ship y)) + (drawTruth canvas rect truth + (if (> (+ y (float32 4.0)) (- (sivRectBottom rect) (float32 61.0))) + (+ y (float32 4.0)) (- (sivRectBottom rect) (float32 61.0)))))))))) + + (def (drawVitals (canvas : Canvas) (rect : RectF) + (actor : JSONObject) (y : Float32)) : Float32 + (modifiers private) + (let ((power (sivJsonObject actor "power-status")) + (movement (sivJsonObject actor "movement")) + (shields (sivJsonObject actor "shields")) + (maximum (sivJsonObject actor "max-shields"))) + (begin + (sivPaintAlignSet smallPaint (sivLeft)) + (sivDrawText canvas + (fitText + (string-append "HULL " + (string-append (int32->string + (sivJsonInt actor "remaining-internals" (int32 0))) + (string-append " SH " + (string-append (int32->string (objectTotal shields)) + (string-append "/" (int32->string + (sivMaxInt (objectTotal maximum) (objectTotal shields)))))))) + smallPaint (- (sivRectWidth rect) (float32 16.0))) + (+ (sivRectLeft rect) (float32 8.0)) y smallPaint) + (sivDrawText canvas + (fitText + (string-append "PWR " + (string-append (int32->string (sivObjectInt power "unspent-energy")) + (string-append "/" (int32->string (sivObjectInt power "total-power"))))) + smallPaint (- (sivRectWidth rect) (float32 16.0))) + (+ (sivRectLeft rect) (float32 8.0)) (+ y (float32 17.0)) smallPaint) + (+ y (float32 38.0))))) + + (def (drawWeaponHeader (canvas : Canvas) (rect : RectF) (y : Float32)) : Unit + (modifiers private) + (begin (sivPaintAlignSet dimPaint (sivLeft)) - (sivDrawText canvas - (if (nullable-null? truth) "No truth report" "Truth report loaded") - (+ (sivRectLeft rect) (float32 8.0)) - (+ (sivRectTop rect) (float32 78.0)) dimPaint)))))))) + (sivDrawText canvas "BANK" (+ (sivRectLeft rect) (float32 8.0)) y dimPaint) + (sivDrawText canvas "READY" (+ (sivRectLeft rect) (* (sivRectWidth rect) (float32 0.48))) y dimPaint) + (sivDrawText canvas "ARC" (+ (sivRectLeft rect) (* (sivRectWidth rect) (float32 0.70))) y dimPaint))) + + (def (drawWeaponLine (canvas : Canvas) (rect : RectF) (y : Float32) + (weapon : (Nullable JSONObject))) : Unit + (modifiers private) + (if (nullable-null? weapon) (begin) + (let ((ready (sivObjectInt weapon "fireable")) + (armed (sivObjectInt weapon "armed")) + (installed (sivObjectInt weapon "installed")) + (inArc (sivObjectInt weapon "fireable-in-arc"))) + (begin + (sivPaintAlignSet smallPaint (sivLeft)) + (sivDrawText canvas + (shortWeapon (sivJsonString (nullable-get weapon) "kind" "-")) + (+ (sivRectLeft rect) (float32 8.0)) y smallPaint) + (drawStatusDot canvas (+ (sivRectLeft rect) (* (sivRectWidth rect) (float32 0.45))) + (- y (float32 5.0)) ready armed inArc) + (sivDrawText canvas + (string-append (int32->string ready) + (string-append "/" (string-append (int32->string armed) + (string-append "/" (int32->string installed))))) + (+ (sivRectLeft rect) (* (sivRectWidth rect) (float32 0.48))) y smallPaint))))) + + (def (drawStatusDot (canvas : Canvas) (x : Float32) (y : Float32) + (ready : Int32) (armed : Int32) (inArc : Int32)) : Unit + (modifiers private) + (sivDrawCircle canvas x y (float32 5.0) + (if (and (> ready (int32 0)) (> inArc (int32 0))) readyPaint + (if (or (> armed (int32 0)) (> ready (int32 0))) warningPaint blockedPaint)))) + + (def (drawSpecialSystems (canvas : Canvas) (rect : RectF) + (actor : JSONObject) (y : Float32)) : Float32 + (modifiers private) + (if (> y (- (sivRectBottom rect) (float32 85.0))) y + (let ((tractor (sivJsonObject actor "tractor-status")) + (transporter (sivJsonObject actor "transporter-status")) + (repair (sivJsonObject actor "repair-status"))) + (begin + (sivDrawText canvas + (fitText (string-append "TRAC " + (string-append (int32->string (sivObjectInt tractor "available-boxes")) + (string-append " TRAN " + (string-append (int32->string (sivObjectInt transporter "available-boxes")) + (string-append " LAB " (int32->string (sivObjectInt repair "lab-count"))))))) + smallPaint (- (sivRectWidth rect) (float32 16.0))) + (+ (sivRectLeft rect) (float32 8.0)) y smallPaint) + (+ y (float32 35.0)))))) + + (def (drawTruth (canvas : Canvas) (rect : RectF) + (truth : (Nullable JSONObject)) (y : Float32)) : Unit + (modifiers private) + (let ((box (new RectF (+ (sivRectLeft rect) (float32 8.0)) y + (- (sivRectRight rect) (float32 8.0)) + (- (sivRectBottom rect) (float32 8.0))))) + (if (< (sivRectHeight box) (float32 28.0)) (begin) + (begin + (sivDrawRoundRect canvas box (float32 6.0) (float32 6.0) gridPaint) + (sivPaintAlignSet labelPaint (sivLeft)) + (sivDrawText canvas + (if (nullable-null? truth) "SSD truth not linked" + (let ((summary (sivJsonObject (nullable-get truth) "summary"))) + (string-append "SSD " + (string-append (int32->string (sivObjectInt summary "group-count")) + (string-append "g " + (string-append (int32->string (sivObjectInt summary "box-count")) " boxes")))))) + (+ (sivRectLeft box) (float32 6.0)) + (+ (sivRectTop box) (float32 18.0)) labelPaint))))) + + (def (drawWeaponRows (canvas : Canvas) (rect : RectF) (y : Float32) + (weapons : JSONArray) (index : Int32) + (limit : Int32)) : Unit + (modifiers private) + (if (or (>= index limit) (>= index (sivArrayLength weapons))) (begin) + (begin + (drawWeaponLine canvas rect (+ y (* (float32 index) (float32 18.0))) + (sivArrayObject weapons index)) + (drawWeaponRows canvas rect y weapons (+ index (int32 1)) limit)))) + (def (sortedWeapons (raw : JSONArray)) : JSONArray + (modifiers private) + (let ((items (mutable-list-empty JSONObject)) (out (new JSONArray))) + (begin + (collectSortedWeapons raw (int32 0) items) + (appendWeapons out items (int32 0)) + out))) + (def (collectSortedWeapons (raw : JSONArray) (index : Int32) + (items : (MutableList JSONObject))) : Unit + (modifiers private) + (if (>= index (sivArrayLength raw)) (begin) + (begin + (let ((weapon (sivArrayObject raw index))) + (if (nullable-null? weapon) (begin) + (insertSortedWeapon items (nullable-get weapon)))) + (collectSortedWeapons raw (+ index (int32 1)) items)))) + (def (insertSortedWeapon (items : (MutableList JSONObject)) + (weapon : JSONObject)) : Unit + (modifiers private) + (let ((at (findWeaponInsert items weapon (int32 0)))) + (if (>= at (list-size items)) (mutable-list-add! items weapon) + (sivMutableObjectAddAt items at weapon)))) + (def (findWeaponInsert (items : (List JSONObject)) (weapon : JSONObject) + (index : Int32)) : Int32 + (modifiers private) + (if (>= index (list-size items)) index + (if (weaponBefore? weapon (list-ref items index)) index + (findWeaponInsert items weapon (+ index (int32 1)))))) + (def (weaponBefore? (a : JSONObject) (b : JSONObject)) : Bool + (modifiers private) + (let ((aa (sivJsonInt a "fireable-in-arc" (int32 0))) + (ba (sivJsonInt b "fireable-in-arc" (int32 0))) + (af (sivJsonInt a "fireable" (int32 0))) + (bf (sivJsonInt b "fireable" (int32 0)))) + (if (not (= aa ba)) (> aa ba) + (if (not (= af bf)) (> af bf) + (< (weaponSortBucket (sivJsonString a "kind" "")) + (weaponSortBucket (sivJsonString b "kind" ""))))))) + (def (appendWeapons (out : JSONArray) (items : (List JSONObject)) + (index : Int32)) : Unit + (modifiers private) + (if (>= index (list-size items)) (begin) + (begin + (sivArrayPut out (list-ref items index)) + (appendWeapons out items (+ index (int32 1)))))) + (def (weaponSortBucket (kind : String)) : Int32 (modifiers private) + (if (string-starts-with? kind "phaser") (int32 2) + (if (or (string-contains? kind "drone") (string-contains? kind "plasma")) + (int32 1) (int32 0)))) + (def (shortWeapon (kind : String)) : String (modifiers private) + (sivUppercase + (sivReplace (sivReplace (sivReplace (sivReplace kind + "phaser-" "PH-") "photon" "PHOT") "disruptor" "DISR") "plasma-" "PL-"))) + (def (compactArray (array : (Nullable JSONArray)) (limit : Int32)) : String + (modifiers private) + (if (or (nullable-null? array) (= (sivArrayLength (nullable-get array)) (int32 0))) "" + (if (nullable-null? (sivArrayAny (nullable-get array) (int32 0))) "" + (sivAnyText (nullable-get (sivArrayAny (nullable-get array) (int32 0))))))) + (def (objectTotal (object : (Nullable JSONObject))) : Int32 + (modifiers private) + (if (nullable-null? object) (int32 0) + (objectTotalKeys (nullable-get object) (sivKeys (nullable-get object)) (int32 0)))) + (def (objectTotalKeys (object : JSONObject) (keys : (Iterator String)) + (total : Int32)) : Int32 + (modifiers private) + (if (not (sivHasNext keys)) total + (objectTotalKeys object keys + (+ total (sivMaxInt (int32 0) + (numberValue (sivJsonAny object (sivNext keys)))))))) + (def (counterValue (counter : (Nullable Any)) (wantedKey : String)) : Int32 + (modifiers private) + (if (nullable-null? counter) (int32 0) + (let ((object (sivAsObject (nullable-get counter)))) + (if (nullable-null? object) (int32 0) + (numberValue (sivJsonAny (nullable-get object) wantedKey)))))) + (def (numberValue (value : (Nullable Any))) : Int32 + (modifiers private) + (if (nullable-null? value) (int32 0) + (let ((number (sivAsNumber (nullable-get value)))) + (if (nullable-null? number) (int32 0) (sivNumberInt (nullable-get number)))))) + (def (truthGroupSample (groups : (Nullable JSONArray))) : String (modifiers private) "") + (def (shortTruthLabel (label : String)) : String (modifiers private) + (sivUppercase (sivReplace (sivReplace label "phaser-" "ph-") "transporter" "tran"))) + (def (truthMatchTag (truth : (Nullable JSONObject))) : String + (modifiers private) + (if (nullable-null? truth) "" + (let ((kind (sivJsonString (nullable-get truth) "_matched-by" ""))) + (if (equal? kind "template-id") "LINK" + (if (equal? kind "box-signature") + (string-append "SIG" (int32->string + (sivJsonInt (nullable-get truth) "_match-overlap" (int32 0)))) ""))))) + (def (fitText (text : String) (paint : Paint) (maxWidth : Float32)) : String + (modifiers private) + (if (<= (sivPaintMeasure paint text) maxWidth) text + (fitTextAt text paint maxWidth (- (string-length-int32 text) (int32 1))))) + (def (fitTextAt (text : String) (paint : Paint) + (maxWidth : Float32) (end : Int32)) : String + (modifiers private) + (if (<= end (int32 4)) (string-take text end) + (let ((candidate (string-append (string-take text end) "..."))) + (if (<= (sivPaintMeasure paint candidate) maxWidth) candidate + (fitTextAt text paint maxWidth (- end (int32 1)))))))))))) --- a/templates/original-tactics-parts/SystemsReadinessView.kt.ss +++ b/templates/original-tactics-parts/SystemsReadinessView.kt.ss @@ -14,10 +14,18 @@ (org json JSONArray) (org json JSONObject)) (typed-library (com jerboa originaltactics) - (export SystemsReadinessView) + (export SystemsReadinessView + make-ReadinessWeaponFamily ReadinessWeaponFamily?) (type Context) (type Canvas) (type Paint) (type Align) (type Style) (type RectF) (type View) (type Resources) (type DisplayMetrics) (type JSONArray) (type JSONObject) (type Int32) (type Float32) + (record ReadinessWeaponFamily + ((kind : String) + (installed : Int32) + (armed : Int32) + (fireable : Int32) + (inArc : Int32) + (cooldown : Int32))) (extern (srvPaintFlag) : Int32 (kotlin-value Paint ANTI_ALIAS_FLAG)) (extern (srvFill) : Style (kotlin-value Paint Style FILL)) (extern (srvStroke) : Style (kotlin-value Paint Style STROKE)) @@ -37,6 +45,8 @@ (kotlin-member-set isFakeBoldText)) (extern (srvPaintAlignSet (paint : Paint) (value : Align)) : Unit (kotlin-member-set textAlign)) + (extern (srvPaintMeasure (paint : Paint) (text : String)) : Float32 + (kotlin-member-call measureText)) (extern (srvInvalidate (view : SystemsReadinessView)) : Unit (kotlin-member-call invalidate)) (extern (srvSuperDraw (canvas : Canvas)) : Unit @@ -72,6 +82,8 @@ (extern (srvRectLeft (rect : RectF)) : Float32 (kotlin-member-get left)) (extern (srvRectTop (rect : RectF)) : Float32 (kotlin-member-get top)) (extern (srvRectRight (rect : RectF)) : Float32 (kotlin-member-get right)) + (extern (srvRectBottom (rect : RectF)) : Float32 (kotlin-member-get bottom)) + (extern (srvRectWidth (rect : RectF)) : Float32 (kotlin-member-call width)) (extern (srvJsonObject (object : JSONObject) (key : String)) : (Nullable JSONObject) (kotlin-member-call optJSONObject)) @@ -84,8 +96,34 @@ (extern (srvJsonBoolean (object : JSONObject) (key : String) (fallback : Bool)) : Bool (kotlin-member-call optBoolean)) + (extern (srvJsonString (object : JSONObject) (key : String) + (fallback : String)) : String + (kotlin-member-call optString)) + (extern (srvArrayObject (array : JSONArray) + (index : Int32)) : (Nullable JSONObject) + (kotlin-member-call optJSONObject)) (extern (srvArrayLength (array : JSONArray)) : Int32 (kotlin-member-call length)) + (extern (srvMutableFamilyAddAt (items : (MutableList ReadinessWeaponFamily)) + (index : Int32) + (value : ReadinessWeaponFamily)) : Unit + (kotlin-member-call add)) + (extern (srvMutableStringAddAt (items : (MutableList String)) + (index : Int32) (value : String)) : Unit + (kotlin-member-call add)) + (extern (srvMapKeys (items : (Map String Int32))) : (Set String) + (kotlin-member-get keys)) + (extern (srvSetToList (items : (Set String))) : (List String) + (kotlin-member-call toList)) + (extern (srvStringReplace (text : String) (old : String) + (replacement : String)) : String + (kotlin-member-call replace)) + (extern (srvStringDropLast (text : String) (count : Int32)) : String + (kotlin-member-call dropLast)) + (extern (srvStringStartsWith (text : String) (prefix : String)) : Bool + (kotlin-member-call startsWith)) + (extern (srvStringContains (text : String) (part : String)) : Bool + (kotlin-member-call contains)) (extern (srvShipDisplayLabel (actor : JSONObject)) : String (kotlin-call shipDisplayLabel)) (def (srvPaint (color : Int32) (style : Style)) : Paint @@ -109,6 +147,22 @@ (if (nullable-null? array) (int32 0) (srvArrayLength (nullable-get array))))) + (def (srvMaxInt (a : Int32) (b : Int32)) : Int32 (if (> a b) a b)) + (def (srvClampFloat (value : Float32) (low : Float32) + (high : Float32)) : Float32 + (if (< value low) low (if (> value high) high value))) + (def (srvObjectInt (object : (Nullable JSONObject)) + (key : String) (fallback : Int32)) : Int32 + (if (nullable-null? object) + fallback + (srvJsonInt (nullable-get object) key fallback))) + (def (srvObjectArray (object : JSONObject) + (key : String)) : JSONArray + (let ((value (srvJsonArray object key))) + (if (nullable-null? value) (new JSONArray) (nullable-get value)))) + (def (srvMapValue (values : (Map String Int32)) (key : String)) : Int32 + (let ((value (map-ref-or-null values key))) + (if (nullable-null? value) (int32 0) (nullable-get value)))) (class SystemsReadinessView ((context : Context)) (extends View context) (var report : (Nullable JSONObject) (nullable-none JSONObject) @@ -189,14 +243,27 @@ (+ (/ drawHeight (float32 2.0)) (float32 6.0)) textPaint))) (def (drawHeader (canvas : Canvas) (current : JSONObject)) : Unit (modifiers private) - (begin + (let ((counts (srvJsonObject current "counts"))) + (begin (srvPaintAlignSet textPaint (srvLeft)) - (srvDrawText canvas "SYSTEMS" (float32 10.0) (float32 24.0) textPaint) + (srvDrawText canvas + (string-append "SYSTEMS S:" + (string-append + (int32->string (srvObjectInt counts "active-seeking" (int32 0))) + (string-append " U:" + (string-append + (int32->string (srvObjectInt counts "active-small-units" (int32 0))) + (string-append " W:" + (string-append + (int32->string (srvObjectInt counts "active-webs" (int32 0))) + (string-append " M:" + (int32->string (srvObjectInt counts "active-mines" (int32 0)))))))))) + (float32 10.0) (float32 24.0) textPaint) (srvPaintAlignSet valuePaint (srvRight)) (srvDrawText canvas (string-append "events " (int32->string (srvJsonInt current "event-count" (int32 0)))) - (- drawWidth (float32 10.0)) (float32 24.0) valuePaint))) + (- drawWidth (float32 10.0)) (float32 24.0) valuePaint)))) (def (drawActorCard (canvas : Canvas) (rect : RectF) (side : String) (actor : (Nullable JSONObject)) @@ -215,22 +282,364 @@ (+ (srvRectLeft rect) (float32 8.0)) (+ (srvRectTop rect) (float32 18.0)) valuePaint) (srvPaintColorSet valuePaint (srvRgb (int32 20) (int32 28) (int32 40))) - (srvPaintAlignSet smallPaint (srvLeft)) (if (or (nullable-null? actor) (not (srvJsonBoolean (nullable-get actor) "ship-present?" #f))) - (srvDrawText canvas "No ship report" - (+ (srvRectLeft rect) (float32 8.0)) - (+ (srvRectTop rect) (float32 52.0)) smallPaint) + (begin + (srvPaintAlignSet smallPaint (srvLeft)) + (srvDrawText canvas "No ship report" + (+ (srvRectLeft rect) (float32 8.0)) + (+ (srvRectTop rect) (float32 52.0)) smallPaint)) (let ((ship (nullable-get actor))) - (begin - (srvDrawText canvas (srvShipDisplayLabel ship) - (+ (srvRectLeft rect) (float32 8.0)) - (+ (srvRectTop rect) (float32 52.0)) smallPaint) - (srvDrawText canvas - (string-append "WEAP " - (string-append - (int32->string (srvArrayCount ship "weapon-status")) - (string-append " SEEK " - (int32->string (srvArrayCount ship "seeking-status"))))) - (+ (srvRectLeft rect) (float32 8.0)) - (+ (srvRectTop rect) (float32 80.0)) smallPaint))))))))))) + (let ((power (srvJsonObject ship "power-status")) + (weapons (srvObjectArray ship "weapon-status")) + (seeking (srvObjectArray ship "seeking-status")) + (seekingSlots (srvObjectArray ship "seeking-launch-slots")) + (fighterBays (srvObjectArray ship "fighter-bays")) + (tractor (srvJsonObject ship "tractor-status")) + (transporter (srvJsonObject ship "transporter-status")) + (repair (srvJsonObject ship "repair-status"))) + (let ((totalPower (srvObjectInt power "total-power" (int32 0))) + (usedBattery (srvObjectInt power "battery-used" (int32 0))) + (unspent (srvObjectInt power "unspent-energy" (int32 0))) + (weaponReady (sumArray weapons "fireable")) + (weaponArmed (sumArray weapons "armed")) + (weaponInArc (sumArray weapons "fireable-in-arc")) + (seekerLoaded (sumArray seeking "loaded-ammo")) + (seekerLaunchable (countTrue seeking "launchable-now?")) + (readyShuttles (srvMaxInt (int32 0) + (srvJsonInt ship "ready-shuttles" (int32 0)))) + (launchCapacity (srvMaxInt (int32 0) + (srvJsonInt ship "total-shuttle-launch-capacity" + (srvJsonInt ship "shuttle-launch-capacity" (int32 0))))) + (recoveryOpen (srvMaxInt (int32 0) + (srvJsonInt ship "shuttle-recovery-open-capacity" (int32 0)))) + (fighterStock (sumArray fighterBays "available")) + (fcs (if (srvJsonBoolean ship "fire-control-active?" #t) + "ON" "OFF"))) + (var ((y (+ (srvRectTop rect) (float32 49.0)))) + (begin + (srvPaintAlignSet smallPaint (srvLeft)) + (srvDrawText canvas + (fitText (srvShipDisplayLabel ship) smallPaint + (- (srvRectWidth rect) (float32 16.0))) + (+ (srvRectLeft rect) (float32 8.0)) y smallPaint) + (set! y (+ y (float32 22.0))) + (drawReadinessBar canvas (+ (srvRectLeft rect) (float32 8.0)) y + (- (srvRectWidth rect) (float32 16.0)) "POWER" + unspent (srvMaxInt (int32 1) totalPower)) + (set! y (+ y (float32 33.0))) + (drawReadinessBar canvas (+ (srvRectLeft rect) (float32 8.0)) y + (- (srvRectWidth rect) (float32 16.0)) "WEAP" + weaponReady (srvMaxInt (int32 1) weaponArmed)) + (set! y (+ y (float32 33.0))) + (drawReadinessBar canvas (+ (srvRectLeft rect) (float32 8.0)) y + (- (srvRectWidth rect) (float32 16.0)) "ARC" + weaponInArc (srvMaxInt (int32 1) weaponReady)) + (set! y (+ y (float32 33.0))) + (let ((weaponText (weaponFamilySummary weapons))) + (if (string-blank? weaponText) + (begin) + (begin + (srvDrawText canvas + (fitText (string-append "WPN " weaponText) smallPaint + (- (srvRectWidth rect) (float32 16.0))) + (+ (srvRectLeft rect) (float32 8.0)) y smallPaint) + (set! y (+ y (float32 21.0)))))) + (let ((profileText (slotProfileSummary seekingSlots))) + (srvDrawText canvas + (fitText + (string-append "SEEK launch " + (string-append (int32->string seekerLaunchable) + (string-append " loaded " + (string-append (int32->string seekerLoaded) + (if (string-blank? profileText) "" + (string-append " " profileText)))))) + smallPaint (- (srvRectWidth rect) (float32 16.0))) + (+ (srvRectLeft rect) (float32 8.0)) y smallPaint)) + (set! y (+ y (float32 21.0))) + (srvDrawText canvas + (fitText + (string-append "UNITS sh " + (string-append (int32->string readyShuttles) + (string-append " launch " + (string-append (int32->string launchCapacity) + (string-append + (if (> (srvArrayLength fighterBays) (int32 0)) + (string-append " bays " + (string-append (int32->string (srvArrayLength fighterBays)) + (string-append " stock " (int32->string fighterStock)))) + "") + (string-append " rec " (int32->string recoveryOpen))))))) + smallPaint (- (srvRectWidth rect) (float32 16.0))) + (+ (srvRectLeft rect) (float32 8.0)) y smallPaint) + (set! y (+ y (float32 21.0))) + (srvDrawText canvas + (fitText + (string-append "TRAC " + (string-append (int32->string + (srvObjectInt tractor "available-boxes" (int32 0))) + (string-append " TRAN " + (string-append (int32->string + (srvObjectInt transporter "available-boxes" (int32 0))) + (string-append " DC " (int32->string