Skip to content

Instantly share code, notes, and snippets.

@AndreiRudenko
Last active July 4, 2018 19:19
Show Gist options
  • Save AndreiRudenko/87787bbaf60d6d3ce787ea53dd841ba9 to your computer and use it in GitHub Desktop.
Save AndreiRudenko/87787bbaf60d6d3ce787ea53dd841ba9 to your computer and use it in GitHub Desktop.
Source code for my OMGJAM 4 entiry
// author: Andrei Rudenko (https://github.com/RudenkoArts)
// desc: omgjam4
// script: wren
// you can use this code in TIC-80 0.70 version (current git version)
// TIC-80 starting with 0.70 support wren language
// https://github.com/nesbox/TIC-80
import "random" for Random
// utils
class DynamicPool {
construct new(size, create_cb) {
_items = []
_cf = create_cb
_sz = size
for (i in 0...size) {
_items.add(_cf.call())
}
}
get() { _items.count > 0 ? _items.removeAt(-1) : _cf.call() }
put(item) {
if(_items.count < _sz) {
_items.add(item)
}
}
}
class Timer {
static time(){ 0}
static init(){
__timers = []
}
static add(t){
__timers.add(t)
return t
}
static remove(t){
var ot = null
for (i in 0...__timers.count) {
if (ot == __timers[i]) {
__timers.removeAt(i)
break
}
}
}
static schedule(tl){ schedule_from(0, tl, null) }
static schedule(tl, cb){ schedule_from(0, tl, cb) }
static schedule_from(ct, tl){ schedule_from(ct, tl, null) }
static schedule_from(ct, tl, cb){
var t = Timer.new()
t.start_from(ct, tl, cb)
return t
}
static update(dt){
for (t in __timers) {
if (t.active && !t.finished && t.time_limit >= 0){
t.update(dt)
}
}
}
time_limit { _time_limit }
time_limit=(v) { _time_limit = v }
loops { _loops }
loops=(v) { _loops = v }
active { _active }
active=(v) { _active = v }
elapsed_time { _time }
elapsed_time=(v) { _time = v }
use_timescale { _use_ts }
use_timescale=(v) { _use_ts = v }
finished { _finished }
elapsed_loops { _loops_counter }
time_left { _time_limit - _time }
loops_left { _loops - _loops_counter }
progress { (_time_limit > 0) ? (_time / _time_limit) : 0 }
construct new(){
_time = 0
_time_limit = 0
_start_time = 0
_loops = 0
_loops_counter = 0
_inarray = false
_active = true
_use_ts = true
_finished = false
}
start(tl) { start_from(0, tl, null) }
start(tl, cb) { start_from(0, tl, cb) }
start_from(st, tl) { start_from(st, tl, null) }
start_from(st, tl, cb) {
stop(false)
if (!_inarray) {
Timer.add(this)
_inarray = true
}
_active = true
_finished = false
if(cb != null){
_oncomplete = cb
}
_time_limit = tl.abs
_start_time = (_time_limit..st).min
_time = _start_time
_loops = 1
_loops_counter = 0
return this
}
stop() { stop(true) }
stop(finish) {
if(!_finished) {
_finished = true
_active = false
if (_inarray){
Timer.remove(this)
_inarray = false
}
if (finish && _oncomplete != null) {
_oncomplete.call()
}
}
}
oncomplete(cb){
_oncomplete = cb
return this
}
update(dt){
if (_use_ts) dt = dt * Game.timescale
_time = _time + dt
while (!_finished && _time_limit < _time) {
_loops_counter = _loops_counter + 1
if (_loops > 0 && (_loops_counter >= _loops)) {
stop()
break
}
_time = _time - _time_limit
}
}
}
class Vector {
construct new() {
_x = 0
_y = 0
}
construct new(x,y) {
_x = x
_y = y
}
x=(v) { _x = v }
y=(v) { _y = v }
length=(v) { normalize().multiply(v) }
x { _x }
y { _y }
length { ( x * x + y * y ).sqrt }
lengthsq { x * x + y * y }
copy(o) {
_x = o.x
_y = o.y
return this
}
set(x, y) {
_x = x
_y = y
return this
}
normalize() { divide( length ) }
dot(o) { x * o.x + y * o.y }
add(o) {
if (o is Num) {
_x = _x + o
_y = _y + o
} else{
_x = _x + o.x
_y = _y + o.y
}
return this
}
add(x, y) {
_x = _x + x
_y = _y + y
return this
}
subtract(o) {
if (o is Num) {
_x = _x - o
_y = _y - o
} else{
_x = _x - o.x
_y = _y - o.y
}
return this
}
subtract(x, y) {
_x = _x - x
_y = _y - y
return this
}
multiply(o) {
if (o is Num) {
_x = _x * o
_y = _y * o
} else{
_x = _x * o.x
_y = _y * o.y
}
return this
}
multiply(x, y) {
_x = _x * x
_y = _y * y
return this
}
divide(o) {
if (o is Num) {
_x = _x / o
_y = _y / o
} else{
_x = _x / o.x
_y = _y / o.y
}
return this
}
divide(x, y) {
_x = _x / x
_y = _y / y
return this
}
toString { "{ x:%(x), y:%(y) }" }
}
class Utils {
static list_remove(l,v){
for (i in 0...l.count) {
if (l[i] == v) {
l.removeAt(i)
return true
}
}
return false
}
static elegant_pair(x, y) {
var z = (x >= y) ? (x * x + x + y) : (y * y + x)
if(z < 0) {
Fiber.abort("pairing error")
}
return z
}
static random_point_in_unit_circle(into) {
var r = Game.random.float().sqrt
var t = (-1 + (2 * Game.random.float())) * 6.283185307179586 // two PI
into.x = r * t.cos
into.y = r * t.sin
return into
}
static rotate(cx,cy,angle,p) {
var rad = angle*Num.pi/180
var s = rad.sin
var c = rad.cos
p.x = p.x - cx
p.y = p.y - cy
var xnew = p.x * c - p.y * s
var ynew = p.x * s + p.y * c
p.x = xnew + cx
p.y = ynew + cy
return p
}
}
class Maths {
static get_sphere_mass(r,d){ (4/3 * Num.pi * r.pow(3)) * d }
static distance(x1,y1,x2,y2) {
var x = x2-x1
var y = y2-y1
return ( x * x + y * y ).sqrt
}
static clamp(value, a, b) {
return ( value < a ) ? a : ( ( value > b ) ? b : value )
}
static mod(a,b) {
var r = a % b
return r < 0 ? r + b : r
}
static lerp(value, target, t) {
t = Maths.clamp(t, 0, 1)
return (value + t * (target - value))
}
}
class Pow {
static require(x) {
if(x == 0) return 1
x = x - 1
x = x | x >> 1
x = x | x >> 2
x = x | x >> 4
x = x | x >> 8
x = x | x >> 16
return x + 1
}
static to_pow(num) { ((num.log)/(2).log).round }
}
class Space {
x { _x }
y { _y }
w { _w }
h { _h }
objects { _objs }
count { _count }
construct new(x,y,w,h) {
_x = x
_y = y
_w = w
_h = h
_hw = w*0.5
_hh = h*0.5
_objs = {}
_count = 0
}
check(b) {
if (!_objs.containsKey(b.entity)) {
if (Collision.circle_rect_fast(b.x,b.y,b.r,_x,_y,_x+_w,_y+_h)) {
_objs[b.entity] = b
_count = _count + 1
}
} else if(!Collision.circle_rect_fast(b.x,b.y,b.r,_x,_y,_x+_w,_y+_h)) {
_objs.remove(b.entity)
_count = _count - 1
}
}
remove(b) {
if (_objs.remove(b.entity) != null) {
_count = _count - 1
}
}
draw() {
var c = 11
TIC.print("contacts:%(_count)", 0, 8, 11)
TIC.rectb(x, y, w, h, c)
for (o in _objs.values) {
TIC.circb(o.x, o.y, o.r, 12)
}
}
}
class Collision {
static circle_circle(c1x,c1y,c1r,c2x,c2y,c2r,ci) {
ci.reset()
var dx = c1x-c2x
var dy = c1y-c2y
var r = c1r + c2r
var dist2 = dx*dx+dy*dy
if(dist2 >= r*r) return false
var dist = dist2.sqrt
if(dist < 0.001) return false
var mtd_x = dx * (r - dist) / dist
var mtd_y = dy * (r - dist) / dist
ci.separation = (mtd_x * mtd_x + mtd_y * mtd_y).sqrt
ci.normal.set(mtd_x, mtd_y).divide(ci.separation)
return true
}
static circle_circle_fast(c1x,c1y,c1r,c2x,c2y,c2r) {
var dx = c1x - c2x
var dy = c1y - c2y
var r = c1r + c2r
return (dx * dx + dy * dy) < (r * r)
}
static circle_rect_fast(cx,cy,cr,minx,miny,maxx,maxy) {
var cx_ = cx
var cy_ = cy
if (cx < minx) cx = minx
if (cx > maxx) cx = maxx
if (cy < miny) cy = miny
if (cy > maxy) cy = maxy
var dx = cx_ - cx
var dy = cy_ - cy
return ( dx * dx + dy * dy < cr * cr )
}
static aabb_aabb_fast(b1x,b1y,b1w,b1h,b2x,b2y,b2w,b2h ){
if((b1x - b2x).abs > (b1w + b2w)) return false
if((b1y - b2y).abs > (b1h + b2h)) return false
return true
}
static solve_pos(c,p) {
p.x = p.x + c.separation * c.normal.x
p.y = p.y + c.separation * c.normal.y
}
static solve_vel(c,v,r) {
var vn = v.x * c.normal.x + v.y * c.normal.y
if (vn < 0) {
var j = -(1 + r) * vn
v.x = v.x + c.normal.x * j
v.y = v.y + c.normal.y * j
}
}
static get_contacts(b,into) {
var cid = -1
var c = null
for (oth in Game.space.objects.values) {
if (oth != b) {
if (Collision.circle_circle_fast(b.x,b.y,b.r,oth.x,oth.y,oth.r)) {
cid = Utils.elegant_pair(b.entity,oth.entity)
c = into[cid]
if (c == null) {
c = Game.contacts_pool.get()
c.id = cid
c.entity = b.entity
c.other = oth.entity
into[cid] = c
} else {
c.remove = false
}
}
}
}
// clear contacts
for (c in into.values) {
if (c.remove) {
Game.contacts_pool.put(c)
into.remove(c.id)
c.clear()
} else {
c.remove = true
}
}
}
static get_contacts2(b,into) {
for (oth in Game.space.objects.values) {
if (oth != b) {
var c = Game.contacts_pool.get()
c.entity = b.entity
c.other = oth.entity
into.add(c)
}
}
}
static remove_contacts2(into) {
for (c in into) {
Game.contacts_pool.put(c)
}
into.clear()
}
}
class CollisionInfo {
id { _id }
entity { _entity }
other { _other }
normal { _norm }
separation { _sep }
remove { _rem }
id=(v) { _id=v }
entity=(v) { _entity=v }
other=(v) { _other=v }
normal=(v) { _norm=v }
separation=(v) { _sep=v }
remove=(v) { _rem=v }
construct new() {
_norm = Vector.new()
_id = -1
_sep = 0
_rem = false
}
reset() {
_norm.set(0,0)
_sep = 0
}
clear() {
reset()
_id = -1
_rem = false
_entity = null
_other = null
}
}
// renderer
class Drawable {
x { _x }
y { _y }
x=(v) { _x = v }
y=(v) { _y = v }
ox { _ox }
oy { _oy }
ox=(v) { _ox = v }
oy=(v) { _oy = v }
visible { _visible }
visible=(v) { _visible = v }
layer { _layer }
layer=(v) {
if (_rl != null) {
_rl.remove(this)
_layer = v
_rl = Game.renderer.add(this)
} else {
_layer = v
}
}
depth { _depth }
depth=(v) { _depth = v }
construct new() {
_visible = true
_layer = 0
_depth = 0
_x = 0
_y = 0
_ox = 0
_oy = 0
_rl = null
}
init() {
_rl = Game.renderer.add(this)
}
draw() {}
destroy() {
if (_rl != null) {
_rl.remove(this)
}
}
}
class RenderLayer {
construct new() {
_objects = []
}
add(e) {
_objects.add(e)
}
remove(e) {
Utils.list_remove(_objects, e)
}
draw() {
for (e in _objects){
if (e.visible) {
e.draw()
}
}
}
}
class Renderer {
color { _color }
color=(v) { _color=v }
construct new() {
_color = 0
_layers_list = []
_layers = {}
}
create_layer(idx) {
if (_layers.containsKey(idx)) return
var rl = RenderLayer.new()
_layers[idx] = rl
if (_layers_list.count == 0) {
_layers_list.add(idx)
} else {
insert_sorted_key(_layers_list, idx)
}
}
destroy_layer(idx) {
if (_layers.containsKey(idx)) {
_layers.remove(idx)
Utils.list_remove(_layers_list, idx)
}
}
add(e) {
var rl = _layers[e.layer]
if (rl != null) rl.add(e)
return rl
}
remove(e) {
var rl = _layers[e.layer]
if (rl != null) rl.remove(e)
return rl
}
process() {
TIC.cls(_color)
for (lid in _layers_list){
_layers[lid].draw()
}
}
insert_sorted_key(list, key) {
var result = 0
var mid = 0
var min = 0
var max = list.count - 1
while (max >= min) {
mid = min + ((max - min) / 2).floor
result = list[mid] - key
if (result > 0) {
max = mid - 1
} else if(result < 0) {
min = mid + 1
} else {
return
}
}
list.insert(result > 0 ? mid : mid + 1, key)
}
}
// particles
class ParticleList is Sequence {
length { _len }
capacity { _cp }
construct new(n) {
_idxs = []
_buff = []
for (i in 0...n) {
_idxs.add(i)
_buff.add(Particle.new(i))
}
_cp = n
_len = 0
_wridx = 0
}
[i]{_buff[i]}
ensure() {
var p = _buff[_len]
_len = _len+1
return p
}
wrap() {
var lidx = _len-1
swap(_wridx, lidx)
_wridx = (_wridx+1)%(_cp-1)
return _buff[lidx]
}
remove(p) {
var idx = _idxs[p.id]
var lidx = _len-1
if(idx != lidx) swap(idx, lidx)
_len = _len-1
}
swap(a, b) {
var ia = _buff[a]
var ib = _buff[b]
_idxs[ia.id] = b
_idxs[ib.id] = a
_buff[a] = ib
_buff[b] = ia
}
clear () {
for (i in 0..._cp) {
_idxs[i] = i
_buff[i] = Particle.new(i)
}
_len = 0
}
iterate(i) {
if (i == null) i = 0 else i = i + 1
return i >= _len ? null : i
}
iteratorValue(i) { _buff[i] }
toString {
var lst = []
for (i in 0..._len) {
lst.add(_buff[i].id)
}
return lst.toString
}
}
class Particle {
id { _id }
x { _x }
y { _y }
vx { _vx }
vy { _vy }
w { _w }
h { _h }
color { _clr }
life { _lf }
stlife { _slf }
phase { _ph }
x=(v) { _x=v }
y=(v) { _y=v }
vx=(v) { _vx=v }
vy=(v) { _vy=v }
w=(v) { _w=v }
h=(v) { _h=v }
color=(v) { _clr=v }
life=(v) { _lf=v }
stlife=(v) { _slf=v }
phase=(v) { _ph=v }
construct new(id) {
_id = id
_x = 0
_y = 0
_vx = 0
_vy = 0
_w = 2
_h = 2
_clr = 11
_lf = 1
_ph = 0
_slf = 1
}
}
class ParticleSystem is Drawable {
active { _active }
active=(v) { _active=v }
emitters { _ems }
construct new() {
super()
_active = true
_ems = []
}
add(em) {
_ems.add(em)
em.init(this)
return this
}
update(dt) {
if (_active) _ems.each{|e|e.update(dt)}
}
start() { _ems.each{|e|e.start()} }
stop() {stop(false)}
stop(kill) { _ems.each{|e|e.stop(kill)} }
draw() { _ems.each{|e|e.draw()} }
}
class ParticleEmitter {
x { _x }
y { _y }
enabled { _en }
particles { _prts }
modules { _mds }
rendrer { _rend }
system { _ps }
duration { _dr }
duration_max { _drm }
cache_size { _cs }
cache_wrap { _cwr }
rate { _rate }
rate_max { _ratemx }
life { _life }
life_max { _lifemx }
count { _count }
count_max { _countmx }
random { _rnd }
x=(v) { _x=v }
y=(v) { _y=v }
enabled=(v) { _en=v }
duration=(v) {
_dr=v
calc_dur()
}
duration_max=(v) {
_drm=v
calc_dur()
}
cache_wrap=(v) { _cwr=v }
rate=(v) {
_rate=v
_invrt = v>0 ? 1/v : 0
}
rate_max=(v) {
_ratemx=v
_invrtmx = v>0 ? 1/v : 0
}
life=(v) { _life=v }
life_max=(v) { _lifemx=v }
count=(v) { _count=v }
count_max=(v) { _countmx=v }
construct new(cs,mds,rend) {
_cs = cs
_en = true
_cwr = false
_x = 0
_y = 0
rate = 10
rate_max = 0
_life = 1
_lifemx = 0
_count = 1
_countmx = 0
_dr = -1
_drm = 0
_cdr = -1
_mds = mds
_rend = rend
_prts = ParticleList.new(_cs)
_rnd = Random.new()
_frt = 0
_invrt = 0
_invrtmx = 0
_time = 0
}
init(ps) {
_ps = ps
for (m in _mds) {
m.setup(this)
m.init()
}
_rend.setup(this)
}
start() {start(null)}
start(d) {
_en = true
_time = 0
_frt = 0
if(d == null) {
calc_dur()
} else {
_cdr = d
}
}
stop() {stop(false)}
stop(k) {
_en = false
_time = 0
_frt = 0
if(k) unspawn_all()
}
emit() {
var cnt = 0
if(_countmx > 0) {
cnt = random.int(_count, _countmx)
} else {
cnt = _count
}
cnt = cnt > _cs ? _cs : cnt
for (i in 0...cnt) {
spawn()
}
}
spawn() {
if(_prts.length < _prts.capacity) {
spawn_p_(_prts.ensure())
} else if(cache_wrap) {
var p = _prts.wrap()
unspawn_p_(p)
spawn_p_(p)
}
}
unspawn(p) {
_prts.remove(p)
unspawn_p_(p)
}
unspawn_all() {
for (p in _prts) {
for (m in _mds) {
m.onunspawn(p)
}
}
_prts.clear()
}
spawn_p_(p) {
for (m in _mds) {
p.stlife = _lifemx > 0 ? random.float(_life, _lifemx) : _life
p.life = 0
p.phase = 0
m.onspawn(p)
}
}
unspawn_p_(p) { _mds.each{|m|m.onunspawn(p)} }
update(dt) {
var p = null
var i = 0
var len = _prts.length
while(i < len) {
p = _prts[i]
p.life = p.life + dt
p.phase = p.life / p.stlife
if(p.life >= p.stlife) {
unspawn(p)
len = _prts.length
} else {
i = i+1
}
}
if(_en && _rate > 0) {
_frt = _frt + dt
var ir = 0
while(_frt > 0) {
emit()
ir = _ratemx > 0 ? random.float(_invrt, _invrtmx) : _invrt
if(ir == 0) {
_frt = 0
break
}
_frt = _frt-ir
}
_time = _time + dt
if(_cdr >= 0 && _time >= _cdr) stop()
}
for (m in _mds) {
m.update(dt)
}
for (p in _prts) {
p.x = p.x+p.vx*dt
p.y = p.y+p.vy*dt
}
}
draw() {
_rend.draw()
}
calc_dur() {
if(_dr >= 0 && _drm > _dr) {
_cdr = random.float(_dr, _drm)
} else {
_cdr = _dr
}
}
random_1_to_1() { random.float() * 2 - 1 }
}
class ParticleModule {
enabled { _enabled }
emitter { _emtr_ }
particles { _prts_ }
construct new() {
_enabled = true
}
init() {}
setup(e) {
_emtr_= e
_prts_= _emtr_.particles
}
ondestroy() {}
onspawn(p) {}
onunspawn(p) {}
update(dt) {}
}
class RadialSpawnModule is ParticleModule {
radius { _r }
radius=(v) { _r=v }
construct new(r) {
super()
_r = r
_rnd_point = Vector.new()
}
onspawn(p) {
Utils.random_point_in_unit_circle(_rnd_point)
p.x = emitter.system.x + emitter.x + _rnd_point.x * _r
p.y = emitter.system.y + emitter.y + _rnd_point.y * _r
}
}
class ColorLifeModule is ParticleModule {
colors { _colors }
colors=(v) { _colors=v }
construct new(cl) {
super()
_colors = cl
}
update(dt) {
var clen = _colors.count
particles.each{|p|p.color = _colors[(p.phase*clen).floor]}
}
}
class ScaleLifeModule is ParticleModule {
construct new(ss,es) {
super()
_ss = ss
_es = es
}
update(dt) {
for (p in particles) {
var s = (1-p.phase)*_ss+p.phase*_es
p.w = s
p.h = s
}
}
}
class VelocityModule is ParticleModule {
construct new(vx,vy) {
super()
_vx = vx
_vy = vy
}
construct new(vx,vy,mvx,mvy) {
super()
_vx = vx
_vy = vy
_mvx = mvx
_mvy = mvy
}
onspawn(p) {
if (_mvx != null) {
p.vx = emitter.random.int(_vx,_mvx)
p.vy = emitter.random.int(_vy,_mvy)
} else {
p.vx = _vx
p.vy = _vy
}
}
}
class VelocityLifeModule is VelocityModule {
construct new(vx,vy,evx,evy) {
super(vx,vy)
_evx = evx
_evy = evy
}
onspawn(p) {
p.vx = _vx
p.vy = _vy
}
update(dt) {
for (p in particles) {
var vx = (1-p.phase)*_vx+p.phase*_evx
var vy = (1-p.phase)*_vy+p.phase*_evy
p.vx = vx
p.vy = vy
}
}
}
class GravityModule is ParticleModule {
x { _x }
y { _y }
x=(v) { _x=v }
y=(v) { _y=v }
construct new(x,y) {
super()
_x = x
_y = y
}
update(dt) {
for (p in particles) {
p.vx = p.vx + _x * dt
p.vy = p.vy + _y * dt
}
}
}
class ParticleRenderer {
emitter { _emtr_ }
particles { _prts_ }
construct new() {}
setup(e) {
_emtr_= e
_prts_= _emtr_.particles
}
}
class CircleDrawModule is ParticleRenderer {
construct new() { super() }
draw() { particles.each{|p|TIC.circ(p.x-Camera.x, p.y-Camera.y, p.w*0.5, p.color)} }
}
class FPS {
static value { __vl }
static init() {
__vl = 0
__frms = 0
__lt = 0
}
static update() {
if (TIC.time() - __lt <= 1000) {
__frms = __frms+1
} else {
__vl = __frms
__frms = 0
__lt = TIC.time()
}
}
}
// ecs
class IdBuffer {
used { _used }
construct new(n) {
_cp = n
_used = 0
_mask = n - 1
_head = 0
_tail = 0
if((_mask & n) != 0) Fiber.abort("capacity %(n) must be power of two")
_buffer = List.filled(n, 0)
for (i in 0...n) {
_buffer[i] = i
}
}
pop() {
if(_used >= _cp) Fiber.abort("Out of entities, max allowed %(_cp)")
_used = _used + 1
var ppat = _head
_head = ppat + 1
_head = _head & _mask
return _buffer[ppat]
}
push(v) {
_used = _used - 1
var plat = _tail
_buffer[plat] = v
plat = plat + 1
_tail = plat & _mask
}
clear(){
_head = 0
_tail = 0
_buffer = List.filled(_cp, 0)
for (i in 0..._cp) {
_buffer[i] = i
}
}
}
class BitVector {
construct new(count) {
_list = List.filled((count/32).ceil, 0)
_lrs = Fn.new { |x,n|(x >> n) & ~(((0x1 << 32) >> n) << 1) }
}
[i]{
var adress = _lrs.call(i, 5)
var mask = 0x1 << (i & 0x1F)
return (_list[adress] & mask) != 0
}
[i]=(v){
var adress = _lrs.call(i, 5)
var mask = 0x1 << (i & 0x1F)
_list[adress] = v ? _list[adress] | mask : _list[adress] & ~mask
}
clear () {
for (i in 0..._list.count) {
_list[i] = 0
}
}
}
class IntVector is Sequence {
construct new(n) {
_idxs = List.filled(n, -1)
_buff = List.filled(n, 0)
_len = 0
}
length { _len }
add(id){
_buff[_len] = id
_idxs[id] = _len
_len = _len + 1
}
has(idx){_idxs[idx] != -1}
[i]{_buff[i]}
remove(id){
var idx = _idxs[id]
var last_idx = _len - 1
if(idx != last_idx) {
var last_id = _buff[last_idx]
_buff[idx] = last_id
_idxs[last_id] = idx
}
_idxs[id] = -1
_len = _len - 1
}
clear () {
_idxs.each {|id| id = -1 } // bug
_len = 0
}
iterate(i) {
if (i == null) i = 0 else i = i + 1
return i >= _len ? null : i
}
iteratorValue(i) { _buff[i] }
toString {
var lst = []
for (i in 0..._len) {
lst.add(_buff[i])
}
return lst.toString
}
}
class BitFlag {
bits0 { _b0 }
bits1 { _b1 }
construct new() {
_b0 = 0
_b1 = 0
}
set_true(b) {
if (b < 33) {
_b0 = _b0 | 1 << (b - 1)
} else if(b < 65) {
_b1 = _b1 | 1 << (b - 33)
}
}
set_false(b) {
if (b < 33) {
_b0 = _b0 & ~(1 << (b - 1 ))
} else if (b < 65) {
_b1 = _b1 & ~(1 << (b - 33))
}
}
flip() {
_b0 = ~_b0
_b1 = ~_b1
}
clear() {
_b0 = 0
_b1 = 0
}
contains(f) {
if (_b0 & f.bits0 == f.bits0 &&
_b1 & f.bits1 == f.bits1) {
return true
}
return false
}
}
class Signal {
length { _lsn.count }
construct new() {
_lsn = []
_chk = false
}
add(h){
if (h is Fn) {
if (!has(h)) {
_lsn.add(h)
} else {
Fiber.abort("Signal: attempted to add the same listener twice")
}
}
}
remove(h){
for (i in 0..._lsn.count) {
if (_lsn[i] == h) {
_lsn[i] = null
_chk = true
break
}
}
}
has(h){ _lsn.contains(h) }
emit(args){
var idx = 0
var count = _lsn.count
var fn = null
while(idx < count) {
fn = _lsn[idx]
if(fn != null) fn.call(args)
idx = idx + 1
}
if (_chk) {
while(count > 0) {
if(_lsn[count-1] == null) _lsn.removeAt(count-1)
count = count - 1
}
_chk = false
}
}
clear(){
_lsn.clear()
_chk = false
}
}
class World {
static current { __cw }
static init(n) { __cw = World.new_(n) }
static empty() { __cw.empty() }
static update(dt) { __cw.update(dt) }
capacity { _capacity }
comp_flags { _comp_flags }
comp_types { _comp_types }
construct new_(n) {
_inited = false
_capacity = n
_eid_pool = IdBuffer.new(n)
_entities = IntVector.new(n)
_alive_mask = BitVector.new(n)
_changed_mask = BitVector.new(n)
_comp_flags = List.filled(n, null)
_comp_types = {}
_comps = []
_families = {}
_processors = {}
_active_processors = []
_changed = []
_destroyed = []
// private functions
_destroy_entity = Fn.new{|e|
_entities.remove(e)
_eid_pool.push(e)
_comp_flags[e] = null
}
init() // todo
}
init() {
_inited = true
for (p in _processors.values) {
p.init()
}
}
empty() {
for (e in 0..._capacity) {
if (_alive_mask[e]) {
entity_destroy(e)
}
}
upd_()
}
// entity
entity_create() {
var id = _eid_pool.pop()
_alive_mask[id] = true
_entities.add(id)
_comp_flags[id] = BitFlag.new()
return id
}
entity_destroy(e) {
if (!entity_alive(e)) Fiber.abort("entity %(e) destroying repeatedly")
_alive_mask[e] = false
_comps.each {|c| c.remove(e)}
_destroyed.add(e)
}
entity_alive(e) { _alive_mask[e] }
entity_changed(e){
if (!_changed_mask[e]) {
_changed_mask[e] = true
_changed.add(e)
}
}
// component
component_set(e,comp, ctype){
if (comp is List) {
for (c in comps) {
ctype = c is Class ? ctype = c : ctype = c.type
_comps[comp_get_type(ctype)].set_(e,c, false)
}
entity_changed(e)
} else {
if (ctype == null) ctype = comp is Class ? ctype = comp : ctype = comp.type
_comps[comp_get_type(ctype)].set_(e,comp,true)
}
}
oncompadded(e, ct, ev) {
_comp_flags[e].set_true(ct + 1)
if (ev) entity_changed(e)
}
oncompremoved(e, ct) {
_comp_flags[e].set_false(ct + 1)
entity_changed(e)
}
comp_get_type(comp_class){
var ct = -1
var cname = comp_class.name
if(_comp_types.containsKey(cname)) {
ct = _comp_types[cname]
} else {
ct = _comps.count
if (ct > 64) Fiber.abort("Cant't have more than 64 type of components")
_comp_types[cname] = ct
_comps.add(Components.new(this, ct))
}
return ct
}
comps_get(comp_class){ _comps[comp_get_type(comp_class)] }
// family
family_create(name, incl, excl) {
if (_families.containsKey(name)) Fiber.abort("Family named: %(name) already exists")
var f = Family.new_(this, name, incl, excl)
_families[f.name] = f
return f
}
family_remove(f){ // does i need this?
_families.remove(f.name)
}
family_get(fname){ _families[fname] }
// processors
processor_add(p, prior, enabled){
var pc = p.type
p.priority = prior
_processors[pc.name] = p
p.setup_(this)
p.onadded()
if(_inited) p.init()
if(enabled) processor_enable(pc)
return p
}
processor_get(pc){ _processors[pc.name] }
processor_remove(pc){
var p = _processors[pc.name]
if (p != null) {
if(p.active) processor_disable(pc)
p.onremoved()
p.setup_(null)
_processors.remove(pc.name)
return p
}
return null
}
processor_enable(pc){
var p = processor_get(pc)
if (p != null && !p.active) {
p.onenabled()
p.active = true
if (_active_processors.isEmpty) {
_active_processors.add(p)
} else {
var added = false
for (i in 0..._active_processors.count) {
if (p.priority <= _active_processors[i].priority) {
_active_processors.insert(i,p)
added = true
break
}
}
if (!added) _active_processors.add(p)
}
}
}
processor_disable(pc){
var p = processor_get(pc)
if (p != null && p.active) {
p.ondisabled()
p.active = false
for (i in 0..._active_processors.count) {
if (_active_processors[i] == p) {
_active_processors.removeAt(i)
break
}
}
}
}
upd_() {
if (_changed.count > 0) {
_changed.each {|e|
for (f in _families.values) {
f.check(e)
}
}
_changed_mask.clear()
_changed.clear()
}
for (c in _comps) {
c.update()
}
if (_destroyed.count > 0) {
_destroyed.each {|e| _destroy_entity.call(e)}
_destroyed.clear()
}
}
update(dt) {
upd_()
_active_processors.each {|p| p.update(dt)}
upd_()
}
}
class Components {
static get(ccl) { World.current.comps_get(ccl) }
static set(e,comp) { set(e,comp,null) }
static set(e,comp,ctype) { World.current.component_set(e,comp,ctype) }
construct new(world, ctype) {
_world = world
_type = ctype
_comps = List.filled(_world.capacity, null)
_removed_mask = BitVector.new(_world.capacity)
_removed = []
}
set(e, c){ set_(e, c, true) }
set_(e, c, ev){
remove(e)
_comps[e] = c
_world.oncompadded(e, _type, ev)
}
get(e){ _comps[e] }
has(e){ _comps[e] != null }
remove(e){
if (has(e)) {
_world.oncompremoved(e, _type)
if (!_removed_mask[e]) {
_removed_mask[e] = true
_removed.add(e)
}
// _comps[e] = null
}
}
clear(){
for (i in 0..._comps.length) {
if(_comps[i] != null) {
world.oncompremoved(i, _type)
_comps[i] = null
}
}
}
update() {
if (_removed.count > 0) {
for (e in _removed) {
_comps[e] = null
}
_removed_mask.clear()
_removed.clear()
}
}
toString {
var cname = ""
for (t in _world.comp_types.keys) {
if (_type == _world.comp_types[t]) cname = t
}
var comps = 0
var arr = []
for (j in 0..._comps.count) {
if(_comps[j] != null) {
arr.add(j)
comps = comps + 1
}
}
return "%(cname): ents:%(comps) %(arr)"
}
}
class Family is Sequence {
static create(name, incl) { create(name, incl, null) }
static create(name, incl, excl) { World.current.family_create(name, incl, excl) }
static get(name) { World.current.family_get(name) }
static remove(name) { World.current.family_remove(name) }
name { _name }
onadded { _onadd }
onremoved { _onrem }
construct new_(world, name, incl, excl) {
_world = world
_name = name
_onadd = Signal.new()
_onrem = Signal.new()
_incl = BitFlag.new()
_excl = BitFlag.new()
_excl.flip()
_ents = IntVector.new(_world.capacity)
incl.each {|c| _incl.set_true(_world.comp_get_type(c)+1) }
if (excl != null) excl.each {|c| _incl.set_false(_world.comp_get_type(c)+1) }
// private functions
_match_entity = Fn.new{|e|
var flags = _world.comp_flags[e]
return flags.contains(_incl) && _excl.contains(flags)
}
}
has(e) { _ents.has(e) }
check(e) {
if(!has(e)) {
if(_match_entity.call(e)){
_ents.add(e)
_onadd.emit(e)
}
} else if(!_match_entity.call(e)) {
_onrem.emit(e)
_ents.remove(e)
}
}
remove(e) {
if(has(e)) {
_onrem.emit(e)
_ents.remove(e)
}
}
iterate(i) {
if (i == null) i = 0 else i = i + 1
return i >= _ents.length ? null : i
}
iteratorValue(i) { _ents[i] }
toString { "%(_name):%(_ents.toString)" }
}
class Processor {
static add(p) { add(p,null,true) }
static add(p,pr) { add(p,pr,true) }
static add(p,pr,en) { World.current.processor_add(p,pr,en)}
static get(pc) { World.current.processor_get(pc) }
static remove(pc) { World.current.processor_remove(pc) }
active{_active}
active=(v){_active = v}
priority{_priority}
priority=(v){_priority = v}
construct new() {
_priority = 0
_active = false
}
setup_(w) { _world = w }
init(){}
onadded(){}
onremoved(){}
onenabled(){}
ondisabled(){}
update(dt){}
}
class Entity {
static create() { World.current.entity_create() }
static destroy(e) { World.current.entity_destroy(e) }
static has(e) { World.current.entity_alive(e) }
}
// components
class Bounds {
entity { _e }
x { _x }
y { _y }
r{ _r }
x=(v) { _x=v }
y=(v) { _y=v }
r=(v) { _r=v }
contacts {_cnt}
tag {_tp}
construct new(e,x,y,r,tp) {
_e = e
_x = x
_y = y
_r = r
_tp = tp
_cnt = {}
}
}
class Star {
paralax { _p }
construct new(p) {
_p = p
}
}
class Planet {
density { _d }
radius { _r }
radius=(v) { _r=v }
grav_radius { _gr }
mass { _m }
construct new(r,d) {
_r = r
_gr = r+(d)
_d = d
_m = Maths.get_sphere_mass(r,1)
}
update_mass() {
_m = Maths.get_sphere_mass(_r,1)
}
}
class Comet is Planet {
polarity { _pol }
polarity=(v) { _pol=v }
hitcd { _hcd }
hitcd=(v) { _hcd=v }
sunhit { _sh }
sunhit=(v) { _sh=v }
construct new(r,d) {
super(r,d)
_pol = -1
_hcd = 0
_sh = 0
}
}
class Text {
x { _x }
y { _y }
scale { _sc }
color { _clr }
text { _txt }
x=(v) { _x=v }
y=(v) { _y=v }
scale=(v) { _sc=v }
color=(v) { _clr=v }
text=(v) { _txt=v }
construct new(txt,x,y,clr,sc) {
_txt = txt
_x = x
_y = y
_sc = sc
_clr = clr
}
draw() {
TIC.print(_txt,_x,_y,_clr,false,_sc)
}
}
class Lines is Drawable {
lines { _lns }
lines2 { _lns2 }
color { _c }
color2 { _c2 }
color=(v) { _c=v }
color2=(v) { _c2=v }
construct new(n,c,c2) {
super()
_c = c
_c2 = c2
_lns = []
_lns2 = []
for (i in 0...n) {
_lns.add(Vector.new())
_lns2.add(Vector.new())
}
}
draw() {
_lns2.each{|d| TIC.pix(d.x-Camera.x, d.y-Camera.y, color2) }
_lns.each{|d| TIC.pix(d.x-Camera.x, d.y-Camera.y, color) }
}
}
class PlanetImage is Drawable {
radius { _r }
radius2 { _r2 }
color { _c }
color2 { _c2 }
radius2=(v) { _r2=v }
radius=(v) { _r=v }
color=(v) { _c=v }
color2=(v) { _c2=v }
construct new(r,r2,c,c2) {
super()
_r = r
_r2 = r2
_c = c
_c2 = c2
layer = 2
}
draw() {
TIC.circb(x, y, radius2, color2)
TIC.circ(x, y, radius, color)
}
}
class BlackholeImage is Drawable {
radius { _r }
radius2 { _r2 }
color { _c }
color2 { _c2 }
radius2=(v) { _r2=v }
radius=(v) { _r=v }
color=(v) { _c=v }
color2=(v) { _c2=v }
construct new(r,r2,c,c2) {
super()
_r = r
_r2 = r2
_c = c
_c2 = c2
layer = 2
}
draw() {
for (i in radius..radius2) {
if (i%4 == 0) {
TIC.circb(x, y, i, color2)
}
}
TIC.circ(x, y, radius, color)
}
}
class IceImage is Drawable {
radius { _r }
color { _c }
color=(v) { _c=v }
construct new(r,c) {
super()
_r = r
_c = c
layer = 2
_tvert = [
Vector.new(-1,-1),
Vector.new(1,-1),
Vector.new(1,1),
Vector.new(-1,1),
]
_tind = [
3,0,1,
1,2,3
]
_tmpvec = Vector.new()
for (v in _tvert) {
Utils.random_point_in_unit_circle(_tmpvec).multiply(0.25)
v.add(_tmpvec)
}
_av = Game.random.int(-60,60)
}
draw() {
for (v in _tvert) {
Utils.rotate(0,0, _av/60, v)
}
var n = 0
for (i in 0...(_tind.count/3).floor) {
n = i*3
TIC.tri(_tvert[_tind[n]].x*_r+x, _tvert[_tind[n]].y*_r+y, _tvert[_tind[n+1]].x*_r+x, _tvert[_tind[n+1]].y*_r+y,_tvert[_tind[n+2]].x*_r+x, _tvert[_tind[n+2]].y*_r+y, color)
}
}
}
class Circle is Drawable {
radius { _r }
color { _c }
radius=(v) { _r=v }
color=(v) { _c=v }
construct new(r,c,l) {
super()
_r = r
_c = c
layer = l
}
draw() {
TIC.circ(x-ox, y-oy, radius, color)
}
}
class CometImage is Drawable {
radius { _r }
color { _c }
angvel { _av }
radius=(v) { _r=v }
color=(v) { _c=v }
angvel=(v) { _av=v }
construct new(r,c,l) {
super()
_r = r
_c = c
layer = l
_tvert = [
Vector.new(-0.7,-0.7),
Vector.new(0,-1),
Vector.new(0.7,-0.7),
Vector.new(1,0),
Vector.new(0.7,0.7),
Vector.new(0,1),
Vector.new(-0.7,0.7),
Vector.new(-1,0)
]
_tind = [
7,0,1,
1,2,3,
3,4,5,
5,6,7,
5,7,1,
1,3,5
]
_tmpvec = Vector.new()
for (v in _tvert) {
Utils.random_point_in_unit_circle(_tmpvec).multiply(0.25)
v.add(_tmpvec)
}
_av = Game.random.int(-60,60)
}
draw() {
if (_av.abs > 30) {
_av = _av * 0.999
}
for (v in _tvert) {
Utils.rotate(0,0, _av/60, v)
}
var n = 0
for (i in 0...(_tind.count/3).floor) {
n = i*3
TIC.tri(_tvert[_tind[n]].x*_r+x, _tvert[_tind[n]].y*_r+y, _tvert[_tind[n+1]].x*_r+x, _tvert[_tind[n+1]].y*_r+y,_tvert[_tind[n+2]].x*_r+x, _tvert[_tind[n+2]].y*_r+y, color)
}
}
}
class Position is Vector {
construct new(x,y) {
super(x,y)
}
}
class Velocity is Vector {
damping { _damp }
damping=(v) { _damp=v }
construct new(x,y, d) {
super(x,y)
_damp = d
}
}
// processors
class DrawProcessor is Processor {
construct new() {
super()
}
onenabled() {
_ln_comps = Components.get(Lines)
_draw_comps = Components.get(Drawable)
_star_comps = Components.get(Star)
_pos_comps = Components.get(Position)
_ps_comps = Components.get(ParticleSystem)
_cm_comps = Components.get(Comet)
_comets = Family.get("comets")
_planets = Family.get("planets")
_stars = Family.get("stars")
_particles = Family.get("particles")
_draw_added = Fn.new {|e|
var p = _pos_comps.get(e)
var d = _draw_comps.get(e)
var s = _star_comps.get(e)
if (s != null) {
d.x = (p.x - (Camera.x*s.paralax)).floor
d.y = (p.y - (Camera.y*s.paralax)).floor
} else {
d.x = (p.x - Camera.x).floor
d.y = (p.y - Camera.y).floor
}
d.init()
}
_cm_added = Fn.new {|e|
var p = _pos_comps.get(e)
var d = _draw_comps.get(e)
d.x = (p.x - Camera.x).floor
d.y = (p.y - Camera.y).floor
_ln_comps.get(e).init()
d.init()
}
_cm_removed = Fn.new {|e|
_ln_comps.get(e).destroy()
_draw_comps.get(e).destroy()
}
_ps_added = Fn.new {|e|
var d = _ps_comps.get(e)
d.init()
}
_draw_removed = Fn.new {|e|
_draw_comps.get(e).destroy()
}
_planets.onadded.add(_draw_added)
_planets.onremoved.add(_draw_removed)
_comets.onadded.add(_cm_added)
_comets.onremoved.add(_cm_removed)
_stars.onadded.add(_draw_added)
_stars.onremoved.add(_draw_removed)
_particles.onadded.add(_ps_added)
}
ondisabled() {
_planets.onadded.remove(_draw_added)
_planets.onremoved.remove(_draw_removed)
_comets.onadded.remove(_cm_added)
_comets.onremoved.remove(_cm_removed)
_stars.onadded.remove(_draw_added)
_stars.onremoved.remove(_draw_removed)
_particles.onadded.remove(_ps_added)
}
set_dr_pos(e) {
var p = _pos_comps.get(e)
var d = _draw_comps.get(e)
d.x = (p.x - Camera.x).floor
d.y = (p.y - Camera.y).floor
}
update(dt) {
var d
var p
var s
for (e in _comets) {
set_dr_pos(e)
}
for (e in _planets) {
set_dr_pos(e)
}
for (e in _stars) {
p = _pos_comps.get(e)
d = _draw_comps.get(e)
s = _star_comps.get(e)
d.x = (p.x - (Camera.x*s.paralax)).floor
d.y = (p.y - (Camera.y*s.paralax)).floor
}
}
}
class CometProcessor is Processor {
construct new() {
super()
}
onenabled() {
_comet_comps = Components.get(Comet)
_ln_comps = Components.get(Lines)
_b_comps = Components.get(Bounds)
_planet_comps = Components.get(Planet)
_dr_comps = Components.get(Drawable)
_pos_comps = Components.get(Position)
_vel_comps = Components.get(Velocity)
_ps_comps = Components.get(ParticleSystem)
_comets = Family.get("comets")
_planets = Family.get("planets")
_nsup = 1024
_btmp = Bounds.new(0,0,0,0,null)
_vtmp = Vector.new(0,0)
_ptmp = Vector.new(0,0)
_cont = []
}
ondisabled() {
_planet_comps = null
_comet_comps = null
_pos_comps = null
_vel_comps = null
_planets = null
_comets = null
}
hit(e, burst) {
Camera.shake(6)
var cm = _comet_comps.get(e)
var ps = _ps_comps.get(e)
var dr = _dr_comps.get(e)
var b = _b_comps.get(e)
cm.radius = cm.radius -1
if (cm.radius <= 0) {
cm.radius = 1 // dead
burst = true
_comet_comps.remove(e)
ps.stop()
TIC.sfx(20,20,-1,1,15)
TIC.sfx(16,20,-1,0,15)
Timer.schedule(1,Fn.new {
Game.fsm.set("gameover")
})
} else {
TIC.sfx(19,20,-1,1,15)
}
b.r = cm.radius
ps.emitters[0].modules[0].radius = cm.radius
ps.emitters[2].modules[0].radius = cm.radius+2
dr.radius = cm.radius
dr.angvel = Game.random.int(-360,360)
if (burst) {
ps.emitters[1].emit()
}
Game.remove_score(4)
cm.hitcd = 1
cm.update_mass()
}
grow(e, burst) {
var cm = _comet_comps.get(e)
var ps = _ps_comps.get(e)
var dr = _dr_comps.get(e)
var b = _b_comps.get(e)
cm.radius = cm.radius + 0.5
if (cm.radius > 28) {
cm.radius = 28
}
b.r = cm.radius
ps.emitters[0].modules[0].radius = cm.radius
ps.emitters[2].modules[0].radius = cm.radius+2
dr.radius = cm.radius
Game.add_score(8)
TIC.sfx(18,30,-1,1,15)
cm.update_mass()
}
update(dt) {
var vel
var pos
var pos_b
var pl
var cm
var dr
var dist
var ps
var b
var ln
var contacts
Game.speed = Maths.lerp(Game.chances[0][8], Game.chances[1][8], Game.prog) * Game.gravity
for (e in _comets) {
cm = _comet_comps.get(e)
pos = _pos_comps.get(e)
vel = _vel_comps.get(e)
ps = _ps_comps.get(e)
b = _b_comps.get(e)
dr = _dr_comps.get(e)
ln = _ln_comps.get(e)
contacts = b.contacts
vel.x = Game.speed
if (TIC.btn(4)) {
cm.polarity = -1
TIC.sfx(1,24,8,0,2)
} else {
cm.polarity = 1
}
Collision.get_contacts(b,contacts)
if (cm.hitcd > 0) {
cm.hitcd = cm.hitcd - dt
} else {
cm.hitcd = 0
}
var grmodule = ps.emitters[2].modules[3]
grmodule.x = 0
grmodule.y = 0
ps.emitters[2].enabled = false
var gf = Game.gravity
var at_sun = false
var other = null
var velb = null
for (c in contacts.values) {
velb = _vel_comps.get(c.other)
other = _b_comps.get(c.other)
pl = _planet_comps.get(c.other)
pos_b = _pos_comps.get(c.other)
if (other.tag == "planet" || other.tag == "sun" || other.tag == "blackhole" || other.tag == "ice") {
if (Collision.circle_circle(pos.x,pos.y,cm.radius,pos_b.x,pos_b.y,pl.grav_radius,c)) {
var ima = 1 / cm.mass
var imb = 1 / pl.mass
var ims = ima + imb
var imp_n = c.separation / pl.grav_radius / ims
if (other.tag == "sun") {
ps.emitters[2].enabled = true
grmodule.x = grmodule.x + c.normal.x * imp_n * ima * 1000 * gf
grmodule.y = grmodule.y + c.normal.y * imp_n * ima * 1000 * gf
at_sun = true
}
var sign = pos.y > pos_b.y ? 1 : -1
if (other.tag == "blackhole") {
vel.y = vel.y - imp_n * ims * sign * Settings.bh_force * gf
if (cm.polarity < 0) {
vel.y = vel.y + imp_n * ims * sign * Settings.bh_revforce * gf
}
TIC.sfx(21,24,16,0,15)
} else if(other.tag == "sun" || other.tag == "planet"){
var f_ = 1
if (cm.polarity < 0) f_ = Settings.pl_factor
vel.y = vel.y - imp_n * ima * sign * cm.polarity * f_ * Settings.pl_force * gf
if (other.tag == "sun") TIC.sfx(17,60,16,0,10)
} else if(other.tag == "ice"){
velb.x = velb.x + c.normal.x * ims * imp_n * Settings.ice_force * gf
velb.y = velb.y + c.normal.y * ims * imp_n * Settings.ice_force * gf
}
if (c.separation > pl.grav_radius - pl.radius){
if (other.tag == "blackhole") {
cm.radius = cm.radius - (4..cm.radius*0.5).max.floor
if (cm.hitcd == 0) hit(e,true)
} else if (other.tag == "ice") {
grow(e, false)
Entity.destroy(c.other)
} else {
if (pl.radius < cm.radius) {
Game.add_score(pl.radius)
var ps_other = _ps_comps.get(c.other)
ps_other.x = pos_b.x
ps_other.y = pos_b.y
ps_other.emitters[0].emit()
TIC.sfx(22,10,-1,1,15)
_dr_comps.remove(c.other)
_b_comps.remove(c.other)
contacts.remove(c.id)
} else {
c.separation = c.separation - (pl.grav_radius - pl.radius)
Collision.solve_vel(c,vel,Settings.comet_rest)
Collision.solve_pos(c,pos)
if (cm.hitcd == 0) hit(e,true)
}
}
}
}
}
}
if (at_sun) {
cm.sunhit = cm.sunhit - dt
if (cm.sunhit <= 0) {
cm.sunhit = Settings.sun_hittime
hit(e,false)
}
} else {
if (cm.sunhit < Settings.sun_hittime) {
cm.sunhit = cm.sunhit + dt
} else {
cm.sunhit = Settings.sun_hittime
}
}
if (vel.y.abs < 0.1) vel.y = 0
var lim = Settings.camera_limit
// cam
if (pos.y-Camera.y < cm.radius+lim) {
Camera.y = Camera.y - (cm.radius+lim-pos.y+Camera.y)
} else if (pos.y-Camera.y > Screen.height-cm.radius-lim) {
Camera.y = Camera.y - (Screen.height-cm.radius-lim-pos.y+Camera.y)
}
ps.x = pos.x
ps.y = pos.y
if (cm.polarity > 0) {
dr.color = 11
} else {
dr.color = 3
}
ps.emitters[0].modules[2].colors[0] = dr.color
Camera.x = pos.x - Settings.comet_dist
// var cl = System.clock
// trajectory stuff
Collision.get_contacts2(_btmp,_cont)
getnextpos(pos,vel,cm,cm.polarity,ln.lines)
getnextpos(pos,vel,cm,cm.polarity*-1,ln.lines2)
Collision.remove_contacts2(_cont)
// TIC.trace("elapsed: %(System.clock-cl)")
}
}
getnextpos(p,v,cm,pol,into) {
var damp = v.damping
var gf = Game.gravity
_ptmp.set(p.x,p.y)
_vtmp.set(v.x,v.y)
_btmp.x = p.x - Camera.x
_btmp.y = p.y - Camera.y
_btmp.r = cm.radius
var other
var pl
var pos_b
var ni = 0
var dead = false
for (i in 0...into.count*4) {
_vtmp.y = _vtmp.y * damp
_ptmp.x = _ptmp.x + _vtmp.x * Game.dt
_ptmp.y = _ptmp.y + _vtmp.y * Game.dt
_btmp.x = _ptmp.x - Camera.x
_btmp.y = _ptmp.y - Camera.y
_vtmp.x = Game.speed
if (_vtmp.y.abs < 0.1) _vtmp.y = 0
for (c in _cont) {
other = _b_comps.get(c.other)
if (other.tag == "planet" || other.tag == "sun" || other.tag == "blackhole") {
pl = _planet_comps.get(c.other)
pos_b = _pos_comps.get(c.other)
if (Collision.circle_circle(_ptmp.x,_ptmp.y,cm.radius,pos_b.x,pos_b.y,pl.grav_radius,c)) {
var ima = 1 / cm.mass
var imb = 1 / pl.mass
var ims = ima + imb
var imp_n = c.separation / pl.grav_radius / ims
var sign = _ptmp.y > pos_b.y ? 1 : -1
if (other.tag == "blackhole") {
_vtmp.y = _vtmp.y - imp_n * ims * sign * Settings.bh_force * gf
if (pol < 0) {
_vtmp.y = _vtmp.y + imp_n * ims * sign * Settings.bh_revforce * gf
}
} else if(other.tag == "sun" || other.tag == "planet"){
var f_ = 1
if (pol < 0) f_ = Settings.pl_factor
_vtmp.y = _vtmp.y - imp_n * ima * sign * pol * f_ * Settings.pl_force * gf
}
}
}
}
if (i%4 == 0) {
into[ni].set(_ptmp.x, _ptmp.y)
ni = ni+1
}
}
}
}
class PosVelProcessor is Processor {
construct new() {
super()
}
onenabled() {
_pos_comps = Components.get(Position)
_vel_comps = Components.get(Velocity)
_pos_vel = Family.get("pos_vel")
}
update(dt) {
var p
var v
for (e in _pos_vel) {
p = _pos_comps.get(e)
v = _vel_comps.get(e)
v.x = v.x * v.damping
v.y = v.y * v.damping
p.x = p.x + v.x * dt
p.y = p.y + v.y * dt
}
}
}
class SpawnProcessor is Processor {
construct new() {
super()
}
onenabled() {
_planet_comps = Components.get(Planet)
_pos_comps = Components.get(Position)
_star_comps = Components.get(Star)
_planets = Family.get("planets")
_stars = Family.get("stars")
_snextdist = 0
var ch = Game.chances[0]
_pnextdist = Game.random.int(ch[0],ch[1])
_sunnext = Game.random.int(ch[2],ch[3])
_dhnext = Game.random.int(ch[4],ch[5])
_icenext = Game.random.int(ch[6],ch[7])
_last_star = null
_last_cam = 0
}
ondisabled() {
_planet_comps = null
_pos_comps = null
_planets = null
}
update(dt) {
var pos
var pl
var s
var ch = Game.chances
var cp = Camera.x
var t = Game.prog
var spp = Camera.x+Screen.width
var rmin = 0
var rmax = 0
while (_pnextdist < spp) {
var r = Game.random.int(2,8)
var d = Game.random.int(8*r,16*r)
var gr = r+d
var sy = Game.random.int(Camera.y-Screen.height*1.5,Camera.y+Screen.height+Screen.height*1.5)
var sx = _pnextdist+gr
var e = EntityCreator.planet(sx,sy,r,d)
rmin = Maths.lerp(ch[0][0],ch[1][0],t)
rmax = Maths.lerp(ch[0][1],ch[1][1],t)
_pnextdist = _pnextdist + Game.random.int(rmin,rmax)
}
while (_sunnext < spp) {
var r = Game.random.int(8,24)
var d = Game.random.int(4*r,8*r)
var gr = r+d
var sy = Game.random.int(Camera.y-(Screen.height*1.5),Camera.y+Screen.height+(Screen.height*1.5))
var sx = _sunnext+gr
var e = EntityCreator.sun(sx,sy,r,d)
rmin = Maths.lerp(ch[0][2],ch[1][2],t)
rmax = Maths.lerp(ch[0][3],ch[1][3],t)
_sunnext = _sunnext + Game.random.int(rmin,rmax)
}
while (_dhnext < spp) {
var r = Game.random.int(1,4)
var d = Game.random.int(16*r,32*r)
var gr = r+d
var sy = Game.random.int(Camera.y-(Screen.height*1.5),Camera.y+Screen.height+(Screen.height*1.5))
var sx = _dhnext+gr
var e = EntityCreator.blackhole(sx,sy,r,d)
rmin = Maths.lerp(ch[0][4],ch[1][4],t)
rmax = Maths.lerp(ch[0][5],ch[1][5],t)
_dhnext = _dhnext + Game.random.int(rmin,rmax)
}
while (_icenext < spp) {
var sy = Game.random.int(Camera.y-(Screen.height*1.5),Camera.y+Screen.height+(Screen.height*1.5))
var sx = _icenext+87
var e = EntityCreator.ice(sx,sy)
rmin = Maths.lerp(ch[0][6],ch[1][6],t)
rmax = Maths.lerp(ch[0][7],ch[1][7],t)
_icenext = _icenext + Game.random.int(rmin,rmax)
}
while (_snextdist < spp) {
var sy = Game.random.int(Camera.y-(Screen.height*0.5),Camera.y+Screen.height+(Screen.height*0.5))
var sx = _snextdist+4
var e = EntityCreator.star(0,0)
var s = _star_comps.get(e)
var spos = _pos_comps.get(e)
spos.x = Camera.x*s.paralax+(sx-Camera.x)
spos.y = Camera.y*s.paralax+(sy-Camera.y)
_snextdist = _snextdist + Game.random.int(32,96)
}
for (e in _planets) {
pos = _pos_comps.get(e)
pl = _planet_comps.get(e)
if (pos.x+pl.grav_radius < Camera.x-4) {
Entity.destroy(e)
}
}
for (e in _stars) {
pos = _pos_comps.get(e)
s = _star_comps.get(e)
if (pos.x-Camera.x*s.paralax < -4) {
Entity.destroy(e)
}
}
}
}
class ParticlesProcessor is Processor {
construct new() {
super()
}
onenabled() {
_ps_comps = Components.get(ParticleSystem)
_particles = Family.get("particles")
_ps_added = Fn.new {|e|
}
_ps_removed = Fn.new {|e|
var ps = _ps_comps.get(e)
ps.stop(true)
}
_particles.onadded.add(_ps_added)
_particles.onremoved.add(_ps_removed)
}
ondisabled() {
_particles.onadded.remove(_ps_added)
_particles.onremoved.remove(_ps_removed)
_particles = null
_ps_comps = null
}
update(dt) {
for (e in _particles) {
_ps_comps.get(e).update(dt)
}
}
}
class BoundsProcessor is Processor {
construct new() {
super()
}
onenabled() {
_b_comps = Components.get(Bounds)
_p_comps = Components.get(Position)
_bounds = Family.get("bounds")
_b_added = Fn.new {|e|
var b = _b_comps.get(e)
var p = _p_comps.get(e)
b.x = p.x
b.y = p.y
Game.space.check(b)
}
_b_removed = Fn.new {|e|
var b = _b_comps.get(e)
Game.space.remove(b)
}
_bounds.onadded.add(_b_added)
_bounds.onremoved.add(_b_removed)
}
ondisabled() {
_bounds.onadded.remove(_b_added)
_bounds.onremoved.remove(_b_removed)
_b_comps = null
_p_comps = null
_bounds = null
}
update(dt) {
var p
var b
for (e in _bounds) {
b = _b_comps.get(e)
p = _p_comps.get(e)
b.x = p.x - Camera.x
b.y = p.y - Camera.y
Game.space.check(b)
}
}
}
class CameraProcessor is Processor {
construct new() {
super()
}
onenabled() {
_shake_vector = Vector.new()
}
update(dt) {
if (Camera.shaking) {
Utils.random_point_in_unit_circle(_shake_vector)
_shake_vector.multiply(Camera.shake_amount)
Camera.shake_amount = Camera.shake_amount * 0.9
if (Camera.shake_amount < 0.1) {
Camera.shaking = false
}
Camera.x = Camera.x + _shake_vector.x
Camera.y = Camera.y + _shake_vector.y
}
}
}
class Screen {
static width { 240 }
static height { 136 }
}
class Camera {
static x { __x }
static y { __y }
static shaking { __shaking }
static shake_amount { __shake_amount }
static shake_amount=(v) { __shake_amount=v }
static shaking=(v) { __shaking=v }
static x=(v) { __x=v }
static y=(v) { __y=v }
static init() {
__x = 0
__y = 0
__shaking = false
__shake_amount = 0
}
static shake(v) {
__shaking = true
__shake_amount = v
}
}
// create
class EntityCreator {
static planet(x,y,r,d) {
var e = Entity.create()
var gr = r+d
var c = 7
var rnd = Game.random.float()
if (rnd < 0.25) {
c = 6
} else if (rnd < 0.5) {
c = 9
} else if (rnd < 0.75) {
c = 1
} else if (rnd < 0.85) {
c = 6
}
Components.set(e, Planet.new(r,d))
Components.set(e, Position.new(x,y))
Components.set(e, Velocity.new(0,0,0.99))
Components.set(e, PlanetImage.new(r,gr,c,15), Drawable)
Components.set(e, Bounds.new(e,0,0,gr,"planet"))
var ps = ParticleSystem.new()
var em2 = ParticleEmitter.new(
128,
[
RadialSpawnModule.new(r),
ScaleLifeModule.new(r/3,1),
ColorLifeModule.new([4,3,2]),
VelocityModule.new(-100,-100,100,100),
],
CircleDrawModule.new()
)
em2.count = 128
em2.life = 0.8
em2.enabled = false
ps.add(em2)
ps.layer = 3
Components.set(e, ps)
return e
}
static sun(x,y,r,d) {
var e = Entity.create()
var gr = r+d
Components.set(e, Planet.new(r,d))
Components.set(e, Position.new(x,y))
Components.set(e, Velocity.new(0,0,0.99))
Components.set(e, PlanetImage.new(r,gr,4,4), Drawable)
Components.set(e, Bounds.new(e,0,0,gr,"sun"))
var ps = ParticleSystem.new()
var em2 = ParticleEmitter.new(
128,
[
RadialSpawnModule.new(r),
ScaleLifeModule.new(r/3,1),
ColorLifeModule.new([4,3,2]),
VelocityModule.new(-100,-100,100,100),
],
CircleDrawModule.new()
)
em2.count = 128
em2.life = 0.8
em2.enabled = false
ps.add(em2)
ps.layer = 3
Components.set(e, ps)
return e
}
static ice(x,y) {
var e = Entity.create()
var r = 2
var gr = r+48
var hgs = Game.speed * 0.5
Components.set(e, Planet.new(r+2,gr))
Components.set(e, Position.new(x,y))
Components.set(e, Velocity.new(Game.random.int(-hgs,hgs),Game.random.int(-hgs,hgs),0.99))
Components.set(e, IceImage.new(r,10), Drawable)
Components.set(e, Bounds.new(e,0,0,gr,"ice"))
return e
}
static blackhole(x,y,r,d) {
var e = Entity.create()
var gr = r+d
Components.set(e, Planet.new(r,d))
Components.set(e, Position.new(x,y))
Components.set(e, Velocity.new(0,0,0.99))
Components.set(e, BlackholeImage.new(r,gr,14,14), Drawable)
Components.set(e, Bounds.new(e,0,0,gr,"blackhole"))
return e
}
static star(x,y) {
var e = Entity.create()
var s = Star.new(Game.random.float(0.05,0.15))
Components.set(e, s)
Components.set(e, Position.new(x ,y))
Components.set(e, Circle.new(Game.random.int(0,2),13,1), Drawable)
return e
}
static comet(r) {
var e = Entity.create()
Components.set(e, Comet.new(r,1))
Components.set(e, Position.new(48,Screen.height/2))
Components.set(e, Velocity.new(0,0,0.99))
Components.set(e, CometImage.new(r,15,3), Drawable)
Components.set(e, Bounds.new(e,0,0,r,"comet"))
Components.set(e, Lines.new((((0..Game.vis-Game.diff).max)*10).floor,9,15))
var ps = ParticleSystem.new()
var em = ParticleEmitter.new(
512,
[
RadialSpawnModule.new(r),
ScaleLifeModule.new(2,4),
ColorLifeModule.new([1,10,10,9,9]),
VelocityModule.new(0,-12,0,12),
],
CircleDrawModule.new()
)
var em2 = ParticleEmitter.new(
128,
[
RadialSpawnModule.new(r),
ScaleLifeModule.new(3,1),
ColorLifeModule.new([4,3,2]),
VelocityModule.new(-100,-100,100,100),
],
CircleDrawModule.new()
)
var em3 = ParticleEmitter.new(
512,
[
RadialSpawnModule.new(r),
ScaleLifeModule.new(2,4),
ColorLifeModule.new([4,3]),
GravityModule.new(0,0),
VelocityModule.new(0,0,0,0),
],
CircleDrawModule.new()
)
em.cache_wrap = true
em.rate = 200
em.life = 0.2
em.life_max = 1
em2.count = 64
em2.life = 0.8
em2.enabled = false
em3.enabled = false
ps.add(em)
ps.add(em2)
ps.add(em3)
ps.layer = 3
Components.set(e, ps)
return e
}
}
class FSM {
current { _current }
states { _states }
construct new() {
_states = {}
}
add(s) {
if (_states.containsKey(s.name)) {
Fiber.abort("state with name: %(s.name) already exists")
}
_states[s.name] = s
s.init()
}
remove(n) {
var s = _states[n]
if (s != null) {
if (_current == s) {
_current.onleave(null)
_current = null
}
_states.remove(n)
}
}
set(n) {set(n,null,null)}
set(n,ed) {set(n,ed,null)}
set(n,ed,ld) {
var s = _states[n]
if (s != null) {
if (_current != null) {
_current.onleave(ld)
}
s.onenter(ed)
_current = s
}
}
update(dt){
if (_current != null) {
_current.update(dt)
}
}
draw() {
if (_current != null) {
_current.draw()
}
}
}
class State {
name { _name }
construct new(n) {
_name = n
}
init() { }
onenter(d) { }
onleave(d) { }
update(dt) { }
draw() { }
}
class MenuState is State {
construct new() {
super("menu")
}
init(){
}
onenter(d){
_sel = 0
_title = Text.new("KOMET",84,40,5,2)
_s = Circle.new(2,11,3)
_s.ox = -2
_s.oy = -2
_s.x = 78
_s.y = 80
_p1 = Text.new("play",88,80,11,1)
_diff = Text.new("difficulty 0",88,90,11,1)
_vis = Text.new("visibility 0",88,100,11,1)
_mustxt = Text.new("music %(Game.music ? "on" : "off")",88,110,11,1)
_ps = ParticleSystem.new()
var em = ParticleEmitter.new(
512,
[
RadialSpawnModule.new(3),
ScaleLifeModule.new(2,4),
ColorLifeModule.new([11,10,10,9,9]),
VelocityModule.new(-100,-12,0,12),
],
CircleDrawModule.new()
)
em.cache_wrap = true
em.rate = 200
em.life = 0.2
em.life_max = 1
_ps.add(em)
_ps.x = _s.x+2
_ps.y = _s.y+2
upd()
}
upd() {
_diff.text = "difficulty %(Game.diff)"
_vis.text = "visibility %(Game.vis)"
_mustxt.text = "music %(Game.music ? "on" : "off")"
}
update(dt) {
if(TIC.keyp(50) || TIC.btnp(4)) { // z
Game.fsm.set("play")
}
if(TIC.btnp(0)) {
_sel = Maths.mod(_sel-1, 4)
_s.y = 80 + _sel*10
} else if(TIC.btnp(1)) {
_sel = (_sel+1)%4
_s.y = 80 + _sel*10
} else if(TIC.btnp(2)) {
if (_sel == 1) {
Game.diff = Game.diff - 1
if (Game.diff < 0) {
Game.diff = 0
}
upd()
} else if (_sel == 2) {
Game.vis = Game.vis - 1
if (Game.vis < 0) {
Game.vis = 0
}
upd()
} else if (_sel == 3) {
Game.music = false
upd()
}
} else if(TIC.btnp(3)) {
if (_sel == 1) {
Game.diff = Game.diff + 1
if (Game.diff > 3) {
Game.diff = 3
}
upd()
} else if (_sel == 2) {
Game.vis = Game.vis + 1
if (Game.vis > 3) {
Game.vis = 3
}
upd()
} else if (_sel == 3) {
Game.music = true
upd()
}
}
}
draw() {
_title.color = 11
_title.y = 41
_title.draw()
_title.color = 10
_title.y = 40
_title.draw()
_title.color = 9
_title.y = 39
_title.draw()
_s.draw()
_p1.draw()
_diff.draw()
_vis.draw()
_mustxt.draw()
_ps.x = _s.x+2
_ps.y = _s.y+2
_ps.update(1/60)
_ps.draw()
}
}
class GameOverState is State {
construct new() {
super("gameover")
}
onenter(d){
_texts = []
_main = Text.new("GAME OVER",64,28,2,2)
_score = Text.new("score: %(Game.score.floor)",90,50,11,1)
_playtext = Text.new("press z to play again",62,100,11,1)
_menutext = Text.new("press s to menu",62,110,11,1)
_texts.add(_main)
_texts.add(_score)
_texts.add(_playtext)
_texts.add(_menutext)
}
update(dt) {
if(TIC.btnp(4)) {
Game.fsm.set("play")
} else if(TIC.btnp(7)) {
Game.fsm.set("menu")
}
}
draw() {
for (t in _texts) {
t.draw()
}
}
}
class PlayState is State {
construct new() {
super("play")
}
init(){
_dist_text = Text.new("Score: 0",0,0,12,1)
}
onenter(d){
Camera.x = 0
Camera.y = 0
Game.score = 0
Game.time = 0
_last_cam = Camera.x
Processor.add(SpawnProcessor.new(), 1)
Processor.add(PosVelProcessor.new(), 8)
Processor.add(BoundsProcessor.new(), 9)
Processor.add(CometProcessor.new(), 10)
Processor.add(CameraProcessor.new(), 11)
Processor.add(ParticlesProcessor.new(), 100)
Processor.add(DrawProcessor.new(), 999)
EntityCreator.comet(3)
}
onleave(d){
Camera.x = 0
Camera.y = 0
World.empty()
Processor.remove(SpawnProcessor)
Processor.remove(PosVelProcessor)
Processor.remove(BoundsProcessor)
Processor.remove(CometProcessor)
Processor.remove(CameraProcessor)
Processor.remove(ParticlesProcessor)
Processor.remove(DrawProcessor)
}
update(dt) {
Game.time = Game.time + dt
_last_cam = Camera.x
World.update(Game.dt)
var dist = Camera.x - _last_cam
Game.score = Game.score + (dist * 0.001)
_dist_text.text = "Score: %(Game.score.floor)"
if(TIC.btn(7)) {
Game.fsm.set("menu")
// World.empty()
}
}
draw() {
Game.renderer.process()
_dist_text.draw()
}
}
class Settings {
static camera_limit { 40 }
static comet_dist { 48 }
static comet_rest { 0.5 }
static ice_force { 8 }
static sun_hittime { 3 }
static pl_force { 4 }
static pl_factor { 1.5 }
static bh_force { 8 }
static bh_revforce { 10 }
}
// game
class Game is TIC {
static dt { __dt }
static prog { __tm/__tm_max }
static time { __tm }
static space { __space }
static renderer { __renderer }
static random { __rnd }
static speed { __spd }
static speed=(v) { __spd=v }
static contacts_pool { __cpool }
static diff { __diff }
static diff=(v) {
__gr = 1 + v*0.25
__diff=v
}
static vis { __vis }
static vis=(v) { __vis=v }
static music { __mus }
static music=(v) {
if (v) {
TIC.music(0)
} else {
TIC.music()
}
__mus = v
}
static fsm { __fsm }
static score { __score }
static score=(v) { __score=v }
static timescale { __ts }
static timescale=(v) { __ts=v }
static time=(v) { __tm=v }
static chances { __ch }
static gravity { __gr }
construct new(){
__mus = true
TIC.music(0)
__tm_max = 10*60 // 10 mins
__gr = 1
__tm = 0
__vis = 3
__ts = 1
__diff = 0
__score = 0
__spd = 100
__dt = 1/60
var m = 64
__ch = [
[
0.8,1.0, // planet
11.0,13.0, // sun
10.0,16.0, // blackhole
2.0,4.0, // ice
1.0 // speed
],
[
0.1,0.2, // planet
3.5,6.0, // sun
3.0,8.0, // blackhole
0.4,0.8, // ice
1.75 // speed
]
]
for (i in 0...__ch.count) {
for (j in 0...__ch[i].count) {
__ch[i][j] = __ch[i][j] * m
}
}
Timer.init()
__rnd = Random.new()
// FPS.init()
__cpool = DynamicPool.new(32, Fn.new { CollisionInfo.new() })
__space = Space.new(40,0,Screen.width-40,Screen.height)
__renderer = Renderer.new()
Camera.init()
// create Layers
__renderer.create_layer(0) // bg
__renderer.create_layer(1) // stars
__renderer.create_layer(2) // planets
__renderer.create_layer(3) // comet
__renderer.create_layer(4) // fg
World.init(4096)
Family.create("planets", [Planet, Drawable, Position])
Family.create("comets", [Comet, Drawable, Position])
Family.create("particles", [ParticleSystem, Position])
Family.create("bounds", [Bounds, Position])
Family.create("pos_vel", [Position,Velocity])
Family.create("stars", [Star, Drawable, Position])
__fsm = FSM.new()
__fsm.add(GameOverState.new())
__fsm.add(MenuState.new())
__fsm.add(PlayState.new())
__fsm.set("menu")
// __fsm.set("play")
}
static add_score(v) {
__score = __score + v
}
static remove_score(v) {
__score = __score - v
if (__score < 0) {
__score = 0
}
}
TIC(){
__fsm.update(Game.dt)
Timer.update(Game.dt)
TIC.cls(0)
__fsm.draw()
// __space.draw()
// TIC.trace(__space)
// FPS.update()
// TIC.print("FPS : %(FPS.value)",196,4,3)
}
}
// <WAVES>
// 000:0123456789abcdeffedcba9876543210
// 001:000012111555558cddd99deeeeefffff
// 002:0000000000000000ffffffffffffffff
// 003:3211000000001123cdeeffffffffeedc
// 004:75321100001123578acdeeffffeedca6
// 005:2223456789abcddffedcba9876543222
// 006:89bcdeefffeedcb98754322111223457
// 008:75321100000000578acdeeffffeedca6
// 010:00112233445566778899aabbccddeeff
// 011:7010100000000000fffffffffffffffa
// 012:75321100001123578acdeeffffeedca8
// 015:0123456789abcdeffedcba9876543210
// </WAVES>
// <SFX>
// 000:060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600340000080808
// 001:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000
// 002:0e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e00000000000000
// 016:0207020602050204020312021201220032005200520062007200820092009200b200b200c200d200e200f200f200f200f200f200f200f200f200f200900000000000
// 017:d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900f00000000000
// 018:020012012202420352046205720682069205b204c203d202e201e200e200f200f200f200f200f200f200f200f200f200f200f200f200f200f200f200a00000000000
// 019:0207120622054204520472039201a200b200c200d200e200e200f200f200f200f200f200f200f200f200f200f200f200f200f200f200f200f200f200900000000000
// 020:1207120622053205420452046203620362037202820282029202a201a201b201b201c200c200c200d200d200d200e200e200e200e200f200f200f200800000000000
// 021:c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200100000000000
// 022:020722063205520469038902a902b903c904d905e906f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907900000000000
// </SFX>
// <PATTERNS>
// 000:4d00060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dd0004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dd0004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
// 004:8d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd00060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
// 005:8d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd00060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008d00060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
// 008:ba0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
// </PATTERNS>
// <TRACKS>
// 000:0001410001810000000000000000000000000000000000000000000000000000000000000000000000000000000000004c0000
// </TRACKS>
// <PALETTE>
// 000:1a1c2c572956b14156ee7b58ffd079a0f07238b86e276e7b29366f405bd04fa4f786ecf8f4f4f493b6c1557185324056
// </PALETTE>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment