479 lines
22 KiB
Plaintext
479 lines
22 KiB
Plaintext
(loadFrom "kiss-tools" "src/kiss_tools/RefactorUtil.kiss")
|
|
|
|
(prop &mut :Jigsawx jigsaw)
|
|
(prop &mut :FlxCamera pieceCamera)
|
|
(prop &mut :FlxCamera uiCamera)
|
|
|
|
(load "PuzzlePacks.kiss")
|
|
|
|
(defAlias &ident textSize SimpleWindow.textSize)
|
|
|
|
(method &override :Void create []
|
|
(#when debug
|
|
(add cameraBounds))
|
|
|
|
(add logTexts)
|
|
(set Prelude.printStr log)
|
|
(set pieceCamera FlxG.camera)
|
|
(set cameraBounds.cameras [pieceCamera])
|
|
(set uiCamera (new FlxCamera))
|
|
(set uiCamera.bgColor FlxColor.TRANSPARENT)
|
|
(pieceCamera.copyFrom FlxG.camera)
|
|
(set FlxG.camera pieceCamera)
|
|
(FlxG.cameras.add uiCamera)
|
|
(FlxG.plugins.add (new FlxMouseControl))
|
|
(set FlxMouseControl.sortIndex "priorityID")
|
|
(set bgColor FlxColor.TRANSPARENT)
|
|
(super.create))
|
|
|
|
(defAlias &ident KEYBOARD_SCROLL_SPEED (keyboardScrollSpeed))
|
|
(method keyboardScrollSpeed []
|
|
(/ 200 rewardSprite.scale.x))
|
|
|
|
(prop &mut :EntryType typeAdding Todo)
|
|
(prop &mut :FlxInputText entryNameText)
|
|
|
|
(prop :FlxSprite cameraBounds (new FlxSprite))
|
|
|
|
(method &override :Void update [:Float elapsed]
|
|
(super.update elapsed)
|
|
|
|
(#when debug
|
|
(let [b (pieceCamera.getScrollBounds)]
|
|
(set cameraBounds.x b.x)
|
|
(set cameraBounds.y b.y)
|
|
(cameraBounds.makeGraphic (Std.int b.width) (Std.int b.height) FlxColor.TRANSPARENT true)
|
|
(cameraBounds.drawRect 0 0 b.width b.height FlxColor.TRANSPARENT (object color FlxColor.LIME thickness 5))))
|
|
|
|
(pieceCamera.updateScrollWheelZoom elapsed 5)
|
|
(pieceCamera.updateMouseBorderControl elapsed KEYBOARD_SCROLL_SPEED 0.002 uiCamera)
|
|
|
|
// Hold left-click to hide the habit text and see the image clearly:
|
|
(when entryWindow (if FlxG.mouse.pressed (entryWindow.hide) (entryWindow.show)))
|
|
|
|
(when FlxG.keys.justPressed.ESCAPE
|
|
(Sys.exit 0))
|
|
|
|
// TODO provide a saner/configurable set of bindings to trigger these ui action functions
|
|
{
|
|
(when (and FlxG.keys.justPressed.SPACE !entryNameText)
|
|
(defAndCall method toggleBackgroundColor
|
|
(set save.data.backgroundIndex #{(save.data.backgroundIndex + 1) % backgroundOptions.length;}#)
|
|
(save.flush)
|
|
// setModel so the entry text gets remade in inverted/lightened colors when necessary
|
|
(refreshModel)))
|
|
|
|
(method startAdding [:EntryType type]
|
|
(set typeAdding type)
|
|
(set entryNameText (new FlxInputText 0 0 FlxG.width "" textSize true))
|
|
(set entryNameText.cameras [uiCamera])
|
|
(set entryNameText.hasFocus true)
|
|
(add entryNameText))
|
|
|
|
(when FlxG.keys.justPressed.ENTER
|
|
(cond
|
|
(entryNameText
|
|
// addEntry() calls save()
|
|
(model.addEntry typeAdding [entryNameText.text])
|
|
(refreshModel)
|
|
(entryNameText.kill)
|
|
(set entryNameText null))
|
|
(true
|
|
(startAdding Todo))))
|
|
(when FlxG.keys.justPressed.UP
|
|
(startAdding Bonus))
|
|
}
|
|
|
|
|
|
// Left and right arrow keys can switch between unlocked puzzles
|
|
(unless entryNameText
|
|
(when FlxG.keys.justPressed.LEFT
|
|
(unless (= rewardFileIndex 0)
|
|
(-= rewardFileIndex 1)
|
|
(refreshModel)))
|
|
(when FlxG.keys.justPressed.RIGHT
|
|
(unless (= rewardFileIndex maxRewardFile)
|
|
(+= rewardFileIndex 1)
|
|
(refreshModel)))))
|
|
|
|
(prop &mut :FlxSave save null)
|
|
(prop &mut :SimpleWindow entryWindow null)
|
|
(prop &mut :FlxTypedGroup<FlxText> logTexts (new FlxTypedGroup))
|
|
(prop &mut :FlxKeyShortcutHandler<Entry> shortcutHandler null)
|
|
|
|
(prop &mut :HabitModel model null)
|
|
|
|
|
|
(method scaledToTheImageThatWorkedNice [v]
|
|
~(* v (/ (smallerDimension) 367)))
|
|
(method smallerDimension [] (min rewardSprite.pixels.width rewardSprite.pixels.height))
|
|
// TODO these variables don't do exactly what I think they do when scaled, like at all:
|
|
(defAlias &ident EDGE_LEEWAY 25)
|
|
(defAlias &ident BUBBLE_SIZE 15)
|
|
|
|
(var PUZZLE_WIDTH 6)
|
|
(var PUZZLE_HEIGHT 5)
|
|
(var TOTAL_PIECES (* PUZZLE_WIDTH PUZZLE_HEIGHT))
|
|
(prop &mut :FlxSprite rewardSprite null)
|
|
(prop &mut :FlxTypedGroup<KissExtendedSprite> rewardSprites null)
|
|
(prop &mut :Map<Int,KissExtendedSprite> matchingPiecesLeft (new Map))
|
|
(prop &mut :Map<Int,KissExtendedSprite> matchingPiecesRight (new Map))
|
|
(prop &mut :Map<Int,KissExtendedSprite> matchingPiecesUp (new Map))
|
|
(prop &mut :Map<Int,KissExtendedSprite> matchingPiecesDown (new Map))
|
|
(prop &mut :Map<Int,JigsawPiece> pieceData (new Map))
|
|
(prop &mut :Map<Int,Array<KissExtendedSprite>> connectedPieces (new Map))
|
|
(prop &mut :Map<KissExtendedSprite,Int> indexMap (new Map))
|
|
(prop &mut :Map<Int,KissExtendedSprite> spriteMap (new Map)) // Because rewardSprites will be re-ordered in depth handling, this is required
|
|
|
|
(prop &mut lastRewardFileIndex -1)
|
|
(prop &mut rewardFileIndex 0)
|
|
(prop &mut maxRewardFile 0)
|
|
|
|
(defAlias &ident SCROLL_BOUND_MARGIN (scrollBoundMargin))
|
|
|
|
(method scrollBoundMargin []
|
|
(fHalf (/ (max FlxG.width FlxG.height) rewardSprite.scale.x)))
|
|
|
|
(prop &mut :KissExtendedSprite draggingSprite null)
|
|
(prop &mut :FlxPoint draggingLastPos null)
|
|
|
|
// Main.hx sets off 99% of the app's logic by parsing the model file and calling setModel on startup and on a 30s loop:
|
|
|
|
(method setModel [m &opt :RewardFile currentRewardFile]
|
|
(set model m)
|
|
(set shortcutHandler (new FlxKeyShortcutHandler))
|
|
|
|
(let [p (m.totalPoints)
|
|
&mut i 0
|
|
&mut puzzleUnlocked -1]
|
|
// Find, load, and add the current reward image as big as possible:
|
|
(unless currentRewardFile
|
|
(set currentRewardFile (nth m.rewardFiles 0))
|
|
(while (> p .startingPoints (nth m.rewardFiles i))
|
|
(set rewardFileIndex i)
|
|
(set currentRewardFile (nth m.rewardFiles i))
|
|
(set maxRewardFile i)
|
|
(when (>= ++i m.rewardFiles.length)
|
|
(let [lastStartingPoints .startingPoints (nth m.rewardFiles --i)
|
|
nextStartingPoints (+ lastStartingPoints TOTAL_PIECES)]
|
|
(when (> p nextStartingPoints)
|
|
(set puzzleUnlocked nextStartingPoints))
|
|
(break)))))
|
|
|
|
(set save (new FlxSave))
|
|
(save.bind currentRewardFile.path)
|
|
(unless save.data.storedPositions
|
|
(set save.data.storedPositions (new Map<Int,FlxPoint>)))
|
|
(unless save.data.backgroundIndex
|
|
(set save.data.backgroundIndex 0))
|
|
(set pieceCamera.bgColor (nth backgroundOptions save.data.backgroundIndex))
|
|
|
|
(unless (and (= lastRewardFileIndex rewardFileIndex) (= lastTotalPoints (m.totalPoints)))
|
|
(set rewardSprite
|
|
(new FlxSprite 0 0
|
|
(BitmapData.fromFile
|
|
currentRewardFile.path)))
|
|
(when rewardSprites
|
|
(remove rewardSprites))
|
|
(rewardSprite.setGraphicSize FlxG.width 0)
|
|
(rewardSprite.updateHitbox)
|
|
(when (> rewardSprite.height FlxG.height)
|
|
(rewardSprite.setGraphicSize 0 FlxG.height))
|
|
(rewardSprite.updateHitbox)
|
|
(rewardSprite.screenCenter)
|
|
|
|
(set pieceCamera.zoom rewardSprite.scale.x)
|
|
|
|
(set rewardSprites (new FlxTypedGroup))
|
|
|
|
(doFor map [matchingPiecesLeft matchingPiecesRight matchingPiecesUp matchingPiecesDown]
|
|
(map.clear))
|
|
(connectedPieces.clear)
|
|
(doFor i (range TOTAL_PIECES) (dictSet connectedPieces i []))
|
|
(indexMap.clear)
|
|
|
|
(let [r (new FlxRandom (Strings.hashCode currentRewardFile.path))
|
|
graphicWidth rewardSprite.pixels.width
|
|
graphicHeight rewardSprite.pixels.height
|
|
pieceAssetWidth (/ (- graphicWidth (* EDGE_LEEWAY 2)) PUZZLE_WIDTH)
|
|
pieceAssetHeight (/ (- graphicHeight (* EDGE_LEEWAY 2)) PUZZLE_HEIGHT)
|
|
j (new Jigsawx pieceAssetWidth pieceAssetHeight graphicWidth graphicHeight EDGE_LEEWAY BUBBLE_SIZE PUZZLE_HEIGHT PUZZLE_WIDTH r)
|
|
PIECE_WIDTH
|
|
(/ rewardSprite.width PUZZLE_WIDTH)
|
|
PIECE_HEIGHT
|
|
(/ rewardSprite.height PUZZLE_HEIGHT)
|
|
:Array<FlxPoint> startingPoints []]
|
|
(let [&mut i 0]
|
|
(doFor y (range PUZZLE_HEIGHT)
|
|
(doFor x (range PUZZLE_WIDTH)
|
|
(startingPoints.push
|
|
(new FlxPoint (+ rewardSprite.x (* x PIECE_WIDTH)) (+ rewardSprite.y (* y PIECE_HEIGHT))))
|
|
(+= i 1))))
|
|
(r.shuffle startingPoints)
|
|
(set jigsaw j)
|
|
(r.shuffle jigsaw.jigs)
|
|
(localVar spriteGrid (for y (range PUZZLE_HEIGHT) (for x (range PUZZLE_WIDTH) null)))
|
|
(localVar indexGrid (for y (range PUZZLE_HEIGHT) (for x (range PUZZLE_WIDTH) 0)))
|
|
(doFor i (range (min TOTAL_PIECES (- p currentRewardFile.startingPoints)))
|
|
(let [jig (nth jigsaw.jigs i)
|
|
pos (ifLet [point (dictGet (the Map<Int,FlxPoint> save.data.storedPositions) i)]
|
|
point
|
|
(nth startingPoints i))
|
|
s (new KissExtendedSprite pos.x pos.y)
|
|
source (new FlxSprite)
|
|
mask (new FlxSprite)
|
|
sourceRect (new Rectangle jig.xy.x jig.xy.y jig.wh.x jig.wh.y)]
|
|
(set s.priorityID i)
|
|
(setNth spriteGrid jig.row jig.col s)
|
|
(setNth indexGrid jig.row jig.col i)
|
|
(dictSet pieceData i jig)
|
|
(dictSet indexMap s i)
|
|
(dictSet spriteMap i s)
|
|
(set s.draggable true)
|
|
(s.enableMouseDrag false true)
|
|
(set s.mouseStartDragCallback
|
|
->:Void [s x y]
|
|
(let [s (cast s KissExtendedSprite)]
|
|
(set s.priorityID (+ 1 .priorityID (last (the kiss.List<KissExtendedSprite> rewardSprites.members))))
|
|
(let [connectedPieces (recursivelyConnectedPieces s)]
|
|
// Bring currently held pieces to the front:
|
|
(rewardSprites.bringAllToFront (cast (concat [s] connectedPieces)))
|
|
(set s.connectedSprites connectedPieces))
|
|
(set draggingSprite s)
|
|
(set draggingLastPos (new FlxPoint s.x s.y))))
|
|
(set s.mouseStopDragCallback
|
|
->:Void [s x y]
|
|
(let [s (cast s KissExtendedSprite)]
|
|
(set draggingSprite null)
|
|
(checkMatches i)
|
|
(dictSet (the Map<Int,FlxPoint> save.data.storedPositions) i (new FlxPoint s.x s.y))
|
|
(doFor connected (recursivelyConnectedPieces s)
|
|
(checkMatches (dictGet indexMap connected))
|
|
(dictSet (the Map<Int,FlxPoint> save.data.storedPositions) (dictGet indexMap connected) (new FlxPoint connected.x connected.y)))
|
|
|
|
(pieceCamera.calculateScrollBounds rewardSprites uiCamera SCROLL_BOUND_MARGIN)
|
|
(save.flush)))
|
|
|
|
(source.makeGraphic (Std.int sourceRect.width) (Std.int sourceRect.height) FlxColor.TRANSPARENT true)
|
|
(source.pixels.copyPixels rewardSprite.pixels sourceRect (new Point 0 0))
|
|
|
|
(mask.makeGraphic (Std.int sourceRect.width) (Std.int sourceRect.height) FlxColor.TRANSPARENT true)
|
|
(drawPieceShape mask jig FlxColor.BLACK)
|
|
(FlxSpriteUtil.alphaMask s source.pixels mask.pixels)
|
|
|
|
(set s.cameras [pieceCamera])
|
|
// Uncomment for debugging match zones:
|
|
**(#when debug
|
|
(let [matchZones [(matchZoneLeft s) (matchZoneRight s)(matchZoneUp s)(matchZoneDown s)]]
|
|
(doFor z matchZones
|
|
(unless z.isEmpty
|
|
(FlxSpriteUtil.drawRect s (- z.x s.x) (- z.y s.y) z.width z.height FlxColor.TRANSPARENT (object thickness 1 color FlxColor.RED))))))
|
|
|
|
(rewardSprites.add s)))
|
|
(doFor row (range PUZZLE_HEIGHT)
|
|
(doFor col (range PUZZLE_WIDTH)
|
|
(let [id (nth indexGrid row col)]
|
|
// combination of try/whenLet should cover target languages
|
|
// where out-of-bounds nth throws an error AND languages
|
|
// where it returns null
|
|
(try (whenLet [toLeft (nth spriteGrid row (- col 1))]
|
|
(dictSet matchingPiecesLeft id toLeft)) (catch [e] null))
|
|
(try (whenLet [toRight (nth spriteGrid row (+ col 1))]
|
|
(dictSet matchingPiecesRight id toRight)) (catch [e] null))
|
|
(try (whenLet [toUp (nth spriteGrid (- row 1) col)]
|
|
(dictSet matchingPiecesUp id toUp)) (catch [e] null))
|
|
(try (whenLet [toDown (nth spriteGrid (+ row 1) col)]
|
|
(dictSet matchingPiecesDown id toDown)) (catch [e] null)))))
|
|
(add rewardSprites)
|
|
(doFor i (range TOTAL_PIECES)
|
|
(checkMatches i))))
|
|
(set lastRewardFileIndex rewardFileIndex)
|
|
(prop &mut lastTotalPoints -1)
|
|
(set lastTotalPoints (m.totalPoints))
|
|
|
|
(pieceCamera.calculateScrollBounds rewardSprites uiCamera SCROLL_BOUND_MARGIN)
|
|
|
|
(when entryWindow (entryWindow.hide))
|
|
(set entryWindow (new SimpleWindow "" (FlxColor.fromRGBFloat 0 0 0 0.5) FlxColor.WHITE 0.9 0.9))
|
|
(set entryWindow.cameras [uiCamera])
|
|
(set entryWindow.textColor FlxColor.LIME)
|
|
(_makeText "Puzzle #$(+ 1 rewardFileIndex) / ${model.rewardFiles.length}" (- TOTAL_PIECES (- p currentRewardFile.startingPoints)))
|
|
(set entryWindow.textColor FlxColor.ORANGE)
|
|
(map (m.activeDailyEntries) makeText)
|
|
(set entryWindow.textColor FlxColor.GREEN)
|
|
(map (m.activeMonthlyEntries) makeText)
|
|
(set entryWindow.textColor FlxColor.BLUE)
|
|
(map (m.activeIntervalEntries) makeText)
|
|
(set entryWindow.textColor FlxColor.WHITE)
|
|
(map (m.activeBonusEntries) makeText)
|
|
(set entryWindow.textColor FlxColor.YELLOW)
|
|
(map (m.activeTodoEntries) makeText)
|
|
(set entryWindow.textColor FlxColor.GRAY)
|
|
(_makeText "[SPACE] Cycle background color" 0)
|
|
(entryWindow.show)
|
|
|
|
(when !(= puzzleUnlocked -1)
|
|
(startPuzzlePackChoice puzzleUnlocked))))
|
|
|
|
(method refreshModel [&opt m]
|
|
(let [m (or m model)]
|
|
(setModel m (nth m.rewardFiles rewardFileIndex))))
|
|
|
|
(prop &mut textY 0)
|
|
|
|
(prop :Array<FlxColor> backgroundOptions [
|
|
FlxColor.BLACK
|
|
FlxColor.WHITE
|
|
FlxColor.GRAY
|
|
])
|
|
|
|
(method makeText [:Entry e]
|
|
(let [label (HabitModel.activeLabel e)]
|
|
(_makeText label.label label.points ->:Void text {
|
|
// TODO move all of this logic other than setModel into HabitModel logic
|
|
(let [label (HabitModel.activeLabel e)]
|
|
(+= label.points 1)
|
|
(whenLet [(Daily days lastDayDone) e.type]
|
|
(set e.type (Daily days (HabitModel.todayString))))
|
|
(whenLet [(Monthly days lastDayDone) e.type]
|
|
(set e.type (Monthly days (.toString (DateTime.now)))))
|
|
(whenLet [(Interval days lastDayDone) e.type]
|
|
(set e.type (Interval days (.toString (DateTime.now)))))
|
|
(model.save)
|
|
(setModel model))
|
|
})))
|
|
|
|
|
|
// TODO configurable text size
|
|
(method _makeText [:String s :Int points &opt :Action action]
|
|
(entryWindow.makeText (+ s (pointsStr points)) action))
|
|
|
|
(method log [message]
|
|
(prop &mut logTextY 0)
|
|
(#when debug
|
|
(when (> logTextY FlxG.height)
|
|
(logTexts.clear)
|
|
(set logTextY 0))
|
|
(let [text (new FlxText FlxG.width logTextY 0 message textSize)]
|
|
(set text.color entryWindow.textColor)
|
|
(set text.cameras [uiCamera])
|
|
(+= logTextY text.height)
|
|
(-= text.x text.width)
|
|
(logTexts.add text))))
|
|
|
|
// TODO properly tune the match zones to bubbles
|
|
(method :FlxRect matchZone [:KissExtendedSprite s compass]
|
|
(let [bubblePoints (dictGet .bubblePoints (dictGet pieceData (dictGet indexMap s)) compass)]
|
|
(unless bubblePoints
|
|
(return (new FlxRect 0 0 0 0)))
|
|
(let [pointsX (for point bubblePoints point.x)
|
|
pointsY (for point bubblePoints point.y)
|
|
minX (apply min pointsX)
|
|
minY (apply min pointsY)
|
|
maxX (apply max pointsX)
|
|
maxY (apply max pointsY)
|
|
rect (.fromTwoPoints (new FlxRect) (new FlxPoint minX minY) (new FlxPoint maxX maxY))]
|
|
(+= rect.x s.x)
|
|
(+= rect.y s.y)
|
|
rect)))
|
|
|
|
(method :FlxRect matchZoneLeft [:KissExtendedSprite s]
|
|
(matchZone s WEST))
|
|
(method :FlxRect matchZoneRight [:KissExtendedSprite s]
|
|
(matchZone s EAST))
|
|
(method :FlxRect matchZoneUp [:KissExtendedSprite s]
|
|
(matchZone s NORTH))
|
|
(method :FlxRect matchZoneDown [:KissExtendedSprite s]
|
|
(matchZone s SOUTH))
|
|
|
|
(prop &mut c 0)
|
|
(method :Void connectPiece [id self toSprite selfMatchZone toSpriteMatchZone]
|
|
(let [thisConnectedPieces (dictGet connectedPieces id)
|
|
toConnectedPieces (dictGet connectedPieces (dictGet indexMap toSprite))]
|
|
|
|
// Don't add duplicates or snap for pieces alread connected
|
|
(when (contains thisConnectedPieces toSprite)
|
|
(return))
|
|
(+= c 1)
|
|
|
|
// Snap the pieces together
|
|
(let [offsetX (- toSpriteMatchZone.x selfMatchZone.x)
|
|
offsetY (- toSpriteMatchZone.y selfMatchZone.y)]
|
|
(doFor piece (.concat (recursivelyConnectedPieces self) [self])
|
|
(+= piece.x offsetX)
|
|
(+= piece.y offsetY))
|
|
// TODO check for matches created by snapping all the pieces?
|
|
// Or is it fine not to?
|
|
)
|
|
|
|
|
|
(thisConnectedPieces.push toSprite)
|
|
(toConnectedPieces.push self)))
|
|
|
|
(method :Void checkMatches [id]
|
|
(when !(pieceData.exists id) (return))
|
|
(let [s (dictGet spriteMap id)
|
|
jig (dictGet pieceData id)
|
|
row jig.row
|
|
col jig.col]
|
|
|
|
(whenLet [toLeft (dictGet matchingPiecesLeft id)
|
|
mzl (matchZoneLeft s)
|
|
mzr (matchZoneRight toLeft)]
|
|
(unless .isEmpty (mzl.intersection mzr)
|
|
(connectPiece id s toLeft mzl mzr)))
|
|
(whenLet [toRight (dictGet matchingPiecesRight id)
|
|
mzr (matchZoneRight s)
|
|
mzl (matchZoneLeft toRight)]
|
|
(unless .isEmpty (mzl.intersection mzr)
|
|
(connectPiece id s toRight mzr mzl)))
|
|
(whenLet [toUp (dictGet matchingPiecesUp id)
|
|
mzu (matchZoneUp s)
|
|
mzd (matchZoneDown toUp)]
|
|
(unless .isEmpty (mzu.intersection mzd)
|
|
(connectPiece id s toUp mzu mzd)))
|
|
(whenLet [toDown (dictGet matchingPiecesDown id)
|
|
mzd (matchZoneDown s)
|
|
mzu (matchZoneUp toDown)]
|
|
(unless .isEmpty (mzu.intersection mzd)
|
|
(connectPiece id s toDown mzd mzu)))))
|
|
|
|
(method :Array<KissExtendedSprite> recursivelyConnectedPieces [s &opt :Array<KissExtendedSprite> collected]
|
|
(unless collected (set collected []))
|
|
(whenLet [directlyConnected (dictGet connectedPieces (dictGet indexMap s))]
|
|
(doFor piece directlyConnected
|
|
(unless (contains collected piece)
|
|
(collected.push piece)
|
|
(recursivelyConnectedPieces piece collected))))
|
|
collected)
|
|
|
|
(prop &mut :FlxGroup nextPuzzleChoiceGroup null)
|
|
|
|
(method startPuzzlePackChoice [nextStartingPoints]
|
|
(unless nextPuzzleChoiceGroup
|
|
(set nextPuzzleChoiceGroup (new FlxGroup))
|
|
(set nextPuzzleChoiceGroup.cameras [uiCamera])
|
|
|
|
// TODO position these aesthetically with a partly transparent background behind them
|
|
// like the habit ui window should also have
|
|
(let [x 0 &mut y 0]
|
|
(doFor pack (availablePacks model)
|
|
(let [text (new FlxText x y 0 "$(haxe.io.Path.withoutDirectory pack.path): ${pack.puzzlesDone}/${pack.puzzlesTotal}" textSize)]
|
|
// TODO not that color though
|
|
(set text.color FlxColor.LIME)
|
|
(nextPuzzleChoiceGroup.add text)
|
|
(whenLet [(Some np) pack.nextPuzzle]
|
|
(nextPuzzleChoiceGroup.add (new FlxButton (+ x text.width) y "CHOOSE" ->:Void {
|
|
(remove nextPuzzleChoiceGroup)
|
|
(set nextPuzzleChoiceGroup null)
|
|
(model.addRewardFile np.path nextStartingPoints)
|
|
(setModel model)
|
|
|
|
}))))
|
|
(+= y textSize)))
|
|
(add nextPuzzleChoiceGroup)))
|
|
|
|
(function pointsStr [points]
|
|
(let [tallyUnit 5]
|
|
(+ (* "*" (Math.floor (/ points tallyUnit)))
|
|
(* "+" (% points tallyUnit))))) |