(prop :FlxActionDigital continueAction) (prop actionManager (new FlxActionManager)) (prop &mut :Movie movie) (defNew [] (set continueAction (new FlxActionDigital "Continue" onContinue)) // TODO allow configuring continue keys -- any key, specifically mapped keys, etc. (continueAction.addKey SPACE JUST_PRESSED) (continueAction.addMouse LEFT JUST_PRESSED) (actionManager.addAction continueAction) (FlxG.inputs.add actionManager) (set actionManager.resetOnStateSwitch NONE)) (prop &mut :SceneFlxState currentState) (method :Void showScene [:Scene scene :Appearance appearance :Continuation cc] // Close the last scene state (when currentState (currentState.close)) // TODO on the first appearance, give a super (for some scenes but probably not others... hm....) (set currentState (cast scene SceneFlxState)) (set currentState.parent FlxG.state) (FlxG.state.openSubState currentState) (cc)) (method :Void cleanup [] (FlxG.state.openSubState null)) (var STAGE_LEFT_X 150) (var STAGE_RIGHT_X (- 1280 150)) (var ACTOR_Y 500) (var ACTOR_WIDTH 300) (method :Void showCharacter [:Character character :Appearance appearance :Continuation cc] // TODO on the first appearance, show name and description (maybe? also probably not for all?) // TODO also allow for manually defined flipped frames so text doesn't mirror (set character.actor.flipX ?!(= character.stageFacing character.actor.defaultFacing)) (character.actor.setGraphicSize ACTOR_WIDTH) (character.actor.updateHitbox) (set character.actor.x (- (case character.stagePosition (Left STAGE_LEFT_X) (Right STAGE_RIGHT_X) (otherwise (throw "unsupported stage position"))) (/ character.actor.width 2))) (set character.actor.y ACTOR_Y) (currentState.add character.actor) (cc)) (method :Void hideCharacter [:Character character :Continuation cc] (currentState.remove character.actor) (cc)) (prop &mut :Null nextCC) (method onContinue [:FlxActionDigital continueAction] (whenLet [cc nextCC] (set nextCC null) (cc))) (method :Void startWaitForInput [:Continuation cc] (set nextCC cc)) (method :Void stopWaitForInput [] (set nextCC null)) (var DIALOG_X 300) (var DIALOG_WIDTH (- 1280 ACTOR_WIDTH ACTOR_WIDTH)) (var DIALOG_Y 500) (var DIALOG_HEIGHT (- 720 DIALOG_Y)) // TODO these could be customizable to the Actor, wrylies, etc. (var DIALOG_BOX_COLOR FlxColor.BLACK) (var DIALOG_COLOR FlxColor.WHITE) (var DIALOG_SIZE 24) (var &mut :FlxSprite dialogBox) (var &mut :FlxText dialogText) (var &mut :FlxText speakerNameText) (method showDialog [:String speakerName :SpeechType type :String wryly :String text :Continuation cc] // TODO handle text messages, wrylies, off-screen, from-phone, etc. via (case type) // TODO attribute on-screen dialogue to the character's stageposition // Make a dialog box (unless dialogBox (set dialogBox (new FlxSprite DIALOG_X DIALOG_Y)) (dialogBox.makeGraphic DIALOG_WIDTH DIALOG_HEIGHT DIALOG_BOX_COLOR)) (currentState.add dialogBox) (dialogBox.revive) // show the dialog (unless dialogText (set dialogText (new FlxText DIALOG_X DIALOG_Y DIALOG_WIDTH "" DIALOG_SIZE))) (currentState.add dialogText) (set dialogText.text text) // TODO actually page through the dialog instead of sizing it down? (set dialogText.size DIALOG_SIZE) (while (< 720 (+ dialogText.y dialogText.height)) (-= dialogText.size 6)) // show the speaker name (unless speakerNameText (set speakerNameText (new FlxText DIALOG_X DIALOG_Y DIALOG_WIDTH "" DIALOG_SIZE))) (currentState.add speakerNameText) (if speakerName { (set speakerNameText.text "${speakerName}:") (speakerNameText.revive) (set dialogText.y (+ DIALOG_Y speakerNameText.height)) } (set dialogText.y DIALOG_Y)) (dialogText.revive) (startWaitForInput cc)) (method :Void hideDialog [] (dialogText.kill) (speakerNameText.kill) (dialogBox.kill)) (method :Void playSound [:FlxSound sound :Float volumeMod :Bool waitForEnd :Continuation cc] (let [originalVolume sound.volume restoreOriginalVolume ->(set sound.volume originalVolume)] (*= sound.volume volumeMod) (set sound.onComplete (if waitForEnd ->{(restoreOriginalVolume) (cc)} restoreOriginalVolume))) (sound.play) (unless waitForEnd (cc))) (method :Void playVoiceTrack [:FlxSound track :Float volumeMod :Float start :Float end :Continuation cc] (let [originalVolume track.volume restoreOriginalVolume ->(set track.volume originalVolume)] (*= track.volume volumeMod) (set track.onComplete ->{(restoreOriginalVolume) (movie.delay 0.1 cc)})) (track.play true (* 1000 start) (* 1000 end))) (prop &mut :FlxSound music) (prop MUSIC_FADE_SEC 1) (prop MUSIC_FADE_STEPS 10) (method :Void playSong [:String song :Float volumeMod :Bool loop :Bool waitForEnd :Continuation cc] (set music (FlxG.sound.play song 0 loop null true (if waitForEnd cc ->{}))) (.start (new FlxTimer) (/ MUSIC_FADE_SEC MUSIC_FADE_STEPS) ->:Void _ (+= music.volume (/ volumeMod MUSIC_FADE_STEPS)) MUSIC_FADE_STEPS) (set music.persist true) (unless waitForEnd (cc))) (method :Void stopSong [] (when music (music.stop))) (var PROP_MIN_WIDTH 200) (var PROP_MAX_WIDTH 500) (method :Void showPropOnScreen [:FlxSprite prop :FlxScreenPosition position :Continuation cc] // TODO assign the other possible positions // TODO allow absolute position and relative position by screen percentages (let [[x y] (case position (Center [(/ 1280 2) (/ 720 2)]) (otherwise (throw "not implemented")))] (let [width (min (max prop.width PROP_MIN_WIDTH) PROP_MAX_WIDTH)] (prop.setGraphicSize width) (prop.updateHitbox) (set prop.x (- x (/ prop.width 2))) (set prop.y (- y (/ prop.height 2))) (currentState.add prop))) // TODO give the prop reveal some time to land (cc)) (method :Void hideProp [prop cc] (currentState.remove prop) (cc))