This article added the game movement mechanics and we are about done! Just need to make some s-expression maps.
Even though my map-editor has hextille game-map cursor movement, my gamejam cursor controls are going to have their own command/s, since they basically are the game logic as well as notion of movement.

EDIT: You could contribute a level to this, or you could use this as a base to do entirely your own thing (ask me on the Mastodon if you want any help or commentary with your own thing).
Back to the implementation bits
*impassable*.radio symbols in the new cell are executed in turn.• (setq inferior-lisp-program "ecl")
• (setq eepitch-buffer-name "*slime-repl ECL*")
• (slime)
(ql:Quickload :McCLIM)
(compile-file "~/Downloads/nicclim.lisp" :load t)
(in-package :nic)
(string '~/game)
(ensure-directories-exist *)
(uiop:chdir (string '~/game/))
(uiop:chdir (string '~/game/)) ;; Twice, for some reason.
There are two problems with writing this:
com-peek which does this, I think that nesting commands is a performance problem on slow machines (like all of mine).My approach was to explicitly write the peek. Even though we could write macros to make the code look mathematically cuter, well, we can just literally write what is literally happening. So with some apologies. All of them are just
intersection with *impassable* is non-nil, do not move, else move.NicCLIM itself.This looks kinda long, but I am just specifying what directions mean on odd/even rows and you can basically skip past this.
(defvar *impassable*
'())
(defmacro
do-events ()
`(with-slots
(table-list cursor-locn)
*application-frame*
(let ((contents
(copy-list
(nth (cadr cursor-locn)
(nth (car cursor-locn)
table-list)))))
(dolist (c contents)
(when (get c :radio-choices)
(execute-frame-command
*application-frame*
`(com-popup ,c)))))))
(define-map-editor-command (com-game-h :name t
:keystroke :left)
()
(with-slots (table-list cursor-locn) *application-frame*
(unless
(intersection *impassable*
(nth (1- (cadr cursor-locn))
(nth (car cursor-locn)
table-list)))
(execute-frame-command *application-frame* '(com-h))
(do-events))))
(define-map-editor-command (com-game-j :name t
:keystroke :down)
()
(with-slots (table-list cursor-locn) *application-frame*
(unless
(intersection *impassable*
(nth (+ (cadr cursor-locn)
(if (oddp (car cursor-locn))
1 0))
(nth (1+ (car cursor-locn))
table-list)))
(execute-frame-command *application-frame* '(com-j))
(do-events))))
(define-map-editor-command (com-game-k :name t
:keystroke :up)
()
(with-slots (table-list cursor-locn) *application-frame*
(unless
(intersection *impassable*
(nth (+ (cadr cursor-locn)
(if (evenp (car cursor-locn))
-1 0))
(nth (1- (car cursor-locn))
table-list)))
(execute-frame-command *application-frame* '(com-k))
(do-events))))
(define-map-editor-command (com-game-l :name t
:keystroke :right)
()
(with-slots (table-list cursor-locn) *application-frame*
(unless
(intersection *impassable*
(nth (1+ (cadr cursor-locn))
(nth (car cursor-locn)
table-list)))
(execute-frame-command *application-frame* '(com-l))
(do-events))))
(define-map-editor-command (com-game-kl :name t
:keystroke
(:up :control))
()
(with-slots (table-list cursor-locn) *application-frame*
(unless
(intersection *impassable*
(nth (+ (1+ (cadr cursor-locn))
(if (evenp (car cursor-locn))
-1 0))
(nth (1- (car cursor-locn))
table-list)))
(execute-frame-command *application-frame* '(com-kl))
(do-events))))
(define-map-editor-command (com-game-jh :name t
:keystroke
(:down :control))
()
(with-slots
(table-list cursor-locn) *application-frame*
(unless
(intersection *impassable*
(nth (+ (1- (cadr cursor-locn))
(if (oddp (car cursor-locn))
1 0))
(nth (1+ (car cursor-locn))
table-list)))
(execute-frame-command *application-frame* '(com-jh))
(do-events))))
Okay, decode the symbol into movement, then execute any contents that are radio-button-choices.
:radio-choice-haverI threw together an example. We can see that (EXAMPLE), which is radio select example symbol for NicCLIM, triggers a radio select with the game movement (you can’t see it, but I am using the left arrowkey ← to move left, and com-l (M-S-l) to move right). The arrowkeys are the game controls, while hjkl are the NicCLIM controls. The left arrow game movement triggers the radio button, and the left arrow game movement fails to pass the wall since I pushed wall to *impassable*.

Well, I want you personally to contribute a level or map or whatever these are, so let us go over that exhaustively. Currently the radio button chooses something, i.e. sets the cur2 cursor according to the choice, but I will add a game button to activate-cursor-2 sometime this weekend. I am imagining the main choice as “go up/down these stairs”.
Sooo the map, however you would make it is
(WALL) (WALL) (WALL) (WALL) (WALL) (WALL) (WALL)
(WALL) NIL NIL NIL NIL NIL (WALL)
(WALL) NIL NIL NIL NIL NIL (WALL)
(WALL) NIL NIL (EXAMPLE) NIL NIL (WALL)
(WALL) NIL NIL NIL NIL NIL (WALL)
(WALL) NIL NIL NIL NIL NIL (WALL)
(WALL) (WALL) (WALL) (WALL) (WALL) (WALL) (WALL)
this file (in my working directory, it is ~/GAME/WALL-RADIO.MAP) is just an s-expression file right? You could make this as a tsv with a spreadsheet program. You can have more than one thing in a list; the one closer to the end of the list will print last, or display on top if they are images.
(push 'wall *impassable*)
deep, I know.
EXAMPLE radio choice from before(setf (get 'EXAMPLE :radio-description)
'("Lots of
text!"
asdf grass solid
(1 2 (3 4) 5))
(get 'EXAMPLE :radio-lisp-hook)
(list (lambda () 'nothing)
(lambda () 'nothing-else))
(get 'EXAMPLE :radio-choices)
'(member
("choice the first" (etc 1))
("choice the second" (etc 2))
("choice the third" (etc 3))))
The :radio-description is a list where symbols with a :bitmap property that is a path to an image will inline images, and everything else will be understood as text (including newlines).
:radio-lisp-hook: obviously those lambdas do nothing, I just put that there in case I wanted to run an audio player in the background with a shell call or something.
:radio-choices : this is just what this is like in clim. The text displayed on the radio box is the first thing like “choice the first”, what is returned (i.e. what the cursor 2 gets set to) is the second thing (like (etc 1)).
We saw pictures in a previous devlog.
Anyway, now I am hoping to be inundated with s-expression maps. We could imagine that everyone who wants to co-author this lispgamejam game with me could send me / link me their own s-expression file just like this (and any symbols/radio-choices you used, and art).
If you did not get how to do something, just tell me what you wanted to happen and I will make it so.
Two days left of the jam, we could have a lot of levels!
#unix_surrealism : https://analognowhere.com/ is contributing reuseable art to this gameSo if you want some incredible surrealist art to go with your symbols, snip it out of technomage comics and scale it down (I think 50x50 pixels is probably a good size).
You can contribute your own art or do whatever compatible with lispgamejam but I will be working in terms of technomage and openblade.
This was a pretty conclusive article
See you on the Mastodon *where I am looking forward to you inundating me with s-expression files like the above, possibly using technomage or other art, to make up our shared dungeons of technomage doom lispgamejam submission. (I will submit NicCLIM with a game map / lisp config tar there at the end of this weekend).
screwlisp proposes kittens