Skip to content

Instantly share code, notes, and snippets.

@AlecTroemel
Created October 3, 2021 21:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlecTroemel/bb55751106dac8f84a5870fce2d4fdd5 to your computer and use it in GitHub Desktop.
Save AlecTroemel/bb55751106dac8f84a5870fce2d4fdd5 to your computer and use it in GitHub Desktop.
Ludum Dare 49 game about an angry earthquake
;; title: game title
;; author: game developer
;; desc: short description
;; script: fennel
;; ls | entr -r ~/Applications/tic80 ld49.fnl --skip --fs .
;; 0 TAB: Globals
;; (var vector (require :vector))
(var vector (do (local assert assert)
(local (sqrt cos sin atan2) (values math.sqrt math.cos math.sin math.atan2))
(local vector {})
(set vector.__index vector)
(fn new [x y]
(setmetatable {:x (or x 0) :y (or y 0)} vector))
(local zero (new 0 0))
(fn from-polar [angle radius]
(set-forcibly! radius (or radius 1))
(new (* (cos angle) radius) (* (sin angle) radius)))
(fn random-direction [len-min len-max]
(set-forcibly! len-min (or len-min 1))
(set-forcibly! len-max (or len-max len-min))
(assert (> len-max 0) "len_max must be greater than zero")
(assert (>= len-max len-min)
"len_max must be greater than or equal to len_min")
(from-polar (* (* (math.random) 2) math.pi)
(+ (* (math.random) (- len-max len-min)) len-min)))
(fn isvector [v]
(and (and (= (type v) :table) (= (type v.x) :number)) (= (type v.y) :number)))
(fn vector.clone [self]
(new self.x self.y))
(fn vector.unpack [self]
(values self.x self.y))
(fn vector.__tostring [self]
(.. "(" (tonumber self.x) "," (tonumber self.y) ")"))
(fn vector.__unm [a]
(new (- a.x) (- a.y)))
(fn vector.__add [a b]
(assert (and (isvector a) (isvector b))
"Add: wrong argument types (<vector> expected)")
(new (+ a.x b.x) (+ a.y b.y)))
(fn vector.__sub [a b]
(assert (and (isvector a) (isvector b))
"Sub: wrong argument types (<vector> expected)")
(new (- a.x b.x) (- a.y b.y)))
(fn vector.__mul [a b]
(if (= (type a) :number) (new (* a b.x) (* a b.y)) (= (type b) :number)
(new (* b a.x) (* b a.y))
(do
(assert (and (isvector a) (isvector b))
"Mul: wrong argument types (<vector> or <number> expected)")
(+ (* a.x b.x) (* a.y b.y)))))
(fn vector.__div [a b]
(assert (and (isvector a) (= (type b) :number))
"wrong argument types (expected <vector> / <number>)")
(new (/ a.x b) (/ a.y b)))
(fn vector.__eq [a b]
(and (= a.x b.x) (= a.y b.y)))
(fn vector.__lt [a b]
(or (< a.x b.x) (and (= a.x b.x) (< a.y b.y))))
(fn vector.__le [a b]
(and (<= a.x b.x) (<= a.y b.y)))
(fn vector.permul [a b]
(assert (and (isvector a) (isvector b))
"permul: wrong argument types (<vector> expected)")
(new (* a.x b.x) (* a.y b.y)))
(fn vector.toPolar [self]
(new (atan2 self.x self.y) (self:len)))
(fn vector.len2 [self]
(+ (* self.x self.x) (* self.y self.y)))
(fn vector.len [self]
(sqrt (+ (* self.x self.x) (* self.y self.y))))
(fn vector.dist [a b]
(assert (and (isvector a) (isvector b))
"dist: wrong argument types (<vector> expected)")
(local dx (- a.x b.x))
(local dy (- a.y b.y))
(sqrt (+ (* dx dx) (* dy dy))))
(fn vector.dist2 [a b]
(assert (and (isvector a) (isvector b))
"dist: wrong argument types (<vector> expected)")
(local dx (- a.x b.x))
(local dy (- a.y b.y))
(+ (* dx dx) (* dy dy)))
(fn vector.normalizeInplace [self]
(let [l (self:len)]
(when (> l 0)
(set-forcibly! (self.x self.y) (values (/ self.x l) (/ self.y l))))
self))
(fn vector.normalized [self]
(: (self:clone) :normalizeInplace))
(fn vector.rotateInplace [self phi]
(let [(c s) (values (cos phi) (sin phi))]
(set-forcibly! (self.x self.y)
(values (- (* c self.x) (* s self.y))
(+ (* s self.x) (* c self.y))))
self))
(fn vector.rotated [self phi]
(let [(c s) (values (cos phi) (sin phi))]
(new (- (* c self.x) (* s self.y)) (+ (* s self.x) (* c self.y)))))
(fn vector.perpendicular [self]
(new (- self.y) self.x))
(fn vector.projectOn [self v]
(assert (isvector v) (.. "invalid argument: cannot project vector on "
(type v)))
(local s (/ (+ (* self.x v.x) (* self.y v.y)) (+ (* v.x v.x) (* v.y v.y))))
(new (* s v.x) (* s v.y)))
(fn vector.mirrorOn [self v]
(assert (isvector v) (.. "invalid argument: cannot mirror vector on "
(type v)))
(local s (/ (* 2 (+ (* self.x v.x) (* self.y v.y)))
(+ (* v.x v.x) (* v.y v.y))))
(new (- (* s v.x) self.x) (- (* s v.y) self.y)))
(fn vector.cross [self v]
(assert (isvector v) "cross: wrong argument types (<vector> expected)")
(- (* self.x v.y) (* self.y v.x)))
(fn vector.trimInplace [self max-len]
(var s (/ (* max-len max-len) (self:len2)))
(set s (or (and (> s 1) 1) (math.sqrt s)))
(set-forcibly! (self.x self.y) (values (* self.x s) (* self.y s)))
self)
(fn vector.angleTo [self other]
(when other
(let [___antifnl_rtn_1___ (- (atan2 self.y self.x) (atan2 other.y other.x))]
(lua "return ___antifnl_rtn_1___")))
(atan2 self.y self.x))
(fn vector.trimmed [self max-len]
(: (self:clone) :trimInplace max-len))
(setmetatable {: new
:fromPolar from-polar
:randomDirection random-direction
: isvector
: zero}
{:__call (fn [_ ...]
(new ...))})))
(var particles (do (global particle-systems {})
(set-forcibly! make-psystem (fn [minlife
maxlife
minstartsize
maxstartsize
minendsize
maxendsize]
(let [ps {:autoremove true
: minlife
: maxlife
: minstartsize
: maxstartsize
: minendsize
: maxendsize
:particles {}
:emittimers {}
:emitters {}
:drawfuncs {}
:affectors {}}]
(table.insert particle-systems ps)
ps)))
(set-forcibly! update-psystems
(fn []
(let [timenow (time)]
(each [key ps (pairs particle-systems)]
(update-ps ps timenow)))))
(set-forcibly! update-ps (fn [ps timenow]
(each [key et (pairs ps.emittimers)]
(local keep (et.timerfunc ps et.params))
(when (= keep false)
(table.remove ps.emittimers key)))
(each [key p (pairs ps.particles)]
(set p.phase
(/ (- timenow p.starttime)
(- p.deathtime p.starttime)))
(each [key a (pairs ps.affectors)]
(a.affectfunc p a.params))
(set p.x (+ p.x p.vx))
(set p.y (+ p.y p.vy))
(var dead false)
(when (>= timenow p.deathtime)
(set dead true))
(when (= dead true)
(table.remove ps.particles key)))
(when (and (= ps.autoremove true)
(<= (length ps.particles) 0))
(local psidx (- 1))
(each [pskey pps (pairs particle-systems)]
(when (= pps ps)
(table.remove particle-systems pskey)
(lua "return "))))))
(set-forcibly! draw-ps (fn [ps params]
(each [key df (pairs ps.drawfuncs)]
(df.drawfunc ps df.params))))
(set-forcibly! draw-psystems (fn []
(each [key ps (pairs particle-systems)]
(draw-ps ps))))
(set-forcibly! emit-particle
(fn [psystem]
(let [p {}
ecount nil
e (. psystem.emitters
(math.random (length psystem.emitters)))]
(e.emitfunc p e.params)
(set p.phase 0)
(set p.starttime (time))
(set p.deathtime
(+ (+ (time) (frnd (- psystem.maxlife psystem.minlife)))
psystem.minlife))
(set p.startsize
(+ (frnd (- psystem.maxstartsize psystem.minstartsize))
psystem.minstartsize))
(set p.endsize
(+ (frnd (- psystem.maxendsize psystem.minendsize))
psystem.minendsize))
(table.insert psystem.particles p))))
(set-forcibly! frnd (fn [max]
(* (math.random) max)))
(set-forcibly! emittimer-burst (fn [ps params]
(for [i 1 params.num 1]
(emit-particle ps))
false))
(set-forcibly! emittimer-constant (fn [ps params]
(when (<= params.nextemittime (time))
(emit-particle ps)
(set params.nextemittime
(+ params.nextemittime params.speed)))
true))
(set-forcibly! emitter-point
(fn [p params]
(set p.x params.x)
(set p.y params.y)
(set p.vx (+ (frnd (- params.maxstartvx params.minstartvx))
params.minstartvx))
(set p.vy (+ (frnd (- params.maxstartvy params.minstartvy))
params.minstartvy))))
(set-forcibly! emitter-box
(fn [p params]
(set p.x (+ (frnd (- params.maxx params.minx)) params.minx))
(set p.y (+ (frnd (- params.maxy params.miny)) params.miny))
(set p.vx (+ (frnd (- params.maxstartvx params.minstartvx))
params.minstartvx))
(set p.vy (+ (frnd (- params.maxstartvy params.minstartvy))
params.minstartvy))))
(set-forcibly! affect-force
(fn [p params]
(set p.vx (+ p.vx params.fx))
(set p.vy (+ p.vy params.fy))))
(set-forcibly! affect-forcezone
(fn [p params]
(when (and (and (and (>= p.x params.zoneminx)
(<= p.x params.zonemaxx))
(>= p.y params.zoneminy))
(<= p.y params.zonemaxy))
(set p.vx (+ p.vx params.fx))
(set p.vy (+ p.vy params.fy)))))
(set-forcibly! affect-stopzone
(fn [p params]
(when (and (and (and (>= p.x params.zoneminx)
(<= p.x params.zonemaxx))
(>= p.y params.zoneminy))
(<= p.y params.zonemaxy))
(set p.vx 0)
(set p.vy 0))))
(set-forcibly! affect-bouncezone
(fn [p params]
(when (and (and (and (>= p.x params.zoneminx)
(<= p.x params.zonemaxx))
(>= p.y params.zoneminy))
(<= p.y params.zonemaxy))
(set p.vx (* (- p.vx) params.damping))
(set p.vy (* (- p.vy) params.damping)))))
(set-forcibly! affect-attract
(fn [p params]
(when (< (+ (math.abs (- p.x params.x))
(math.abs (- p.y params.y)))
params.mradius)
(set p.vx (+ p.vx (* (- p.x params.x) params.strength)))
(set p.vy (+ p.vy (* (- p.y params.y) params.strength))))))
(set-forcibly! affect-orbit
(fn [p params]
(set params.phase (+ params.phase params.speed))
(set p.x (+ p.x (* (math.sin params.phase) params.xstrength)))
(set p.y (+ p.y (* (math.cos params.phase) params.ystrength)))))
(set-forcibly! draw-ps-fillcirc
(fn [ps params]
(each [key p (pairs ps.particles)]
(global c (+ (math.floor (* p.phase (length params.colors)))
1))
(global r
(+ (* (- 1 p.phase) p.startsize)
(* p.phase p.endsize)))
(circ p.x p.y r (. params.colors c)))))
(set-forcibly! draw-ps-pixel
(fn [ps params]
(each [key p (pairs ps.particles)]
(global c (+ (math.floor (* p.phase (length params.colors)))
1))
(pix p.x p.y (. params.colors c)))))
(set-forcibly! draw-ps-streak
(fn [ps params]
(each [key p (pairs ps.particles)]
(global c (+ (math.floor (* p.phase (length params.colors)))
1))
(line p.x p.y (- p.x p.vx) (- p.y p.vy) (. params.colors c)))))
(set-forcibly! draw-ps-animspr
(fn [ps params]
(set params.currframe (+ params.currframe params.speed))
(when (> params.currframe (length params.frames))
(set params.currframe 1))
(each [key p (pairs ps.particles)]
(spr (. params.frames
(% (math.floor (+ params.currframe p.startsize))
(length params.frames)))
p.x p.y 0))))
(set-forcibly! draw-ps-agespr
(fn [ps params]
(each [key p (pairs ps.particles)]
(local f (+ (math.floor (* p.phase (length params.frames)))
1))
(spr (. params.frames f) p.x p.y 0))))
(set-forcibly! draw-ps-rndspr
(fn [ps params]
(each [key p (pairs ps.particles)]
(spr (. params.frames (math.floor p.startsize)) p.x p.y 0))))
{:make make-psystem
:update update-psystems
:draw draw-psystems
:emittimer_burst emittimer-burst
:emitter_box emitter-box
:draw_ps_fillcirc draw-ps-fillcirc}))
(var GS (do (fn __NULL__ [])
(local state-init
(setmetatable {:leave __NULL__}
{:__index (fn []
(error "Gamestate not initialized. Use Gamestate.switch()"))}))
(local stack {1 state-init})
(local initialized-states (setmetatable {} {:__mode :k}))
(var state-is-dirty true)
(local GS {})
(fn GS.new [t]
(or t {}))
(fn change-state [stack-offset to ...]
(let [pre (. stack (length stack))]
((or (or (. initialized-states to) to.init) __NULL__) to)
(tset initialized-states to __NULL__)
(tset stack (+ (length stack) stack-offset) to)
(set state-is-dirty true)
((or to.enter __NULL__) to pre ...)))
(fn GS.switch [to ...]
(assert to "Missing argument: Gamestate to switch to")
(assert (not= to GS) "Can't call switch with colon operator")
((or (. (. stack (length stack)) :leave) __NULL__) (. stack (length stack)))
(change-state 0 to ...))
(fn GS.push [to ...]
(assert to "Missing argument: Gamestate to switch to")
(assert (not= to GS) "Can't call push with colon operator")
(change-state 1 to ...))
(fn GS.pop [...]
(assert (> (length stack) 1) "No more states to pop!")
(local (pre to) (values (. stack (length stack))
(. stack (- (length stack) 1))))
(tset stack (length stack) nil)
((or pre.leave __NULL__) pre)
(set state-is-dirty true)
((or to.resume __NULL__) to pre ...))
(fn GS.current []
(. stack (length stack)))
(local function-cache {})
(setmetatable GS {:__index (fn [_ func]
(when (or (not state-is-dirty) (= func :update))
(set state-is-dirty false)
(tset function-cache func
(or (. function-cache func)
(fn [...]
((or (. (. stack (length stack))
func)
__NULL__) (. stack
(length stack))
...))))
(let [___antifnl_rtn_1___ (. function-cache func)]
(lua "return ___antifnl_rtn_1___")))
__NULL__)})
GS ))
(var tiny (do (local tiny {})
(local tinsert table.insert)
(local tremove table.remove)
(local tsort table.sort)
(local setmetatable setmetatable)
(local type type)
(local select select)
(local tiny-manage-entities nil)
(local tiny-manage-systems nil)
(var tiny-add-entity nil)
(var tiny-add-system nil)
(var tiny-add nil)
(var tiny-remove-entity nil)
(var tiny-remove-system nil)
(local filter-join nil)
(local filter-build-string nil)
(let [loadstring (or loadstring load)]
(fn getchr [c]
(.. "\\" (c:byte)))
(fn make-safe [text]
(: (: (: "%q" :format text) :gsub "\n" :n) :gsub "[�-�]" getchr))
(fn filter-join-raw [prefix seperator ...]
(let [accum {}
build {}]
(for [i 1 (select "#" ...) 1]
(local item (select i ...))
(if (= (type item) :string)
(tset accum (+ (length accum) 1)
(: "(e[%s] ~= nil)" :format (make-safe item)))
(= (type item) :function)
(do
(tset build (+ (length build) 1)
(: "local subfilter_%d_ = select(%d, ...)" :format i i))
(tset accum (+ (length accum) 1)
(: "(subfilter_%d_(system, e))" :format i)))
(error "Filter token must be a string or a filter function.")))
(local source (: "%s\nreturn function(system, e) return %s(%s) end"
:format (table.concat build "\n") prefix
(table.concat accum seperator)))
(local (loader err) (loadstring source))
(when err
(error err))
(loader ...)))
(set-forcibly! filter-join
(fn [...]
(let [(state value) (pcall filter-join-raw ...)]
(if state value (values nil value)))))
(fn build-part [str]
(let [accum {}
sub-parts {}]
(set-forcibly! str
(str:gsub "%b()"
(fn [p]
(tset sub-parts (+ (length sub-parts) 1)
(build-part (p:sub 2 (- 2))))
(: "�%d" :format (length sub-parts)))))
(each [invert part sep (str:gmatch "(%!?)([^%|%&%!]+)([%|%&]?)")]
(if (part:match "^�%d+$")
(let [part-index (tonumber (part:match (part:sub 2)))]
(tset accum (+ (length accum) 1)
(: "%s(%s)" :format (or (and (= invert "") "") :not)
(. sub-parts part-index))))
(tset accum (+ (length accum) 1)
(: "(e[%s] %s nil)" :format (make-safe part)
(or (and (= invert "") "~=") "=="))))
(when (not= sep "")
(tset accum (+ (length accum) 1)
(or (and (= sep "|") " or ") " and "))))
(table.concat accum)))
(set-forcibly! filter-build-string
(fn [str]
(let [source (: "return function(_, e) return %s end"
:format (build-part str))
(loader err) (loadstring source)]
(when err
(error err))
(loader)))))
(fn tiny.requireAll [...]
(filter-join "" " and " ...))
(fn tiny.requireAny [...]
(filter-join "" " or " ...))
(fn tiny.rejectAll [...]
(filter-join :not " and " ...))
(fn tiny.rejectAny [...]
(filter-join :not " or " ...))
(fn tiny.filter [pattern]
(let [(state value) (pcall filter-build-string pattern)]
(if state value (values nil value))))
(local system-table-key {1 :SYSTEM_TABLE_KEY})
(fn is-system [table]
(. table system-table-key))
(fn processing-system-update [system dt]
(let [pre-process system.preProcess
process system.process
post-process system.postProcess]
(when pre-process
(pre-process system dt))
(when process
(if system.nocache
(let [entities system.world.entities
filter system.filter]
(when filter
(for [i 1 (length entities) 1]
(local entity (. entities i))
(when (filter system entity)
(process system entity dt)))))
(let [entities system.entities]
(for [i 1 (length entities) 1]
(process system (. entities i) dt)))))
(when post-process
(post-process system dt))))
(fn sorted-system-on-modify [system]
(let [entities system.entities
indices system.indices]
(var sort-delegate system.sortDelegate)
(when (not sort-delegate)
(local compare system.compare)
(set sort-delegate (fn [e1 e2]
(compare system e1 e2)))
(set system.sortDelegate sort-delegate))
(tsort entities sort-delegate)
(for [i 1 (length entities) 1]
(tset indices (. entities i) i))))
(fn tiny.system [table]
(set-forcibly! table (or table {}))
(tset table system-table-key true)
table)
(fn tiny.processingSystem [table]
(set-forcibly! table (or table {}))
(tset table system-table-key true)
(set table.update processing-system-update)
table)
(fn tiny.sortedSystem [table]
(set-forcibly! table (or table {}))
(tset table system-table-key true)
(set table.onModify sorted-system-on-modify)
table)
(fn tiny.sortedProcessingSystem [table]
(set-forcibly! table (or table {}))
(tset table system-table-key true)
(set table.update processing-system-update)
(set table.onModify sorted-system-on-modify)
table)
(var world-meta-table nil)
(fn tiny.world [...]
(let [ret (setmetatable {:entitiesToRemove {}
:entitiesToChange {}
:systemsToAdd {}
:systemsToRemove {}
:entities {}
:systems {}}
world-meta-table)]
(tiny-add ret ...)
(tiny-manage-systems ret)
(tiny-manage-entities ret)
(values ret ...)))
(fn tiny.addEntity [world entity]
(let [e2c world.entitiesToChange]
(tset e2c (+ (length e2c) 1) entity)
entity))
(set tiny-add-entity tiny.addEntity)
(fn tiny.addSystem [world system]
(assert (= system.world nil) "System already belongs to a World.")
(local s2a world.systemsToAdd)
(tset s2a (+ (length s2a) 1) system)
(set system.world world)
system)
(set tiny-add-system tiny.addSystem)
(fn tiny.add [world ...]
(for [i 1 (select "#" ...) 1]
(local obj (select i ...))
(when obj
(if (is-system obj) (tiny-add-system world obj)
(tiny-add-entity world obj))))
...)
(set tiny-add tiny.add)
(fn tiny.removeEntity [world entity]
(let [e2r world.entitiesToRemove]
(tset e2r (+ (length e2r) 1) entity)
entity))
(set tiny-remove-entity tiny.removeEntity)
(fn tiny.removeSystem [world system]
(assert (= system.world world) "System does not belong to this World.")
(local s2r world.systemsToRemove)
(tset s2r (+ (length s2r) 1) system)
system)
(set tiny-remove-system tiny.removeSystem)
(fn tiny.remove [world ...]
(for [i 1 (select "#" ...) 1]
(local obj (select i ...))
(when obj
(if (is-system obj) (tiny-remove-system world obj)
(tiny-remove-entity world obj))))
...)
(set-forcibly! tiny-manage-systems
(fn [world]
(let [(s2a s2r) (values world.systemsToAdd
world.systemsToRemove)]
(when (and (= (length s2a) 0) (= (length s2r) 0))
(lua "return "))
(set world.systemsToAdd {})
(set world.systemsToRemove {})
(local world-entity-list world.entities)
(local systems world.systems)
(for [i 1 (length s2r) 1]
(local system (. s2r i))
(local index system.index)
(local on-remove system.onRemove)
(when (and on-remove (not system.nocache))
(local entity-list system.entities)
(for [j 1 (length entity-list) 1]
(on-remove system (. entity-list j))))
(tremove systems index)
(for [j index (length systems) 1]
(tset (. systems j) :index j))
(local on-remove-from-world system.onRemoveFromWorld)
(when on-remove-from-world
(on-remove-from-world system world))
(tset s2r i nil)
(set system.world nil)
(set system.entities nil)
(set system.indices nil)
(set system.index nil))
(for [i 1 (length s2a) 1]
(local system (. s2a i))
(when (not= (. systems (or system.index 0)) system)
(when (not system.nocache)
(set system.entities {})
(set system.indices {}))
(when (= system.active nil)
(set system.active true))
(set system.modified true)
(set system.world world)
(local index (+ (length systems) 1))
(set system.index index)
(tset systems index system)
(local on-add-to-world system.onAddToWorld)
(when on-add-to-world
(on-add-to-world system world))
(when (not system.nocache)
(local entity-list system.entities)
(local entity-indices system.indices)
(local on-add system.onAdd)
(local filter system.filter)
(when filter
(for [j 1 (length world-entity-list) 1]
(local entity (. world-entity-list j))
(when (filter system entity)
(local entity-index (+ (length entity-list) 1))
(tset entity-list entity-index entity)
(tset entity-indices entity entity-index)
(when on-add
(on-add system entity)))))))
(tset s2a i nil)))))
(set-forcibly! tiny-manage-entities
(fn [world]
(let [e2r world.entitiesToRemove
e2c world.entitiesToChange]
(when (and (= (length e2r) 0) (= (length e2c) 0))
(lua "return "))
(set world.entitiesToChange {})
(set world.entitiesToRemove {})
(local entities world.entities)
(local systems world.systems)
(for [i 1 (length e2c) 1]
(local entity (. e2c i))
(when (not (. entities entity))
(local index (+ (length entities) 1))
(tset entities entity index)
(tset entities index entity))
(for [j 1 (length systems) 1]
(local system (. systems j))
(when (not system.nocache)
(local ses system.entities)
(local seis system.indices)
(var index (. seis entity))
(local filter system.filter)
(if (and filter (filter system entity))
(when (not index)
(set system.modified true)
(set index (+ (length ses) 1))
(tset ses index entity)
(tset seis entity index)
(local on-add system.onAdd)
(when on-add
(on-add system entity)))
index
(do
(set system.modified true)
(local tmp-entity (. ses (length ses)))
(tset ses index tmp-entity)
(tset seis tmp-entity index)
(tset seis entity nil)
(tset ses (length ses) nil)
(local on-remove system.onRemove)
(when on-remove
(on-remove system entity))))))
(tset e2c i nil))
(for [i 1 (length e2r) 1]
(local entity (. e2r i))
(tset e2r i nil)
(local list-index (. entities entity))
(when list-index
(local last-entity (. entities (length entities)))
(tset entities last-entity list-index)
(tset entities entity nil)
(tset entities list-index last-entity)
(tset entities (length entities) nil)
(for [j 1 (length systems) 1]
(local system (. systems j))
(when (not system.nocache)
(local ses system.entities)
(local seis system.indices)
(local index (. seis entity))
(when index
(set system.modified true)
(local tmp-entity (. ses (length ses)))
(tset ses index tmp-entity)
(tset seis tmp-entity index)
(tset seis entity nil)
(tset ses (length ses) nil)
(local on-remove system.onRemove)
(when on-remove
(on-remove system entity))))))))))
(fn tiny.refresh [world]
(tiny-manage-systems world)
(tiny-manage-entities world)
(local systems world.systems)
(for [i (length systems) 1 (- 1)]
(local system (. systems i))
(when system.active
(local on-modify system.onModify)
(when (and on-modify system.modified)
(on-modify system 0))
(set system.modified false))))
(fn tiny.update [world dt filter]
(tiny-manage-systems world)
(tiny-manage-entities world)
(local systems world.systems)
(for [i (length systems) 1 (- 1)]
(local system (. systems i))
(when system.active
(local on-modify system.onModify)
(when (and on-modify system.modified)
(on-modify system dt))
(local pre-wrap system.preWrap)
(when (and pre-wrap (or (not filter) (filter world system)))
(pre-wrap system dt))))
(for [i 1 (length systems) 1]
(local system (. systems i))
(when (and (and (not= system nil) system.active)
(or (not filter) (filter world system)))
(local update system.update)
(when update
(local interval system.interval)
(if interval
(do
(var buffered-time (+ (or system.bufferedTime 0) dt))
(while (>= buffered-time interval)
(set buffered-time (- buffered-time interval))
(update system interval))
(set system.bufferedTime buffered-time))
(update system dt)))
(set system.modified false)))
(for [i 1 (length systems) 1]
(local system (. systems i))
(local post-wrap system.postWrap)
(when (and (and post-wrap system.active)
(or (not filter) (filter world system)))
(post-wrap system dt))))
(fn tiny.clearEntities [world]
(let [el world.entities]
(for [i 1 (length el) 1]
(tiny-remove-entity world (. el i)))))
(fn tiny.clearSystems [world]
(let [systems world.systems]
(for [i (length systems) 1 (- 1)]
(tiny-remove-system world (. systems i)))))
(fn tiny.getEntityCount [world]
(length world.entities))
(fn tiny.getSystemCount [world]
(length world.systems))
(fn tiny.setSystemIndex [world system index]
(tiny-manage-systems world)
(local old-index system.index)
(local systems world.systems)
(when (< index 0)
(set-forcibly! index (+ (+ (tiny.getSystemCount world) 1) index)))
(tremove systems old-index)
(tinsert systems index system)
(for [i old-index index (or (and (>= index old-index) 1) (- 1))]
(tset (. systems i) :index i))
old-index)
(fn tiny.entity [t]
(let [cmpt {}]
(set-forcibly! t (or t {}))
(setmetatable t {:__index cmpt
:__add (fn [self cmp]
(assert cmp._cn)
(tset self cmp._cn cmp)
self)
:__sub (fn [self cn]
(tset self cn nil)
self)})
t))
(fn tiny.component [cn t]
(set-forcibly! t (or t {}))
(set t._cn cn)
t)
(set world-meta-table {:__index {:add tiny.add
:addEntity tiny.addEntity
:addSystem tiny.addSystem
:remove tiny.remove
:removeEntity tiny.removeEntity
:removeSystem tiny.removeSystem
:refresh tiny.refresh
:update tiny.update
:clearEntities tiny.clearEntities
:clearSystems tiny.clearSystems
:getEntityCount tiny.getEntityCount
:getSystemCount tiny.getSystemCount
:setSystemIndex tiny.setSystemIndex
:entity tiny.entity
:component tiny.component}
:__tostring (fn []
:<tiny-ecs_World>)})
tiny))
(global lume (do (local lume {:_version :2.3.0})
(local (pairs ipairs) (values pairs ipairs))
(local (type assert unpack) (values type assert (or unpack table.unpack)))
(local (tostring tonumber) (values tostring tonumber))
(local math-floor math.floor)
(local math-ceil math.ceil)
(local math-atan2 (or math.atan2 math.atan))
(local math-sqrt math.sqrt)
(local math-abs math.abs)
(fn noop [])
(fn identity [x]
x)
(fn patternescape [str]
(str:gsub "[%(%)%.%%%+%-%*%?%[%]%^%$]" "%%%1"))
(fn absindex [len i]
(or (and (< i 0) (+ (+ len i) 1)) i))
(fn iscallable [x]
(when (= (type x) :function)
(lua "return true"))
(local mt (getmetatable x))
(and mt (not= mt.__call nil)))
(fn getiter [x]
(if (lume.isarray x) (lua "return ipairs")
(= (type x) :table) (lua "return pairs"))
(error "expected table" 3))
(fn iteratee [x]
(when (= x nil)
(lua "return identity"))
(when (iscallable x)
(lua "return x"))
(when (= (type x) :table)
(let [___antifnl_rtn_1___ (fn [z]
(each [k v (pairs x)]
(when (not= (. z k) v)
(lua "return false")))
true)]
(lua "return ___antifnl_rtn_1___")))
(fn [z]
(. z x)))
(fn lume.clamp [x min max]
(or (and (< x min) min) (or (and (> x max) max) x)))
(fn lume.round [x increment]
(when increment
(let [___antifnl_rtn_1___ (* (lume.round (/ x increment)) increment)]
(lua "return ___antifnl_rtn_1___")))
(or (and (>= x 0) (math-floor (+ x 0.5))) (math-ceil (- x 0.5))))
(fn lume.sign [x]
(or (and (< x 0) (- 1)) 1))
(fn lume.lerp [a b amount]
(+ a (* (- b a) (lume.clamp amount 0 1))))
(fn lume.smooth [a b amount]
(let [t (lume.clamp amount 0 1)
m (* (* t t) (- 3 (* 2 t)))]
(+ a (* (- b a) m))))
(fn lume.pingpong [x]
(- 1 (math-abs (- 1 (% x 2)))))
(fn lume.distance [x1 y1 x2 y2 squared]
(let [dx (- x1 x2)
dy (- y1 y2)
s (+ (* dx dx) (* dy dy))]
(or (and squared s) (math-sqrt s))))
(fn lume.angle [x1 y1 x2 y2]
(math-atan2 (- y2 y1) (- x2 x1)))
(fn lume.vector [angle magnitude]
(values (* (math.cos angle) magnitude) (* (math.sin angle) magnitude)))
(fn lume.random [a b]
(when (not a)
(set-forcibly! (a b) (values 0 1)))
(when (not b)
(set-forcibly! b 0))
(+ a (* (math.random) (- b a))))
(fn lume.randomchoice [t]
(. t (math.random (length t))))
(fn lume.weightedchoice [t]
(var sum 0)
(each [_ v (pairs t)]
(assert (>= v 0) "weight value less than zero")
(set sum (+ sum v)))
(assert (not= sum 0) "all weights are zero")
(var rnd (lume.random sum))
(each [k v (pairs t)]
(when (< rnd v)
(lua "return k"))
(set rnd (- rnd v))))
(fn lume.isarray [x]
(and (= (type x) :table) (not= (. x 1) nil)))
(fn lume.push [t ...]
(let [n (select "#" ...)]
(for [i 1 n 1]
(tset t (+ (length t) 1) (select i ...)))
...))
(fn lume.remove [t x]
(let [iter (getiter t)]
(each [i v (iter t)]
(when (= v x)
(if (lume.isarray t) (do
(table.remove t i)
(lua :break))
(do
(tset t i nil)
(lua :break)))))
x))
(fn lume.clear [t]
(let [iter (getiter t)]
(each [k (iter t)]
(tset t k nil))
t))
(fn lume.extend [t ...]
(for [i 1 (select "#" ...) 1]
(local x (select i ...))
(when x
(each [k v (pairs x)]
(tset t k v))))
t)
(fn lume.shuffle [t]
(let [rtn {}]
(for [i 1 (length t) 1]
(local r (math.random i))
(when (not= r i)
(tset rtn i (. rtn r)))
(tset rtn r (. t i)))
rtn))
(fn lume.sort [t comp]
(let [rtn (lume.clone t)]
(if comp (if (= (type comp) :string)
(table.sort rtn
(fn [a b]
(< (. a comp) (. b comp))))
(table.sort rtn comp)) (table.sort rtn))
rtn))
(fn lume.array [...]
(let [t {}]
(each [x ...]
(tset t (+ (length t) 1) x))
t))
(fn lume.each [t ___fn-__ ...]
(let [iter (getiter t)]
(if (= (type ___fn-__) :string)
(each [_ v (iter t)]
((. v ___fn-__) v ...))
(each [_ v (iter t)]
(___fn-__ v ...)))
t))
(fn lume.map [t ___fn-__]
(set-forcibly! ___fn-__ (iteratee ___fn-__))
(local iter (getiter t))
(local rtn {})
(each [k v (iter t)]
(tset rtn k (___fn-__ v)))
rtn)
(fn lume.all [t ___fn-__]
(set-forcibly! ___fn-__ (iteratee ___fn-__))
(local iter (getiter t))
(each [_ v (iter t)]
(when (not (___fn-__ v))
(lua "return false")))
true)
(fn lume.any [t ___fn-__]
(set-forcibly! ___fn-__ (iteratee ___fn-__))
(local iter (getiter t))
(each [_ v (iter t)]
(when (___fn-__ v)
(lua "return true")))
false)
(fn lume.reduce [t ___fn-__ first]
(var started (not= first nil))
(var acc first)
(local iter (getiter t))
(each [_ v (iter t)]
(if started (set acc (___fn-__ acc v))
(do
(set acc v)
(set started true))))
(assert started "reduce of an empty table with no first value")
acc)
(fn lume.unique [t]
(let [rtn {}]
(each [k (pairs (lume.invert t))]
(tset rtn (+ (length rtn) 1) k))
rtn))
(fn lume.filter [t ___fn-__ retainkeys]
(set-forcibly! ___fn-__ (iteratee ___fn-__))
(local iter (getiter t))
(local rtn {})
(if retainkeys (each [k v (iter t)]
(when (___fn-__ v)
(tset rtn k v)))
(each [_ v (iter t)]
(when (___fn-__ v)
(tset rtn (+ (length rtn) 1) v))))
rtn)
(fn lume.reject [t ___fn-__ retainkeys]
(set-forcibly! ___fn-__ (iteratee ___fn-__))
(local iter (getiter t))
(local rtn {})
(if retainkeys (each [k v (iter t)]
(when (not (___fn-__ v))
(tset rtn k v)))
(each [_ v (iter t)]
(when (not (___fn-__ v))
(tset rtn (+ (length rtn) 1) v))))
rtn)
(fn lume.merge [...]
(let [rtn {}]
(for [i 1 (select "#" ...) 1]
(local t (select i ...))
(local iter (getiter t))
(each [k v (iter t)]
(tset rtn k v)))
rtn))
(fn lume.concat [...]
(let [rtn {}]
(for [i 1 (select "#" ...) 1]
(local t (select i ...))
(when (not= t nil)
(local iter (getiter t))
(each [_ v (iter t)]
(tset rtn (+ (length rtn) 1) v))))
rtn))
(fn lume.find [t value]
(let [iter (getiter t)]
(each [k v (iter t)]
(when (= v value)
(lua "return k")))
nil))
(fn lume.match [t ___fn-__]
(set-forcibly! ___fn-__ (iteratee ___fn-__))
(local iter (getiter t))
(each [k v (iter t)]
(when (___fn-__ v)
(lua "return v, k")))
nil)
(fn lume.count [t ___fn-__]
(var count 0)
(local iter (getiter t))
(if ___fn-__ (do
(set-forcibly! ___fn-__ (iteratee ___fn-__))
(each [_ v (iter t)]
(when (___fn-__ v)
(set count (+ count 1)))))
(do
(when (lume.isarray t)
(let [___antifnl_rtn_1___ (length t)]
(lua "return ___antifnl_rtn_1___")))
(each [_ (iter t)]
(set count (+ count 1)))))
count)
(fn lume.slice [t i j]
(set-forcibly! i (or (and i (absindex (length t) i)) 1))
(set-forcibly! j (or (and j (absindex (length t) j)) (length t)))
(local rtn {})
(for [x (or (and (< i 1) 1) i) (or (and (> j (length t)) (length t)) j) 1]
(tset rtn (+ (length rtn) 1) (. t x)))
rtn)
(fn lume.first [t n]
(when (not n)
(let [___antifnl_rtn_1___ (. t 1)]
(lua "return ___antifnl_rtn_1___")))
(lume.slice t 1 n))
(fn lume.last [t n]
(when (not n)
(let [___antifnl_rtn_1___ (. t (length t))]
(lua "return ___antifnl_rtn_1___")))
(lume.slice t (- n) (- 1)))
(fn lume.invert [t]
(let [rtn {}]
(each [k v (pairs t)]
(tset rtn v k))
rtn))
(fn lume.pick [t ...]
(let [rtn {}]
(for [i 1 (select "#" ...) 1]
(local k (select i ...))
(tset rtn k (. t k)))
rtn))
(fn lume.keys [t]
(let [rtn {}
iter (getiter t)]
(each [k (iter t)]
(tset rtn (+ (length rtn) 1) k))
rtn))
(fn lume.clone [t]
(let [rtn {}]
(each [k v (pairs t)]
(tset rtn k v))
rtn))
(fn lume.fn [___fn-__ ...]
(assert (iscallable ___fn-__) "expected a function as the first argument")
(local args {1 ...})
(fn [...]
(let [a (lume.concat args {1 ...})]
(___fn-__ (unpack a)))))
(fn lume.once [___fn-__ ...]
(let [f (lume.fn ___fn-__ ...)]
(var done false)
(fn [...]
(when done
(lua "return "))
(set done true)
(f ...))))
(local memoize-fnkey {})
(local memoize-nil {})
(fn lume.memoize [___fn-__]
(let [cache {}]
(fn [...]
(var c cache)
(for [i 1 (select "#" ...) 1]
(local a (or (select i ...) memoize-nil))
(tset c a (or (. c a) {}))
(set c (. c a)))
(tset c memoize-fnkey (or (. c memoize-fnkey) {1 (___fn-__ ...)}))
(unpack (. c memoize-fnkey)))))
(fn lume.combine [...]
(let [n (select "#" ...)]
(when (= n 0)
(lua "return noop"))
(when (= n 1)
(local ___fn-__ (select 1 ...))
(when (not ___fn-__)
(lua "return noop"))
(assert (iscallable ___fn-__) "expected a function or nil")
(lua "return ___fn-__"))
(local funcs {})
(for [i 1 n 1]
(local ___fn-__ (select i ...))
(when (not= ___fn-__ nil)
(assert (iscallable ___fn-__) "expected a function or nil")
(tset funcs (+ (length funcs) 1) ___fn-__)))
(fn [...]
(each [_ f (ipairs funcs)]
(f ...)))))
(fn lume.call [___fn-__ ...]
(when ___fn-__
(___fn-__ ...)))
(fn lume.time [___fn-__ ...]
(let [start (os.clock)
rtn {1 (___fn-__ ...)}]
(values (- (os.clock) start) (unpack rtn))))
(local lambda-cache {})
(fn lume.lambda [str]
(when (not (. lambda-cache str))
(local (args body) (str:match "^([%w,_ ]-)%->(.-)$"))
(assert (and args body) "bad string lambda")
(local s (.. "return function(" args ")\nreturn " body "\nend"))
(tset lambda-cache str (lume.dostring s)))
(. lambda-cache str))
(var serialize nil)
(local serialize-map
{:boolean tostring
:nil tostring
:string (fn [v]
(string.format "%q" v))
:number (fn [v]
(if (not= v v) (lua "return \"0/0\"")
(= v (/ 1 0)) (lua "return \"1/0\"")
(= v (/ (- 1) 0)) (lua "return \"-1/0\""))
(tostring v))
:table (fn [t stk]
(set-forcibly! stk (or stk {}))
(when (. stk t)
(error "circular reference"))
(local rtn {})
(tset stk t true)
(each [k v (pairs t)]
(tset rtn (+ (length rtn) 1)
(.. "[" (serialize k stk) "]=" (serialize v stk))))
(tset stk t nil)
(.. "{" (table.concat rtn ",") "}"))})
(setmetatable serialize-map
{:__index (fn [_ k]
(error (.. "unsupported serialize type: " k)))})
(set serialize (fn [x stk]
((. serialize-map (type x)) x stk)))
(fn lume.serialize [x]
(serialize x))
(fn lume.deserialize [str]
(lume.dostring (.. "return " str)))
(fn lume.split [str sep]
(if (not sep) (lume.array (str:gmatch "([%S]+)"))
(do
(assert (not= sep "") "empty separator")
(local psep (patternescape sep))
(lume.array (: (.. str sep) :gmatch (.. "(.-)(" psep ")"))))))
(fn lume.trim [str chars]
(when (not chars)
(let [___antifnl_rtn_1___ (str:match "^[%s]*(.-)[%s]*$")]
(lua "return ___antifnl_rtn_1___")))
(set-forcibly! chars (patternescape chars))
(str:match (.. "^[" chars "]*(.-)[" chars "]*$")))
(fn lume.wordwrap [str limit]
(set-forcibly! limit (or limit 72))
(var check nil)
(if (= (type limit) :number)
(set check (fn [s]
(>= (length s) limit))) (set check limit))
(local rtn {})
(var line "")
(each [word spaces (str:gmatch "(%S+)(%s*)")]
(local s (.. line word))
(if (check s) (do
(table.insert rtn (.. line "\n"))
(set line word)) (set line s))
(each [c (spaces:gmatch ".")]
(if (= c "\n") (do
(table.insert rtn (.. line "\n"))
(set line ""))
(set line (.. line c)))))
(table.insert rtn line)
(table.concat rtn))
(fn lume.format [str vars]
(when (not vars)
(lua "return str"))
(fn f [x]
(tostring (or (or (. vars x) (. vars (tonumber x))) (.. "{" x "}"))))
(str:gsub "{(.-)}" f))
(fn lume.trace [...]
(let [info (debug.getinfo 2 :Sl)
t {1 (.. info.short_src ":" info.currentline ":")}]
(for [i 1 (select "#" ...) 1]
(var x (select i ...))
(when (= (type x) :number)
(set x (string.format "%g" (lume.round x 0.01))))
(tset t (+ (length t) 1) (tostring x)))
(print (table.concat t " "))))
(fn lume.dostring [str]
((assert ((or loadstring load) str))))
(fn lume.uuid []
(fn ___fn-__ [x]
(var r (- (math.random 16) 1))
(set r (or (and (= x :x) (+ r 1)) (+ (% r 4) 9)))
(: :0123456789abcdef :sub r r))
(: :xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx :gsub "[xy]" ___fn-__))
(fn lume.hotswap [modname]
(let [oldglobal (lume.clone _G)
updated {}]
(fn update [old new]
(when (. updated old)
(lua "return "))
(tset updated old true)
(local (oldmt newmt) (values (getmetatable old) (getmetatable new)))
(when (and oldmt newmt)
(update oldmt newmt))
(each [k v (pairs new)]
(if (= (type v) :table) (update (. old k) v) (tset old k v))))
(var err nil)
(fn onerror [e]
(each [k (pairs _G)]
(tset _G k (. oldglobal k)))
(set err (lume.trim e)))
(var (ok oldmod) (pcall require modname))
(set oldmod (or (and ok oldmod) nil))
(xpcall (fn []
(do
(tset package.loaded modname nil)
(local newmod (require modname))
(when (= (type oldmod) :table)
(update oldmod newmod))
(each [k v (pairs oldglobal)]
(when (and (not= v (. _G k)) (= (type v) :table))
(update v (. _G k))
(tset _G k v))))) onerror)
(tset package.loaded modname oldmod)
(when err
(lua "return nil, err"))
oldmod))
(fn ripairs-iter [t i]
(set-forcibly! i (- i 1))
(local v (. t i))
(when (not= v nil)
(values i v)))
(fn lume.ripairs [t]
(values ripairs-iter t (+ (length t) 1)))
(fn lume.color [str mul]
(set-forcibly! mul (or mul 1))
(var (r g b a) nil)
(set-forcibly! (r g b) (str:match "#(%x%x)(%x%x)(%x%x)"))
(if r (do
(set r (/ (tonumber r 16) 255))
(set g (/ (tonumber g 16) 255))
(set b (/ (tonumber b 16) 255))
(set a 1)) (str:match "rgba?%s*%([%d%s%.,]+%)")
(let [f (str:gmatch "[%d.]+")]
(set r (/ (or (f) 0) 255))
(set g (/ (or (f) 0) 255))
(set b (/ (or (f) 0) 255))
(set a (or (f) 1)))
(error (: "bad color string '%s'" :format str)))
(values (* r mul) (* g mul) (* b mul) (* a mul)))
(local chain-mt {})
(set chain-mt.__index (lume.map (lume.filter lume iscallable true)
(fn [___fn-__]
(fn [self ...]
(set self._value (___fn-__ self._value ...))
self))))
(set chain-mt.__index.result (fn [x]
x._value))
(fn lume.chain [value]
(setmetatable {:_value value} chain-mt))
(setmetatable lume {:__call (fn [_ ...]
(lume.chain ...))})
lume ))
;; (global lume (require :lume))
;; (var vector (require :vector))
;; (var particles (require :pslib))
;; (var GS (require :gamestates))
;; (var tiny (require :tiny))
(global create-world tiny.world)
(global ent tiny.entity)
(global cmp tiny.component)
(global filter tiny.filter)
(global req-all tiny.requireAll)
(global rej-all tiny.rejectAll)
(global add-ent tiny.addEntity)
(global rmv-ent tiny.removeEntity)
(global add-sys tiny.addSystem)
(global set-sys-index tiny.setSystemIndex)
(global clear-systems tiny.clearSystems)
(global clear-entities tiny.clearEntities)
(global refresh tiny.refresh)
(global draw-system-filter (req-all :drawing-system))
(global update-system-filter (rej-all :drawing-system))
(macro sys [filter update ...]
`(tiny.system
{:drawing-system false
:filter ,filter
:update ,update}))
(macro draw-sys [filter update ...]
`(tiny.system
{:drawing-system true
:filter ,filter
:update ,update}))
(macro proc-sys [filter process ?additional]
`(tiny.processingSystem
{:drawing-system false
:filter ,filter
:process ,process}))
(macro draw-proc-sys [filter process ...]
`(tiny.processingSystem
{:drawing-system true
:filter ,filter
:process ,process}))
(macro draw-sort-proc-sys [filter process compare]
`(tiny.sortedProcessingSystem
{:drawing-system true
:filter ,filter
:process ,process
:compare ,compare}))
;; Lume
(global any lume.any)
(global lmap lume.map)
(global reduce lume.reduce)
(global filter lume.filter)
(global extend lume.extend)
(global count lume.count)
(global all lume.all)
(global merge lume.merge)
(global round lume.round)
(global find lume.find)
;; Math
(global abs math.abs)
(global rnd math.random)
(global min math.min)
(global max math.max)
(global sin math.sin)
(global cos math.cos)
(global flr math.floor)
(global sqrt math.sqrt)
;; String
(global sub string.sub)
(global srt table.sort)
;; Table
(global rmv table.remove)
(global add table.insert)
(fn rnd-point-in-circle [x y radius]
(let [r (* radius (sqrt (rnd)))
theta (* (rnd) 2 math.pi)
x (+ x (* r (cos theta)))
y (+ y (* r (sin theta)))]
(vector x y)))
(var T 0)
(var WORLD-W 560)
(var WORLD-H 320)
;; TAB: Global Camera
(fn lerp [a b t] (+ (* (- 1 t) a) (* t b)))
(var CAMERA
{:x (/ WORLD-W 2)
:y (/ WORLD-H 2)
:follow nil
:update
(fn [self dt]
(when (not= self.follow nil)
(set self.x (min 120 (lerp self.x (- 120 self.follow.x) 0.05)))
(set self.y (min 64 (lerp self.y (- 64 self.follow.y) 0.05)))))
:relx (fn [self x] (+ self.x x))
:rely (fn [self y] (+ self.y y))
:in-view (fn [self x y]
(let [rx (self:relx x)
ry (self:rely y)]
;; (trace rx)
(and (> rx 0) (< rx 240)
(> ry 0) (< ry 128))))
})
;; TAB: particle systems
(fn draw-ps-fillcirc [ps params]
(each [key p (pairs ps.particles)]
(let [c (+ (flr (* p.phase (# params.colors))) 1)
r (+ (* (- 1 p.phase) p.startsize) (* p.phase p.endsize))]
(circ (CAMERA:relx p.x) (CAMERA:rely p.y) r (. params.colors c)))))
(fn make-explosion-ps [ex ey]
(var ps (particles.make 100 500 9 14 1 3))
(add ps.emittimers {"timerfunc" particles.emittimer_burst
:params {:num 4}})
(add ps.emitters {:emitfunc particles.emitter_box
:params {:minx (- ex 4)
:maxx (+ ex 4)
:miny (- ey 4)
:maxy (+ ey 4)
:minstartvx 0
:maxstartvx 0
:minstartvy 0
:maxstartvy 0}})
(add ps.drawfuncs {:drawfunc draw-ps-fillcirc
:params {:colors [12 0 3 2 2 1]}}))
(fn make-poof-ps [ex ey]
(var ps (particles.make 100 500 9 14 1 3))
(add ps.emittimers {"timerfunc" particles.emittimer_burst
:params {:num 4}})
(add ps.emitters {:emitfunc particles.emitter_box
:params {:minx (- ex 4)
:maxx (+ ex 4)
:miny (- ey 4)
:maxy (+ ey 4)
:minstartvx -1
:maxstartvx 1
:minstartvy -1
:maxstartvy 1}})
(add ps.drawfuncs {:drawfunc draw-ps-fillcirc
:params {:colors [4 4 4 12 12 13 13 13 14 14 14]}}))
(fn make-BIG-poof-ps [ex ey]
(var ps (particles.make 100 500 9 14 1 3))
(add ps.emittimers {"timerfunc" particles.emittimer_burst
:params {:num 20}})
(add ps.emitters {:emitfunc particles.emitter_box
:params {:minx (- ex 10)
:maxx (+ ex 10)
:miny (- ey 10)
:maxy (+ ey 10)
:minstartvx -1
:maxstartvx 1
:minstartvy -1
:maxstartvy 1}})
(add ps.drawfuncs {:drawfunc draw-ps-fillcirc
:params {:colors [4 4 4 12 12 13 13 13 14 14 14]}}))
;; TAB: Timer
(fn create-timer [wld t i cb fin]
(+ (ent)
(cmp :timer {:c 0 ; internal counter
: t ; times to run
: i ; interval
: cb ; interval callback
: fin}))) ; finished cb
(var sys-timer
(proc-sys
(req-all :timer)
(fn [{: world} e dt]
(tset e.timer :c (+ e.timer.c 1))
(when (= e.timer.c e.timer.i)
(: e.timer :cb)
(tset e.timer :t (- e.timer.t 1))
(tset e.timer :c 0))
(when (= e.timer.t 0)
(when e.timer.fin (: e.timer :fin))
(rmv-ent world e)))))
;; TAB: Screenshake
(fn shake-it [wld d p]
(add-ent wld (+ (ent)
(cmp :shaker {: d : p}))))
(var sys-shake
(proc-sys
(req-all :shaker)
(fn [{: world} e dt]
(let [{: d : p} e.shaker]
;; time to shake
(when (> d 0)
(poke 0x3FF9 (rnd (- p) p))
(poke 0x3FFA (rnd (- p) p))
(tset e.shaker :d (- d 1)))
;; shake all done
(when (= d 0)
(memset 0x3FF9 0 2)
(rmv-ent world e))))))
;; TAB: Popup
(var POPUP {:active false
:text []
:cb nil
:mouse-up false
:mouse-last-pressed false
:create (fn [self text cb]
(set self.active true)
(set self.text text)
(set self.cb cb )
)
:update (fn [self dt]
(when (or (btnp 0) (btnp 1) (btnp 2) (btnp 3)
(btnp 4) (btnp 5) (btnp 6) (btnp 7)
self.mouse-last-pressed)
(set self.mouse-up false)
(set self.mouse-last-pressed false)
(self:cb))
(let [(x y left) (mouse)]
(when (not left)
(set self.mouse-up true))
(when (and left self.mouse-up)
(set self.mouse-last-pressed true))
)
)
:draw (fn [self]
(rect 10 10 200 100 0)
(rectb 10 10 200 100 12)
(each [i t (ipairs self.text)]
(print t 16 (+ 16 (* (- i 1) 8)) 12))
(print "press a button to continue." 60 100 13)
)})
;; 1 TAB: Components
(fn pos [x y locked]
(let [v (vector x y)]
(set v.locked locked)
(cmp :pos v)))
(fn des-pos [x y speed]
(let [v (vector x y)]
(set v.speed speed)
(cmp :des-pos v)))
(fn vel [x y mx my]
(cmp :vel {: x : y : mx : my}))
(fn fric [f]
(cmp :fric {: f}))
(fn bounds [min-x min-y max-x max-y]
(cmp :bounds {: min-x : min-y : max-x : max-y}))
(fn spring [a b len stiffness]
(cmp :spring {: a : b
: len
: stiffness}))
(fn dinode []
(cmp :dinode {}))
(fn anim [current states ?paused ?hidden]
(cmp :anim {:tick (rnd 0 40)
:frame (rnd 0 (# (. states current)))
:paused (or ?paused false)
:hidden (or ?hidden false)
:frames (# (. states current))
: current
: states}))
(fn person [city-pt]
(cmp :person {: city-pt
:state :idle
:tick 0
:despos nil
}))
(fn building [city-pt height]
(cmp :building {: height
:max-height (. [2 3 3 4] (rnd 1 4))
: city-pt
:tick (rnd 200 600)
:state :grow}))
(fn city [radius foliage]
(cmp :city {: radius
: foliage
:buildings []
:people []
:state :living
:spawn-timer 60
:next-spawn 500
:spawn-tries 0
:color (. [:red :blue] (rnd 1 2))}))
(fn earthquaker-common [i]
(cmp :earthquaker-common {: i :t 0 :active false :pulse 0 :height 0}))
(fn earthquaker-core []
(cmp :earthquaker-core
{:tick 0 :rings [] :joints []
:max-rings 15
:mouse-up false
:remove-ring (fn [self world]
(rmv-ent world (rmv self.rings (# self.rings)))
(rmv-ent world (rmv self.joints (# self.joints)))
)
:add-ring (fn [self world eq]
(let [i (+ 1 (# self.rings))
new-ring (create-earthquaker-ring eq.pos.x eq.pos.y i)
stretch (/ 1 (/ i 1.5))
new-spring (+ (ent) (spring eq new-ring 1 stretch))]
(add self.rings new-ring)
(add-ent world new-ring)
(add self.joints new-spring)
(add-ent world new-spring)))}))
(fn earthquaker-ring [i]
(cmp :earthquaker-ring {: i}))
(fn minimap []
(cmp :minimap {}))
(fn powerup []
(cmp :powerup {}))
;; 3 TAB: Systems
(var sys-positions
(proc-sys
(req-all :pos :des-pos)
(fn [_ {: pos : des-pos} dt]
(tset pos :x (+ pos.x (/ (- des-pos.x pos.x) des-pos.speed)))
(tset pos :y (+ pos.y (/ (- des-pos.y pos.y) des-pos.speed))))))
(var sys-velocity
(proc-sys
(req-all :pos :vel)
(fn [_ {: pos : vel} dt]
(set vel.x (max (min vel.x vel.mx) (- vel.mx)))
(set vel.y (max (min vel.y vel.my) (- vel.my)))
(set pos.x (+ pos.x vel.x))
(set pos.y (+ pos.y vel.y)))))
(var sys-friction
(proc-sys
(req-all :fric :vel)
(fn [_ {: vel : fric} dt]
(set vel.x (* vel.x fric.f))
(set vel.y (* vel.y fric.f)))))
(var sys-bounds
(proc-sys
(req-all :bounds :pos)
(fn [_ {: bounds : pos} dt]
(let [{: min-x : min-y : max-x : max-y} bounds
{: x : y} pos]
(tset pos :x (max min-x (min max-x x)))
(tset pos :y (max min-y (min max-y y)))))))
(var sys-verlet
(proc-sys
(req-all :spring)
(fn [_ {: spring} dt]
(let [{: a : b : len : stiffness} spring
{:pos apos} a
{:pos bpos} b
dx (- bpos.x apos.x)
dy (- bpos.y apos.y)
d2 (sqrt (+ (* dx dx) (* dy dy)))
d3 (/ (- d2 len) d2)
d3 (if (~= d3 d3) 0 d3)]
(when (not apos.locked)
(tset apos :x (+ apos.x (* 0.5 dx d3 stiffness)))
(tset apos :y (+ apos.y (* 0.5 dy d3 stiffness))))
(when (not bpos.locked)
(tset bpos :x (- bpos.x (* 0.5 dx d3 stiffness)))
(tset bpos :y (- bpos.y (* 0.5 dy d3 stiffness))))))))
(var sys-anim
(proc-sys
(req-all :anim :pos)
(fn [_ e dt]
(let [{: anim : pos} e
{: x : y} pos
cstate (. anim.states anim.current)
frames cstate.frames
speed cstate.speed]
(when (not anim.paused)
(tset anim :tick (% (+ anim.tick 1) speed))
(when (= anim.tick 0)
(tset anim :frame (% (+ anim.frame 1) (# frames))))
(when (> anim.frame (# frames))
(tset anim :frame 0)))))))
(var drawsys-anim
(draw-proc-sys
(req-all :anim :pos)
(fn [_ {: anim : pos} dt]
(let [{: x : y} pos
cstate (. anim.states anim.current)
frames cstate.frames
flip (or cstate.flip 0)
rotate (or cstate.rotate 0)
width (or cstate.width 1)
height (or cstate.height 1)
colorkey (or cstate.colorkey -1)
scale (or cstate.scale 1)
s (. frames (+ anim.frame 1))]
(when (not anim.hidden)
(spr s (CAMERA:relx x) (CAMERA:rely y) colorkey scale flip rotate width height))))))
;; Earthquak systems
(var earthquaker-state :idle)
(var C-LOW-SCALE ["A-2" "A-2" "A-2"
"B-2"
"C-2" "C-2"
"D-2"
"E-2" "E-2"
"F-2" "F-2"
"G-2" "G-2"])
(var sys-earthquaker
(proc-sys
(req-all :pos :vel :earthquaker-core)
(fn [{: world} {: pos : vel :earthquaker-core core} dt]
(let [(x y left middle right) (mouse)]
(set vel.x (/ (- x 120) 40))
(set vel.y (/ (- y 64) 40))
(when (not left)
(set core.mouse-up true))
(match earthquaker-state
:idle
(when (and (> (# core.joints) 1)
(or (btnp 4) (btnp 5) (btnp 6) (btnp 7)
(and core.mouse-up left)))
(set core.mouse-up false)
(set earthquaker-state :quake)
(sfx 24 (. C-LOW-SCALE (rnd 1 (# C-LOW-SCALE))) -1 0)
(set core.tick 50)
(core:remove-ring world)
(shake-it world 30 1)
)
:quake
(if (= core.tick 0)
(set earthquaker-state :idle)
(set core.tick (- core.tick 1)))))
)))
(var sys-earthquaker-common
(proc-sys
(req-all :earthquaker-common)
(fn [_ {: earthquaker-common} dr]
(match earthquaker-state
:quake
(do
(if
earthquaker-common.active
(let [lt earthquaker-common.t
i earthquaker-common.i
pulse-speed 7
pulse-intensity 1.2
jump-speed 7
jump-intensity 10]
(set earthquaker-common.pulse (* pulse-intensity (sin (/ (+ (* i pulse-speed) lt) pulse-speed))))
(set earthquaker-common.height (* jump-intensity (+ 1 (sin (+ math.pi (/ (- lt (* i 2)) jump-speed))))))
)
(and (> earthquaker-common.t (* (- earthquaker-common.i 1) 3))
(not earthquaker-common.active))
(do (set earthquaker-common.active true)
(set earthquaker-common.t 0)))
(set earthquaker-common.t (+ 1 earthquaker-common.t)))
:idle
(do
(set earthquaker-common.active false)
(set earthquaker-common.t 0)
(set earthquaker-common.pulse (* earthquaker-common.pulse 0.9))
(set earthquaker-common.height (* earthquaker-common.height 0.9)))))))
(var drawsys-earthquaker-core
(draw-proc-sys
(req-all :pos :earthquaker-core :earthquaker-common)
(fn [_ {: pos : earthquaker-core : earthquaker-common}]
(print (# earthquaker-core.rings) 0 0 12)
(spr (match earthquaker-state :idle 256 :quake 257)
(CAMERA:relx (- pos.x 8))
(CAMERA:rely (- pos.y 4 earthquaker-common.height))
5 1 0)
(spr (match earthquaker-state :idle 256 :quake 257)
(CAMERA:relx (- pos.x 0))
(CAMERA:rely (- pos.y 4 earthquaker-common.height))
5 1 1))))
(var drawsys-earthquaker-ring
(draw-sort-proc-sys
(req-all :pos :earthquaker-ring :earthquaker-common)
(fn [self {: pos : earthquaker-ring : earthquaker-common}]
(let [rings-count (# self.eq.earthquaker-core.rings)
i earthquaker-ring.i
h (/ earthquaker-common.height (max 1.2 (* i 0.8)))
s (+ 5 (* i 2))]
(when (or (< i (* self.eq.earthquaker-core.max-rings 0.66))
(> h 1))
(circb (CAMERA:relx pos.x)
(CAMERA:rely (- pos.y h))
(+ earthquaker-common.pulse s)
(match (lume.round h)
0 1
1 1
2 2
3 3
4 3
5 4
6 12
_ 12))))
;; need to sort every frame because of height
(self:onModify))
(fn [_ e1 e2]
(if (= e1.earthquaker-common.height e2.earthquaker-common.height)
(< e1.earthquaker-common.i e2.earthquaker-common.i)
(< e1.earthquaker-common.height e2.earthquaker-common.height)))))
;; person systems
(var C-SCALE ["A-4" "A-4"
"C-4" "C-4"
"E-4" "E-4"
"G#4"
"A-5" "A-5" "A-5"
"C-5" "C-5" "C-5"
"E-5" "E-5"
"G#5"
])
(var sys-person-ai
(proc-sys
(req-all :pos :vel :anim :person)
(fn [{: eq} {: pos : vel : anim : person}]
(set person.state
(if (< (pos:dist eq.pos) 25) :run-from-eq
(> (pos:dist person.city-pt.pos) person.city-pt.city.radius) :run-to-city
:idle))
(when (= person.city-pt.city.state :dead)
(set person.state :dead))
(match person.state
:dead
(tset anim :current :ko)
:run-to-city
(let [desired (* (: (- person.city-pt.pos pos) :normalized) 0.3)]
(tset vel :x desired.x)
(tset vel :y desired.y)
(tset anim :current :idle))
:run-from-eq
(let [desired (* (: (- pos eq.pos) :normalized) 1.5)]
(tset vel :x desired.x)
(tset vel :y desired.y)
(tset anim :current :aahh)
(when (and (= (% T 6) 0)
(CAMERA:in-view pos.x pos.y))
(sfx 6 (. C-SCALE (rnd 1 (# C-SCALE))) -1 1)))
:idle
(do
(tset anim :current :idle)
;; wander to new random location in city
(if (or (= person.despos nil) (= person.tick 0))
;; find random point in city circle
(let [{: x : y} person.city-pt.pos
r person.city-pt.city.radius
dpos (rnd-point-in-circle x y r)]
(tset person :despos dpos)
(tset person :tick (rnd 200 400))
(when (CAMERA:in-view pos.x pos.y)
(sfx 6 (. C-SCALE (rnd 1 (# C-SCALE))) -1 1)
)
)
;; else countdown the timer
(set person.tick (- person.tick 1)))
(let [desired (* (: (- person.despos pos) :normalized) 0.3)]
(when (> (pos:dist desired) 0.1)
(tset vel :x desired.x)
(tset vel :y desired.y))))))))
(var drawsys-person-debug
(draw-proc-sys
(req-all :pos :vel :anim :person)
(fn [{: eq} {: pos : vel : anim : person}]
(when (not= person.despos nil)
(circ
(CAMERA:relx person.despos.x)
(CAMERA:rely person.despos.y)
2 2)))))
(var sys-building
(proc-sys
(req-all :pos :building)
(fn [{: eq} {: pos : building}]
(let [centered-pos (+ pos (vector 4 4))
powerlevel (+ 10 (* 1.1 (# eq.earthquaker-core.rings)))]
(if
(and (< (centered-pos:dist eq.pos) powerlevel)
(= earthquaker-state :quake))
(do
(set building.state :tumble)
(set building.tick 1))
(= building.city-pt.city.state :dead)
(do
(set building.state :dead)
(set building.tick 1))
(and (= building.state :tumble) (= building.height 0))
(do
(set building.state :grow)
(set building.tick (rnd 200 400)))))
(if (and (not= building.state :dead) (= building.tick 0))
(match building.state
:grow
(do
(when (< building.height building.max-height)
(when (CAMERA:in-view pos.x (- pos.y 8 (* building.height 8)))
(make-poof-ps pos.x (- pos.y 8 (* building.height 8)))
(sfx 18 nil -1 1)))
(set building.height (min building.max-height (+ building.height 1)))
(set building.tick (rnd 300 800)))
:tumble
(do
(when (CAMERA:in-view pos.x (- pos.y 8 (* building.height 8)))
(make-explosion-ps pos.x (- pos.y (* building.height 8)))
(sfx 21 nil -1 1))
(set building.height (max 0 (- building.height 1)))
(set building.tick 30)))
(set building.tick (- building.tick 1)))
)))
(var drawsys-building
(draw-sort-proc-sys
(req-all :pos :building)
(fn [_ {: pos : building}]
(if (= building.height 0)
(spr (match building.city-pt.city.color
:blue 66
:red 70)
(CAMERA:relx (- pos.x 8))
(CAMERA:rely pos.y)
5 1 0 0 2 2)
(for [i 1 building.height]
(var x-offset 0)
(when (= building.state :tumble)
(set x-offset (sin (+ i (/ T 7)))))
(spr (match building.city-pt.city.color
:blue 48
:red 52)
(CAMERA:relx (+ pos.x -8 x-offset))
(CAMERA:rely (- pos.y 8 (* (- i 1) 16)))
5 1 0 0 2 3))))
(fn [_ e1 e2]
(< e1.pos.y e2.pos.y))))
(var sys-city
(proc-sys
(req-all :city :pos)
(fn [{: world : cities} e dt]
;; city has reached full growth, spawn a new one
(let [{: city : pos} e]
(when (and (< city.spawn-tries 15)
(all city.buildings (fn [b] (= b.building.height b.building.max-height))))
(if (= city.spawn-timer 0)
(let [newr (rnd 30 50)
dirvec (vector.randomDirection (+ 2 newr city.radius))
newx (+ pos.x dirvec.x)
newy (+ pos.y dirvec.y)]
(if (city-location-valid? cities newx newy newr)
;; Actually spawn the city
(do (factory-city world cities newx newy newr)
(set city.spawn-timer city.next-spawn)
(set city.next-spawn (* city.next-spawn 2))
(set city.spawn-tries 0)
(make-BIG-poof-ps newx newy)
(when (CAMERA:in-view newx newy)
(sfx 19 nil -1 3))
)
(do (set city.spawn-timer city.next-spawn)
(set city.spawn-tries (+ city.spawn-tries 1)))))
(set city.spawn-timer (- city.spawn-timer 1))))
;; City is dead
(when (and (not= city.state :dead)
(all city.buildings (fn [b] (= b.building.height 0))))
(set city.state :dead)
;; despawn
(add-ent world
(create-timer
world 1 150
(fn [self]
(each [i e2 (ipairs city.people)] (rmv-ent world e2))
(each [i e2 (ipairs city.buildings)] (rmv-ent world e2))
(make-BIG-poof-ps e.pos.x e.pos.y)
(when (CAMERA:in-view e.pos.x e.pos.y)
(sfx 19 nil -1 3))
(rmv cities (find cities e))
(rmv-ent world e)
(when (= (# cities) 0)
(music -1)
(POPUP:create
["You've destroyed everthing.. I hope"
"you feel better."]
(fn [] (GS.switch gs-title))))
))))))))
(var drawsys-city-foliage
(draw-proc-sys
(req-all :pos :city)
(fn [_ {: pos : city}]
;; (circ (CAMERA:relx pos.x) (CAMERA:rely pos.y) city.radius 15)
(each [i v (ipairs city.foliage)]
(spr (if (= city.state :living) v.s (+ v.s 2))
(CAMERA:relx v.x)
(CAMERA:rely v.y)
0)))))
(var drawsys-minimap
(draw-proc-sys
(req-all :minimap)
(fn [_ {: minimap}]
(map 1 1 8 5 10 10 5))))
(var drawsys-city-minimap
(draw-proc-sys
(req-all :pos :city)
(fn [_ {: pos : city}]
(circ (+ 10 (/ pos.x 10))
(+ 10 (/ pos.y 10))
(/ city.radius 14)
(match city.state
:living 10
:dead 1)))))
(var drawsys-earthquake-minimap
(draw-proc-sys
(req-all :pos :earthquaker-core)
(fn [_ {: pos}]
(pix (+ 10 (/ pos.x 10))
(+ 10 (/ pos.y 10))
5))))
(var sys-powerup
(proc-sys
(req-all :pos :powerup)
(fn [{: world : eq} e dt]
(let [core eq.earthquaker-core
size (+ 5 (* 1 (# core.rings)))]
(when (< (e.pos:dist eq.pos) size)
(sfx 17 nil -1 3)
(core:add-ring world eq)
(rmv-ent world e))))))
(var drawsys-powerup-minimap
(draw-proc-sys
(req-all :pos :powerup)
(fn [_ {: pos}]
(pix (+ 10 (/ pos.x 10))
(+ 10 (/ pos.y 10))
2))))
;; TAB: Entities
(fn create-earthquaker-core [x y]
(+ (ent)
(pos x y true)
(bounds -30 -30 (+ WORLD-W 30) (+ WORLD-H 30))
(vel 0 0 2 2)
(dinode)
(earthquaker-common 1)
(earthquaker-core)))
(global create-earthquaker-ring (fn [x y i]
(+ (ent)
(pos x y)
(dinode)
(earthquaker-common i)
(earthquaker-ring i))))
(fn create-person [city-pt]
(+ (ent)
(person city-pt)
(pos city-pt.pos.x city-pt.pos.y)
(vel 0 0 2 2)
(fric 0.94)
(bounds 0 0 WORLD-W WORLD-H)
(anim
:idle
{:idle {:frames [288 289] :speed 30 :colorkey 0}
:ko {:frames [290] :speed 30 :colorkey 0}
:aahh {:frames [291 292] :speed 10 :colorkey 0}})))
(fn create-building [city-pt x y height]
(+ (ent)
(pos x y)
(building city-pt (+ (rnd 0 1) height))))
(fn create-city [x y radius]
(var foliage [])
(for [i 1 (rnd 20 25)]
(let [pos (rnd-point-in-circle x y radius)]
(add foliage {:s (. [1 2] (rnd 1 2))
:x pos.x
:y pos.y})))
(+ (ent)
(pos x y)
(city radius foliage)))
(fn create-powerup []
(+ (ent)
(pos (rnd 10 (- WORLD-W 10))
(rnd 10 (- WORLD-H 10)))
(powerup)
(anim :idle {:idle {:frames [304 305 306 307 308 309 310 311 304 304]
:speed 6
:colorkey 0}})))
;; 5 TAB: Factories
(fn factory-earthquaker [world count x y]
(var earthquaker (add-ent world (create-earthquaker-core x y)))
(for [i 1 count]
(let [{: rings : joints} earthquaker.earthquaker-core]
(add rings (add-ent world (create-earthquaker-ring (+ x (rnd)) (+ y (rnd)) i)))
(add joints (add-ent world (+ (ent)
(spring earthquaker (. rings (# rings)) 1 (/ 1 (/ i 1.5))))))))
earthquaker)
(fn factory-people [world city count]
(var people [])
(for [i 1 count]
(add people (add-ent world (create-person city))))
people)
(fn factory-buildings [world city count]
(var buildings [])
(for [i 1 count]
(let [position (rnd-point-in-circle city.pos.x city.pos.y city.city.radius)]
(add buildings (add-ent world (create-building city position.x position.y 1)))))
buildings)
(global city-location-valid?
(fn city-location-valid? [cities px py pr]
;; raidus's of all existing cities dont overlap with new potential one
;; also the city shouldnt be out of bound!s
(all cities
(fn [c]
(and (> (c.pos:dist (vector px py)) (+ c.city.radius pr))
(< 0 (- px pr)) ;; left
(> WORLD-W (+ px pr)) ;; right
(< 0 (- py pr)) ;; top
(> WORLD-H (+ py pr)) ;; bottom
)))))
(global factory-city
(fn factory-city [world cities newx newy newr]
(let [city (add-ent world (create-city newx newy newr))]
(tset city.city :people (factory-people world city (round (/ newr 7))))
(tset city.city :buildings (factory-buildings world city (round (/ newr 10))))
(add cities city))))
(fn factory-cities [world count]
(var cities [])
(for [i 1 count]
(var newx (rnd 10 WORLD-W))
(var newy (rnd 10 WORLD-H))
(var newr (rnd 30 50))
(var try 0)
(while (and (not (city-location-valid? cities newx newy newr))
(< try 10))
(set newx (rnd 10 WORLD-W))
(set newy (rnd 10 WORLD-H))
(set try (+ try 1)))
(factory-city world cities newx newy newr))
cities)
;; A TAB: Main Gamestate
(fn main-enter [self]
(var world (create-world))
(var earthquaker (factory-earthquaker world 8 (/ WORLD-W 2) (/ WORLD-H 2)))
(set CAMERA.follow earthquaker.pos)
(for [i 1 100] (CAMERA:update 1))
(var cities (factory-cities world 5))
(add-ent world (+ (ent) (minimap)))
;; Powerups
(for [i 1 5] (add-ent world (create-powerup)))
(add-ent world (create-timer world -1 200
(fn [self] (add-ent world (create-powerup)))))
(add-sys world sys-shake)
(add-sys world sys-timer)
(add-sys world sys-positions)
(add-sys world sys-velocity)
(add-sys world sys-friction)
(add-sys world sys-bounds)
(add-sys world sys-verlet)
(add-sys world sys-earthquaker)
(add-sys world sys-earthquaker-common)
(add-sys world sys-anim)
(tset sys-city :cities cities)
(add-sys world sys-city)
(tset sys-powerup :eq earthquaker)
(add-sys world sys-powerup)
(tset sys-building :eq earthquaker)
(add-sys world sys-building)
(tset sys-person-ai :eq earthquaker)
(add-sys world sys-person-ai)
;; (tset sys-person-debug :eq earthquaker)
;; (add-sys world sys-person-debug)
(tset drawsys-earthquaker-ring :eq earthquaker)
(add-sys world drawsys-earthquaker-ring)
(add-sys world drawsys-earthquaker-core)
(add-sys world drawsys-city-foliage)
(add-sys world drawsys-anim)
(add-sys world drawsys-building)
(add-sys world drawsys-minimap)
(add-sys world drawsys-city-minimap)
(add-sys world drawsys-earthquake-minimap)
(add-sys world drawsys-powerup-minimap)
;; (add-sys world drawsys-person-debug)
(set self.world world)
(POPUP:create
["After a particularly emotional"
"breakup, Tectonica the earthquake is"
"feeling a little unstable."
""
"What better way to blow off some"
"steam then to BRING THE FEEBLY"
"CONSTRUCTED BUILDINGS OF THOSE"
"INSIGNIFICANT ANTS TO THE GROUND!"
""
" Should be fun :) "]
(fn []
(POPUP:create
["Use the mouse to move."
""
"Click the keyboard buttons or mouse"
"to unleash your shake to bring down"
"buildings."
""
"Shaking will use up your rings, so"
"be sure to collect those shiny"
"tremors to refuel them."]
(fn []
(POPUP:create
["Take down all the buildings, or"
"just watch them grow and multiply."
""
"It's really up to you."]
(fn []
(music 2)
(set POPUP.active false))))))))
(fn main-update [{: world} dt]
(if POPUP.active
(POPUP:update 1)
(do
(CAMERA:update 1)
(world:update dt update-system-filter)
(particles.update))))
(fn main-draw [{: world}]
;; (trace POPUP.active)
(if POPUP.active
(POPUP:draw)
(do
(cls)
(world:update 0 draw-system-filter)
(particles.draw))))
(fn main-leave [self]
(clear-systems self.world)
(clear-entities self.world)
(refresh self.world)
(set self.world nil))
(var gs-main {:enter main-enter :update main-update :draw main-draw :leave main-leave })
;; TAB: Title screen gamestate
(fn title-enter [self]
(music 0))
(fn title-update [self dt]
(let [(x y left middle right) (mouse)]
(when (or (btnp 0) (btnp 1) (btnp 2) (btnp 3)
(btnp 4) (btnp 5) (btnp 6) (btnp 7)
left middle right)
(GS.switch gs-main))))
(fn title-draw [{: world}]
(cls)
(for [i 1 50]
(let [s (* 10 (% (* T 0.02) 20))
s (+ -170 s (* i 20))]
(circb 120 164 s 1)))
(print "TECTONICALYPSE" 40 40 12 true 3 true)
(print "Click to begin" 90 104 12 true 1 true))
(global gs-title { :enter title-enter :update title-update :draw title-draw})
;; TAB: tic80 tic
(GS.switch gs-title)
(global TIC
(fn tic []
(GS.update 1)
(GS.draw)
(set T (+ T 1))))
;; <TILES>
;; 001:0000000000000000000000000000000000070000000706000000060000000000
;; 002:0000000000000000000007000000700006007060007070600000000000000000
;; 003:0000000000000000000000000000000000020000000203000000030000000000
;; 004:0000000000000000000002000000200003002030002020300000000000000000
;; 016:eddddddcd000000cccccccccc000000cc004400cc004400cd000000dedddccde
;; 017:fedeeeede000000dddddddddd000000dd004400dd004400de000000eeddddeee
;; 018:1111eeed1000000deeeddddde000000ee004400ee00440011000000111111111
;; 048:5555555558eededeed000000ee000000ec000000dc0eee00dd0eee00dc000000
;; 049:55555555ddddddc5000000cc000ee0cc000ee0cc000000cc000000cc000000cc
;; 052:555555555f11212112000000110000001c0000002c011100220111002c000000
;; 053:55555555222222c5000000cc000110cc000110cc000000cc000000cc000000cc
;; 056:555555555feededeed000000ee000000ec000000dc0eee00dd0eee00dc000000
;; 057:55555555ddddddc5000000cc000ee0cc000ee0cc000000cc000000cc000000cc
;; 064:ccccccccdddddddddd000000dd0eeee0dd0e4ce0dd0e44e0dd0e88e0dd000000
;; 065:ccccccccdddddddc000000dd0eeee0dd0ec4e0dd0e44e0dd0e8ee0dd000000dd
;; 066:5555555555555555ccd55555c88d5555d888d555ce888d55ce888855c88e88d5
;; 067:5555555555555555555555555555555555555555555555cc55555dec5555deed
;; 068:cccccccc22222222220000002201111022014c10220144102201ff1022000000
;; 069:cccccccc2222222c000000220111102201c410220144102201f1102200000022
;; 070:5555555555555555cc255555cff255552fff2555c1fff255c1ffff55cff1ff25
;; 071:5555555555555555555555555555555555555555555555cc5555521c55552112
;; 072:ccccccccdddddddddd000000dd0eeee0dd0e4ce0dd0e44e0dd0effe0dd000000
;; 073:ccccccccdddddddc000000dd0eeee0dd0ec4e0dd0e44e0dd0efee0dd000000dd
;; 074:5555555555555555ccd55555cffd5555dfffd555cefffd55ceffff55cffeffd5
;; 075:5555555555555555555555555555555555555555555555cc55555dec5555deed
;; 080:dd000000dd0eeee0dd0ec4e0ed0e4480dd0ee880dd000000ede00000eeeddded
;; 081:000000dd0eeee0de0ec4e0dd0e44e0dd088ee0dd000000de00000ededdededee
;; 082:deeeeeeed00eee00d0800000e08880008088800d8008800de000dd008eedddee
;; 083:edddeeee0000000eeee0080ceee0880cd00080cdd00000dd00000dddeeeddddd
;; 084:22000000220111102201c410120144f022011ff0220000001210000011122212
;; 085:000000220111102101c41022014410220ff11022000000210000012122121211
;; 086:211111112001110020f0000020fff000f0fff002f00ff00210002200f1122211
;; 087:122211110000000111100f0c1110ff0c2000f0c2200000220000022211122222
;; 088:dd000000dd0eeee0dd0ec4e0ed0e44f0dd0eeff0dd000000ede00000eeeddded
;; 089:000000dd0eeee0de0ec4e0dd0e44e0dd0ffee0dd000000de00000ededdededee
;; 090:deeeeeeed00eee00d0f00000e0fff000f0fff00df00ff00de000dd00feedddee
;; 091:edddeeee0000000eeee00f0ceee0ff0cd000f0cdd00000dd00000dddeeeddddd
;; 112:eeeeeeeee0000000e0000000e0000000e0000000e0000000e0000000e0000000
;; 113:e5555555e5555555e5555555e5555555e5555555e5555555e5555555e5555555
;; 128:eeeeeeee55555555555555555555555555555555555555555555555555555555
;; 129:5555555555555555555555555555555555555555555555555555555555555555
;; </TILES>
;; <SPRITES>
;; 000:555c00005550c00055000c005500c0c055021c0055002000555000cc55550c00
;; 001:555c00005550c00055000c005500c0c055021c005500200055500c00555500cc
;; 016:00000000000000000000000000000000000c000000ccd000000c000000c0c000
;; 017:00000000000000000000000000000000000cd0000c0c000000ccc00000000000
;; 018:000000000000000000000000000000000000000000000000000d000000cccc00
;; 032:000000000000000000ecc00000ecc00000dcc0000c0c0d0000d0c00000000000
;; 033:000000000000000000ecc00000ecc00000dcc0000d0c0c0000c0d00000000000
;; 034:000000000000000000000000000000000e0ecc0000decce00ccccc000000d000
;; 035:000000000000000000ecc000c0ecc0c000dcc000000c0c0000d0000000000000
;; 036:000000000000000000ecc000c0ecc0c000dcc0000d0c00000000c00000000000
;; 048:1111111110000001101111011010010110100101101111011000000111111111
;; 049:1111111110000001102222011020020110200201102222011000000111111111
;; 050:1111111110000001103333011030030110300301103333011000000111111111
;; 051:1111111110444401104004011040040110444401100000011000000111111111
;; 052:11cccc1110c00c0110c00c0110cccc0110000001100000011000000111111111
;; 053:2222222220444402204004022040040220444402200000022000000222222222
;; 054:3333333330000003303333033030030330300303303333033000000333333333
;; 055:2222222220000002202222022020020220200202202222022000000222222222
;; 056:4444444440000004401111044010010440100104401111044444444400000000
;; 057:3333333330000003301111033010010330100103301111033000000333333333
;; 058:2222222220000002201111022010010220100102201111022000000222222222
;; </SPRITES>
;; <MAP>
;; 001:070707070707070717000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
;; 002:070707070707070717000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
;; 003:070707070707070717000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
;; 004:070707070707070717000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
;; 005:080808080808080818000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
;; </MAP>
;; <WAVES>
;; 000:deedca876789a97532112578876678ac
;; 001:0123456789abcdeffedcba9876543210
;; 002:0123456789abcdef0123456789abcdef
;; 003:93000368adeffffec8510000159defff
;; 004:00000000ffffffff00000000ffffffff
;; 005:44444044004040044440444404440404
;; 006:0000000000000000000fffffffffffff
;; </WAVES>
;; <SFX>
;; 000:c30063000300030023002300230033004300430043004300430043004300430043014302430143004300430f430e430f4300430043004300430043003070000000fa
;; 001:c30063000300030023003300430053006300730073008300830093009300a300a301b302b301c300c300c30fd30ed30fe300e300f300f300f300f3003070000000fa
;; 002:d100d100d100c100b100a100810061005100410031003100310031004100410041014102410141004100410f410e410f4100410041004100410041003070000000fa
;; 003:110011002100210021003100310041004100510051006100610071007100810081019102a101b100c100c10fd10ed10fe100e100e100e100e100e1003070000000fa
;; 004:00001000200020003000400040005000500060006000600070007000800180018002900190019000a000a00fa00fa00eb00fb00fb00fb000b00fc0005000000000cf
;; 005:31003100110011001100210041005100510061006100610071007100810181018102910191019100a100a10fa10fa10eb10fb10fb10fb100b10fc1005000000000cf
;; 006:30001000000000000000200040005000600070007000800090009000a001a001b002c001c001c000c000d00fd00fe00ee00fe00fe00fe000e00ff0004200000000cf
;; 008:960026002600260086009600a600b600b600c600d600e600e6008600260026002600a600a600c600c600c600d600d600d600d600e600f600f600f600500000000000
;; 009:160026004600560086009600a600b600b600c600d600e600e600e600e600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600500000000000
;; 012:008000001090208030804070507060607060806090509040a040b030b000c020c020d000d010e010e000f000f000f000f000f000f000f000f000f000400000000000
;; 013:0130013001b041b041b041b0f1b0f1b0f1b0f100b130b13041304180518051705170617061607150815091509140f100f100f100f100f100f100f100500000000000
;; 014:03606360c360c360e360e32bf320f300f300f300f300f300f300f300f300f300f300f300f300f300f300f300f300f300f300f300f300f300f300f300502000000000
;; 016:a6088608c607e607f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600304000000000
;; 017:00f8000800f8000800f8000800f9000900fa000b00fb000c00fd000e00ff000010f1100220f4300540f6500750f7600780f7a007c0f7e007f0f7f007329000000000
;; 018:4708378947fa778cb72fc710d702d703d705d706d706d700e700e700e700e700e700e700e700e700f700f700f700f700f700f700f700f700f700f700410000000000
;; 019:07f517e117dd27cc47bd67a07781877287639761975fb740b732c733c736d724d72bd71dd710d713e713e71fe70de70ff700f702f702f701f700f70030b000000000
;; 020:a7f797e677d657d647d637c527b517b517a4079407940794078407840773077307630752075207511741174027403730473f672f972ea71dc71cf70b370000000000
;; 021:06f006e006d006b006a016801670266036504630662076108600b600d600f600f600f600f600f600f600f600f600f600f600f600f600f600f600f600210000000000
;; 024:d00090007000400030002000100000000000000000000000000000000000000000000000000110012001200e300040026003700ea00fc002e00df00e370000000000
;; 025:f7f0d7f0c7e0c7b0c7a0c780e770e77fe76fe75fe75ef74df74df73cf72cf72bf71af71af719f709f708f708f700f700f700f700f700f700f700f700207000000000
;; 026:e742e773e771d78ed78ed781c771c75fc740c752d750d75de75fe771f780d700d700c700b700b700c700d700e700d700d700d700d700d700e700e7002000000f0906
;; </SFX>
;; <PATTERNS>
;; 000:dff142000000800046000000f00046000000800048000000f0004800000080004a000000f0004a00000080004c000000d0004c00000080004c000000f0004a00000080004a000000fff148000000800048000000f00046000000800046000000dff142000000800046000000f00046000000800048000000f0004800000080004a000000f0004a00000080004c000000d0004c00000080004c000000f0004a00000080004a000000fff148000000800048000000f00046000000800046000000
;; 001:90004200000060004600000090004600000060004800000090004800000060004a00000090004a00000060004c000000f0004a00000090004a00000060004a000000900048000000600048000000900046000000600046000000f0004400000090004200000060004600000090004600000060004800000090004800000060004a00000090004a00000060004c000000f0004a00000090004a00000060004a000000900048000000600048000000900046000000600046000000f00044000000
;; 002:600044000000d00044000000600046000000d00046000000600048000000d0004800000060004a000000d0004a00000080004c000000d0004a00000060004a000000d00048000000600048000000d00046000000600046000000d00044000000600044000000d00044000000600046000000d00046000000600048000000d0004800000060004a000000d0004a00000080004c000000d0004a00000060004a000000d00048000000600048000000d00046000000600046000000d00044000000
;; 003:000000400046000000d00046000000400048000000d0004800000040004a000000d0004a00000040004c000000c0004c000000c0004c00000040004c000000d0004a00000040004a000000d00048000000400048000000d00046000000400046000000400046000000d00046000000400048000000d0004800000040004a000000d0004a00000040004c000000c0004c000000c0004c00000040004c000000d0004a00000040004a000000d00048000000400048000000d00046000000400046
;; 004:000000d00044000000800046000000d00046000000800048000000d0004800000080004a000000d0004a00000040004c000000d0004a00000080004a000000d00048000000800048000000d00046000000800046000000400046000000d00044000000d00044000000800046000000d00046000000800048000000d0004800000080004a000000d0004a00000040004c000000d0004a00000080004a000000d00048000000800048000000d00046000000800046000000400046000000d00044
;; 005:000000900044000000f00044000000900046000000f00046000000900048000000f0004800000090004a000000f0004a000000f0004a00000090004a000000f00048000000900048000000f00046000000900046000000f00044000000900044000000900044000000f00044000000900046000000f00046000000900048000000f0004800000090004a000000f0004a000000f0004a00000090004a000000f00048000000900048000000f00046000000900046000000f00044000000900044
;; 006:000000d95144000000800046000000f00046000000800048000000f0004800000080004a000000f0004a00000080004c000000d0004c00000080004c000000f0004a00000080004a000000fff048000000800048000000f00046000000800046000000dff044000000800046000000f00046000000800048000000f0004800000080004a000000f0004a00000080004c000000d0004c00000080004c000000f0004a00000080004a000000fff048000000800048000000f00046000000800046
;; 007:00000095914400000060004600000090004600000060004800000090004800000060004a00000090004a00000060004c000000f0004a00000090004a00000060004a000000900048000000600048000000900046000000600046000000f0004400000090004400000060004600000090004600000060004800000090004800000060004a00000090004a00000060004c000000f0004a00000090004a00000060004a000000900048000000600048000000900046000000600046000000f00044
;; 008:000000659144000000d00044000000600046000000d00046000000600048000000d0004800000060004a000000d0004a00000080004c000000d0004a00000060004a000000d00048000000600048000000d00046000000600046000000d00044000000600044000000d00044000000600046000000d00046000000600048000000d0004800000060004a000000d0004a00000080004c000000d0004a00000060004a000000d00048000000600048000000d00046000000600046000000d00044
;; 009:000000000000459146000000d00046000000400048000000d0004800000040004a000000d0004a00000040004c000000c0004c000000c0004c00000040004c000000d0004a00000040004a000000d00048000000400048000000d00046000000400046000000400046000000d00046000000400048000000d0004800000040004a000000d0004a00000040004c000000c0004c000000c0004c00000040004c000000d0004a00000040004a000000d00048000000400048000000d00046000000
;; 010:400046000000d95144000000800046000000d00046000000800048000000d0004800000080004a000000d0004a00000040004c000000d0004a00000080004a000000d00048000000800048000000d00046000000800046000000400046000000d00044000000d00044000000800046000000d00046000000800048000000d0004800000080004a000000d0004a00000040004c000000d0004a00000080004a000000d00048000000800048000000d00046000000800046000000400046000000
;; 011:d00044000000995144000000f00044000000900046000000f00046000000900048000000f0004800000090004a000000f0004a000000f0004a00000090004a000000f00048000000900048000000f00046000000900046000000f00044000000900044000000900044000000f00044000000900046000000f00046000000900048000000f0004800000090004a000000f0004a000000f0004a00000090004a000000f00048000000900048000000f00046000000900046000000f00044000000
;; 012:800044000000f00044000000800046000000f00046000000800048000000f0004800000080004a000000f0004a000000a0004c000000f0004a00000080004a000000f00048000000800048000000f00046000000800046000000f00044000000800044000000f00044000000800046000000f00046000000800048000000f0004800000080004a000000f0004a000000c0004c000000f0004a00000080004a000000f00048000000800048000000f00046000000800046000000f00044000000
;; 013:000000d00044000000600046000000d00046000000600048000000d0004800000060004a000000d0004a00000060004c00000060004c000000d0004a00000060004a000000d00048000000600048000000d00046000000600046000000d00044000000c00044000000600046000000c00046000000600048000000c0004800000060004a000000c0004a00000080004c00000080004c000000c0004a00000060004a000000c00048000000600048000000c00046000000600046000000c00044
;; 014:000000859144000000f00044000000800046000000f00046000000800048000000f0004800000080004a000000f0004a000000a0004c000000f0004a00000080004a000000f00048000000800048000000f00046000000800046000000f00044000000800044000000f00044000000800046000000f00046000000800048000000f0004800000080004a000000f0004a000000c0004c000000f0004a00000080004a000000f00048000000800048000000f00046000000800046000000f00044
;; 015:895146000000d95144000000600046000000d00046000000600048000000d0004800000060004a000000d0004a00000060004c00000060004c000000d0004a00000060004a000000d00048000000600048000000d00046000000600046000000d00044000000c00044000000600046000000c00046000000600048000000c0004800000060004a000000c0004a00000080004c00000080004c000000c0004a00000060004a000000c00048000000600048000000c00046000000600046000000
;; 016:d55142000040100040000040100040000000100040000000100040000000100040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
;; 017:100040000000800046000000100040100040400046000000100040000000100040000000100040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
;; 019:d00056000000000000000000400058000050000000000000800058000000000000000000c00058000000000000000000d00058000000000000000000f0005800000040005a000000f00058000000000000000000d00058000000000000000000c00058000000d00058000000f00058000000800058000050a00058000000c00058000050d00058000000000000000000600058000000700058000000900058000000b00058000050800058000000000050000000b00058000000400058000000
;; 020:900058000000000000000000800058000000000000000000600058000000000000000000400058000000000000000000f00056000000000000000000400058000000000000000000600058000000000000000000b00058000000000000000000900058000000800058000000600058000000400058000000600058000000700058000000800058000050c00058000000d00058000000800058000000400058000000800058000000d00056000000800056000000d00054000000000000000000
;; 021:800058000000000000000000000000000000000000000000d0005800000000000000000000005000000000000000000080005a00000000000000000060005a00000000000000000080005a000000000000000000000000000000000000000000900058000000000000000000600058000000000000000000c00058000000c00056000050d00056000050f00056000000400058000000000000000000d00056000000b00056000000800056000000000000000000000000000000000000000000
;; 022:600056000000000000000000000000000000000000000050b00056000000000000000000000050000000000000000000800056000000000000000000000050000000000050000000f00056000000000000000000000000000000000000000000d00058000000f0005800000040005a00000000000000000080005a000000000000000000800058000000000000000000d00058000000000000000000d00056000000000000000000d00052000000000000000000b00056000000100050000000
;; 023:400058000000000000000000800058000000000000000000b0005800000000000000000040005a000000000000000000f0005800000040005a00000060005a00000040005a000000f00058000000d00058000000b00058000000000000000000000050000000000000000000900058000000000000000000900058000000000000000000b00058000000000000000000900058b00058900058b00058900058000000800058000000800058000000000000000000000000000000000000000000
;; 024:b00056000000000000000000000000000000000000000000d00056000000000000000000800056000000000000000000900056000000800056000000600056000000400056000000600056000000000000000000000000000000000000000000600056000000000000000000b00056000000000000000000600056000000800056000000900056000000b00056000000900056000000000050000000800056000000000000000000800056000000000000000000000050000000000000000000
;; 025:d00058000000000000000000600058000000000000000000400058000000000050000000a00058000000000000000000b00058000000000000000000d00058000000000000000000f00058000000000000000000a0005800000000000000000040005a000000f00058000000d00058000000000000000000c00058000000d00058000000c00058000000000000000000d00058000000000000000000700058000000000050000000800058000000000000000000000000000000000000000000
;; 026:600056000000000000000000a00056000000000050000000a00056000000000050000000b00056000000000000000000f00056000000000000000050b00054000000000000000000b00054000000000000000000000000000000000000000000d00056000000b00056000000a00056000000800056000000600056000000700056000000800056000000c00056000000d00056000000000000000000800056000000000000000000d00054000000000000000000d00052000000000000000000
;; </PATTERNS>
;; <TRACKS>
;; 000:1017822418c2381903d83f04000000000000000000000000000000000000000000000000000000000000000000000000be0020
;; 001:0007820008c2000903000f04000000000000000000000000000000000000000000000000000000000000000000000000000060
;; 002:0004950005d5000856000ad60000000000000000000000000000000000000000000000000000000000000000000000006f0000
;; </TRACKS>
;; <PALETTE>
;; 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
;; </PALETTE>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment