123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- #!/usr/bin/guile
- !#
- ; A Lattice Game of Cosmic Insignificance:
- ; A small game about mathematical lattices and tribes.
- ; Copyright (C) 2019 <houkime at protonmail.com>
- ; 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 <https://www.gnu.org/licenses/>.
- (use-modules (chickadee)
- (chickadee math vector)
- (chickadee math rect)
- (chickadee render font)
- (chickadee render sprite)
- (chickadee render texture)
- (oop goops)
- (oop goops describe)
- (srfi srfi-1)
- (ice-9 format)
- )
- (define-class <node> ()
- (name #:init-keyword #:name)
- (more #:init-keyword #:more #:init-value '())
- (less #:init-keyword #:less #:init-value '())
- (init_type #:init-keyword #:init_type #:init-value "mammalian");
- (type_changed #:init-keyword #:type_changed #:init-value #f))
- (define list_interrow_dist 15)
- (define action "join"); can be join or meet
- (define target #f) ; these 2 are specified at load time
- (define current #f)
- (define imbalance 0)
- (define turns-taken 0)
- (define (bump_turns)
- (set! turns-taken (+ turns-taken 1))
- (update-turns-label))
- (define (update-turns-label)
- (slot-set! turns-taken-label 'str (simple-format #f "~A Turns Taken" turns-taken)))
- (define (typestat type)
- (fold + 0 (map (lambda (node)
- (if (eqv? (get-node-type node) type) 1 0)) lattice)))
- (define (calculate-imbalance)
- (set! imbalance (- (typestat "mammalian") (typestat "bird")))
- (slot-set! imbalance-label 'str (simple-format #f "Cosmic imbalance is ~A" imbalance))
- (if (eqv? imbalance 0) (display-term "Balance is restored. you sorta won")))
- (define-class <tree_node> ()
- (position #:init-keyword #:position #:init-value #v(0 0))
- (visible #:init-value #t #:init-keyword #:visible)
- (parent #:init-value #f #:init-keyword #:parent)
- (children #:init-value '())
- )
- (define-class <clickable> (<tree_node>)
- (rect #:init-keyword #:rect #:init-value (make-rect 0 0 100 15))
- (click-enabled #:init-keyword #:click-enabled #:init-value #t)
- (on_click #:init-keyword #:on_click #:init-value (lambda (self)
- (display "click!")))
- )
- (define-class <button> (<clickable>)
- (str #:init-keyword #:str))
- (define-class <terminal_widget> (<tree_node>)
- (item_height #:init-value 15)
- (max_lines #:init-value 20)
- (width #:init-value 300)
- (lines #:init-value '())
- )
- (define-method (add-entry (term <terminal_widget>) str)
- (add-child term (make <label> #:str str))
- (if (> (length (slot-ref term 'children)) (slot-ref term 'max_lines))
- (begin
- (display "unparenting excessive stuff")
- (unparent (list-ref (slot-ref term 'children) 0))
- ))
- )
- (define-method (clear-children (node <tree_node>))
- (let ((children-list (slot-ref node 'children)))
- (slot-set! node 'children '())
- (for-each unparent children-list)))
- (define (display-term str)
- (add-entry terminal str))
- (define-class <label> (<tree_node>)
- (str #:init-value "label" #:init-keyword #:str))
- (define-class <list_widget> (<tree_node>)
- (item_height #:init-value 15)
- (on_selected #:init-keyword #:on_selected #:init-value (lambda (self key)
- (display "list clicked"))))
- (define-class <list_entry> (<button>)
- (key #:init-keyword #:key)
- (on_click #:init-keyword #:on_click
- #:init-value (lambda (self)
- ((slot-ref (slot-ref self 'parent) 'on_selected)
- (slot-ref self 'parent) (slot-ref self 'key))))
- )
- (define-method (activate (lw <list_widget>))
- (for-each (lambda (x)
- (slot-set! x 'visible #t)
- (slot-set! x 'click-enabled #t))
- (slot-ref lw 'children)))
- (define-method (inactivate (lw <list_widget>))
- (for-each (lambda (x)
- (slot-set! x 'visible #f)
- (slot-set! x 'click-enabled #f))
- (slot-ref lw 'children)))
- (define-method (toggle_active (lw <list_widget>))
- (for-each (lambda (x)
- (slot-set! x 'visible (not (slot-ref x 'visible)))
- (slot-set! x 'click-enabled (not (slot-ref x 'click-enabled))))
- (slot-ref lw 'children)))
- (define-class <folding_list> (<button>)
- lw
- (on_click #:init-keyword #:on_click
- #:init-value (lambda (self)
- (for-each (lambda (x) (toggle_active x))
- (slot-ref self 'children) ))))
- (define-method (initialize (instance <folding_list>) . initargs)
- (next-method)
- (let ((lw (make <list_widget> #:position #v(0 15))))
- (slot-set! instance 'lw lw)
- (add-child instance lw))
- (display "initializing a folding list mutafuka\n")
- )
- (define-method (tree-node-self-draw (button <button>))
- (let ((pos (get_global_position button)))
- (draw-nine-patch list_background_patch (rect-move-vec2
- (make-rect 0 0 100 list_interrow_dist)
- pos)
- #:margin 6)
- (draw-text (slot-ref button 'str) pos)))
- (define-method (tree-node-self-draw (label <label>))
- (let ((pos (get_global_position label)))
- (draw-text (slot-ref label 'str) pos)))
- (define-method (draw-tree (node <tree_node>))
- (if (slot-ref node 'visible)
- (begin
- (tree-node-self-draw node)
- (for-each draw-tree (slot-ref node 'children))
- )))
- (define-method (add-child (node <tree_node>) (child <tree_node>))
- ;(describe child)
- (slot-set! node 'children (append (slot-ref node 'children) (list child)))
- ;(display (slot-ref node 'children))
- (slot-set! child 'parent node))
-
- (define-method (unparent (child <tree_node>))
- (let ((parent (slot-ref child 'parent)))
- (slot-set! parent 'children (delq child (slot-ref parent 'children))))
- (slot-set! child 'parent #f))
- (define-method (tree-node-self-draw (node <tree_node>)))
- (define scene (make <tree_node>)); the scene root
- (define list_background_patch #f)
- (define-method (tree-node-self-draw (lst <list_widget>))
- ;(display "drawing list\n")
- (let ((offset 0))
- (for-each (lambda (child)
- (slot-set! child 'position
- #v(0 offset))
- (set! offset (+ offset list_interrow_dist)))
- (slot-ref lst 'children))))
- (define-method (tree-node-self-draw (term <terminal_widget>))
- (let* ((offset 0)
- (pos (get_global_position term))
- (overall_height (* list_interrow_dist (slot-ref term 'max_lines)))
- (term_bg_rect (rect-move-vec2
- (make-rect 0 0 (slot-ref term 'width) overall_height)
- (vec2+ pos
- #v(0 (- (- overall_height list_interrow_dist))))))
- )
- (draw-nine-patch list_background_patch term_bg_rect #:margin 6)
- (for-each (lambda (child)
- (slot-set! child 'position
- #v(0 offset))
- (set! offset (- offset list_interrow_dist)))
- (slot-ref term 'children))
- ))
- (define-method (clickable-click (clickable <clickable>) x y)
- ;(display (in_bound? clickable x y))
- ;(newline)
- (if (and (in_bound? clickable x y) (slot-ref clickable 'click-enabled))
- ((slot-ref clickable 'on_click) clickable)))
- (define-method (clickable-click clickable x y))
- (define-method (in_bound? (clickable <clickable>) x y)
- ;(display (list "clickable" clickable x y))
- ;(newline)
- (let ((global_rect (rect-move-vec2 (slot-ref clickable 'rect)
- (get_global_position clickable))))
- ;(display global_rect)
- ;(newline)
- (rect-contains? global_rect x y)))
- (define-method (get_global_position (node <tree_node>))
- (if (slot-ref node 'parent)
- (vec2+ (slot-ref node 'position) (get_global_position
- (slot-ref node 'parent)))
- (slot-ref node 'position)))
- (define-method (add-entry (lst <folding_list>) str key)
- (add-child (slot-ref lst 'lw) (make <list_entry> #:str str #:key key
- #:visible #f #:click-enabled #f)))
- (define-method (clear-entries (lst <folding_list>))
- (for-each unparent (slot-ref (slot-ref lst 'lw) 'children)))
- #!
- (define lattice
- (list
- (make <node> #:name "Raven" #:init_type "divine")
- (make <node> #:name "Coyote" #:init_type "divine" #:more '("Falcon" "Jay" "Gnu"))
- (make <node> #:name "Bear" #:init_type "mammalian" #:more '("Raven"))
- (make <node> #:name "Eagle" #:init_type "bird" #:more '("Bear"))
- (make <node> #:name "Gnu" #:init_type "mammalian" #:more '("Eagle"))
- (make <node> #:name "Jay" #:init_type "bird" #:more '("Raven"))
- (make <node> #:name "Tit" #:init_type "bird" #:more '("Bear"))
- (make <node> #:name "Falcon" #:init_type "bird" #:more '("Tit"))
- ))
- !#
- (define lattice
- (list
- (make <node> #:name "Raven" #:init_type "divine")
- (make <node> #:name "Coyote" #:init_type "divine" #:more '("Tit" "Gnu"))
- (make <node> #:name "Gnu" #:init_type "mammalian" #:more '("Dodo" "Jay"))
- (make <node> #:name "Jay" #:init_type "bird" #:more '("Tit"))
- (make <node> #:name "Dodo" #:init_type "bird" #:more '("Cuckoo" "Falcon" "Owl"))
- (make <node> #:name "Falcon" #:init_type "bird" #:more '("Beaver"))
- (make <node> #:name "Cuckoo" #:init_type "bird" #:more '("Bear"))
- (make <node> #:name "Beaver" #:init_type "mammalian" #:more '("Raven"))
- (make <node> #:name "Bear" #:init_type "mammalian" #:more '("Eagle"))
- (make <node> #:name "Owl" #:init_type "bird" #:more '("Eagle"))
- (make <node> #:name "Tit" #:init_type "bird" #:more '("Plover" "Heron"))
- (make <node> #:name "Plover" #:init_type "bird" #:more '("Eagle"))
- (make <node> #:name "Eagle" #:init_type "bird" #:more '("Raven"))
- (make <node> #:name "Heron" #:init_type "bird" #:more '("Raven"))
- ))
- (define (add-less lat)
- (for-each (lambda (node)
- (for-each (lambda (more-node-name)
- (let ((target-node (get-node more-node-name)))
- (slot-set! target-node 'less (append
- (list (slot-ref node 'name))
- (slot-ref target-node 'less)))))
- (slot-ref node 'more)))
- lat))
- (define (get-node name)
- (let ((lst (filter (lambda (node) (eqv? (slot-ref node 'name) name)) lattice)))
- (list-ref lst 0)))
- (define (get-rel-tree node symbol)
- (append (list node)
- (delete-duplicates
- (concatenate (map (lambda (n)
- (get-rel-tree n symbol))
- (map get-node (slot-ref node symbol)))))))
- (define-method (get-name (node <node>))
- (slot-ref node 'name))
- (define (find-join lst)
- (find-rel lst 'more #f))
- (define (find-meet lst)
- (find-rel lst 'less #f))
- (define (anti-rel symbol)
- (if (eq? 'more symbol) 'less 'more))
- (define (find-rel lst symbol restricted)
- (display (list "trying to rel with symbol" symbol))
- (newline)
- (display (map get-name lst))
- (newline)
- (let ((intersec (apply lset-intersection
- (append (list eqv?)
- (map (lambda (n) (get-rel-tree n symbol))
- lst)))))
- (display "intersection\n")
- (display (map get-name intersec))
- (if restricted
- (list-ref (lset-intersection eqv? intersec lst) 0)
- (find-rel intersec (anti-rel symbol) #t))
- )
- )
- (define-method (get-node-type (node <node>))
- (if (not (slot-ref node 'type_changed)); "divine" never changes type
- (slot-ref node 'init_type)
- (if (eqv? (slot-ref node 'init_type) "mammalian") "bird" "mammalian")))
- (define (list-valid-nodes current)
- (let* ((current (get-node current))
- (faction (get-node-type current)))
- (if (not (string=? (get-node-type current) "divine"))
- (if (eqv? action "join")
- (filter (lambda (node)
- (and
- (not (eqv? (get-node-type node) faction))
- (not (eqv? (get-node-type node) "divine"))))
- lattice)
- (filter (lambda (node)
- (and
- (eqv? (get-node-type node) faction)
- (not (eqv? (get-node-type node) "divine"))
- (not (eqv? node current))))
- lattice))
- (filter (lambda (node) (not (eqv? (get-node-type node) "divine"))) lattice)
- )))
- (define action_list
- (begin
- (let ((lst (make <folding_list> #:str "action_list" #:position #v(0 0))))
- (add-entry lst "join" "join")
- (add-entry lst "meet" "meet")
- (slot-set! (slot-ref lst 'lw)
- 'on_selected
- (lambda (self key)
- (display (list "selected" key))
- (set! action key)
- (slot-set! (slot-ref self 'parent) 'str key)
- (inactivate self)
- (fill_with_choices node_list)
- ))
-
- (slot-set! lst 'str action)
- lst
- )))
- (define node_list
- (make <folding_list> #:str "node_list" #:position #v(100 0)))
- (define (fill_with_choices node_list)
- (clear-entries node_list)
- (let ((nodes (list-valid-nodes current)))
- (for-each (lambda (node)
- (add-entry node_list
- (get-full-name (slot-ref node 'name))
- (slot-ref node 'name)))
- nodes)
- (set! target (slot-ref (list-ref nodes 0) 'name))
- (slot-set! node_list 'str (get-full-name target))))
- (define (get-full-name node-name)
- (let ((node (get-node node-name)))
- (if (slot-ref node 'type_changed); divine never changes type
- (if (eqv? (get-node-type node) "mammalian"); new type, not old
- (string-append node-name "-With-Tits")
- (string-append "Feathered " node-name))
- node-name)))
- (define (take_action self)
- (display "taking a decisive action\n")
- (let ((target-node (get-node target))
- (current-node (get-node current)))
- (if (eqv? action "join")
- (begin
- (if (not (eqv? (get-node-type current-node) "divine"))
- (begin
- (slot-set! current-node 'type_changed
- (not (slot-ref current-node 'type_changed)))
- (display-term (simple-format #f "~A helps you overcome your past" (get-full-name target)))
- (display-term "You transform.")
- (display-term (simple-format #f "you are now known as ~A" (get-full-name current))))
- (begin
- (display-term (simple-format #f "You come to ~A in his dreams" (get-full-name target)))))
-
- (calculate-imbalance)
- (set! current (slot-ref (find-join (map get-node (list current target))) 'name))
- )
- (begin
- (if (not (eqv? (get-node-type current-node) "divine"))
- (begin
- (display-term (simple-format #f "Meeting with The ~A" (get-full-name target)))
- (display-term "You eat pretzels and discuss clanly matters"))
- (begin
- (display-term (simple-format #f "You come to ~A in his dreams" (get-full-name target)))))
- (set! current (slot-ref (find-meet (map get-node (list current target))) 'name))
- )))
- (bump_turns)
- (fill_with_choices node_list)
- (morning-message)
- )
- (define (morning-message)
- (display-term "* * *")
- (display-term "Sun rises and you wake up.")
- (display-term (simple-format #f "You are The ~A." (get-full-name current)))
- (if (eqv? (get-node-type (get-node current)) "divine")
- (display-term "... a supposedly divine being."))
- )
- (define terminal
- (make <terminal_widget> #:position #v(0 400)))
- (define imbalance-label
- (make <label> #:position #v(0 450)))
- (define turns-taken-label
- (make <label> #:position #v(0 435)))
- (define (reset-lattice)
- (for-each (lambda (n)
- (slot-set! n 'type_changed #f))
- lattice))
- (define (reset-scene)
- (set! scene (make <tree_node>)))
- (define (load)
- (set! current "Bear")
- (add-less lattice)
- (add-child scene imbalance-label)
- (add-child scene turns-taken-label)
- (calculate-imbalance)
- (update-turns-label)
- (display (list "imbalance is " imbalance))
- ;(for-each describe lattice)
- ;(display (map (lambda (node) (list (slot-ref node 'name) (get-node-type node))) lattice))
- (set! list_background_patch (load-image "images/dialog-box.png"))
-
- (add-child scene terminal)
- (morning-message)
- (display-term "You brush your beary teeth.")
- (display-term "Annoyingly, you feel like cosmic balance is off")
- (display-term "However that might be just your stomache.")
- (add-child scene action_list)
- (fill_with_choices node_list)
- (add-child scene node_list)
- (slot-set! (slot-ref node_list 'lw)
- 'on_selected
- (lambda (self key)
- (display (list "selected" key))
- (set! target key)
- (slot-set! (slot-ref self 'parent) 'str (get-full-name key))
- (inactivate self)))
- (add-child scene (make <button>
- #:str "make turn"
- #:position #v(200 0)
- #:on_click take_action))
- (add-child scene (make <button>
- #:str "reset"
- #:position #v(200 465)
- #:on_click reset))
- (describe scene))
- (define (reset self)
- (display "reset called\n")
- (reset-lattice)
- (display "lattice cleared\n")
- (reset-scene)
- (clear-children terminal)
- (display "scene cleared\n")
- (load)
- (display "scene reloaded\n")
- (set! turns-taken 0)
- (update-turns-label)
- )
- (define (draw alpha)
- (draw-tree scene))
- (define-method (click-rec (node <tree_node>) x y)
- ;(display (list node x y))
- ;(newline)
- (clickable-click node x y)
- (for-each (lambda (child) (click-rec child x y)) (slot-ref node 'children)))
- (define (mouse-release button x y)
- (click-rec scene x y)
- ;(newline)
- )
- (run-game #:draw draw #:load load #:mouse-release mouse-release
- #:window-width 300 #:window-title "A Lattice Game of Cosmic Insignificance")
|