You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
5.6 KiB
209 lines
5.6 KiB
#lang racket |
|
|
|
(require lux |
|
(prefix-in raart: raart) |
|
racket/match) |
|
|
|
(require goblins |
|
goblins/actor-lib/env |
|
goblins/actor-lib/ticker) |
|
|
|
(define (raart-render-game get-game-display |
|
[width 80] [height 24]) |
|
(raart:matte |
|
width height |
|
(raart:place-cursor-after |
|
(val->raart (or ($ get-game-display) |
|
(raart:blank 0 0))) |
|
0 0))) |
|
|
|
(struct game |
|
(;; actormap of participants |
|
actormap |
|
;; ticker |
|
ticker |
|
;; environment reset |
|
reset-env |
|
;; display object |
|
display-obj) |
|
#:methods gen:word |
|
[(define (word-tick gw) |
|
;; Actors we'll call |
|
(define reset-env (game-reset-env gw)) |
|
(define ticker (game-ticker gw)) |
|
;; Transactionally update actors for this tick. |
|
;; Either all of this succeeds or nothing succeeds. |
|
(define (transactional-update!) |
|
;; reset the environment |
|
($ reset-env) |
|
;; run all objects |
|
($ ticker)) |
|
(actormap-run! (game-actormap gw) |
|
transactional-update!) |
|
gw) |
|
(define (word-event gw e) |
|
(match e |
|
;; quit |
|
["q" #f] |
|
[_ gw])) |
|
(define (word-output gw) |
|
(define (compose-display) |
|
(raart-render-game (game-display-obj gw))) |
|
;; Return the raart to be displayed. |
|
;; Note that we use actormap-run rather than -run! because |
|
;; there shouldn't be any applicable side effects. |
|
(actormap-run (game-actormap gw) |
|
compose-display)) |
|
(define (word-label gw frame-time) |
|
"Cauldron time") |
|
(define (word-fps gw) |
|
;; 30? 60??? |
|
;; probably 30 is something terminals can reliably |
|
;; keep up with... |
|
30.0) |
|
(define (word-return gw) |
|
(void))]) |
|
|
|
(define (new-game) |
|
(define actormap (make-actormap)) |
|
(define (make-new-game) |
|
(define display-cell |
|
(spawn ^cell)) |
|
(match-define (list env reset-env) |
|
(spawn-env-pair)) |
|
(match-define (list ticker-register ticker-tick) |
|
(spawn-ticker-pair)) |
|
(define spawn-ticked |
|
(procedure-rename |
|
(make-keyword-procedure |
|
(lambda (kws kw-args constructor . args) |
|
(define ref |
|
(keyword-apply spawn kws kw-args constructor args)) |
|
($ ticker-register ref) |
|
ref)) |
|
'spawn-ticked)) |
|
(spawn-ticked ^cauldron spawn-ticked display-cell env) |
|
(game actormap ticker-tick reset-env display-cell)) |
|
(actormap-run! actormap make-new-game)) |
|
|
|
(define cauldron-drawing |
|
"\ |
|
.--------------. |
|
'-- ---- -' |
|
/ \\ |
|
; ; |
|
: : |
|
'. .' |
|
'----------'") |
|
|
|
(define cauldron-raart |
|
(raart:vappend* |
|
#:halign 'left |
|
(map (lambda (l) |
|
(raart:text l)) |
|
(string-split cauldron-drawing "\n")))) |
|
|
|
(define cauldron-width |
|
(raart:raart-w cauldron-raart)) |
|
|
|
(define bubble-max-height 10) |
|
|
|
(define (^bubble bcom env bubble-display) |
|
(define bubble-lifetime |
|
(random 2 bubble-max-height)) |
|
(define (modify-drift drift) |
|
(define drift-it |
|
(random -1 2)) |
|
(max -1 (min 1 (+ drift drift-it)))) |
|
(define raise-delay (random 10 30)) |
|
(define ((lp x y time-till-raise drift)) |
|
(define time-to-live |
|
(- bubble-lifetime y)) |
|
(define bubble-shape |
|
(cond |
|
;; big bubbles |
|
[(>= time-to-live 6) |
|
#\O] |
|
;; medium bubbles |
|
[(>= time-to-live 2) |
|
#\o] |
|
[else #\.])) |
|
($ env 'write bubble-display |
|
(list x y bubble-shape)) |
|
(define raise-time? |
|
(eqv? time-till-raise 0)) |
|
(cond |
|
[raise-time? |
|
(define new-y |
|
(add1 y)) |
|
(if (eqv? new-y bubble-lifetime) |
|
;; o/~ I tried so hard... and went so far... o/~ |
|
'die |
|
;; Time to move and adjust |
|
(bcom (lp (max 0 ; drift, but stay within confines |
|
(min (+ x drift) |
|
(sub1 cauldron-width))) |
|
new-y ; move up |
|
raise-delay ; reset |
|
(modify-drift drift))))] |
|
;; stay the same.. |
|
[else |
|
(bcom (lp x y (sub1 time-till-raise) drift))])) |
|
(lp (random 2 (- cauldron-width 2)) |
|
0 raise-delay 0)) |
|
|
|
(define (^cauldron bcom spawn-ticked display-cell env) |
|
(define bubble-display-key |
|
($ env 'new-key #;'bubble-display)) |
|
(define bubble-canvas |
|
(raart:blank cauldron-width bubble-max-height)) |
|
(define (new-bubble-cooldown) |
|
(random 15 40)) |
|
(define ((next [bubble-cooldown (new-bubble-cooldown)])) |
|
(define bubble-time? (eqv? bubble-cooldown 0)) |
|
(when bubble-time? |
|
(spawn-ticked ^bubble env bubble-display-key)) |
|
(define (do-display) |
|
(define all-bubbles |
|
($ env 'read bubble-display-key)) |
|
(define bubbled-canvas |
|
(for/fold ([canvas bubble-canvas]) |
|
([bubble-info all-bubbles]) |
|
(match bubble-info |
|
[(list col row char) |
|
(raart:place-at canvas |
|
(sub1 (- bubble-max-height row)) |
|
col (raart:char char))]))) |
|
(raart:vappend |
|
#:halign 'center |
|
;; green |
|
(raart:fg 'green |
|
bubbled-canvas) |
|
;; yellow |
|
(raart:fg 'yellow |
|
cauldron-raart))) |
|
($ display-cell do-display) |
|
(bcom (next (if bubble-time? |
|
(new-bubble-cooldown) |
|
(sub1 bubble-cooldown))))) |
|
(next)) |
|
|
|
(define (val->raart val) |
|
(match val |
|
[(? raart:raart?) val] |
|
[(? procedure?) (val)])) |
|
|
|
(define (list->raart lst) |
|
(map (lambda (v) |
|
(val->raart v)) |
|
lst)) |
|
|
|
(define (start-game) |
|
(call-with-chaos |
|
(raart:make-raart) |
|
(lambda () |
|
(fiat-lux (new-game)))) |
|
(void)) |
|
|
|
(module+ main |
|
(start-game))
|
|
|