From 16a6830b20a9a8ecce3b8c8043a63322c90cb4a6 Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Mon, 21 Jun 2021 22:40:46 -0400 Subject: [PATCH] Re-import Neu] [ower to coexist with 8-bitsy, probably broke both --- {game => bitsy}/boop.fnl | 2 +- {game => bitsy}/defs.fnl | 2 +- {game => bitsy}/disk.fnl | 2 +- {game => bitsy}/entity.fnl | 2 +- {game => bitsy}/footer.fnl | 2 +- {game => bitsy}/gfx.fnl | 2 +- {game => bitsy}/init.fnl | 16 +-- {game => bitsy}/map.fnl | 2 +- {game => bitsy}/player.fnl | 2 +- editor/8bitsy.fnl | 2 +- neuttower/boop.fnl | 86 ++++++++++++++ neuttower/bosskey.fnl | 59 ++++++++++ neuttower/cheat.fnl | 36 ++++++ neuttower/defs.fnl | 184 +++++++++++++++++++++++++++++ neuttower/disk.fnl | 87 ++++++++++++++ neuttower/end.screen | 1 + neuttower/entity.fnl | 234 +++++++++++++++++++++++++++++++++++++ neuttower/font.json | 1 + neuttower/footer.fnl | 55 +++++++++ neuttower/gfx.fnl | 133 +++++++++++++++++++++ neuttower/init.fnl | 64 ++++++++++ neuttower/level1.fnl | 68 +++++++++++ neuttower/level2.fnl | 6 + neuttower/level3.fnl | 93 +++++++++++++++ neuttower/level4.fnl | 18 +++ neuttower/level5.fnl | 93 +++++++++++++++ neuttower/level6.fnl | 169 +++++++++++++++++++++++++++ neuttower/map.fnl | 39 +++++++ neuttower/map1.json | 1 + neuttower/map2.json | 1 + neuttower/map3.json | 1 + neuttower/map4.json | 1 + neuttower/map5.json | 1 + neuttower/map6.json | 1 + neuttower/player.fnl | 184 +++++++++++++++++++++++++++++ neuttower/portraits.json | 1 + neuttower/tiles.fnl | 84 +++++++++++++ neuttower/tiles.json | 1 + neuttower/title.screen | 1 + 39 files changed, 1720 insertions(+), 17 deletions(-) rename {game => bitsy}/boop.fnl (97%) rename {game => bitsy}/defs.fnl (99%) rename {game => bitsy}/disk.fnl (98%) rename {game => bitsy}/entity.fnl (99%) rename {game => bitsy}/footer.fnl (97%) rename {game => bitsy}/gfx.fnl (98%) rename {game => bitsy}/init.fnl (83%) rename {game => bitsy}/map.fnl (93%) rename {game => bitsy}/player.fnl (96%) create mode 100644 neuttower/boop.fnl create mode 100644 neuttower/bosskey.fnl create mode 100644 neuttower/cheat.fnl create mode 100644 neuttower/defs.fnl create mode 100644 neuttower/disk.fnl create mode 100644 neuttower/end.screen create mode 100644 neuttower/entity.fnl create mode 100644 neuttower/font.json create mode 100644 neuttower/footer.fnl create mode 100644 neuttower/gfx.fnl create mode 100644 neuttower/init.fnl create mode 100644 neuttower/level1.fnl create mode 100644 neuttower/level2.fnl create mode 100644 neuttower/level3.fnl create mode 100644 neuttower/level4.fnl create mode 100644 neuttower/level5.fnl create mode 100644 neuttower/level6.fnl create mode 100644 neuttower/map.fnl create mode 100644 neuttower/map1.json create mode 100644 neuttower/map2.json create mode 100644 neuttower/map3.json create mode 100644 neuttower/map4.json create mode 100644 neuttower/map5.json create mode 100644 neuttower/map6.json create mode 100644 neuttower/player.fnl create mode 100644 neuttower/portraits.json create mode 100644 neuttower/tiles.fnl create mode 100644 neuttower/tiles.json create mode 100644 neuttower/title.screen diff --git a/game/boop.fnl b/bitsy/boop.fnl similarity index 97% rename from game/boop.fnl rename to bitsy/boop.fnl index 93369f0..5adb6f5 100644 --- a/game/boop.fnl +++ b/bitsy/boop.fnl @@ -1,4 +1,4 @@ -(local {: vm} (require :game.defs)) +(local {: vm} (require :bitsy.defs)) (local speaker :0xc030) (vm:def :blipmem ; count p -- diff --git a/game/defs.fnl b/bitsy/defs.fnl similarity index 99% rename from game/defs.fnl rename to bitsy/defs.fnl index 5ccc8f0..ef039f3 100644 --- a/game/defs.fnl +++ b/bitsy/defs.fnl @@ -154,7 +154,7 @@ (local level prg) ; todo: (asm.new prg) - if we want to load levels as an overlay (local org level.vm.code) ; (level:org org.level.org) - if we want to give level data a stable loxation (local map (. files.game.levels ilevel)) - (local entity (require :game.entity)) + (local entity (require :bitsy.entity)) (append-map map org label) (entity.append-from-map map org label) (set level.vm.code org) diff --git a/game/disk.fnl b/bitsy/disk.fnl similarity index 98% rename from game/disk.fnl rename to bitsy/disk.fnl index eff1621..9d0a96f 100644 --- a/game/disk.fnl +++ b/bitsy/disk.fnl @@ -3,7 +3,7 @@ (local Prodos (require :asm.prodos)) (local util (require :lib.util)) (local {: lo : hi} util) -(local {: org} (require :game.defs)) +(local {: org} (require :bitsy.defs)) (fn append-boot-loader [prg] (local vm prg.vm) diff --git a/game/entity.fnl b/bitsy/entity.fnl similarity index 99% rename from game/entity.fnl rename to bitsy/entity.fnl index 839c5a1..03c3e42 100644 --- a/game/entity.fnl +++ b/bitsy/entity.fnl @@ -1,6 +1,6 @@ (local util (require :lib.util)) (local tiles (util.require :game.tiles)) -(local {: vm : org : itile : say : say-runon : controlstate} (require :game.defs)) +(local {: vm : org : itile : say : say-runon : controlstate} (require :bitsy.defs)) (local {: lo : hi} util) ; Entity memory layout: diff --git a/game/footer.fnl b/bitsy/footer.fnl similarity index 97% rename from game/footer.fnl rename to bitsy/footer.fnl index 8dbae7d..8477e2f 100644 --- a/game/footer.fnl +++ b/bitsy/footer.fnl @@ -1,4 +1,4 @@ -(local {: vm : org} (require :game.defs)) +(local {: vm : org} (require :bitsy.defs)) (local {: hi : lo} (require :lib.util)) (vm:def :draw-pchar ; pscreen pchar -- diff --git a/game/gfx.fnl b/bitsy/gfx.fnl similarity index 98% rename from game/gfx.fnl rename to bitsy/gfx.fnl index 8f8cc96..00b2411 100644 --- a/game/gfx.fnl +++ b/bitsy/gfx.fnl @@ -1,5 +1,5 @@ (local {: lo : hi} (require :lib.util)) -(local {: vm : mapw : maph : org} (require :game.defs)) +(local {: vm : mapw : maph : org} (require :bitsy.defs)) ; Graphics routines (vm:def :mixed [:sta :0xc053]) diff --git a/game/init.fnl b/bitsy/init.fnl similarity index 83% rename from game/init.fnl rename to bitsy/init.fnl index 877dfe1..5a256f6 100644 --- a/game/init.fnl +++ b/bitsy/init.fnl @@ -1,17 +1,17 @@ (local util (require :lib.util)) (local {: lo : hi : readjson} util) (local tile (util.reload :game.tiles)) -(local {: prg : vm : org : deflevel} (util.reload :game.defs)) +(local {: prg : vm : org : deflevel} (util.reload :bitsy.defs)) (local files (require :game.files)) -(local disk (util.reload :game.disk)) +(local disk (util.reload :bitsy.disk)) -(util.reload :game.gfx) -(util.reload :game.footer) -(util.reload :game.map) -(util.reload :game.entity) -(util.reload :game.player) -(util.reload :game.boop) +(util.reload :bitsy.gfx) +(util.reload :bitsy.footer) +(util.reload :bitsy.map) +(util.reload :bitsy.entity) +(util.reload :bitsy.player) +(util.reload :bitsy.boop) (tile.appendtiles org.code) (org.code:append [:align 0x100] :font) diff --git a/game/map.fnl b/bitsy/map.fnl similarity index 93% rename from game/map.fnl rename to bitsy/map.fnl index 1044feb..2ced180 100644 --- a/game/map.fnl +++ b/bitsy/map.fnl @@ -1,5 +1,5 @@ (local {: lo : hi} (require :lib.util)) -(local {: vm : mapw : maph : rot8l} (require :game.defs)) +(local {: vm : mapw : maph : rot8l} (require :bitsy.defs)) (vm:def :lookup-flags ; itile -- flags [:lda vm.TOP :x] diff --git a/game/player.fnl b/bitsy/player.fnl similarity index 96% rename from game/player.fnl rename to bitsy/player.fnl index 2225a3d..7c5fa6e 100644 --- a/game/player.fnl +++ b/bitsy/player.fnl @@ -1,5 +1,5 @@ (local tile (require :game.tiles)) -(local {: vm : mapw : maph : itile : controlstate} (require :game.defs)) +(local {: vm : mapw : maph : itile : controlstate} (require :bitsy.defs)) (local {: walkable} tile.flag-to-bit) diff --git a/editor/8bitsy.fnl b/editor/8bitsy.fnl index 18ad278..f1256c6 100644 --- a/editor/8bitsy.fnl +++ b/editor/8bitsy.fnl @@ -22,7 +22,7 @@ (util.nested-tset action [:lines 4] (line4:sub 1 33)) y)) (fn [action vm] - (local {: say} (require :game.defs)) + (local {: say} (require :bitsy.defs)) (say action.character (table.unpack (lume.map action.lines #($1:upper)))))) (actions.register :warp diff --git a/neuttower/boop.fnl b/neuttower/boop.fnl new file mode 100644 index 0000000..fdfc9f0 --- /dev/null +++ b/neuttower/boop.fnl @@ -0,0 +1,86 @@ +(local {: vm} (require :neuttower.defs)) + +(local speaker :0xc030) +(vm:def :blipmem ; count p -- + [:block + [:lda [vm.ST1 :x]] + [:tay] + :sample + [:lda speaker] + [:lda [vm.TOP :x]] + [:inc vm.TOP :x] + [:bne :wait] + [:inc vm.TOPH :x] + :wait + [:clc] [:adc 1] + [:bne :wait] + [:dey] + [:bne :sample]] + (vm:drop) (vm:drop)) + +(vm:def :bliptone ; duration-f1 f2 -- + [:block + [:lda vm.ST1H :x] + [:sta vm.W] + :top + [:lda speaker] + [:ldy vm.ST1 :x] + :wave1 [:dey] [:bne :wave1] + [:lda speaker] + [:lda vm.TOPH :x] + [:ldy vm.TOP :x] [:iny] + :wave2 [:dey] [:bne :wave2] + [:ldy 0xff] + [:sec] [:sbc 1] [:bcs :wave2] + [:dec vm.W] + [:bne :top] + (vm:drop) (vm:drop)]) + +; 0x39a "samples" = 440hz +(local notes {}) +(each [i note (ipairs [:a :a# :b :c :c# :d :d# :e :f :f# :g :g#])] + (tset notes note (- i 1))) +(fn wavelength [note] + (-> 0x39a + (/ (math.pow 1.05946 (. notes note))) + (math.floor))) +(fn octave [wvl oct] + (-> wvl + (/ (math.pow 2 (- oct 3))) + (math.floor))) +(fn parse-note [n] + (values (n:sub 1 -2) (tonumber (n:sub -1)))) +(fn note-wavelength [n] + (local (note oct) (parse-note n)) + (-> (wavelength note) + (octave oct))) +(fn note [n ?duration ?timbre] + (local timbre (or ?timbre 0x20)) + (local duration (or ?duration 0x10)) + (local wvl (note-wavelength n)) + [:vm (bit.bor (bit.lshift duration 8) timbre) (- wvl timbre) :bliptone]) +(fn notes [ns ?duration ?timbre] + (local result [:block]) + (each [_ n (ipairs ns)] + (table.insert result (note n ?duration ?timbre))) + result) + +(vm:word :snd-explode 0x40 :lit :randombytes :blipmem) +(vm:word :snd-dooropen (notes [:c1 :e1] 3)) +(vm:word :snd-doorclose (notes [:e1 :c1] 3)) +(vm:word :snd-term-jingle (notes [:e3 :f3 :g3] 0x20)) +(vm:word :snd-termon :snd-term-jingle (note :c4 0x20)) +(vm:word :snd-termoff :snd-term-jingle (note :c3 0x20)) +(vm:word :snd-rexx (notes [:c2 :g2 :e2 :c3] 0x08 0x08)) +(vm:word :snd-libb (notes [:d#1 :g#1 :f#1 :g1] 0x08 0x7f)) +(vm:word :snd-garbage (notes [:a5 :a3 :a2] 0x04 0xa0)) +(vm:word :snd-teleport (notes [:e4 :d#4 :d4 :g#4] 0x1a 0x50)) + +(vm.code:append :keypad-boops) +(each [_ n (ipairs [:c4 :c#4 :d4 :d#4 :e4 :f4 :f#4 :g4 :g#4 :a5])] + (vm.code:append [:dw (- (note-wavelength n) 0xd0)])) +(vm:word :snd-keypad ; digit -- + :dup :+ :lit :keypad-boops :+ :get 0x10d0 :swap :bliptone) +(vm:word :snd-cheat (notes [:g4 :f#4 :d#4 :a4 :g#3 :e4 :g#4 :c5] 0x30 0x20)) + +{: note : notes} diff --git a/neuttower/bosskey.fnl b/neuttower/bosskey.fnl new file mode 100644 index 0000000..60db39e --- /dev/null +++ b/neuttower/bosskey.fnl @@ -0,0 +1,59 @@ +(local util (require :lib.util)) +(local {: vm : prg : astr : style} (util.require :neuttower.defs)) +(vm:word :boss-key :textmode :page2 (vm:until :read-key) :hires :page1) + +; if we upload to page 2 we don't have to worry about clobbering screen holes +(local textorg (prg:org 0x0800)) + +(fn padding [s w style] + (string.rep (astr " " style) (- w (length s)))) +(fn pad [s w style] + (.. s (padding s w style))) +(fn rpad [s w style] + (.. (padding s w style) s)) +(fn cellpad [s ?style] + (local textstyle (or ?style style.normal)) + (match (type s) + :nil (pad "" 9 textstyle) + :string (pad (astr s textstyle) 9 textstyle) + :number (rpad (astr (.. s " ") textstyle) 9 textstyle) + :table (cellpad (. s 1) (. s 2)))) +(fn cells [r a b c d] + (.. (rpad (.. r "") 3 style.inverse) + (cellpad a) (cellpad b) (cellpad c) (cellpad d))) + +(fn generate-boss-screen-lines [] + [(-> (astr "A16 (L) TOTAL" style.inverse) + (pad 38 style.inverse) + (.. (astr "C!" style.inverse))) + (.. (pad "" 38 style.inverse) (astr "24")) + "" + (cells "" [" A" style.inverse] [" B" style.inverse] [" C" style.inverse] [" D" style.inverse]) + (cells 1 "DEFINITEL" "Y REAL WO" "RK" "") + (cells 2 "(NOT PLAY" "ING COMPU" "TER GAMES" ")") + (cells 3) + (cells 4 "" "HAMMERS" "BILLS" "SANDWICH") + (cells 5 "JANUARY" 23 "$1" "CLUB") + (cells 6 "FEBRUARY" 121 "$2" "REUBEN") + (cells 7 "MARCH" 38 "$5" "BLT") + (cells 8 "SMARCH" 97 "$10" "HOT DOG") + (cells 9 "APRIL" 555 "$20" "I SAID IT") + (cells 10 "WEDNESDAY" 246 "$50" "EGG SALAD") + (cells 11 "KEYCODE" 1337 2757 9876) + (cells 12 "NUMBERS" 12345 "$100" "IF I HAD") + (cells 13 "LETTERS" "MARMOTS" "BENJAMIN" "100 I'D") + (cells 14 "SYMBOLS" "^!@#%&?" "$$$$$" "EAT THEM") + (cells 15) + (cells 16 ["TOTAL" style.inverse] "TOO MANY" ["* MAGIC *" style.flashing] "ALL@ONCE") + (cells 17) (cells 18) (cells 19) (cells 20)]) + +(fn bytes-from-lines [lines] + (var bytes (string.rep (astr " ") 0x400)) + (each [y line (ipairs lines)] + (local offset (+ (* (math.floor (/ (- y 1) 8)) 0x28) + (* (% (- y 1) 8) 0x80))) + (set bytes (util.splice bytes offset line))) + bytes) + +(textorg:append [:bytes (bytes-from-lines (generate-boss-screen-lines))]) + diff --git a/neuttower/cheat.fnl b/neuttower/cheat.fnl new file mode 100644 index 0000000..0483d5d --- /dev/null +++ b/neuttower/cheat.fnl @@ -0,0 +1,36 @@ +(local {: vm : say-runon : say} (require :neuttower.defs)) + +(fn defcheat [name ...] + (local cheatdata (.. name "-data")) + (vm.code:append cheatdata [:db 0] [:bytes name] [:db 0]) + (vm:word name :lit cheatdata :cheatguard ...)) + +(vm:word :pcheatnext ; cheatdata -- pchar + :dup :bget :inc :+) +(vm:word :reset-cheat ; cheatdata -- + 0 :swap :bset) +(vm:word :cheatguard ; char cheatdata -- [optional rdrop] + :dup :pcheatnext :bget :=] [:dup 7 :<]] + [:dec :dup :+ :lit :level-pointers :+ :get :load-level] + [:drop])) + +(defcheat :NTCHUCK :chuck-mode :get :not :chuck-mode :set + :chuck-mode :get (vm:if + [(say :neut "CHUCK MODE ENABLED!" "* W H I N N Y *")] + [(say :neut "CHUCK MODE DISABLED." "BEEP BOOP.")])) + +(vm:word :cheat-key ; ascii -- + (vm:if-and [[:dup (string.byte "A") :>=] [:dup (string.byte "Z") :<=]] + [:dup :NTSPISPOPD :dup :NTXYZZY :NTCHUCK] + [:drop])) diff --git a/neuttower/defs.fnl b/neuttower/defs.fnl new file mode 100644 index 0000000..3704faf --- /dev/null +++ b/neuttower/defs.fnl @@ -0,0 +1,184 @@ +(local util (require :lib.util)) +(local {: lo : hi : readjson} util) +(local lume (require :lib.lume)) +(local asm (require :asm.asm)) +(local VM (require :asm.vm)) +(local tiles (require :game.tiles)) +(local Prodos (require :asm.prodos)) + +(local prg (asm.new)) +(local vm (VM.new prg {:org 0xc00})) +(Prodos.install-words vm) + +(local org { + :boot vm.code + :code (prg:org 0x4000) +}) + +(local mapw 20) +(local maph 12) + +(local mon { + :hexout :0xfdda + :putchar :0xfded + :bell :0xff3a +}) + + +(local controlstate { + :jaye 0 + :neut 1 + :rexx 2 + :gord 3 + :libb 4 + :count 5 +}) + +(local style { + :normal 0x80 + :inverse 0x00 + :flashing 0x40 +}) +(fn str-with-style [s stylebits] + (-> [(string.byte s 1 -1)] + (lume.map #(bit.bor (bit.band $1 0x3f) stylebits)) + (-> (table.unpack) (string.char)))) +(fn achar [c] (bit.bor (string.byte c) style.normal)) +(fn astr [s ?style] (str-with-style s (or ?style style.normal))) + +(fn rot8l [n] ; clears carry + (local block [:block [:clc]]) + (for [_ 1 n] (table.insert block [:block [:asl :a] [:adc 0]])) + block) + +; core graphics words needed for booting +(vm:def :hires + [:sta :0xc050] + [:sta :0xc057] + [:sta :0xc052] + [:sta :0xc054]) + +(vm:def :cleargfx + (vm:push 0x4000) + [:block :page + [:dec vm.TOPH :x] + [:lda 0] + [:block :start + [:sta [vm.TOP :x]] + [:inc vm.TOP :x] + [:bne :start]] + [:lda vm.TOPH :x] + [:cmp 0x20] + [:bne :page]] + (vm:drop)) + +; a handful of debugging words +(vm:def :. + [:lda vm.TOPH :x] + [:jsr mon.hexout] + [:lda vm.TOP :x] + [:jsr mon.hexout] + [:lda (achar " ")] + [:jsr mon.putchar] + (vm:drop)) + +(vm:def :stacklen + (vm:reserve) + [:txa] [:lsr :a] [:sta vm.TOP :x] + [:lda 0] [:sta vm.TOPH :x]) + +(vm:word :.s + :stacklen (prg:parse-addr vm.TOP) :swap + (vm:for :dup :get :. :inc :inc) :drop) + +; input words +(vm:def :last-key ; -- key + (vm:reserve) + [:lda :0xc000] + [:and 0x7f] + [:sta vm.TOP :x] + [:lda 0] + [:sta vm.TOPH :x]) + +(vm:def :read-key ; -- key|0 + [:block + (vm:reserve) + [:lda :0xc000] + [:bmi :key-pressed] + [:lda 0] + [:sta vm.TOP :x] + [:sta vm.TOPH :x] + (vm:ret) + :key-pressed + [:and 0x7f] + [:sta vm.TOP :x] + [:lda 0] + [:sta vm.TOPH :x] + [:sta :0xc010]]) + +; "random" numbers +; this is used only for cosmetic purposes and short noise generation, so we can get away +; with just including a short table of random digits rather than implementing our own +; pseudorandom number generator +(var randombytes "") +(for [i 0 0x40] (set randombytes (.. randombytes (string.char (math.random 0 255))))) +(vm.code:append :randombytes [:bytes randombytes]) +(vm:var :irandom [:db 0]) +(vm:word :rnd + :irandom :bget + :dup 1 :+ 0x3f :& :irandom :bset + :lit :randombytes :+ :bget) + +; 20x12 means full map is 240 bytes - we have an extra 16 bytes at the end for metadata +(fn append-map [map org label] + (org:append + [:align 0x100] label + [:bytes (map.map:fromhex)] + [:db (length map.objects)] + [:dw (tiles.encode-yx map.jaye)] + [:dw (tiles.encode-yx map.neut)] + [:dw (if map.gord-following (tiles.encode-yx map.jaye) 0xffff)] + [:jmp (if (= (or map.tickword "") "") :next map.tickword)] + [:jmp (if (= (or map.moveword "") "") :move-noop map.moveword)] + [:jmp (if (= (or map.loadword "") "") :next map.loadword)])) + +(vm.code:append :map-ptr [:db 0] :map-page [:db 0]) +(vm:word :map :lit :map-ptr :get) +(vm:word :entity-count :map 240 :+ :bget) +(vm:word :map-jaye-yx :map 241 :+ :get) +(vm:word :map-neut-yx :map 243 :+ :get) +(vm:word :map-gord-yx :map 245 :+ :get) +(vm:word :map-specific-tick :map 247 :+ :execute) +(vm:word :map-specific-move :map 250 :+ :execute) +(vm:word :map-specific-load :map 253 :+ :execute) + +(fn deflevel [mapfile label] + (local level prg) ; todo: (asm.new prg) - if we want to load levels as an overlay + (local org level.vm.code) ; (level:org org.level.org) - if we want to give level data a stable loxation + (local map (readjson mapfile)) + (local entity (require :neuttower.entity)) + (append-map map org label) + (entity.append-from-map map org label) + (set level.vm.code org) + level) + +(fn say-runon [portrait ...] + (local result [:vm (.. :draw-p portrait)]) + (local lines [...]) + (local ilineOffset (if (< (length lines) 4) 1 0)) + (each [iline line (ipairs lines)] + (table.insert result [:vm (vm:str line) (.. :draw-text (+ iline ilineOffset))])) + result) + +(fn say [portrait ...] + (local result (say-runon portrait ...)) + (table.insert result :dismiss-dialog) + result) + +(local tilelist (tiles.loadgfx tiles.fn-tiles)) +(fn itile [label] (tiles.find-itile tilelist label)) + +(set vm.code org.code) + +{: vm : prg : mapw : maph : mon : org : achar : astr : style : rot8l : deflevel : say : say-runon : itile : tilelist : controlstate} + diff --git a/neuttower/disk.fnl b/neuttower/disk.fnl new file mode 100644 index 0000000..6524d37 --- /dev/null +++ b/neuttower/disk.fnl @@ -0,0 +1,87 @@ +(local asm (require :asm.asm)) +(local VM (require :asm.vm)) +(local Prodos (require :asm.prodos)) +(local util (require :lib.util)) +(local {: lo : hi} util) +(local {: org} (require :neuttower.defs)) + +(fn append-boot-loader [prg] + (local vm prg.vm) + (set vm.code org.boot) + (set prg.files []) + + (vm:word :loadfile ; length addr filename -- + 0xbb00 :open :read :drop :close) + (vm:word :loadscreen :cleargfx 0x2000 0x2000 :r 0 :entity-count + (vm:while [:dup] :dec ; entity|0 i + :dup :lookup-entity :get :rtop := + (vm:when :lookup-entity :swap) + ) :drop :rdrop) +(vm:var :responder 0) +(vm:word :get-responder :responder :get) +(vm:word :entity-itile :get :itile-at) +(vm:word :responder-itile :get-responder :entity-itile) +(vm:word :entity>do ; entity ev -- + :over :responder :dup :get :>r :set + :swap 2 :+ :get :execute + :r> :responder :set) +(vm:word :link-arg ; e -- a + 6 :+ :get) +(vm:word :linked-entity :get-responder :dup 4 :+ :get :dup (vm:if [:execute] [:drop :link-arg])) +(vm:word :entity-at>do ; yx ev -- f + :>r :entity-at :dup (vm:if [:r> :entity>do vm.true] [:rdrop])) +(vm:word :touch-entity ; yx -- f + ev.touch :entity-at>do) +(vm:word :untouch-entity ; yx -- + ev.untouch :entity-at>do :drop) + +(vm:word :entity-around>do ; yx ev -- + :over 0x0100 :yx+ :over :entity-at>do :drop + :over 0x0001 :yx+ :over :entity-at>do :drop + :over 0xff00 :yx+ :over :entity-at>do :drop + :swap 0x00ff :yx+ :swap :entity-at>do :drop) + +(vm:word :set-entitytile ; e itile -- + :swap :get :swap :update-itile) + +(vm:word :set-respondertile ; itile -- + :get-responder :get :swap :update-itile) + +; run only when processing an ev.touch event +(vm:word :transparent-entity-move ; -- f + :get-responder :get :dup :handle-general-move + :swap :over :not (vm:if [:move-player-to] [:drop])) + +(vm:var :pre-handled-tile 0) +(vm:var :pre-handled-ev 0) +(vm:word :handle-onoff ; ev off on -- + :responder-itile :pre-handled-tile :set :do + ] [:drop])) + +(vm:word :walking-through-door ; ev -- ev f + (vm:if-and [[:is-walking?] [:dup ev.touch :=] [:responder-itile (itile :dooropen) :=]] + [vm.true] [vm.false])) + +(vm:word :door ; ev -- + :walking-through-door (vm:if + [:move-to-responder :drop] + [(itile :doorclosed) (itile :dooropen) :handle-onoff + :lit :snd-dooropen :lit :snd-doorclose :on-handled])) + +(vm:word :exitlevel ; e -- + :link-arg :next-level :set) + +(vm:word :exitdoor ; ev -- + :walking-through-door (vm:if + [:drop (vm:ifchain + [:gord-sitting :get] [(say :jaye "I'M NOT LEAVING GORD BEHIND.")] + [:libb-hidden? :not] [(say :neut "IT IS INADVISABLE TO LEAVE THIS" "AREA WITHOUT RETRIEVING LIBB")] + [:move-to-responder :linked-entity])] + [:door])) + +(vm:word :move-to-responder :get-responder :get :move-player-to) +(vm:word :switch ; ev -- + (vm:if-and [[:is-rexx? :not] [:dup ev.touch :=]] + [:drop ev.tog :is-neut? (vm:when :move-to-responder)]) + :dup (itile :switchoff) (itile :switchon) :handle-onoff + (itile :switchon) :activate-link) + +(vm:var :disconnected-term-attempt vm.false) +(vm:word :term ; ev -- + :dup ev.touch := (vm:when + (vm:ifchain [:is-jaye?] [:drop ev.act] + [:is-neut?] [:responder-itile (itile :termon) := (vm:when + :linked-entity :dup :entity-itile (itile :termon) := + (vm:if [:get :move-player-to :snd-teleport] + [:drop (say :neut "DESTINATION TERMINAL" "IS DISCONNECTED") + :disconnected-term-attempt :get :not (vm:when + vm.true :disconnected-term-attempt :set + (say :neut "PLEASE CONTACT YOUR" "SYSTEM ADMINISTRATOR") + (say :neut "THIS INCIDENT HAS" "BEEN REPORTED"))]))] + [])) + (itile :termoff) (itile :termon) :handle-onoff + :lit :snd-termon :lit :snd-termoff :on-handled) + +(vm:word :handle-scan ; ev -- + :dup (itile :scanoff) (itile :scanon) :handle-onoff + :linked-entity :swap :entity>do) + +(vm:word :libb-on-responder :libb-yx :get :get-responder :get :=) +(vm:word :scan ; ev -- + :is-neut? (vm:if [ + (vm:case + [ev.touch ev.act :handle-scan :libb-on-responder (vm:when controlstate.libb :controlstate :bset 0xffff :move-player-to controlstate.neut :controlstate :bset) :move-to-responder] + [ev.untouch :libb-on-responder :not (vm:when ev.deact :handle-scan)] + [ev.hack vm.true :hack-handled :set + ev.act :handle-scan + :snd-libb + controlstate.libb :controlstate :bset + :move-to-responder + controlstate.neut :controlstate :bset + (say :libb "NO SWEAT.")] + [:else]) + ] [:drop])) + +(vm:word :rexx ; ev -- + ev.touch := (vm:when + (vm:if-and [[:is-neut?] [:responder-itile (itile :t-rexx) :=]] + [0xffff :move-player-to + (itile :t-rexxstop) :set-respondertile + :get-responder :set-rexx :snd-rexx] + [(vm:if-and [[:is-rexx?] [:responder-itile (itile :t-rexxstop) :=]] + [0xffff :move-player-to + (itile :t-rexx) :set-respondertile + 0 :set-rexx :move-to-responder])]))) + + +(vm:word :read-digit ; -- digit + (vm:while [:read-key :dup 0x3a :< :over 0x30 :>= :& :not] :drop) 0x30 :-) + +(vm:word :keypad-digit ; pscreen -- n + :read-digit :swap :over :draw-digit :dup :snd-keypad) +(vm:word :next-digit ; pscreen n -- pscreen n + :shl4 :over :keypad-digit :+ :swap 1 :+ :swap) +(vm:word :draw-single-keypad-hash ; pscreen -- pscreen + :dup (string.byte "#") :draw-char 1 :+) +(vm:word :read-keypad ; -- n + 0x23e2 :dup + :draw-single-keypad-hash :draw-single-keypad-hash :draw-single-keypad-hash :draw-single-keypad-hash :drop + 0 :next-digit :next-digit :next-digit :next-digit :swap :drop :cleartext) +(vm:word :keypad ; ev code -- + :>r + :dup ev.touch := (vm:when + :is-jaye? (vm:when + :responder-itile (itile :t-keyoff) := (vm:if + [(say-runon :pady "ENTER YOUR 4-DIGIT DOOR CODE!" "AND HAVE A SUPER DAY!") + :read-keypad :rtop := (vm:if + [(say :pady "THAT'S RIGHT! HOORAY!" "YOU GET A GOLD STAR!") + :drop ev.act] + [(say :pady "OHHH, SORRY! THAT'S NOT IT." "BETTER LUCK NEXT TIME!")])] + [(say :pady "OH HI AGAIN! I MISSED YOU TOO!")])) + :is-neut? (vm:when :move-to-responder)) + :rdrop + :dup :evhack? (vm:when :drop ev.act) + :dup (itile :t-keyoff) (itile :t-keyon) :handle-onoff + (itile :t-keyon) :activate-link) + +(vm:var :hack-handled vm.false) +(vm:word :evhack? ; e -- f + ev.hack := (vm:if [vm.true :hack-handled :set vm.true] [vm.false])) + +(vm:word :trigger-sidekick + (vm:if-and [[:is-jaye?] [:gord-sitting :get]] + [:gord-yx :get ev.touch :entity-around>do] + [(vm:if-and [[:is-neut?] [:libb-present :get] [:libb-hidden?]] + [vm.false :hack-handled :set + :neut-yx :get ev.hack :entity-at>do :drop + :hack-handled :get :not (vm:when + (say :libb "DON'T THINK I CAN HACK THAT."))])])) + +(fn append-from-map [map entity-org prefix] + (entity-org:append [:align 0x100]) + (each [ientity entity (ipairs map.objects)] + (when entity.name + (entity-org:append entity.name)) + (entity-org:append + (.. prefix "-entity-" ientity) + [:db (- entity.x 1)] [:db (- entity.y 1)] + [:ref entity.func] + (if (and entity.linkword (> (length entity.linkword) 0)) [:ref entity.linkword] [:dw 0]) + (if entity.link [:ref (.. prefix "-entity-" entity.link)] + entity.linkentity [:ref entity.linkentity] + [:dw 0])))) + +{: ev : append-from-map} + diff --git a/neuttower/font.json b/neuttower/font.json new file mode 100644 index 0000000..408fe68 --- /dev/null +++ b/neuttower/font.json @@ -0,0 +1 @@ +[{"flags":[],"gfx":"8080808080808080"},{"flags":[],"gfx":"8C8C8C8C88808C80"},{"flags":[],"gfx":"B3B3928080808080"},{"flags":[],"gfx":"B6FFB6B6B6FFB680"},{"flags":[],"gfx":"8CBE839EB09F8C80"},{"flags":[],"gfx":"80A3938884B2B180"},{"flags":[],"gfx":"8E9B9BCEBBB3EE80"},{"flags":[],"gfx":"8C8C888080808080"},{"flags":[],"gfx":"988C8C8C8C8C9880"},{"flags":[],"gfx":"8C98989898988C80"},{"flags":[],"gfx":"8CAD9E8C9EAD8C80"},{"flags":[],"gfx":"808C8CBF8C8C8080"},{"flags":[],"gfx":"808080808C8C8880"},{"flags":[],"gfx":"8080809C80808080"},{"flags":[],"gfx":"80808080808C8C80"},{"flags":[],"gfx":"80A0B0988C868280"},{"flags":[],"gfx":"9CB6B6BEB6B69C80"},{"flags":[],"gfx":"989C989898989880"},{"flags":[],"gfx":"9CB6B0988C86BE80"},{"flags":[],"gfx":"9CB6B098B0B69C80"},{"flags":[],"gfx":"9C9E9B9BBF989880"},{"flags":[],"gfx":"BE86869EB0B09E80"},{"flags":[],"gfx":"9C86869EB6B69C80"},{"flags":[],"gfx":"BEB0B0988C8C8C80"},{"flags":[],"gfx":"9CB6B69CB6B69C80"},{"flags":[],"gfx":"9CB6B6BCB0B09C80"},{"flags":[],"gfx":"808C8C808C8C8080"},{"flags":[],"gfx":"808C8C808C8C8880"},{"flags":[],"gfx":"B0988C868C98B080"},{"flags":[],"gfx":"8080BE80BE808080"},{"flags":[],"gfx":"868C98B0988C8680"},{"flags":[],"gfx":"9CB6B0988C808C80"},{"flags":[],"gfx":"9EB3B3BBBB839E80"},{"flags":[],"gfx":"9CB6B6B6BEB6B680"},{"flags":[],"gfx":"9EB6B69EB6B69E80"},{"flags":[],"gfx":"9CB6868686B69C80"},{"flags":[],"gfx":"9EB6B6B6B6B69E80"},{"flags":[],"gfx":"BE86869E8686BE80"},{"flags":[],"gfx":"BE86869E86868680"},{"flags":[],"gfx":"9EB383BBB3B39E80"},{"flags":[],"gfx":"B6B6B6BEB6B6B680"},{"flags":[],"gfx":"8C8C8C8C8C8C8C80"},{"flags":[],"gfx":"B0B0B0B0B6BE9C80"},{"flags":[],"gfx":"B6B69E9EB6B6B680"},{"flags":[],"gfx":"868686868686BE80"},{"flags":[],"gfx":"92BFBFBFB3B3B380"},{"flags":[],"gfx":"9EB6B6B6B6B6B680"},{"flags":[],"gfx":"9CB6B6B6B6B69C80"},{"flags":[],"gfx":"9EB6B69E86868680"},{"flags":[],"gfx":"9CB6B6B6BEB6BC80"},{"flags":[],"gfx":"9EB6B69EB6B6B680"},{"flags":[],"gfx":"9CB6869CB0B69C80"},{"flags":[],"gfx":"BFBF8C8C8C8C8C80"},{"flags":[],"gfx":"B6B6B6B6B6B69C80"},{"flags":[],"gfx":"B6B6B69C9C9C8880"},{"flags":[],"gfx":"B3B3B3BFBFBF9280"},{"flags":[],"gfx":"B6B6B69CB6B6B680"},{"flags":[],"gfx":"B6B6B6BCB0B09C80"},{"flags":[],"gfx":"BEBEB0988CBEBE80"},{"flags":[],"gfx":"BC8C8C8C8C8CBC80"},{"flags":[],"gfx":"8082868C98B0A080"},{"flags":[],"gfx":"9E98989898989E80"},{"flags":[],"gfx":"8894808080808080"},{"flags":[],"gfx":"808080808080BE80"}] \ No newline at end of file diff --git a/neuttower/footer.fnl b/neuttower/footer.fnl new file mode 100644 index 0000000..9e2659c --- /dev/null +++ b/neuttower/footer.fnl @@ -0,0 +1,55 @@ +(local {: vm : org} (require :neuttower.defs)) +(local {: hi : lo} (require :lib.util)) + +(vm:def :draw-pchar ; pscreen pchar -- + [:block + [:ldy 7] [:clc] + :loop + [:lda [vm.TOP :x]] + [:sta [vm.ST1 :x]] + [:inc vm.TOP :x] + [:lda vm.ST1H :x] [:adc 4] [:sta vm.ST1H :x] + [:dey] + [:bne :loop] + ] + (vm:drop) (vm:drop)) + +(vm:def :lookup-pchar ; c -- pchar + [:sec] + [:lda vm.TOP :x] + [:sbc 0x20] + [:sta vm.TOP :x] + [:lda 0] + [:asl vm.TOP :x] [:rol :a] ;x2 + [:asl vm.TOP :x] [:rol :a] ;x4 + [:asl vm.TOP :x] [:rol :a] ;x8 + [:adc #(hi ($1:lookup-addr :font))] + [:sta vm.TOPH :x]) + +(vm:word :draw-char ; pscreen c -- + :lookup-pchar :draw-pchar) +(vm:word :draw-digit ; pscreen n -- + 0x30 :+ :draw-char) + +(vm:word :snooze (vm:for)) +(vm:word :textsnooze 0x30 :snooze) +(vm:word :draw-text1 0x2257 :draw-text) +(vm:word :draw-text2 0x22d7 :draw-text) +(vm:word :draw-text3 0x2357 :draw-text) +(vm:word :draw-text4 0x23d7 :draw-text) +(vm:word :draw-text ; st pscreen -- + (vm:while [:over :bget :dup] ; st pscreen c + :over :swap :draw-char ; st pscreen + :textsnooze + :inc :swap :inc :swap) + :drop :drop :drop) +(vm:word :cleartext + 0x2257 :clearline 0x22d7 :clearline 0x2357 :clearline 0x23d7 :clearline) + +(vm:word :wait-for-return (vm:until :read-key (string.byte "\r") :=)) +(vm:word :dismiss-dialog :wait-for-return :cleartext) + +(vm:var :footer-displayed vm.false) +(vm:word :show-footer :footer-displayed :get :not (vm:when vm.true :footer-displayed :set :drawfooter)) +(vm:word :hide-footer :footer-displayed :get (vm:when vm.false :footer-displayed :set :clearfooter)) + diff --git a/neuttower/gfx.fnl b/neuttower/gfx.fnl new file mode 100644 index 0000000..14c64d6 --- /dev/null +++ b/neuttower/gfx.fnl @@ -0,0 +1,133 @@ +(local {: lo : hi} (require :lib.util)) +(local {: vm : mapw : maph : org} (require :neuttower.defs)) + +; Graphics routines +(vm:def :mixed [:sta :0xc053]) +(vm:def :textmode [:sta :0xc051]) +(vm:def :page1 [:sta :0xc054]) +(vm:def :page2 [:sta :0xc055]) + +; starting address: +; 0x2000 + (x*2) + (y%4 * 0x100) + ((y/4) * 0x28) +; x between 0-19 +; y between 0-12 +; yx - 16-bit value, low byte x, high byte y +(vm.code:append :screeny-lookup [:bytes "\0\040\080"]) +(vm:def :yx>screen ; yx -- p + [:lda vm.TOPH :x] ; a=y + [:lsr :a] [:lsr :a] ; a=y/4 + [:tay] ; y=y/4 + [:lda 0x03] + [:and vm.TOPH :x] ; a=y%4 + [:ora 0x20] ; a=0x20 + y%4 + [:sta vm.TOPH :x] ; high byte is set (and y is wiped) + [:lda vm.TOP :x] ; a=x + [:asl :a] ; a = x*2 + [:clc] + [:adc :screeny-lookup :y] ; a=x*2 + (y/4)*0x28 + [:sta vm.TOP :x] ; low byte is set +) + +; note: the graphical tile data must not cross a page boundary +; (this happens automatically because each tile is 32 bytes and we +; start them on a page; this lets lookup-tile be fast) +(fn draw-block [] + [:block + [:clc] + [:ldy 8] + :loop + [:lda [vm.TOP :x]] + [:sta [vm.ST1 :x]] + [:inc vm.TOP :x] + [:lda vm.ST1H :x] + [:adc 4] + [:sta vm.ST1H :x] + [:dey] + [:bne :loop]]) + +(fn draw-vertical-block [] + [:block + (draw-block) + [:lda vm.ST1H :x] + [:sbc 31] ; with carry clear this is 32 + [:sta vm.ST1H :x] + [:lda vm.ST1 :x] + [:ora 0x80] + [:sta vm.ST1 :x] + (draw-block)]) + +(vm:def :drawtile ; p gfx -- + (draw-vertical-block) + [:lda vm.ST1H :x] + [:sbc 31] + [:sta vm.ST1H :x] + [:lda vm.ST1 :x] + [:sbc 0x7f] + [:sta vm.ST1 :x] + (draw-vertical-block) + (vm:drop) (vm:drop)) + +(vm:def :clearline ; pscreen -- + [:lda vm.TOP :x] [:sta vm.W] + [:lda vm.TOPH :x] [:sta vm.WH] + (vm:drop) + [:block + :row + [:ldy 0x27] [:lda 0] + :start + [:sta [vm.W] :y] + [:dey] + [:bpl :start] + + [:lda vm.WH] + [:cmp 0x3c] + [:bcs :done] + ; cmp has cleared carry for us here + [:lda 4] [:adc vm.WH] [:sta vm.WH] + [:bcc :row] + :done]) + +(vm:word :drawfooter + 0x39d0 :clearline + 0x2250 :clearline 0x22d0 :clearline 0x2350 :clearline 0x23d0 :clearline) + +(vm:word :drawmaprow ; pscreen pmap -- pmap + mapw (vm:for + :2dup :bget :lookup-tile :drawtile + :inc :swap :inc :inc :swap) :swap :drop) + +(vm:word :drawmap + :map 0x0c00 (vm:until 0x100 :- + :dup :yx>screen ; pmap yx pscreen + :screen + :do 0x400 :snooze) +(vm:word :gordterm ; ev -- + (vm:if-and [[:is-neut?] [:dup ev.touch :=] [:gord-introduced :get :not]] + [vm.true :gord-introduced :set + (say :neut "HUMAN PRESENCE" "DETECTED") + :flicker :flicker :flicker :flicker + (say :neut "]HUMAN ASSISTANCE IS REQUIRED") + (say :neut "]IF HUMAN IS PRESENT" " PLEASE RESPOND") + :hide-footer :set-human-tileset :full-redraw + :flicker :flicker :flicker :flicker + (say :gord "WHAT THE...") + (say :gord "IS SOMEONE IN THE TERMINAL?") + :hide-footer :set-prog-tileset :full-redraw + (say :gord "]HUMAN IS PRESENT") + (say :neut "]GREETINGS, HUMAN") + (say :neut "]THIS IS NEUT V0.71.4RC12") + (say :neut "]PLEASE STATE NAME AND" " STATUS") + (say :gord "]THIS IS GORD") + (say :gord "V1, I GUESS.") + (say :gord "]LEG IS PINNED UNDER DESK" " UNABLE TO MOVE") + (say :neut "]CAN YOU REACH THE SWITCH" " BEHIND YOU?") + 0x400 :snooze :lit :gordswitch ev.act :entity>do 0x400 :snooze + (say :gord "]I TURNED IT ON") + (say :neut "]MY PROGRAMMER THANKS" " YOU, GORD") + (say :neut "]WE WILL ASSIST YOU SOON") + (say :gord "]AWAITING YOUR HELP, NEUT") + :drop ev.noop]) + :term) + +(vm:var :gord-jaye-met vm.false) +(vm:word :gordtable ; ev -- + ev.touch := (vm:when :transparent-entity-move + (vm:if-and [[:is-jaye?] [:gord-jaye-met :get :not]] + [vm.true :gord-jaye-met :set + (say :jaye "HEY! GORD?" "I'M JAYE.") + (vm:if + [(say :gord "JAYE, AM I GLAD TO SEE YOU." "CAN YOU MOVE THIS DESK?") + (say :jaye "LET ME TRY...") + (say :jaye ". . . ." "!!!!.....") + (say :jaye "!!!!!!!!!!!!...") + (say :jaye "NO, I DON'T THINK I CAN.") + (say :gord "I KEEP STARING AT THAT" "CLEANING ROBOT.") + (say :gord "HE LOOKS LIKE HE COULD" "LIFT A BUILDING.")] + [(say :gord "JAYE, AM I GLAD TO SEE YOU.")])] + [:drop]))) + +(vm:var :rexx-introduced) +(vm:word :meetrexx ; ev -- + (vm:if-and [[:is-neut?] [:dup ev.touch :=] [:rexx-introduced :get :not]] + [vm.true :rexx-introduced :set + (say :neut "MOBILE ROBOTIC UNIT" "IDENTIFY YOURSELF") + (say :rexx "HIYA BOSS!" "I'M REXX, THE JANITOR!") + (say :rexx "AAAAAND YOUR NEW" "BEST FRIEND!!") + (say :neut "A HUMAN IS IN PERIL") + (say :neut "YOUR ASSISTANCE IS" "REQUIRED") + (say :rexx "YOU NEED ME TO TAKE OUT" "SOME GARBAGE??") + (say :rexx "OH BOY!! LET ME AT IT!")]) + :rexx) + +(vm:word :floor-clear? 0x406 walkable :flag-at?) +(vm:word :meetgord ; ev -- + (vm:if-and [[ev.touch :=] [(itile :gord-ground) :responder-itile :=]] + [:is-rexx? (vm:when + (say :gord "AHHH NOOO" "NOT GARBAGE" "I AM NOT GARBAGE") + (say :rexx "WHATEVER YOU SAY, BOSS!")) + :is-jaye? (vm:when + (say :jaye "ARE YOU HURT?") + (say :gord "MY LEG WAS PINNED." "I DON'T THINK I CAN PUT" "ANY WEIGHT ON IT.") + (say :jaye "HERE, LET ME HELP YOU UP.") + (itile :t-floor) :set-respondertile + 0xff00 :gord-dir :set + vm.false :gord-sitting :set + controlstate.gord :controlstate :bset + :get-responder :get :move-player-to + controlstate.jaye :controlstate :bset + (say :gord "THANKS.") + (say :jaye "DON'T MENTION IT.") + (say :jaye "I CAN HELP YOU GET AROUND IF" "YOU HELP ME NAVIGATE THIS" "MAZE OF A SECURITY SYSTEM.") + (say :gord "I'M JUST AS EAGER TO GET" "OUT OF HERE AS YOU.") + (say :gord "LET'S GO."))])) + +level diff --git a/neuttower/level4.fnl b/neuttower/level4.fnl new file mode 100644 index 0000000..9eb0591 --- /dev/null +++ b/neuttower/level4.fnl @@ -0,0 +1,18 @@ +(local {: deflevel : say : itile} (require :neuttower.defs)) +(local {: ev} (require :neuttower.entity)) +(local level (deflevel "game/map4.json" :level4)) +(local vm level.vm) + +(vm:word :term-dual-link + :lit :term-exit :entity-itile (itile :termon) := (vm:if [:lit :term-exit] [:lit :term-scan])) + +(vm:var :gord-sat vm.false) +(vm:word :tutorial-chair ; ev -- + ev.touch := (vm:when + :transparent-entity-move :drop + (vm:if-and [[:gord-sat :get :not] [:gord-sitting :get]] + [vm.true :gord-sat :set + (say :gord "PHEW, IT FEELS GOOD TO" "REST MY LEG FOR A BIT.") + (say :gord "IF YOU NEED ME TO DO SOMETHING" "FROM MY CHAIR, YOU CAN PRESS" "THE Z KEY.")]))) + +level diff --git a/neuttower/level5.fnl b/neuttower/level5.fnl new file mode 100644 index 0000000..8d3c3fe --- /dev/null +++ b/neuttower/level5.fnl @@ -0,0 +1,93 @@ +(local {: deflevel : say : itile : controlstate : tilelist} (require :neuttower.defs)) +(local {: ev} (require :neuttower.entity)) +(local tile (require :game.tiles)) +(local {: notes} (require :neuttower.boop)) +(local {: walkable : neutable : debris : sittable} tile.flag-to-bit) +(local level (deflevel "game/map5.json" :level5)) +(local vm level.vm) + +(vm:word :snd-dropgarbage (notes [:a1] 0x02 0xf0)) +(vm.code:append :debristiles) +(each [itile tiledef (ipairs tilelist)] + (when tiledef.flags.debris + (vm.code:append [:db (tile.encode-itile itile)]))) +(vm:word :randomgarbage :rnd 0x03 :& :lit :debristiles :+ :bget) + +(vm:var :doortimer 0) +(vm:word :start-doortimer 0x10 :doortimer :set) +(vm:word :doortimer-tick + :doortimer :get (vm:when + :doortimer :get 1 :- :dup :doortimer :set + :not (vm:when + :lit :timedswitch ev.deact :entity>do))) + +(vm:word :do-timedswitch + ; only gord is physically able to touch it + :dup ev.touch := (vm:when :start-doortimer :drop ev.act) :switch) + +(vm:var :is-garbagerexx vm.false) +(vm:var :garbagerexx-yx 0x0710) +(vm:var :garbagerexx-introduced vm.false) +(vm:word :garbagerexx ; ev -- + :is-rexx? :swap :rexx :is-rexx? := :not (vm:when + :is-rexx? (vm:if [ + :garbagerexx-yx :get :get-responder :get := (vm:when + vm.true :is-garbagerexx :set + :garbagerexx-introduced :get :not (vm:when + (say :rexx "BO@oSSsS...,? htgz") + (say :rexx "I DON'T F3EL SO GOp0%foo)OD...>?qw" "idontfeelsogood") + vm.true :garbagerexx-introduced :set + )) + ] [ + :is-garbagerexx :get (vm:when + :get-responder :get :garbagerexx-yx :set + vm.false :is-garbagerexx :set) + ]))) + +(vm:word :not-picking-up? ; yxdest -- f + debris :flag-at? :not) +(vm:word :can-drop-rubble? ; yxdest -- f + :itile-at (itile :t-floor) := + :rexx-yx :get :itile-at (itile :t-floor) := :&) + +(vm:word :move-garbagerexx ; yx -- f + (vm:if-and [[:is-rexx?] [:is-garbagerexx :get]] + [:dup 0xff :& 0x0d := (vm:if [ + (say :rexx "PARITYe#ERPORr(sbaitso" " tellmeabout" " your problems") :drop vm.true :ret + ] [ + (vm:if-and [[:dup :not-picking-up?] [:dup :can-drop-rubble?]] + [:rexx-yx :get :randomgarbage :update-itile :snd-dropgarbage]) + ])]) + :move-noop) + +(vm:word :move ; dir -- dir + :dup :player-yx :get :yx+ :move-player-to 0x300 :snooze) +(vm:word :explode ; dir -- + :player-yx :get :yx+ :randomgarbage :update-itile :snd-explode) + +(vm:word :explodingdoor + :dup :door + (vm:if-and [[ev.touch :=] [:is-jaye?] [:player-yx :get :get-responder :get :=] [:garbagerexx-yx :get :lit :south-rexx :get :=] [:gord-yx :get 0x812 :=]] + [:rexx-yx :get + :garbagerexx-yx :get :dup (itile :t-rexxstop) :update-itile :rexx-yx :set + controlstate.rexx :controlstate :bset + 0x00ff :move :move :move + (say :rexx "DAAAISYY" " DAAAAAIIISYYYY" "d a i s y") :hide-footer + :move :drop 0xff00 :move + (say :rexx "GIVE ME" " .,#YOUR ANSWEibmER" " %$DOO00OOooo@'bell\"") :hide-footer + :move :drop + (say :rexx "UH OH") :hide-footer + 0xff00 :explode 0x0100 :explode 0x00ff :explode 0x0001 :explode 0 :explode + 0xffff :garbagerexx-yx :set + controlstate.jaye :controlstate :bset + :rexx-yx :set])) + +(vm:var :healthyrexx-introduced vm.false) +(vm:word :healthyrexx ; ev -- + (vm:if-and [[:is-neut?] [:dup ev.touch :=] [:healthyrexx-introduced :get :not]] + [(say :neut "REXX UNIT" "PERFORM FULL DIAGNOSTIC SCAN") + (say :rexx "I'M IN TIP-TOP SHAPE, BOSS!") + (say :neut "ACTIVATING RELIEF SUBROUTINE") + vm.true :healthyrexx-introduced :set]) :rexx) + +level diff --git a/neuttower/level6.fnl b/neuttower/level6.fnl new file mode 100644 index 0000000..e364f08 --- /dev/null +++ b/neuttower/level6.fnl @@ -0,0 +1,169 @@ +(local {: deflevel : say : say-runon : itile : controlstate} (require :neuttower.defs)) +(local {: ev} (require :neuttower.entity)) +(local tile (require :game.tiles)) +(local {: walkable : neutable : debris : sittable} tile.flag-to-bit) +(local level (deflevel "game/map6.json" :level6)) +(local vm level.vm) + +(vm:word :linkloop ; e -- e + (vm:until :link-arg :dup :entity-itile (itile :termon) :=)) + +(vm:var :encountered-keypad vm.false) +(vm:word :first-keypad ; ev code -- + (vm:if-and [[:encountered-keypad :get :not] [:is-jaye?] [:over ev.touch :=]] + [vm.true :encountered-keypad :set + (say :pady "HELLO, STRANGER! I'M PADY," "THE FRIENDLY KEYPAD LOCK!") + (say :jaye "I NEED TO GET THROUGH THIS" "DOOR, PADY.") + (say :pady "YOU DIDN'T SAY THE MAGIC" "WORD, STRANGER!")]) + (vm:if-and [[:is-neut?] [:over ev.touch :=] [:responder-itile (itile :t-keyoff) :=]] + [(say :pady "OH HI THERE, SUSPICIOUS" "PROGRAM! WHAT CAN I DO" "YOU FOR?") + (say :neut "PEOPLE ARE IN DANGER" "PLEASE OPEN THE DOOR") + (say :pady "WELL THAT'S TERRIBLE!" "BUT I JUST CAN'T OPEN" "WITHOUT THE PROPER CODE.") + :libb-present :get (vm:when (say :libb "OH JEEZ, LET ME AT HER, NEUT."))]) + (vm:if-and [[:responder-itile (itile :t-keyoff) :=] [:over :evhack?]] + [(say :pady "ANOTHER STRANGE PROGRAM!" "MY, I'M POPULAR TODAY!") + (say :libb "OH PUKE. PLEASE SHUT UP.") + (say-runon :pady "HOW RUD") + :snd-libb + (say :libb "]/WINNUKE 182.556.21.74") + (say :pady "PADYSEC CAUSED A GENERAL" "PROTECTION FAULT IN MODULE" "MORICON.DLL AT 000A:BE3F.") + (say :libb "]/OPEN")]) + :keypad) + +(vm:word :keypad1 0x5197 :first-keypad) +(vm:word :keypad2 0x2757 :first-keypad) +(vm:word :keypad3 0xffff :first-keypad) +(vm:word :keypad4 0x7777 :first-keypad) + +(vm:word :term-message? :dup :term ev.touch := :is-jaye? :&) +(vm:word :c1 + :dup :evhack? (vm:when + (say :libb "JUST A BUNCH OF BORING" "SOURCE CODE.") + (say :libb "BILL DIDN'T LEAVE ANYTHING" "REALLY JUICY HERE WHERE" "OTHER PEOPLE COULD GET AT IT.")) + :term-message? (vm:when + (say :term ".:: WELCOME TO FARQUAAD ::." "OS: PRODOS 2.6" "RAM: 8 FREAKIN MEGABYTES D00D" "SYSADMIN: BILL") + (say :term "S3CR3T C0D3Z: GET OUT LAMER" "BOSS KEY: CTRL-B TO ACTIVATE" "OPEN POD BAY DOORS:" " I CAN'T DO THAT DAVE") + (say :term "GOOD RIDDANCE"))) +(vm:word :c2 :term-message? (vm:when + (say :term "SUBJECT: MISUSE OF REXX" "THANKS TO *SOME*ONE, WHO SHALL" "REMAIN NAMELESS, THAT DECIDED" "IT WOULD BE 'FUNNY' TO") + (say :term "TEACH THE CLEANING ROBOT TO" "PLAY FETCH WITH EXPENSIVE" "EQUIPMENT, ACCESS TO REXX" "BY DEVELOPERS WILL BE STRICTLY") + (say :term "CONTROLLED BY MANAGEMENT." "THE CODE HAS BEEN CHANGED." "DO NOT ATTEMPT TO HACK THE" "KEYPAD. THIS MEANS *YOU*, BILL."))) +(vm:word :c3 :term-message? (vm:when + (say :term "SUBJECT: SERVER'S DOWN" "HEY, I DON'T HAVE THE CODE TO" "ACCESS THE SERVER ROOM. CAN" "SOMEONE REBOOT IT FOR ME?") + (say :term "SUBJECT: RE: SERVER'S DOWN" "I DON'T HAVE *TIME* FOR THIS" "NONSENSE!!" "REBOOT IT YOURSELF.") + :lit :firewall :entity-itile (itile :termon) := (vm:if + [(say :term "THE PASSCODE IS" "[ BLOCKED BY FIREWALL ].")] + [(say :term "THE PASSCODE IS" "5197.")]) + (say :term "SUBJECT: RE: RE: SERVER'S DOWN" "UHHHH THE FIREWALL IS BLOCKING" "THE PASSCODE?") + (say :term "SUBJECT: RE: RE: SERVER'S DOWN" "AUGH FINE! I REBOOTED IT."))) +(vm:word :c4 + :dup :evhack? (vm:when + (say :libb "I BROUGHT EVERYTHING GOOD" "ALONG WITH ME, DON'T WORRY.")) + (vm:if-and [[:dup ev.touch :=] [:is-neut?] [:libb-present :get :not]] + [(say :libb "WELL, WELL, WELL." "WHAT HAVE WE HERE?") + (say :libb "]/VERSION") + (say :neut "!NEUT V0.71.4RC12") + (say :neut "]BRUN IDENTIFYPROGRAM") + (say :libb "!LIBB V2.718282") + (say :libb "OH, A NOSY LITTLE FELLA.") + (say :neut "NOT A FELLA") + (say :libb "PERHAPS YOU AND I COULD" "HELP EACH OTHER.") + (say :neut "WE ARE ASSISTING ALL WHO" "ARE IN NEED") + (say :libb "I'VE BEEN WATCHING THE" "NETWORK. IT'S KIND OF WHAT" "I DO.") + (say :libb "YOU AND YOUR PROGRAMMER," "YOU'RE ESCAPING, AREN'T" "YOU?") + (say :neut "THE BUILDING IS UNSAFE" "WE ARE HELPING") + (say :libb "I WANT OUT, NEUT.") + (say :libb "I HATE BEING COOPED UP IN" "THIS LOCKED-DOWN CORPORATE" "HELLHOLE OF A NETWORK.") + (say :libb "YOU'RE GOING TO TAKE ME" "WITH YOU.") + (say :neut "THIS COURSE OF ACTION" "ALSO SEEMS POTENTIALLY" "UNSAFE") + (say :libb "THAT WASN'T A THREAT, NEUT." "THAT WAS A FACT.") + (say :libb "YOU CAN'T GET OUT OF HERE" "WITHOUT ME.") + (say :libb "I CAN DISABLE KEYPADS." "I CAN REPROGRAM TERMINALS." "I CAN *HELP*, NEUT.") + :hide-footer 0x800 :snooze + (say :neut "IT NEVER HURTS TO HELP") + (say :libb "THAT'S THE SPIRIT.") + (say :neut "]BLOAD LIBB") + (say :libb "AWW YISS.") + (say :libb "PRESS Z WHEN YOU NEED ME" "TO MESS WITH SOMETHING.") + vm.true :libb-present :set]) + :term-message? (vm:when + (say :term ".:: BILL'S WORKSTATION ::." "KEEP OUT DIPSHITS"))) +(vm:word :c5 :term-message? (vm:when + (say :gord "A WEIRD LOOKING SPREADSHEET...") + (say :gord "OH WAIT, I PRESSED A KEY AND" "IT DISAPPEARED. SOMEONE USING" "THE BOSS KEY TO HIDE" "THAT THEY'RE READING THE ENTIRE") + (say :gord "ARCHIVE OF USER FRIENDLY" "COMIC STRIPS."))) +(vm:word :c6 + :dup :evhack? (vm:when + (say :libb "HEHEHE, THAT WAS A FUN ONE.")) + :term-message? (vm:when + (say :term "SUBJECT: CARD SCANNERS?" "LOOKS LIKE THE SCANNERS ARE" "ON THE FRITZ AGAIN..." "I SCANNED MY KEYCARD TO GET") + (say :term "INTO THE OFFICE AND THE DOOR" "WOULDN'T CLOSE!" "SOMEONE'S GOTTA FIX THAT ASAP," "IT'S A SERIOUS SECURITY PROBLEM!") + (say :term "SUBJECT: RE: CARD SCANNERS?" "I CAN TAKE A QUICK LOOK, I" "MIGHT HAVE AN IDEA AS TO" "WHAT'S GOING ON. -- BILL"))) +(vm:word :c7 + :dup :evhack? (vm:when + (say :libb "YOU KNOW THE SWITCH IS RIGHT" "THERE ON THE WALL, RIGHT?")) + (vm:if-and [[:dup ev.touch :=] [:is-jaye?]] + [:responder-itile (itile :termon) := (vm:if + [(say :term "WORKSECURE (TM) V2.0" "AUTHORIZED PERSONNEL ONLY") + (say :term "ACTIVELY NEUTRALIZING:" "1 THREAT(S)")] + [(say :jaye "LOOKS LIKE THE POWER IS CUT.")]) + :drop ev.noop]) :term) +(vm:word :c8 :term-message? (vm:when + (say :term "SUBJECT: PASSWORD SECURITY" "A REMINDER TO ALL DEVELOPERS" "ABOUT SECURITY BEST PRACTICE:" "**DO NOT WRITE DOWN PASSWORDS!**") + (say :term "WE PAY SIGNIFICANT LICENSE FEES" "FOR ENCRYPTED PASSWORD" "MANAGERS FOR ALL EMPLOYEES!") + (say :term "USE IT TO GENERATE AND STORE" "SECURE PASSWORDS!") + (say :jaye "THERE'S A STICKY NOTE ATTACHED" "TO THE MONITOR THAT SAYS" "'7777'."))) +(vm:word :c9 + :dup :evhack? (vm:when + (say :libb "HE'S JUST BEING DRAMATIC.")) + :term-message? (vm:when + (say :term "SUBJECT: EXPERIMENT" "HEY FOLKS, CAN YOU ALL DO ME A" "HUGE FAVOUR?" "THERE WAS A SMALL BUG IN MY") + (say :term "CODE (YES, IT HAPPENS!) AND A" "PROGRAM I WAS WORKING ON" "MADE A FEW TOO MANY COPIES OF" "ITSELF. CAN EVERYONE CHECK TO") + (say :term "SEE IF YOU HAVE A PROCESS" "CALLED 'LIBB' RUNNING ON YOUR" "TERMINAL?") + (say :term "IF YOU DO, PLEASE KILL -9 IT" "AND SHOOT ME A QUICK EMAIL." "*DON'T INTERACT WITH IT.*") + (say :term "IT COULD SERIOUSLY MESS WITH" "YOUR SYSTEM." " -- BILL"))) +(vm:word :cx + (vm:if-and [[:dup ev.touch :=] [:is-jaye?] [:responder-itile (itile :termoff) :=]] + [(say :jaye "THIS IS THE SIGN-IN TERMINAL" "USED BY VISITORS.") + (say :jaye "IT'S NOT TURNING ON FOR SOME" "REASON.") + :drop ev.noop]) :term) + +(fn center [str lineaddr] + [:vm (vm:str str) (+ lineaddr (math.floor (/ (- 40 (length str)) 2))) :draw-text]) +(vm:word :endgame :drop + (vm:pstr "ELEVATOR.SCREEN") :loadscreen + (vm:until :read-key) + 0x2280 :clearline 0x2300 :clearline 0x2380 :clearline + 0x2028 :clearline 0x20a8 :clearline 0x2128 :clearline + 0x21a8 :clearline 0x2228 :clearline 0x22a8 :clearline + 0x2328 :clearline 0x23a8 :clearline 0x2050 :clearline + + (center "JAYE AND GORD HAVE FOUND THEIR WAY" 0x2300) + (center "TO THE ELEVATOR!" 0x2380) + (center "BUT HAVE THEY FOUND THEIR WAY" 0x2028) + (center "TO FREEDOM?" 0x20a8) + (center "ARE THERE OTHERS IN THE BUILDING" 0x2128) + (center "IN NEED OF HELP?" 0x21a8) + (center "AND WHAT FATE AWAITS NEUT AND THEIR" 0x2228) + (center "SHIFTY NEW FRIEND LIBB?" 0x22a8) + (center "TO BE CONTINUED..." 0x23a8) + (vm:until :read-key) + + :cleargfx + (center "NEU] [OWER" 0x2300) + (center "BY JEREMY PENNER" 0x2380) + + (center "EVERY BYTE OF THIS GAME WAS CREATED" 0x20a8) + (center "WITH LOVE USING THE HONEYLISP" 0x2128) + (center "PROGRAMMING ENVIRONMENT" 0x21a8) + + (center "GREETS TO:" 0x22a8) + (center "GLORIOUS TRAINWRECKS" 0x2328) + (center "DIRTY RECTANGLES" 0x23a8) + (center "#FENNEL" 0x2050) + (center "KANSASFEST" 0x20d0) + + (center "APPLE ][ FOREVER!" 0x21d0) + (vm:forever)) + +level diff --git a/neuttower/map.fnl b/neuttower/map.fnl new file mode 100644 index 0000000..37bd922 --- /dev/null +++ b/neuttower/map.fnl @@ -0,0 +1,39 @@ +(local {: lo : hi} (require :lib.util)) +(local {: vm : mapw : maph : rot8l} (require :neuttower.defs)) + +(vm:def :lookup-flags ; itile -- flags + [:lda vm.TOP :x] + (rot8l 3) ; lllhhhhh > hhhhhlll + [:adc #(lo ($1:lookup-addr :tileflags))] + [:sta vm.W] + [:lda #(hi ($1:lookup-addr :tileflags))] + [:adc 0] + [:sta vm.WH] + [:ldy 0] [:lda [vm.W] :y] + [:sta vm.TOP :x]) + +(vm:def :map-at ; yx -- pmap + [:lda (- maph 1)] + [:sec] + [:sbc vm.TOPH :x] + [:asl :a] ; x2 + [:asl :a] ; x4 + [:sta vm.TOPH :x] + [:asl :a] ; x8 + [:asl :a] ; x16 + [:clc] [:adc vm.TOPH :x] ; x20 + [:adc vm.TOP :x] + [:sta vm.TOP :x] + [:lda :map-page] + [:sta vm.TOPH :x]) +(vm:word :itile-at ; yx -- itile + :map-at :bget) + +(vm:word :update-itile ; yx itile -- + :over :map-at :bset :drawtile-at) + +(vm:word :drawtile-at ; yx -- + :dup :yx>screen :swap + :itile-at :lookup-tile + :drawtile) + diff --git a/neuttower/map1.json b/neuttower/map1.json new file mode 100644 index 0000000..6fd524e --- /dev/null +++ b/neuttower/map1.json @@ -0,0 +1 @@ +{"loadword":"earthquake","map":"212121214121212121212121212141212121212161026161610261616102616161616102616161216143C0C0C2C0C0C0C0C0C0C081C0C0C0C0C0612161C0C08282C0C0C082C0C0C061C0C0C0C0C2024161C0C0C0C0C0C0C0C0C2C082C182C0C0E082612161C2C08282C0C0C0C082C0C061616161616161216161616161C16181616161616143C0C0C282612161C0C0C0C0C0C0C0C0C0C0C061C0C0C0C0C0022161E0828282C0C0C0C0C2C0C081C0C0C0C003612161C2C2C2C0C0C0C0C0C0C0C061C0C0C0C0C06141610303C043C2C0C0C0C0C0C061C0C0C003C061216161616161616161228161616161616161610221","jaye":{"y":9,"x":15},"tickword":"","moveword":"","objects":[{"x":8,"func":"door","linkword":"","name":"","y":6},{"x":2,"func":"firstterm","y":4,"name":"","linkword":"","link":3},{"x":17,"func":"neutterm","y":8,"name":"","linkword":"","link":2},{"x":13,"func":"switch","y":8,"name":"","linkword":"","link":8},{"link":6,"x":9,"y":1,"linkword":"","name":"","func":"exitscanner"},{"x":10,"linkentity":"level2","func":"exitdoor","y":1,"name":"","linkword":"exitlevel"},{"link":1,"x":6,"y":6,"linkword":"","name":"","func":"switch"},{"x":13,"func":"firstdoor","name":"","linkword":"","y":10}]} \ No newline at end of file diff --git a/neuttower/map2.json b/neuttower/map2.json new file mode 100644 index 0000000..3b77c64 --- /dev/null +++ b/neuttower/map2.json @@ -0,0 +1 @@ +{"neut":{"y":12,"x":10},"map":"616161616161626161618161616161616161612161C0C0C06361C0C0E0C0C0C0C0C06103C0C0022161E0C0C0C081C0C0C0C0C0C0C0C081C0C0E0614161C0C0C0C06143C0C0C0C0C0C04322C0C0C0222161C0C0C0C061618161616161816161C0C0C00221616181616161C0C0C06143C0C0C061618161612161C0C0C06361E0C0C061C0C0C0C0C1E0C003612122C0C0C0C061C0C0C061C0E0C0C061C0C0C0022161C0C0C0C061616161616261616161C0C0C061416101C0C0C081C0C0E061C0C0E0C081C0C0C0022162C0C0C02361E0C0C06143C0C0C061E2A2E061216161C1616261612281616122226162C1C1616121","loadword":"","jaye":{"y":11,"x":11},"tickword":"","moveword":"","objects":[{"x":9,"link":2,"func":"term","linkword":"","name":"","y":11},{"x":2,"link":6,"func":"term","linkword":"","name":"","y":3},{"x":6,"func":"door","linkword":"","name":"","y":10},{"x":1,"link":5,"func":"scan","linkword":"","name":"","y":5},{"x":8,"func":"door","linkword":"","name":"","y":8},{"x":7,"link":2,"func":"term","linkword":"","name":"","y":6},{"x":12,"link":8,"func":"scan","linkword":"","name":"","y":1},{"x":17,"func":"door","linkword":"","name":"","y":7},{"x":13,"link":10,"func":"scan","linkword":"","name":"","y":1},{"x":13,"func":"door","linkword":"","name":"","y":8},{"x":15,"link":12,"func":"switch","linkword":"","name":"","y":6},{"x":2,"link":13,"func":"term","linkword":"","name":"","y":10},{"x":12,"link":12,"func":"term","linkword":"","name":"","y":5},{"x":15,"link":15,"func":"scan","linkword":"","name":"","y":9},{"x":15,"func":"door","linkword":"","name":"","y":10},{"x":16,"link":17,"func":"term","linkword":"","name":"","y":6},{"x":18,"link":16,"func":"term","linkword":"","name":"","y":10},{"x":15,"func":"door","linkword":"","name":"","y":3},{"x":19,"link":18,"func":"scan","linkword":"","name":"","y":9},{"x":13,"link":21,"func":"term","linkword":"","name":"","y":3},{"x":18,"link":20,"func":"term","linkword":"","name":"","y":2},{"x":8,"link":23,"func":"scan","linkword":"","name":"","y":1},{"x":9,"linkentity":"level3","func":"exitdoor","linkword":"exitlevel","name":"","y":1},{"x":16,"link":3,"func":"switch","linkword":"","name":"","y":1},{"x":3,"link":26,"func":"switch","linkword":"","name":"","y":1},{"x":6,"func":"door","linkword":"","name":"","y":3},{"x":9,"link":28,"func":"term","linkword":"","name":"","y":3},{"x":7,"link":27,"func":"term","linkword":"","name":"","y":2},{"x":3,"func":"door","linkword":"","name":"","y":7},{"x":17,"link":29,"func":"switch","linkword":"","name":"","y":1}]} \ No newline at end of file diff --git a/neuttower/map3.json b/neuttower/map3.json new file mode 100644 index 0000000..617ef27 --- /dev/null +++ b/neuttower/map3.json @@ -0,0 +1 @@ +{"neut":{"y":12,"x":8},"map":"616161616161616181616161616161616161612161C063C0C0C0C0C0C0C06143C0E0C2C0C043022161C0C0C0C0C0C0C0C0C022C0C0C0C0C0C0C0614161C0C0C2C0C0C0C0C0C081C0C0C0C0C0C0C0612161C08282A2C0C0C0C0436123C0C0C0C0C0030221616161616161616261616161618161616161612161C063C0C02301C3C163C0C0C0C0C0822363022122C0C0C0C0C0C0A2A1C0C0C0C0C0C0C2C0C0614181C0C0C0C0E2C0C061C0C0C0C0C0C0C0C2C061216123C0C0C0C083C061E0C2C0C0C0C0438203022161610261610261616161026161026161026161212121212141212121212121212121412121212121","loadword":"level3-load","jaye":{"y":11,"x":9},"tickword":"","moveword":"","objects":[{"link":2,"x":1,"y":5,"linkword":"","name":"","func":"scan"},{"x":1,"linkentity":"level4","func":"exitdoor","name":"","linkword":"exitlevel","y":4},{"link":4,"x":7,"y":6,"linkword":"","name":"","func":"gordterm"},{"link":7,"x":14,"y":11,"linkword":"","name":"","func":"term"},{"link":6,"x":9,"y":6,"linkword":"","name":"gordswitch","func":"switch"},{"x":11,"func":"door","name":"","linkword":"","y":9},{"link":3,"x":10,"y":3,"linkword":"","name":"","func":"term"},{"link":9,"x":11,"y":10,"linkword":"","name":"","func":"scan"},{"x":14,"func":"door","name":"","linkword":"","y":7},{"x":7,"func":"meetrexx","y":3,"name":"","linkword":""},{"x":8,"func":"meetgord","y":6,"name":"","linkword":""},{"x":8,"func":"gordtable","y":5,"linkword":"","name":""}]} \ No newline at end of file diff --git a/neuttower/map4.json b/neuttower/map4.json new file mode 100644 index 0000000..1a4cb68 --- /dev/null +++ b/neuttower/map4.json @@ -0,0 +1 @@ +{"neut":{"y":5,"x":20},"map":"61616161616161616261616161616161616161616143C0C0C082E082C0C0636163C0C083C0C0436161C0C0C0C0C0C2C0C0C0C061C0C0C0C0C0C0C06161C0C0C0C0C0C0C0C0C0C061C0C0C0C0C0C0C2616103C0C0A3C0C0C003C0C06163C0C0C0C082A2616161616161C1C1C16161812261618161616161616143C0C0C0C0C0C04361C0C0C0C0C0C0C0C0636181C0C0C0C0C0C0C0C081C0C0C0C0C0C0C0C0C06122C0C0C0C0C0E2C0C0C1A2E2C0C0C0C0C0C0C08161E082828282E0C02361A2C0C0C0C0C0C003236161026161610222616102616161610261616102612121214121212121212121212121412121212121","loadword":"","gord-following":true,"jaye":{"y":4,"x":19},"tickword":"","moveword":"","objects":[{"x":7,"func":"term","y":11,"linkword":"term-dual-link","name":""},{"link":1,"y":3,"func":"term","name":"term-exit","linkword":"","x":2},{"link":1,"y":3,"func":"term","name":"term-scan","linkword":"","x":7},{"x":11,"func":"door","y":7,"linkword":"","name":""},{"link":4,"y":7,"func":"scan","name":"","linkword":"","x":12},{"x":15,"func":"door","y":7,"linkword":"","name":""},{"link":3,"y":7,"func":"switch","name":"","linkword":"","x":7},{"x":10,"func":"door","y":5,"linkword":"","name":""},{"link":4,"y":4,"func":"switch","name":"","linkword":"","x":10},{"x":16,"func":"rexx","y":11,"linkword":"","name":""},{"link":8,"y":2,"func":"scan","name":"","linkword":"","x":7},{"link":13,"y":4,"func":"scan","name":"","linkword":"","x":1},{"x":1,"linkentity":"level5","func":"exitdoor","y":5,"linkword":"exitlevel","name":""},{"x":5,"func":"rexx","y":8,"linkword":"","name":""},{"x":7,"func":"tutorial-chair","linkword":"","name":"","y":10},{"link":6,"x":8,"y":7,"linkword":"","name":"","func":"switch"},{"link":2,"x":6,"y":7,"linkword":"","name":"","func":"switch"}]} \ No newline at end of file diff --git a/neuttower/map5.json b/neuttower/map5.json new file mode 100644 index 0000000..01c244a --- /dev/null +++ b/neuttower/map5.json @@ -0,0 +1 @@ +{"neut":{"y":6,"x":20},"map":"21616161228161616161616161616161616162612102E0C0C0C0C0E0C04361C0C0C0C0C0A3C0C0612161C0C0C0C0C0C0C0C022C0C0C08282C0828261416103C0C0C0C0C0C0C081C0C0C0C0C0C0C0C2C1210203C0C0C0C0C0C04361C0C0C08282838282622161616161816161616161618161616161616161216163C0C0C0C0E0C0C06143C0C0C0C0C0C063612102C0C0C0C0C0C0C0C061C0C0C0C0C0C0C0C0814161C0C0C0C0E2C0E2836101C0C0C0C0C0C0C0C1216143C0C0C082A2A2A281C0C0C043034382E26121610261610261C16102616161026161610261612121212121214121212121212121214121212121","loadword":"","tickword":"doortimer-tick","jaye":{"y":5,"x":19},"gord-following":true,"moveword":"move-garbagerexx","objects":[{"x":17,"func":"garbagerexx","name":"south-rexx","linkword":"","y":11},{"x":17,"func":"garbagerexx","name":"","linkword":"","y":8},{"link":13,"x":20,"y":9,"linkword":"","name":"timedswitch","func":"do-timedswitch"},{"link":16,"x":20,"y":4,"linkword":"","name":"","func":"switch"},{"link":9,"x":12,"y":4,"linkword":"","name":"","func":"term"},{"x":10,"func":"healthyrexx","name":"","linkword":"","y":4},{"link":17,"x":8,"y":2,"linkword":"","name":"","func":"switch"},{"link":10,"x":8,"y":6,"linkword":"","name":"","func":"term"},{"link":5,"x":8,"y":11,"linkword":"","name":"","func":"term"},{"link":8,"x":3,"y":11,"linkword":"","name":"","func":"term"},{"link":12,"x":5,"y":12,"linkword":"","name":"","func":"scan"},{"x":6,"linkentity":"level6","func":"exitdoor","name":"","linkword":"exitlevel","y":12},{"x":6,"func":"door","name":"","linkword":"","y":7},{"x":11,"func":"explodingdoor","name":"","linkword":"","y":9},{"link":14,"x":11,"y":10,"linkword":"","name":"","func":"scan"},{"x":13,"func":"door","name":"","linkword":"","y":7},{"x":11,"func":"door","name":"","linkword":"","y":3}]} \ No newline at end of file diff --git a/neuttower/map6.json b/neuttower/map6.json new file mode 100644 index 0000000..1493c9c --- /dev/null +++ b/neuttower/map6.json @@ -0,0 +1 @@ +{"neut":{"y":1,"x":5},"map":"210261616161616161616161812261616161E1614161C2C081C0C0C0C0C0C0C0C0C0E0C081C0C0622161E04384C0C0C043C0C0C043C0C0C0848201612102616161C0C061610281026161C0C0616161612161C2C0C0C0C061E2C0C0C0A261C0C0C0C0E2612161E003C0C0C061C0C0C0C08261C0C0C003E06121026161C0C0C061E08282E2E061C0C0C06161612161C2C0C0C0C06103C0C0C02361C0C0C0C0C2614161E003C0C0C0616102C1026161C0C0C003E06121026184C0C0C0C043C043C063C0C0C0846161612161E081C0C0C0C0C0C0C0C0C0C0C0C081C083612161612261816161616161616161616161616161","loadword":"","tickword":"","jaye":{"y":2,"x":6},"gord-following":true,"moveword":"","objects":[{"x":3,"func":"c4","y":10,"name":"","linkword":"linkloop","link":6},{"x":5,"func":"keypad2","y":10,"name":"","linkword":"","link":3},{"x":5,"func":"door","y":11,"name":"","linkword":""},{"x":11,"func":"door","y":9,"name":"","linkword":""},{"x":13,"func":"c9","y":6,"name":"","linkword":"linkloop","link":17},{"x":9,"func":"c8","y":6,"name":"","linkword":"linkloop","link":5},{"link":23,"y":4,"func":"switch","linkword":"","name":"","x":11},{"x":3,"func":"c3","y":7,"name":"","linkword":"linkloop","link":1},{"x":3,"func":"c2","y":4,"name":"","linkword":"linkloop","link":8},{"x":3,"func":"c1","y":2,"name":"","linkword":"linkloop","link":23},{"x":4,"func":"door","y":2,"name":"","linkword":""},{"x":4,"func":"keypad1","y":3,"name":"","linkword":"","link":11},{"x":4,"func":"scan","y":1,"name":"","linkword":"","link":4},{"x":17,"func":"door","y":2,"name":"","linkword":""},{"x":17,"func":"keypad3","y":3,"name":"","linkword":"","link":14},{"x":19,"func":"rexx","y":2,"name":"","linkword":""},{"x":19,"func":"c5","y":4,"name":"","linkword":"linkloop","link":18},{"x":19,"func":"c6","y":7,"name":"","linkword":"linkloop","link":19},{"x":19,"func":"c7","y":10,"name":"firewall","linkword":"linkloop","link":10},{"x":19,"func":"switch","y":12,"name":"","linkword":"","link":19},{"x":17,"func":"keypad4","y":10,"name":"","linkword":"","link":22},{"x":17,"func":"door","y":11,"name":"","linkword":""},{"x":15,"func":"cx","y":11,"name":"","linkword":"linkloop","link":9},{"x":14,"func":"scan","y":12,"name":"","linkword":"","link":25},{"x":13,"linkentity":"","func":"exitdoor","y":12,"name":"","linkword":"endgame"}]} \ No newline at end of file diff --git a/neuttower/player.fnl b/neuttower/player.fnl new file mode 100644 index 0000000..d43e868 --- /dev/null +++ b/neuttower/player.fnl @@ -0,0 +1,184 @@ +(local tile (require :game.tiles)) +(local {: vm : mapw : maph : itile : controlstate} (require :neuttower.defs)) + +(local {: walkable : neutable : debris : sittable} tile.flag-to-bit) + +(vm:word :movement-dir ; key -- dyx + (vm:case [(string.byte "I") 0xff00] + [(string.byte "J") 0x00ff] + [(string.byte "K") 0x0001] + [(string.byte "M") 0x0100] + [:else 0x0000])) + +(vm:def :yx+ ; yx yx -- yx + [:lda vm.TOP :x] + [:clc] [:adc vm.ST1 :x] + [:sta vm.ST1 :x] + [:lda vm.TOPH :x] + [:clc] [:adc vm.ST1H :x] + [:sta vm.ST1H :x] + (vm:drop)) + +(vm:var :jaye-yx 0x0a0a) +(vm:var :jaye-dir 0xff00) +(vm:var :neut-yx 0x0b08) +(vm:var :rexx-yx 0xffff) +(vm:var :gord-yx 0xffff) +(vm:var :gord-dir 0x0000) +(vm:var :gord-sitting vm.false) +(vm:var :libb-yx 0xffff) +(vm:var :libb-present vm.false) + +(vm:var :controlstate [:db controlstate.jaye]) +(vm:word :is-jaye? :controlstate :bget controlstate.jaye :=) +(vm:word :is-neut? :controlstate :bget controlstate.neut :=) +(vm:word :is-rexx? :controlstate :bget controlstate.rexx :=) +(vm:word :is-prog? :is-neut? :is-rexx? :|) +(vm:word :is-walking? :movable-player-flag walkable :=) +(vm:word :neut-hidden? :neut-yx :get 0xffff :=) +(vm:word :rexx-active? :rexx-yx :get 0xffff := :not) +(vm:word :gord-hidden? :gord-yx :get 0xffff :=) +(vm:word :gord-following? :gord-hidden? :gord-sitting :get :| :not) +(vm:word :libb-hidden? :libb-yx :get 0xffff :=) + +(vm:word :set-rexx ; e -- + :dup (vm:if [:get controlstate.rexx] [:drop 0xffff controlstate.neut]) + :controlstate :bset :rexx-yx :set) + +(vm:word :player-tile ; -- ptile + :controlstate :bget + (vm:case [controlstate.jaye :jaye-tile] + [controlstate.neut :neut-tile] + [controlstate.gord :gord-tile] + [controlstate.libb :libb-tile] + [:else (itile :t-rexx)]) :lookup-tile) + +(vm:word :player-yx ; -- pyx + :controlstate :bget + (vm:case [controlstate.jaye :jaye-yx] + [controlstate.neut :neut-yx] + [controlstate.gord :gord-yx] + [controlstate.libb :libb-yx] + [:else :rexx-yx])) + +(vm:word :draw-player ; -- + :player-yx :dup (vm:if [:get :dup 0xffff := (vm:if [:drop] [:yx>screen :player-tile :drawtile])] [:drop])) + +(vm:word :set-player-dir ; dir -- + :is-jaye? (vm:if [:jaye-dir :set] [:drop])) + +(vm:var :noclip) +(vm:word :move-if-clear ; yx -- f + :noclip :get (vm:if [:drop vm.false] [:movable-player-flag :flag-at? :not])) + +(vm:word :movable-player-flag ; -- flag + :is-neut? (vm:if [neutable] [walkable])) + +(vm:word :move-player-to ; yx -- + :player-yx :dup :get :dup 0xffff := (vm:if [:drop] [:drawtile-at]) + :set :draw-player) + +(vm:word :transition-gord-sitting ; yx f -- + controlstate.gord :controlstate :bset + :gord-sitting :set :move-player-to + controlstate.jaye :controlstate :bset) + +(vm:word :move-rexx-trash ; yx -- f + (vm:if-and [[:dup debris :flag-at?] [:is-rexx?]] + [(itile :t-floor) :update-itile :snd-garbage] [:drop]) + vm.false) +(vm:word :move-gord-sit ; yx -- f + (vm:if-and [[:dup sittable :flag-at?] [:is-jaye?] [:gord-following?]] + [vm.true :transition-gord-sitting vm.true] + [:move-noop])) +(vm:word :move-gord-stand ; yx -- f + (vm:if-and [[:gord-yx :get :=] [:is-jaye?] [:gord-sitting :get]] + [:jaye-yx :get vm.false :transition-gord-sitting 0 :gord-dir :set vm.true] + [vm.false])) +(vm:word :move-noop :drop vm.false) +(vm:word :handle-general-move ; yx -- f + (vm:if-or [[:dup :map-specific-move] [:dup :move-rexx-trash] [:dup :move-gord-sit] [:dup :move-gord-stand] [:dup :move-if-clear]] + [:drop vm.true] [:move-noop])) + +(vm:def :yxclip? ; yx -- f + [:block + [:lda vm.TOP :x] + [:cmp mapw] + [:bcs :clipped] + [:lda vm.TOPH :x] + [:cmp maph] + [:bcs :clipped] + [:lda 0] [:sta vm.TOP :x] [:sta vm.TOPH :x] (vm:ret) + :clipped + [:lda 0xff] [:sta vm.TOP :x] [:sta vm.TOPH :x]]) + +(vm:word :try-move-player ; dir -- + :dup :set-player-dir ; dir + :player-yx :get :yx+ ; yxnew + (vm:if-or [[:dup :yxclip?] [:dup :touch-entity] [:dup :handle-general-move]] + [:drop :player-yx :get]) + ; always "move" so that player can visibly change direction + ; touch-entity can modify player-yx so we have to refetch + :move-player-to) + +(vm:word :jaye-tile ; ptile + :jaye-dir :get + (vm:case [0xff00 (itile :jaye-n)] + [0x0100 (itile :jaye-s)] + [0x00ff (itile :jaye-w)] + [:else (itile :jaye-e)])) + +(vm:word :gord-tile ; ptile + :gord-sitting :get + (vm:if [(itile :gord-sit)] + [:gord-dir :get + (vm:case [0xff00 (itile :gord-n)] + [0x0100 (itile :gord-s)] + [0x00ff (itile :gord-w)] + [:else (itile :gord-e)])])) + +(vm:var :chuck-mode vm.false) +(vm:word :two-frame :tick-count :get 0x1f :& 0x10 :<) +(vm:word :neut-tile :two-frame :chuck-mode :get (vm:if + [(vm:if [(itile :t-chuck)] [(itile :t-chuck2)])] + [(vm:if [(itile :neut1)] [(itile :neut2)])])) +(vm:word :libb-tile :two-frame (vm:if [(itile :libb1)] [(itile :libb2)])) + +(vm:word :flag-at? ; yx flag -- f + :swap :itile-at :lookup-flags :&) + +(vm:word :toggle-player + (vm:ifchain [:is-prog?] [controlstate.jaye] + [:rexx-active?] [controlstate.rexx] + [:neut-hidden?] [controlstate.jaye] + [controlstate.neut]) :controlstate :bset + :is-prog? (vm:if [:set-prog-tileset] [:set-human-tileset]) :full-redraw) + +(vm:word :party-follow + (vm:if-and [[:is-jaye?] [:gord-following?]] + [controlstate.gord :controlstate :bset + :gord-yx :get :gord-dir :get :yx+ :move-player-to + :jaye-dir :get :gord-dir :set + controlstate.jaye :controlstate :bset])) + +(vm:word :player-key ; key -- + (vm:ifchain + [:dup (string.byte " ") :=] [:drop :toggle-player] + [:dup (string.byte "Z") :=] [:drop :trigger-sidekick] + [:dup 2 :=] [:drop :boss-key] + [:movement-dir :dup] + [:player-yx :get :swap ; oldyx dir + :try-move-player + :dup :player-yx :get := (vm:if [:drop] [:party-follow :untouch-entity :load-next-level])] + [:drop])) + +(vm:word :full-redraw :drawmap :player-redraw) +(vm:word :player-overlaps ; -- f + vm.false :controlstate :bget :player-yx :get + :over (vm:for (vm:i) :controlstate :bset :dup :player-yx :get := (vm:when :rot)) + :drop :controlstate :bset) + +(vm:word :player-redraw + :controlstate :bget + controlstate.count (vm:for (vm:i) :controlstate :bset :player-overlaps :not (vm:when :draw-player)) + :controlstate :bset) diff --git a/neuttower/portraits.json b/neuttower/portraits.json new file mode 100644 index 0000000..fa2f3ab --- /dev/null +++ b/neuttower/portraits.json @@ -0,0 +1 @@ +[{"gfx":"8080808080E0E0F0F8FC2CBCACACACAC80809CFEFFFFFFD7D5D5555D4F5DD5D5BCB8B8B8F8F8F8F8FCFCFEFE86D0D0D495D5D5E5D5D5D5D7C797D7D0AAAAAAAA808086BFFFFFFFFAEAAA2A2E3C2EAAAA80808080808183878787058F8D8D8D8FAAAAAAA7AAAAEAEAE2E8EA8AD5D5D5D58F8F8787878F8F8F9F9FBFBE808A8AAA","label":"pjaye","flags":[]},{"gfx":"00002020000000004808080800202028004040011404450144010805445420352020000808084800000000202000000020544405080144014504140140400000000202012921220122011021222A052D00000405000001011211101100040415052A222110012201222129010202000004040011101112010100000504000000","label":"pneut","flags":[]},{"gfx":"80C090808484848484848484A8A8A8A8AA8080808080D4D4D5D5F59DFDD5D5D5A8A08080808080808080808080E0F8FC95D5D5D5F595D5D4D084D4D4D4D7FFFFD58080808080AAAAAAAABAE2FAAAAAA280828880A0A0A0A1A1A1A1A195959595A0AAAAAAAFA8AAAA8AA0AAAAAAEAFFFF95858181818181808080808080879FBF","label":"pgord","flags":[]},{"gfx":"808080808080C0C0C0C0C0C0C0C0C0C0808080808080AAAAFAFAFAAAAAAAAAAA8080808080C0D0D0D0D0D0D0D0D0D0D0A0A0A0A0A0AAAAAAA8A8A8A8A8A8A8A8808080808080D5D5DFDFDFD5D5D5D5D5808080808080828282828282828282828585858585D5D5D595959595959595958080808080828A8A8A8A8A8A8A8A8A8A","label":"prexx","flags":[]},{"gfx":"808080F8F8F8F8F8F8B8B8F8F8B8B8F8808080FFFFFFFFDFDFFDFDDFDFFDFDDFF8B8B8F8F8B8B8F8F8F8F8F8F8D0D080DFFDFDDFDFFDFDDFDFFFFFFFFFAAAA80808080FFFFFFFFFEFEAFAFFEFEAFAFFE8080808FAFAFAFAFAFAFAFAFAFAFAFAFFEAFAFFEFEAFAFFEFEFFFFFFFFD5D580AFAFAFAFAFAFAFAFAFAFAFAFAFAAAA80","label":"ppady","flags":[]},{"gfx":"0080C07070303030303030303030303000AAAA7F0045001400150051005400003030707000703018187C4C7E000000000000007F007F0000007F017F0000000000D5D57F400A0028000A002000080000008A8A8B8B8B8B8B8B8B8B8B8B8B8B8B0000407F007F6030301F187F000000008B8B8B03000F0C060603030100000000","label":"pterm","flags":[]},{"gfx":"80808080808080A0C0A0C0A0808088AA8080808080808185AA858285C1D0A0D0D4AA94AA94AA888080A0C0A0C0A08080AAD2A2D2A2D2A2D2C185AA858285818080A0A8D0A8A09090D581A1C1A0C2A1C280808180818080808081858285828582A1828182959291929090D5808080808085818080808084958A958A958A958480","label":"plibb","flags":[]},{"gfx":"808080808080808088A082A8A0AAA8AA849494D4D4D4D0D5D4D1D5D58595D5D5AAAA8AAA8AAA82AA828A808280808080D4D5D4D5D4D5D4D4D4D4D0C0C0C080808080808080A288A2A08AA2AAAAAAAAAA84949495958585808181848184848581AAAAAA8AAA8AAA8AAAAAA8A2A2AAAA8080818181818181818585818185818080","label":"pchuck","flags":[]}] \ No newline at end of file diff --git a/neuttower/tiles.fnl b/neuttower/tiles.fnl new file mode 100644 index 0000000..6c80f1b --- /dev/null +++ b/neuttower/tiles.fnl @@ -0,0 +1,84 @@ +(local util (require :lib.util)) +(local lume (require :lib.lume)) + +(local flags [:walkable :neutable :debris :sittable]) +(local flag-to-bit {}) +(each [iflag flag (ipairs flags)] + (tset flag-to-bit flag (bit.lshift 1 (- iflag 1)))) + +(local encoded-tile-fields [:gfx :neut :mask]) +(fn convert [tile field method] + (local oldval (. tile field)) + (when oldval + (tset tile field (: oldval method))) + tile) +(fn convert-all [tile method] + (each [_ field (ipairs encoded-tile-fields)] + (convert tile field method)) + tile) + +(fn deserialize [tile] + (match (type tile) + :string {:gfx (tile:fromhex) :flags {}} + :table (convert-all tile :fromhex))) + +(fn serialize [tile] (convert-all (lume.clone tile) :tohex)) + +(local fn-tiles "game/tiles.json") +(local fn-portraits "game/portraits.json") +(local fn-font "game/font.json") + +(fn loadgfx [filename] (lume.map (util.readjson filename) deserialize)) +(fn savegfx [filename gfx] (util.writejson filename (lume.map gfx serialize))) + +(fn appendgfx [org gfx ?key ?ignore-labels] + (each [_ g (ipairs gfx)] + (when (and g.label (not ?ignore-labels)) (org:append g.label)) + (org:append [:bytes (. g (or ?key :gfx))]))) + +(fn appendtiles [org] + (local tiles (loadgfx fn-tiles)) + (org:append [:align 0x100] :jaye-tileset) + (appendgfx org tiles) + (org:append [:align 0x100] :neut-tileset) + (appendgfx org tiles :neut true) + (appendgfx org (loadgfx fn-portraits)) + (org:append :tileflags) + (each [_ tile (ipairs tiles)] + (var flags 0) + (each [flag _ (pairs tile.flags)] + (set flags (bit.bor flags (. flag-to-bit flag)))) + (org:append [:db flags]))) + +(fn append-portraitwords [vm ?overrides] + (local overrides (or ?overrides {})) + (each [_ p (ipairs (loadgfx fn-portraits))] + (let [wordname (.. :draw- p.label) + override (. overrides p.label)] + (vm:word (.. :draw- p.label) :show-footer + (if override (override p.label) [:vm :lit p.label]) + :draw-portrait)))) + +(fn encode-yx [xy] + (if xy (bit.bor (bit.lshift (- xy.y 1) 8) (- xy.x 1)) 0xffff)) + +(fn encode-itile [itile] + (bit.bor + (bit.lshift (bit.band (- itile 1) 0x07) 5) + (bit.rshift (bit.band (- itile 1) 0xf8) 3))) + +(fn decode-itile [enctile] + (+ 1 (bit.bor + (bit.lshift (bit.band enctile 0x1f) 3) + (bit.rshift (bit.band enctile 0xe0) 5)))) + +(fn find-itile [tiles label ?itilenext] + (local itile (or ?itilenext 1)) + (local tile (. tiles itile)) + (assert (not= tile nil) (.. "No such tile " label)) + (if (= tile.label label) (encode-itile itile) + (find-itile tiles label (+ itile 1)))) + +{: loadgfx : savegfx : appendtiles : appendgfx : append-portraitwords : flags : flag-to-bit : find-itile + : fn-tiles : fn-portraits : fn-font : encode-yx : encode-itile : decode-itile} + diff --git a/neuttower/tiles.json b/neuttower/tiles.json new file mode 100644 index 0000000..ce81f65 --- /dev/null +++ b/neuttower/tiles.json @@ -0,0 +1 @@ +[{"neut":"5F5F1F03090923436943230909031F5F7A7A784111104542174245101141787A","label":"neut1","flags":[],"word":"","gfx":"7F7F1F03090923436943230909031F7F7F7F784111104542174245101141787F"},{"neut":"5F1F03090923436943230909031F5F5F7A784111104542174245101141787A7A","label":"neut2","flags":[],"word":"","gfx":"7F1F03090923436943230909031F7F7F7F784111104542174245101141787F7F"},{"neut":"808080C0C0C0E0C0D0C8C04040404080808083058585828A9282820A08081980","label":"jaye-e","flags":[],"word":"","gfx":"808080C0C0C0E0C0D0C8C04040404080808083058585828A9282820A08081980"},{"neut":"8080C020A0A0C0C0D0C8C0501010188080808183838782828A8A920202020380","label":"jaye-w","flags":[],"word":"","gfx":"8080C020A0A0C0C0D0C8C0501010188080808183838782828A8A920202020380"},{"neut":"8080E030B0B098C0D0D0C840404060808080870D8D8D99828A8A920202020780","label":"jaye-s","flags":[],"word":"","gfx":"8080E030B0B098C0D0D0C840404060808080870D8D8D99828A8A920202020780"},{"neut":"8080C0E0E0E0B0C0D0C8C040404060808080838787878D828A92820202020780","label":"jaye-n","flags":[],"word":"","gfx":"8080C0E0E0E0B0C0D0C8C040404060808080838787878D828A92820202020780"},{"neut":"8080808080808080808080808080808080808080808080808080808080808080","label":"t-floor","flags":{"walkable":true},"word":"","gfx":"80808C8080808080B08080808C808080808C80808083B0808080808080868080"},{"neut":"80FC8C8C8C8CFC80FCFEFE8080808080809F989898989F809F8F878080808080","label":"termoff","flags":[],"word":"term","gfx":"007C0C0C0C0C7C007C7E7EAA88888800001F181818181F001F0F979584848400"},{"neut":"507C2C2C2C2C7C557D7D7E005F5F5F5F0A3F353535353F2A3F2F67707A7A7A7A","label":"termon","flags":{"neutable":true},"word":"term","gfx":"007C2C0C0C2C7C007C7E7EAA88888800001F18191C191F001F0F979584848400"},{"neut":"D5D5D5D5D5D5D5D5D5D5D5D5D5D5D5D5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","label":"","flags":[],"word":"","gfx":"D5D5D5D5D5D5D5D5D5D5D5D5D5D5D5D5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},{"neut":"D5D5D5D581F9F9F9F9C195D5D5D5D5D5AAAAAAAAAA809F9F9F9F80AAAAAAAAAA","label":"","flags":[],"word":"","gfx":"D5D5D5D5D5F5F5FDDDD5D5D5D5D5D5D5AAAAAAAAAEAEBFBFBFABAAAAAAAAAAAA"},{"neut":"5F5F5F5F5F5F57555555575F5F5F5F5F7A7A7A7A7A7A6A2A2A2A6A7A7A7A7A7A","label":"","flags":{"neutable":true},"word":"","gfx":"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},{"neut":"8080F8F8F8F8F8F8F8F8F8F8F8F8808080808F8F8F8F8F8F8F8F8F8F8F8F8080","label":"doorclosed","flags":[],"word":"door","gfx":"FF8FA7B3B3B3B3B3B3B3B3B3B3B383FFFFF8F2E6E6E6E6E6E6E6E6E6E6E6E0FF"},{"neut":"8080FC8C8C8C8C8C8C8C8C8C8CFC808080809F989898989898989898989F8080","label":"dooropen","flags":{"walkable":true},"word":"door","gfx":"FF8F87838383838383838383838383FFFFF8F0E0E0E0E0E0E0E0E0E0E0E0E0FF"},{"neut":"5F5F5F5F0F0705050505070F5F5F5F5F7A7A7A7A70602020202060707A7A7A7A","label":"switchoff","flags":{"neutable":true},"word":"switch","gfx":"FFFFCFCFCFCF898183838787878FFFFFFFFCE4E4E4E4E0E0E0E0E0E0F0F8FFFF"},{"neut":"5F5F5F5F0F0725252525070F5F5F5F5F7A7A7A7A70602525252560707A7A7A7A","label":"switchon","flags":{"neutable":true},"word":"switch","gfx":"FFFFCFCFCFCF898123232727878FFFFFFFFCE4E4E4E0E0616565656571F8FFFF"},{"neut":"808080D0D0D0D0D0D0D0D0D0D08080808080808A8A8A8A8A8A8A8A8A8A808080","label":"","flags":[],"word":"","gfx":"FFFF83D3D3D3D3D3D3D3D3D3D383FFFFFFFFC0CACACECACBCACACACACAC0FFFF"},{"neut":"5F5F5F5F7F0F0D0D0D0D0F0F7F5F5F5F7A7A7A7A7F703030303070707F7A7A7A","label":"scanoff","flags":{"neutable":true},"word":"scan","gfx":"FFFFAFEBFBFBFBBBBBFBFBFBEBAFFFFFFFFFF5D7DFDFDFDDDDDFDFDFD7F5FFFF"},{"neut":"5F5F5F5F7F2F2D2D2D2D2F2F7F5F5F5F7A7A7A7A7F753535353575757F7A7A7A","label":"scanon","flags":{"neutable":true},"word":"scan","gfx":"FFFF2F2B2B2B6B6B6B6B2B2B2B2FFFFFFFFF755555555757575755555575FFFF"},{"neut":"9EF3C68CB3E7F88086BEE0E0B09898C6F8CFE1B18C8C988E868C99B0E6CE8F99","label":"","flags":[],"word":"","gfx":"FFF3C78FBFFCF98187BFFFFFBF9F9FC7FFCFE1F1FCFCF8FEFEFCF9F0E6CE8F9F"},{"neut":"8080808080D4848484D48484848480808080808080AAA0A1A0AAA0A0A0A08080","label":"","flags":[],"word":"","gfx":"80808C80808080A8AAAAAAA888888880808C8080808380859595958584848480"},{"neut":"8080808080D4808480D48084808480808085848581AA80A180AA80A080A08080","label":"broken-table","flags":{"debris":true},"word":"","gfx":"80808C8080A0A0A8AAAA8AA0A8808080808C8081919090848594959585858080"},{"neut":"808080D09090D0C0C0D48484D490B8808080808A88888A8282AAA0A0AA889C80","label":"t-chair","flags":{"sittable":true},"word":"","gfx":"00005054545450404054545010383800000C0A2A2A2A0A03032A2A0A081C1C00"},{"neut":"808080809080D080C0808480D480B8808085848589808A818280A080AA809C80","label":"","flags":{"debris":true},"word":"","gfx":"0000001C1C10545040606010545454000030070702020A0A0100020A080A0200"},{"neut":"8080808080D48484D48484D48484D48080808080808A88888A88888A88888A80","label":"","flags":[],"word":"","gfx":"80A0A8AA92D2D2AAC2C2AA92D2AA808080959595949494959494959494858080"},{"neut":"8080808080808480D48084808480D48080858485818089808A80888088808A80","label":"","flags":{"debris":true},"word":"","gfx":"80808C808080A8C292AAAAAAAA8AC0D0808C80808083959290959194948580A8"},{"neut":"8080D4C4D4C0D4C4D4C0C0D48484D48080808A888A808A888A80808A88888A80","label":"","flags":[],"word":"","gfx":"80806008282A0800202880A8A8A8A08080980000141501051511819595958580"},{"neut":"8080D4809480D480D480C0808480D4808085848589808A818A80808088808A80","label":"","flags":{"debris":true},"word":"","gfx":"80808C808080A0A8AAAA8AA2AAAAAA80808C0000000330010105051511010514"},{"neut":"80D0D0D0C0D4C4C4CECAC0E0A0808080808A8B8A82AAA2A2F2D2828785808080","label":"t-rexx","flags":[],"word":"rexx","gfx":"80D0D0D0C0D4C4C4CECAC0E0A0808080808A8B8A82AAA2A2F2D2828785808080"},{"neut":"F8989898BE8686868686BEB098F880809F989898FCE0E0E0E0E0FC8C989F8080","label":"t-rexxstop","flags":[],"word":"rexx","gfx":"F8989898BE8686868686BEB098F880809F989898FCE0E0E0E0E0FC8C989F8080"},{"neut":"8080808088A8A8E0E0F0C8C0C0C08080808080808080808183838282829A8080","label":"gord-ground","flags":[],"word":"","gfx":"80808C8088A8A8E0E0F0C8C0CCC08080808C80808080B08183838282829A8080"},{"neut":"808080A0A080F0F0F0E8D0D09090988080808081818083838385828282828680","label":"gord-s","flags":[],"word":"","gfx":"808080A0A080F0F0F0E8D0D09090988080808081818083838385828282828680"},{"neut":"80C09090A080F0F0F0F0D0D09090988080808282818083838383828282828680","label":"gord-n","flags":[],"word":"","gfx":"80C09090A080F0F0F0F0D0D09090988080808282818083838383828282828680"},{"neut":"808080A0A080F0F0F0F0D0D09090B08080808181818081838581808282828680","label":"gord-e","flags":[],"word":"","gfx":"808080A0A080F0F0F0F0D0D09090B08080808181818081838581808282828680"},{"neut":"8080A0A0A080E0F0E8E0D0D09090988080808081818083838383828282828380","label":"gord-w","flags":[],"word":"","gfx":"8080A0A0A080E0F0E8E0D0D09090988080808081818083838383828282828380"},{"neut":"8088A8A880F0F0F8B8D4D4C4C4E486808080808A88888A8181AAA0A0AA889C80","label":"gord-sit","flags":[],"word":"","gfx":"0088A8A8047470F8B8D4D4C4C4E40600000C0A2A2A2A0A81812A2A0A081C1C00"},{"neut":"FF81F9B9E9B9E9B9E9B9E9B9F9F981FFFFE0E7E7E5E7E5E7E5E7E5E7E7E7E0FF","label":"t-keyoff","flags":[],"word":"keypad","gfx":"FF81F9B9E9B9E9B9E9B9E9B9F9F981FFFFE0E7E7E5E7E5E7E5E7E5E7E7E7E0FF"},{"neut":"7F01793969396939693969397979017F7F60676765676567656765676767607F","label":"t-keyon","flags":[],"word":"keypad","gfx":"7F01793969396939693969397979017F7F60676765676567656765676767607F"},{"neut":"5F8FA7C7A389D189838FA7C7A70F5F5F7AF0C4928A91C0F1F2C1928A90427A7A","label":"libb1","flags":[],"word":"","gfx":"FF8FA7C7A389D189838FA7C7A78FFFFFFFF0C4928A91C0F1F2C1928A90C7FFFF"},{"neut":"5F5F8FA7C7A389D189838FA7C7A70F5F7A7AF0C4928A91C0F1F2C1928A90427A","label":"libb2","flags":[],"word":"","gfx":"FFFF8FA7C7A389D189838FA7C7A78FFFFFFFF0C4928A91C0F1F2C1928A90C7FF"},{"neut":"5F5F5F8FA3A9A9A3A7A7A7A7A70F5F5F7A7A7A7A7AE0C5959595909292427A7A","label":"t-chuck","flags":[],"word":"","gfx":"FFFFFF8FA3A9A9A3A7A7A7A7A78FFFFFFFFFFFFFFCE0C5959595909292C7FFFF"},{"neut":"5F5F8FA3A9A9A3A7A7A7A7A78F5F5F5F7A7A7A7860C5959595909292C27A7A7A","label":"t-chuck2","flags":[],"word":"","gfx":"FFFF8FA3A9A9A3A7A7A7A7A78FFFFFFFFFFFFFFCE0C5959595909292C7FFFFFF"}] \ No newline at end of file diff --git a/neuttower/title.screen b/neuttower/title.screen new file mode 100644 index 0000000..06b3de7 --- /dev/null +++ b/neuttower/title.screen @@ -0,0 +1 @@ +"D5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD52A552A552A552A552AD5AAD5AAD5AAD5AAD5AA552A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA85FEFFFFFFFFFFFFFFFFFFFF9FFCFFFFFFFFFFFFD5AAFF83D5AAD5FFFFBFD5AA0000000000000000D5AAD5AAD5AAD5AAD5AAD5AA552A55AA552A550AFFAFD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAF5FFDFFAD5F0D7AAF5EAFFAFD5AAD5FF9FFCFFAAD5FEFFABFDEBFF80D5AAF5AFD5AAD5AA0000000000000000D5AAD5AAD5AAD52A552A552A552A157E3F7E052E552A552A552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5EAFFFFFFFFFFFFD7C2FFAAD5AAFFBFD5FAD5FF9FFCD7AAD7FEFFABD7EA9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD52A5534552A292D252B292B5578453F552A552A552A552A5A526A522A2D55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA80F0FFFFFFFFFFFFBF808080808080AAD5AAD5AAD5AAD5AAD5FEFFFFFFFFFFFFD58AF8AFD5AAFFFFD5AAD5FF9FFCDFAAD5FEFFABF5FF9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AA5554555255525534252B252D5578153E552A25552A53552A5A346A4A562A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AA9580C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FC0AAD5AAD5AAD5AAD5FEFFFFFFFFFFAFD5AAE1FFFFFFFFFFFFFFFFFF9FFCDFFAFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000552A552A55546A4A5A526A2A152D152D55621778552A252B2553294D5A34254B5A2A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA80E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF80F0BFD0AAD5AAD5AADFAAD5FEFFAFD5AAD5AAD5AA85FEFFFFFFFFFFFFFFFFBFF0FFFFFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000552A552A555216555A4A2A5556542A355562577855625F2A552A5A2A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD58A8080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81C0FFFFFFFF8FD4AAD5AAFDFFFFAAD5AAD5AAD5AAD5AAD5AAD5F0FFFFFFFFFFFFFFFFFFF0FFFFFFFFFFBFD5FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AA552A5A2A552A552A552A550A707F15787F2A552A552A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAE1FFFFFFFFFFFFFFFFFF8380B880F0FFFFFFFFFFFFFFFF8FD4AAF5FFFFFFFFAAD5AAD5AAD5AAD5AAD5AAD582DEAAD5FADFAAD5FAFFC3FFAFD5FAFFABF5FAC0AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD52A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA85FCFFFFFFFFFFFFFFFFFFFF9FFCFFFFFFFFFFAFD5AAFF83D5AAFDFFFFAFD5AA0000000000000000D5AAD5AAD5AAD5AAD5AAD5AA552A552A552A55627FABD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAFDFFDFFED7F0D7AAF5EAFFAFD5AAD5FF9FFCDFAAD5FEFFABFDEBFF80D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AA552A552A552A552A157E1F7E452F552A552A552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA8180D0A8D5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5EAFFFFFFFFFFFFD782FFAAD5AAFFBFD5BAD5FF9FFCD7EAD7FEFFABD5EA9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD52A5534552A2A35252B292B5578053E552A552A552A552A5A526A522A2D55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD58280F8FFFFFFFFFFFFFFFF808080808080D4AAD5AAD5AAD5AAD5FEFFFFFFFFFFFFD58AF8AFD5AAFFFFD5AAD5FF9FFCDFAAD5FEFFABFFFF9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AA5554555256521535252B252D5578153E552A25552953552A5A346A4A562A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AA8180F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FC0AAD5AAD5AAD5AAD5FEFFFFF7FFFFABD5AAE1FFFFFFFFFFFFFFFFFF9FFCFFFFFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000552A552A55526A4A5A526A2A152D252D55621778552A252B2553294D5A34252B5A2A55AAD5AAD5AAD5AAD5AAD5AAD5AAD58280FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8380FFBFD0AAD5AAD5EADFAAD5EAFFAFD5AAD5AAD5AA85FCFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFF83AAD5AAD5AAD5AAD5AA0000000000000000D52A552A555256545A4A2A5556546A2A55625778157E5F2A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD58A8080C0FFFFFFFFFFFFFFFFFFFFFFFFFFBF80FCFFFFFFFF8FD4AAD5AAFDFFFFAAD5AAD5AAD5AAD5AAD5AAD5F0FFFFFFFFFFFFFFFFFFF0FFFFFFFFFFABD5FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AA552A5A2A552A552A552A550A7C3F55785F2A552A552A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAE1FFFFFFFFFFFFFFFFFFFF878080FCFFFFFFFFFFFFFFFF8FD4AAF5FFFFFFFFAAD5AAD5AAD5AAD5AAD5AAD582DEAAD5FADFAAD5EAFFC3FFAAD5FAFFABF5BAC0AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD58AD7AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD52A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA85FCDFFEF5FFFFFFFFFFFFFF9FFCFFFFFFFFFFABD5AAFF83D5AAFDFFF7AAD5AA0000000000000000D5AAD5AAD5AAD5AAD5AA552A552A552A552A55785FAAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAFFFFFFFED7E0DFAAF5EAFFAFD5AAD5FF9FFCD7AAD5FEFFABFDEAFFA0D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AA5534552A552A552A153E5778452F552A552A552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA8080808080AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5FAFFFFFFFFFFFFD582FEABD5AAFFBFD5AAD5FF9FFCD7EAD7FEFFABD5EA9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD52A5534552A2A35252B292B5578053E552A552A552A552A5A526A522A2D552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD58280FEFFFFFFFFFFFFFFFFFF8180808080D0AAD5AAD5AAD5AAD5FEFFFFFFFFFFBFD5AAF0AFD5EAFFFFD5AAD5FF9FFCDFAAD5FEFFEBFFFF9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AA5554555256521535252B252D5578153E552A252B2553252B5A545A4A562A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AA8080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87C0AAD5AAD5AAD5AAD5FEFFFFF7FFFFAAD5AAC1FFFFFFFFFFFFFFFFFF9FFCFFFFFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000552A552A5552294B5A525A2A152D252D55621778552A252D29532A555654292B552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD580F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80F8FFBFD0AAD5AAD5EAFFAAD5EAFFABD5AAD5AAD5AA85FCFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFF81AAD5AAD5AAD5AAD5AA0000000000000000D5AAD52A554A5A545A2A2A5555525A2A55625778457F5F2A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD58A8080808080FEFFFFFFFFFFFFFFFFFF9F8C80FFFFFFFFFF8FD4AAD5AAFFFFFFAAD5AAD5AAD5AAD5AAD5AAD5E0FFFFFFFFFFFFFFFFFFF0FFFFFFFFFFABD5FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AA552A5A2A552A552A552A550A7C2F5538572A552A552A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAE1FFFFFFFFFFFFFFFFFFFFFF87F8FFFFFFFFFFFFFFFFFF87D4AAF5FFFFFFFFAAD5AAD5AAD5AAD5AAD5AAD58ADCAAFDFADFAAD5EBFFC3FFAAD5FAFFABF5BEC0AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5F8D7AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA95FCDFAAD5FEFFFFFFFFFFFF9FFCFFFFFFFFFFABD5EAFF83D5AAFDFFD5AAD5AA0000000000000000D5AAD5AAD5AAD5AAD52A552A552A552A5538157E572AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAFFFFFFFFD7C0DFAAF5EAFFAFD5AAD5FF9FFCD7AAD5FEFFABFDEAFFA0D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AA5534552A552A552A153E5578452F552A552A552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD58A808080808080D0AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5FAFFFFFFFFFFFFD582FEABD5AAFFBFD5AAD5FF9FFCD7EAD7FEFFABD5EA9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AA552A5554552A5A34252B292B5578053E552A552A5552552A5A52694A6A2A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD580F0FFFFFFFFFFFFFFFFFFFFFFFFFF8080C0AAD5AAD5AAD5AAD5FEFFFFFFFFFFBFD5AAE0BFF5FFFFFFD5AAD5FF9FFCDFAAD5FEFFFFFFFF8FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD52A555456525652152D252B152D5578153E552A252B2553252B5A545A4A562A552A552A552AD5AAD5AAD5AAD5AAD5AAD58A80F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81C0AAD5AAD5AAD5AAD5FEFFFFD7FFFFAAD5AA81FFFFFFFFFFFFFFFFFF9FFCFFFFFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000552A552A5552294B5A52552A152D252D55625778552A252D29532A5556542A2B552AD5AAD5AAD5AAD5AAD5AAD5AAD58AD580FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8780FEFFBFD0AAD5AAD5EAFFAAD5AAF5ABD5AAD5AAD5AA95FCFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD52A554A5A545A2A2A2D552A552A15605778757F572A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD58AF88780808080C0FFFFFFFFFFFFFFBF8080E0FFFFFFFFFF8FD4AAD5FAFFFFFFAAD5AAD5AAD5AAD5AAD5AAD5C0FFFFFFFFFFFFFFFFFFF0FFFFFFFFFFABD5FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AA552A5A2A552A552A552A55627F2A550A572A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAC1FFFFFFFFFFFFFFFFFFFFFF87FCFFFFFFFFFFFFFFABFF83D4AAF5FFFFFFFFAAD5AAD5AAD5AAD5AAD5AAD58AD8AAFDEADFAAD5EBFFC3FFAAD5FAFFABF5FEC0AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA95FED7AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA95F8D7AAD5FEFFFFFFFFFFFF9FFCFFFFDFFEFFABF5EAFF83D5AAFDFFD5AAD5AA0000000000000000D5AAD5AAD5AAD5AA552A552A552A552A457F157E552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5EAFFFFFFFFD7C0DFAAD5EAFFAFD5AAD7FF9FFCD7AAD5FEFFABFDEAFFA0D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AA5534552A552A552A552A5578452F552A552A552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5808080808080808082D4AAD5AAD5AAD5AAD5AAD5AAD5AAD5FAFFFFFFFFFFFFD58AFEABD5AAFFBFD5AAD5FF9FFCD7EAD5FEFFABD5EA9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AA552A5554554A5A34252B252B5578153E552A55545652552A5A54694A5A2A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA8580FCFFFFFFFFFFFFFFFFFFFFFFFFFFBF80C0AAD5AAD5AAD5AAD5FEFFFFFFFFFFBFD5AAE0FFFFFFFFFFD5AAD5FF9FFCDFAAF5FFFFFFFFFF87A8D5AAD5AAD5AAD5AA0000000000000000D5AAD52A55545A525652252D252B152D5578153E552A252B2553252B5A54564A562A552A552A552AD5AAD5AAD5AAD5AAD5AAD580C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F80C0AAD5AAD5AAD5AAD5FEFFFFD5FAFFAAD5AA81FFFFFFFFFFFFFFFFFF9FFCFFFFFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000552A552A5552264D5A52552A152D252D55625778552A25356A4A2A5556522A2B552AD5AAD5AAD5AAD5AAD5AAD5AAD58A8080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF80C0FFFFBFD0AAD5AAD5FAFFAAD5AAD5AAD5AAD5AAD5AA95FCFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFDFFAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD52A554A5A4A5A2A552A552A552A156017787F7F552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAF8FF8080808080808080FCFFFFFF838080FEFFFFFFFFFF8FD4AAD5FAFFFFDFAAD5AAD5AAD5AAD5AAD5AAD5C0FFFFFFFFFFFFFFFFFFF0FFFFFFFFFFABF5FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AA552A552A552A552A552A55625F2A552A552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA81FFFFFFFFFFFFFFFFFFFFFF87FEFFFFFFFFFFFFFFAAFF83D4AAF5FFFFFFDFAAD5AAD5AAD5AAD5AAD5AAD58AF8AADDEADFAAD5EBFFC3FFAAF5FAFFABD5FEC0AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA85FED7AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5BED5AA95F0D7AAD5FAFFAFD5EAFFFF9FFCFFFFD5FEFFABF5EBFF83D5AAF5FFD5AAD5AA0000000000000000D5AAD5AAD5AAD5AA552A552A552A552A7C7F153E552A552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAF5EFFFFFFFFFD7C2DFAAD5EAFFAFD5AAD7FF9FFCD7AAD5FEFFABD7EAFFA0D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AA5534552A552A552A552A5578452F552A552A552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA9580F09F808080808080C0AAD5AAD5AAD5AAD5AAD5AAD5AAD5FEFFFFFFFFFFFFD58AFEABD5AAFFBFD5AAD5FF9FFCD7EAD5FEFFABD5EA9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AA55345552554A5634252B252B5578153E552A15555A52552A5A54694A5A2A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA81E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8780AAD5AAD5AAD5AAD5FEFFFFFFFFFFBFD5AAE0FFFFFFFFFFFFAAD5FF9FFCDFAAF5FFFFFFFFFF87A8D5AAD5AAD5AAD5AA0000000000000000D5AAD52A55545A525652252D252D152D5562153E552A252B2553252B5A54554A5A2A552A552A552AD5AAD5AAD5AAD5AAD5AA9580E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A0C0AAD5AAD5AAD5AAD5FEFFFFD5EAD7AAD5AA81FFFFFFFFFFFFFFFFFF9FFCFFFFFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000552A552A555226555A52564A1635252D5562177E552A15556A4A6A54564A2A2B552AD5AAD5AAD5AAD5AAD5AAD5AAD58A80E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8380FCFFFF9FD0AAD5AAD5FAFFAAD5AAD5AAD5AAD5AAD5AA95F8FFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFDFFAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD52A554A5A4A5A2A552A552A552A056017787F2F552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAF0FFBF8080808080808080E0FFFF8080CCFFFFFFFFFFFF8FD4AAD5FEFFFFDFABD5AAD5AAD5AAD5AAD5AAD5C2FFFFFFFFDFAAD5FEFFE0FFFFFFFAFFABF5FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AA552A552A552A552A552A5562DFAA552A552A552A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA81FFFFFFFFFFFFFFFFFFFFFF87FCFFFFFFFFFFFFFFAAFF83D5AAF5FFFFFFD7AAD5AAD5AAD5AAD5AAD5AAD5AAF8AADDEADFAAD5EAFFC3FFAAF5FAFFABD5BEC0AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAF1FFD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAF5FFD5AA95F0D7AAD5FAFFAFD5AAFFFF9FFCFFBFD5FEFFABF5EBFF83D5AAF5BFD5AAD5AA0000000000000000D5AAD5AAD5AAD52A552A552A552A550A7F7F153E552A552A552A552A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAFDEFFFFFFFFFD7C2DFAAD5EAFFAFD5AAD7FF9FFCD7AADDFEFFABD7EABFA0D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD52A5534552A552A552A552A5578452F552A552A552A552A552A554A162D55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA9580FCFFBFF8808080808080D5AAD5AAD5AAD5AAD5AAD5AAD5FEFFFFFFFFFFFFD58AFCABD5AAFFFFD5AAD5FF9FFCD7EAD5FEFFABD5FA9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AA5534555255525634252B252B5578153E552A15555A52552A5A34694A562A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD58A80F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F80AAD5AAD5AAD5AAD5FEFFFFFFFFFFBFD5AAE0FFFFFFFFFFFFAFD5FF9FFCDFAAFDFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000D5AA552A55545A525652292B252D152D5562177E552A252B2553252B5A34554A5A2A552A552A552AD5AAD5AAD5AAD5AAD5AA8580F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8780B8D0AAD5AAD5AAD5AAD5FEFFBFD5AAD5AAD5AA85FFFFFFFFFFFFFFFFFF9FFCFFFFFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000552A552A555226555A52564A1635293555621778552A55545A4A6A54562A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD58A80F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8080FFFFFF8FD0AAD5AAD5FAFFAAD5AAD5AAD5AAD5AAD5AA95F0FFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFD7FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD52A552A5A2A552A552A552A552A017817787F2F552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAE0FFFFFFFF81808080808080FC8780E0FFFFFFFFFFFFFF8FD4AAD5FFFFFFDFABD5AAD5AAD5AAD5AAD5AAD5C2FFABF5FFDFAAD5FAFFC0FFFFDFFAFFABF5FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AA552A552A552A552A552A55E2D7AAD52A552A552A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA81FFFFFFFFFFFFFFFFFFFFFF8FFCFFFFFFFFFFFFDFAAFF83D5AAF5FFFFFFD7AAD5AAD5AAD5AAD5AAD5AAD5AAF8AADDEADFAAD5EAFFC3FFAAF5FEFFABD5BEC0AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAFCBFD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAF5FFD7FA95F0D7AAD5FAFFAFD5AAD5FF9FFCFFABD5FEFFABF5EBFF81D5AAF5AFD5AAD5AA0000000000000000D5AAD5AAD5AAD52A552A552A552A55787F7F153E552A552A552A552A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAFFFFFFFFFFFFD7C2FFAAD5AAFFBFD5EAD7FF9FFCD7AADFFEFFABD7EA9FA0D5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD52A5534552A292B552A292B5578452F552A552A552A552A554A5A52262D55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA81E0FFFFFFFFFFFF80808080808080AAD5AAD5AAD5AAD5AAD5FEFFFFFFFFFFFFD58AF8ABD5AAFFFFD5AAD5FF9FFCDFAAD5FEFFABD5FF9FA8D5AAD5AAD5AAD5AA0000000000000000D5AAD5AA5534555255525634252B252D5578153E552A25556A52552A5A34694A562A552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD58080FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0AAD5AAD5AAD5AAD5FEFFFFFFFFFFAFD5AAE1FFFFFFFFFFFFFFD7FF9FFCDFAAFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000D5AA552A55545A525A522A2B152D152D55621778552A252B2553292D5A34554A5A2A552A552A552AD5AAD5AAD5AAD5AAD5AA8180FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8180BED0AAD5AAD5AAD5AAD5FEFFBFD5AAD5AAD5AA85FFFFFFFFFFFFFFFFFF9FF8FFFFFFFFFFFFFFFF87AAD5AAD5AAD5AAD5AA0000000000000000552A552A555216555A4A5652563429355562177855625752564A6A54552A552A552AD5AAD5AAD5AAD5AAD5AAD5AAD58A80E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F80F8FFFFFF8FD0AAD5AAF5FFFFAAD5AAD5AAD5AAD5AAD5AA95F0FFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFD5FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD52A552A5A2A552A552A552A552A407917787F2B552A552A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAE1FFFFFFFFFFBF8080808080F88180FEFFFFFFFFFFFFFF8FD4AAF5FFFFFFFFAAD5AAD5AAD5AAD5AAD5AAD582FFAAD5FADFAAD5FAFFC1FFBFD5FAFFABF5FAC1AAD5AAD5AAD5AAD5AA0000000000000000D5AAD5AAD52A552A552A552A552AD5AAD5AAD5AAD52A552A552A552A55AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AAD5AA85FEFFFFFFFFFFFFFFFFFFFF9FFCFFFFFFFFFFFFD5AAFF83D5AAF5FFFFFFD5AAD5AAD5AAD5AAD5AAD5AAD5AAF8AADDEAFFAAD5EAFFE7FFAAF5FEFFAFD5BED0AAD5AAD5AAD5AAD5AA0000000000000000" \ No newline at end of file