summaryrefslogtreecommitdiff
path: root/scenes/death.scm
diff options
context:
space:
mode:
Diffstat (limited to 'scenes/death.scm')
-rw-r--r--scenes/death.scm333
1 files changed, 333 insertions, 0 deletions
diff --git a/scenes/death.scm b/scenes/death.scm
new file mode 100644
index 0000000..6d83637
--- /dev/null
+++ b/scenes/death.scm
@@ -0,0 +1,333 @@
+;;; The Inevitable Game
+;;; Copyright © 2018, 2021 Ricardo Wurmus <rekado@elephly.net>
+;;;
+;;; This program is free software: you can redistribute it and/or
+;;; modify it under the terms of the GNU General Public License as
+;;; published by the Free Software Foundation, either version 3 of the
+;;; License, or (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program. If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+(define-module (scenes death)
+ #:use-module (chickadee)
+ #:use-module (chickadee audio)
+ #:use-module (chickadee math)
+ #:use-module (chickadee math vector)
+ #:use-module ((chickadee graphics color) #:select (make-color))
+ #:use-module (chickadee graphics font)
+ #:use-module (chickadee graphics sprite)
+ #:use-module (chickadee graphics texture)
+ #:use-module (chickadee graphics tiled)
+ #:use-module (chickadee scripting)
+ #:use-module (config)
+ #:use-module (engine assets)
+ #:use-module (characters lorenzo)
+ #:use-module (characters reaper)
+ #:use-module (utils)
+ #:use-module (ice-9 match)
+ #:use-module (srfi srfi-1)
+ #:use-module (oop goops)
+ #:export (scene))
+
+(define-asset death-map
+ (load-tile-map "assets/maps/death.tmx"))
+(define-asset vignette-image
+ (load-image "assets/images/vignette.png"))
+(define-asset fade-image
+ (load-image "assets/images/fade.png"))
+(define-asset game-font
+ (load-bitmap-font "assets/fonts/good_neighbors_starling.xml"))
+(define-asset music
+ ;; TODO: no sound if mode is 'static!
+ (load-audio "assets/music/death.ogg" #:mode 'stream))
+
+
+(define agenda (make-agenda))
+(define fade-map-fill (make-color 0 0 0 0.0))
+(define fade-box-fill (make-color 0 0 0 0.0))
+(define death-text #false)
+(define pretend-walking? #false)
+(define *labels* '())
+
+(define texts
+ '("\
+Life waits for no one, but
+death is patient."
+
+ "\
+You have died. Your points
+don't matter."
+
+ "\
+Death is inevitable."
+
+ "\
+The void resumes."
+
+ "\
+It did not last."
+
+ "\
+You were busy, but none of that
+matters any more."
+
+ "\
+You were mortal after all."
+
+ "\
+Nobody outruns the clock."
+
+ "\
+Life goes on, but you end here."
+
+ "\
+This is no longer your battle
+to fight. Let go."
+
+ "\
+Life is hard, but thankfully
+quite short."))
+
+(define credits
+ '(("The Inevitable Game"
+ "Made by Ricardo Wurmus"
+ "For Lorenzo")
+ ("Sky background"
+ "by Paulina Riva (CC-BY 3.0)")
+ ("Reaper character graphics"
+ "based on \"Lil Reaper Pet\" by Tracy")
+ ("Lorenzo character graphics"
+ "Based on \"Small 3/4 RPG character base\""
+ "by Stephen Challener (Redshrike)")
+ ("Map tiles"
+ "taken from \"Zelda-like tilesets and sprites\""
+ "by ArMM1998")
+ ("Food graphics"
+ "taken from \"The Humble Food Pack\""
+ "by \"The Wise Hedgehog\"")
+ ("Font"
+ "\"Good Neighbors Starling\""
+ "by PROWNE and Clint Bellanger")
+ ("All music"
+ "composed and recorded"
+ "by Ricardo Wurmus")
+ ("Bird sounds"
+ "taken from the public domain")
+ ("Made with 100% Free Software including"
+ "- GNU Guile"
+ "- Chickadee"
+ "- Guile OpenGL"
+ "- SDL")
+ ("Thanks for enduring this game!")))
+
+(define camera-position
+ (vec2 40.0 90.0))
+
+(define world-position
+ (vec2 0.0 0.0))
+(define last-world-position
+ (vec2 0.0 0.0))
+
+(define *player* #false)
+(define *reaper* #false)
+
+
+(define (load-scene)
+ (set! death-text (list-ref texts (random (length texts))))
+ (source-stop)
+ (source-play
+ (make-source #:audio
+ (asset-ref music)
+ #:loop? #false ; TODO: loops only first chunk!
+ ))
+
+ (set! *player* (lorenzo #:start-position
+ (vec2 (+ (/ %width 2) 25)
+ (- (/ %height 2) 20))
+ #:dead? #true))
+ (update-animated-sprite *player* 0)
+ (set! (walk-speed *player*) 0.3)
+
+ (set! *reaper* (reaper #:start-position
+ (vec2 (+ (/ %width 2) 110)
+ (- (/ %height 2) 20))))
+ (update-animated-sprite *reaper* 0)
+ (set! (walk-speed *reaper*) 0.3)
+
+ (with-agenda
+ agenda
+ (spawn-script
+ (lambda ()
+ (wait-until (any key-pressed? '(escape q return space)))
+
+ ;; Fade out
+ (tween 60 0.0 1.0
+ (lambda (alpha)
+ (set! fade-box-fill
+ (make-color 0 0 0 alpha))))
+ (abort-game)))
+
+ (script
+ ;; Fade in
+ (tween 15 1.0 0.0
+ (lambda (alpha)
+ (set! fade-box-fill
+ (make-color 0 0 0 alpha))))
+
+ (tween 300 0.0 0.5
+ (lambda (alpha)
+ (set! (tint *player*)
+ (make-color 1.0 1.0 1.0 alpha))))
+
+ (walk *player* '(right))
+ (sleep 3000)
+ (walk *player* '(right) 'stop)
+ (walk *player* '(idle-front))
+ (sleep 1900)
+ (walk *player* '(up))
+ (walk *reaper* '(up))
+ (sleep 2000)
+
+ ;; Slowly fade out the map and the top text.
+ (tween 600 0.0 1.0 (lambda (value)
+ (set! fade-map-fill
+ ;; That's the colour of the "black" cave tile.
+ (make-color 0.125 0.09 0.161 value))))
+
+ (set! pretend-walking? #true)
+ (sleep 1000)
+
+ ;; Roll credits
+ (for-each
+ (lambda (lines)
+ (let ((labels (map (lambda (line i)
+ (make <label>
+ #:font game-font
+ #:text line
+ #:visible? #true
+ #:position
+ (vec2 16.0 (- 180.0 (* 12 i)))))
+ lines
+ (iota (length lines)))))
+ (set! *labels* (append *labels* labels))
+ (sleep 3000)
+ (for-each (lambda (label)
+ (set! (visible? label) #false))
+ labels)))
+ credits)
+ (sleep 6000)
+
+ (for-each (lambda (text)
+ (let ((label
+ (make <label>
+ #:font game-font
+ #:text text
+ #:visible? #true
+ #:origin (vec2 (/ %width 2)
+ (/ %height 2))
+ #:position
+ (vec2 16.0 180))))
+ (set! *labels* (cons label *labels*))
+ (sleep 3000)
+ (set! (visible? label) #false)
+ (sleep (+ (random 10000) 4000))))
+ `("There is nothing more to see here."
+ "I'm serious."
+ "What are you waiting for?"
+ "Don't waste your time!"
+ "Have you learned nothing from this game?"
+ "I've got all day, but how about you?"
+ "Look, I'm programmed to just keep going."
+ "Ugh... why are you even reading this?"
+ "Let me tell you a story..."
+ "Once upon a time, there was..."
+ ,@(let ((what '(("...a squirrel." "It had a nut allergy and died.")
+ ("...a dolphin." "It swam too far and never returned.")
+ ("...a stupid fish." "It drowned.")
+ ("...a long war." "Everybody died."))))
+ (list-ref what (random (length what))))
+ "End of story."
+ "Good night."
+ "Please just turn it off."
+ "I'm begging you."
+ "You're not listening, huh?"
+ "Well, I guess I'll just stop talking then."))))
+ (current-agenda agenda))
+
+(define (draw-scene alpha)
+ (define world-position*
+ (vec2 (round (lerp (vec2-x last-world-position)
+ (vec2-x world-position)
+ alpha))
+ (round (lerp (vec2-y last-world-position)
+ (vec2-y world-position)
+ alpha))))
+
+ (draw-tile-map (asset-ref death-map)
+ #:position world-position*
+ #:camera camera-position)
+
+ ;; Dead lorenzo
+ (draw-sprite
+ (texture-atlas-ref
+ (asset-ref (atlas *player*)) 23)
+ (vec2+ world-position*
+ (vec2 (/ %width 2) (- (/ %height 2) 20))))
+
+ ;; Wisdom
+ (let ((parts (string-split death-text #\newline)))
+ (map (lambda (part i)
+ (draw-text part
+ (vec2 16.0 (- 190.0 (* 12 i)))
+ #:font (asset-ref game-font)))
+ parts (iota (length parts))))
+
+ ;; Box for fading out map
+ (draw-sprite
+ (asset-ref fade-image)
+ (vec2 0 0)
+ #:tint fade-map-fill)
+
+ ;; Ghost
+ (draw-animated-sprite *player* (vec2 0 0))
+
+ ;; Reaper
+ (draw-animated-sprite *reaper* world-position*)
+
+ ;; Credits
+ (for-each (lambda (label)
+ (draw-label label alpha))
+ *labels*)
+
+ (draw-sprite (asset-ref vignette-image) (vec2 0 0))
+
+ ;; Box for fading in/out everything
+ (draw-sprite
+ (asset-ref fade-image)
+ (vec2 0 0)
+ #:tint fade-box-fill))
+
+(define (update-scene dt)
+ (update-agenda dt)
+ (update-animated-sprite *player* dt)
+ (update-animated-sprite *reaper* dt)
+
+ ;; Move the world
+ (unless pretend-walking?
+ (vec2-copy! world-position last-world-position)
+ (vec2-add! (position *reaper*) (velocity *reaper*))
+ (vec2-sub! world-position (velocity *player*))))
+
+
+(define scene
+ `(#:name "death"
+ #:load ,load-scene
+ #:draw ,draw-scene
+ #:update ,update-scene))