pico-8 cartridge // http://www.pico-8.com version 8 __lua__ -- isaac's descent -- by eevee -- code licensed under MIT -- art, music, and sound -- licensed under CC4-BY-SA --============================-- --==== begin engine code =====-- --============================-- -------------------------------- -- bad constants animframedelay = 4 -------------------------------- -- debugging reprdepth = 0 function _tablerepr(t) if reprdepth > 1 then return "" end reprdepth += 1 local first = true local ret = "{" for k, v in pairs(t) do if not first then ret = ret .. ", " end first = false local rv if v == t then rv = "<...>" else rv = repr(v) end ret = ret .. repr(k) .. ": " .. rv end reprdepth -= 1 return ret .. "}" end function repr(t) if t == true then return "" elseif t == false then return "" elseif t == nil then return "" elseif type(t) == "function" then return "" elseif type(t) ~= "table" then return "" .. t elseif t.__repr then return t:__repr() elseif t.__name then return "" elseif t.new then return "" else return _tablerepr(t) end end function spew(arg) local out = "" for s in all(arg) do out = out .. repr(s) .. " " end printh(out) end -------------------------------- -- misc utilities -- smallest possible value -- 1/256/256 == 1/65536 minfrac = 0.0000152587890625 function ceil(n) return flr(n + 1 - minfrac) end -- copy values from b into a function merge(a, b) for k, v in pairs(b) do a[k] = v end return a end function sort(list, keyfunc) -- insertion sort -- stable, fast enough for -- small lists local keys = {} keyfunc = keyfunc or function(v) return v end for i = 1, #list do keys[i] = keyfunc(list[i]) end for i = 2, #list do local j = i while j > 1 and keys[j - 1] > keys[j] do keys[j], keys[j - 1] = keys[j - 1], keys[j] list[j], list[j - 1] = list[j - 1], list[j] j -= 1 end end end -- print lines of text aligned -- to given point (doesn't handle -- screen edge or newlines!) -- align should be two chars, -- t/m/b + l/m/r. -- if border given, a box will -- be drawn around the text. -- border is not counted in -- alignment! font_height = 6 font_width = 4 -- these characters are double -- width, but alas, there's no -- ord(), so... -- todo chars 128 through 153 -- are all custom double-wides widechars = {} for _ch in all{ "‹", "‘", "”", "ƒ", "Ž", "—", "\135", "\138", } do widechars[_ch] = true end function printat(lines, anchor, align, color, bordercolor, bgcolor) local valign = sub(align, 1, 1) local halign = sub(align, 2, 2) --"multiplier" -- how much of -- the height/width to subtract local vm = ({t=0, m=0.5, b=1})[valign] local hm = ({l=0, m=0.5, r=1})[halign] if type(lines) == "string" then lines = {lines} end local th = #lines * font_height - 1 local y = anchor.y - flr(th * vm) linewidths = {} for line in all(lines) do local lw = 0 for n = 1, #line do lw += font_width if widechars[sub(line, n, n)] then lw += font_width end end add(linewidths, lw - 1) end if bordercolor or bgcolor then local maxw = 0 for lw in all(linewidths) do maxw = max(maxw, lw) end local x = anchor.x - flr(maxw * hm) local rx, ry, rw, rh = x - 4, y - 4, x + maxw + 3, y + th + 3 if bgcolor then rectfill(rx, ry, rw, rh, bgcolor) end if bordercolor then rect(rx, ry, rw, rh, bordercolor) end end for l, line in pairs(lines) do local x = ( anchor.x - flr(linewidths[l] * hm)) print(line, x, y, color) y += font_height end end -------------------------------- -- micro class type function class(base, proto) proto = proto or {} proto.__index = proto local meta = {} setmetatable(proto, meta) if base then meta.__index = base end function meta:__call(...) local this = setmetatable({}, self) if this.init then this:init(...) end return this end return proto end -------------------------------- -- vec2 type (point or size) vec2 = class() function vec2:init(x, y) self.x = x or 0 self.y = y or 0 end function vec2:copy() return vec2(self.x, self.y) end function vec2:__repr() return "" end function vec2:__eq(other) return self.x == other.x and self.y == other.y end function vec2:__add(other) return vec2( self.x + other.x, self.y + other.y) end function vec2:__mul(n) return vec2( self.x * n, self.y * n) end function vec2:__sub(other) return self + other * -1 end -- element-wise multiplication function vec2:elemx(other) return vec2( self.x * other.x, self.y * other.y) end function vec2:at(anchor) return box( anchor.x, anchor.y, self.x, self.y) end -- box type (rectangle) box = class() function box:init(l, t, w, h) if w < 0 then l += w w *= -1 end if h < 0 then t += h h *= -1 end self.l = l self.t = t self.w = w self.h = h end function box:__repr() return "" end function box.__index(self, key) if key == "r" then return self.l + self.w elseif key == "b" then return self.t + self.h else return box[key] end end function box:__add(offset) return box(self.l + offset.x, self.t + offset.y, self.w, self.h) end function box:overlaps(other) -- don't count touching edges -- as overlapping; the right -- and bottom are exclusive return ( self.l < other.r and self.r > other.l and self.t < other.b and self.b > other.t ) end function box:touches(other) return ( self.l <= other.r and self.r >= other.l and self.t <= other.b and self.b >= other.t ) end -------------------------------- -- actor type -- note that the base unit is the -- tile (8px), not the pixel, as -- that's what the map uses actor = class{ __name = "actor", enabled = true, poses = {}, -- collision box, relative to -- top-left corner shape = box(0, 0, 1, 1), -- draw order (ignored for -- decor and other faux actors) z = 0, } function actor:init(pos) self.pos = pos self:reset() end -- called when the map is -- reloaded function actor:reset() -- sprite selection self:set_pose("default") end -- whether to block mobactors; -- default uses the rightmost -- tile flag for the initial function actor:blocks(actor, d) local t = self.sprite:current() if fget(t, 7) then if fget(t, 5) then return d.y > 0 end return true end end -- returns collision box function actor:coll() return self.shape + self.pos end -- called when a mobactor first -- bumps into this one, even if -- not blocked. delta is how -- fast they're colliding, which -- may or may not be meaningful, -- but does indicate direction function actor:oncollide(other, delta) end -- called every tic function actor:update() end -- called every tic, but only -- if actor is visible; this -- should not change state! -- by default actors are -- assumed to be part of the -- map and drawn by map() function actor:draw() end -- set self.pose and switch to -- sprite from self.poses; -- used by subclasses function actor:set_pose(pose) if pose ~= self.pose and self.poses[pose] then self.pose = pose self:set_sprite(self.poses[pose]) end end -- change sprite (allows e.g. -- decor to update the map) function actor:set_sprite(s) self.sprite = to_sprite(s) end -------------------------------- -- actor that can move, is -- subject to gravity, etc. -- supports a few builtin -- poses: walking, jumping, -- and falling mobactor = class(actor, { __name = "mobactor", is_mobile = true, height = 1, width = 1, z = 100, -- physics min_speed = 0.015625, -- 1/64 max_speed = 0.25, -- 1/4 friction = 0.625, }) function mobactor:init(pos) self.pos0 = self.pos0 or pos:copy() actor.init(self, pos) end function mobactor:reset() actor.reset(self) -- reset movement stuff, -- including original pos self.pos = self.pos0:copy() self.vel = vec2() self.sprite_time = 0 self.facing_right = false self.ground = true end function mobactor:blocks() return true end gravity = 1/32 terminal_velocity = 7/8 -- todo would be nice to have a step height, so i could e.g. make the spikes not be a full tile tall and you wouldn't get stuck on them -- todo does the wrong thing if you hit two drops in the same tic function mobactor:update() self.sprite_time += 1 -- used for player, to track -- what usable object they're -- touching self.touching_mechanism = nil local abs, vec2 = abs, vec2 -- speed adjustments local vel = self.vel local friction = self.friction if not self.ground then friction = 1 - (1 - friction) / 2 end vel.x *= friction if abs(vel.x) > self.max_speed then vel.x = sgn(vel.x) * self.max_speed elseif abs(vel.x) < self.min_speed then vel.x = 0 end if not self.floating then vel.y = min( vel.y + gravity, terminal_velocity) end -- state based on velocity local prevx = self._prevx or 0 self._prevx = vel.x if vel.x ~= 0 then self.facing_right = vel.x < 0 end self.ground = false -- ok, now deal with movement -- velocity is in tiles per -- tic, so every tic, move by -- the velocity local move = vel:copy() -- round to a tile when very -- close to one, so actors -- can fall down gaps easily, -- but only when slowing down if abs(vel.x) < abs(prevx) then local goalx = self.pos.x + move.x local d1 = goalx - flr(goalx + 0.5) -- 1/16 is half a pixel if abs(d1) < 1/16 then move.x -= d1 end end local coll = self:coll() local delta = vec2( abs(move.x), abs(move.y)) local sign = vec2( sgn(move.x), sgn(move.y)) local nearx, farx, neary, fary = "l", "r", "t", "b" if sign.x > 0 then nearx, farx = farx, nearx end if sign.y > 0 then neary, fary = fary, neary end -- trim to map bounds local boundx = abs(curzone.box[nearx] - coll[nearx]) if delta.x > boundx then delta.x = boundx vel.x = 0 end local boundy = abs(curzone.box[neary] - coll[neary]) if delta.y > boundy then if vel.y > 0 then self.ground = true end delta.y = boundy vel.y = 0 end -- find actors we might hit local blockers = {} local moverange = box(coll.l, coll.t, coll.w + delta.x, coll.h + delta.y) if sign.x < 0 then moverange.l -= delta.x end if sign.y < 0 then moverange.t -= delta.y end local function add_blocker(other) if not other.enabled then return end if other.oncollide == actor.oncollide and not other:blocks(self, vel) then return end local otherbox = other:coll() if coll:overlaps(otherbox) then -- since we're checking here -- anyway, this is a good -- place to look for whether -- we're touching a gizmo if self.is_player and other.is_usable then self.touching_mechanism = other end elseif moverange:overlaps(otherbox) then local dist = vec2( sign.x * (otherbox[farx] - coll[nearx]), sign.y * (otherbox[fary] - coll[neary])) -- sort in roughly the order we'll encounter actors local order = max(0, dist.x) * delta.y + max(dist.y) * delta.x add(blockers, { actor = other, dist = dist, order = order, coll = otherbox, }) end end -- todo this is the slowest part! maybe i really do need a blockmap for actor in all(curzone.mobs) do if actor ~= self and abs(self.pos.x - actor.pos.x) + abs(self.pos.y - actor.pos.y) <= 8 then add_blocker(actor) end end for x = flr(moverange.l), ceil(moverange.r) do for y = flr(moverange.t), ceil(moverange.b) do add_blocker(curzone:tile(vec2(x, y))) end end sort(blockers, function (blocker) return blocker.order end) local movedby = vec2() for blocker in all(blockers) do -- step 1: move to touch the -- other actor local dist = blocker.dist - movedby dist.x = min(max(0, dist.x), delta.x) dist.y = min(max(0, dist.y), delta.y) local ymult = delta.y * dist.x local xmult = delta.x * dist.y local step = dist:copy() if dist.x == 0 or dist.y == 0 then -- already touching; no trim elseif ymult > xmult then -- touch side first, so trim y distance step.y = delta.y * dist.x / delta.x elseif xmult > ymult then -- touch top/bottom first, so trim x distance step.x = delta.x * dist.y / delta.y end delta -= step movedby += step coll += (step:elemx(sign)) -- step 2: if we were about -- to collide, do oncollide, -- and stop if solid. if coll:touches(blocker.coll) then local touchx = coll[nearx] == blocker.coll[farx] local touchy = coll[neary] == blocker.coll[fary] if touchx and touchy then -- "corner" case, ho ho! -- allow sliding in the -- direction that we're -- moving fastest in if delta.x > delta.y then touchx = false else touchy = false end end local force = move:copy() if not touchx or delta.x == 0 then force.x = 0 end if not touchy or delta.y == 0 then force.y = 0 end blocker.actor:oncollide(self, force) if blocker.actor:blocks(self, force) then if touchx then delta.x = 0 vel.x = 0 else delta.y = 0 if vel.y > 0 then self.ground = true end vel.y = 0 end end end end -- leftover isn't blocked movedby += delta self.pos += (movedby:elemx(sign)) local pose = "default" if self.is_dead then -- dumb hack, but, shouldn't change pose away from the death state pose = self.pose elseif not self.ground then if vel.y <= 0 then pose = "jumping" else pose = "falling" end elseif vel.x ~= 0 then pose = "walking" end self:set_pose(pose) end function mobactor:draw() local p = self.pos:copy() if self.floating then p.y += 0.25 * (sin(curtime % 90 / 90) - 1) end self.sprite:drawat(p, self.sprite_time, self.facing_right) end function mobactor:set_sprite(s) actor.set_sprite(self, s) self.sprite_time = 0 end -------------------------------- -- player actor type -- main difference is that it -- reads input every frame; -- it also has is_player, -- which other actors may check -- for playeractor = class(mobactor, { __name = "playeractor", is_player = true, z = 1000, -- controls xaccel = 0.125, -- 1/8 max_jump_time = 4, -- determined experimentally -- to make max jump 2 tiles yaccel = 7/64, -- multiplied by xaccel while -- airborne aircontrol = 0.5, }) function playeractor:reset() self.is_dead = false mobactor.reset(self) self.jumptime = 0 end function playeractor:update() if self.is_dead then mobactor.update(self) return end local xmult = 1 if not self.ground then xmult = self.aircontrol end if btn(0) then self.vel.x -= self.xaccel * xmult elseif btn(1) then self.vel.x += self.xaccel * xmult end if btn(5) then -- — progress.seenjumphint = true if self.floating then sfx(19) self.floating = false end if self.jumptime < self.max_jump_time then self.vel.y -= self.yaccel if self.jumptime == 0 then sfx(0) end self.jumptime += 1 end elseif self.ground then self.jumptime = 0 else self.jumptime = 999 end mobactor.update(self) -- spawn particles sometimes -- while floating if self.floating and rnd() < 0.1 then curzone:add_actor(particle( self.pos + vec2(rnd(1), 2), 7, rnd(10) + 10, vec2(0, -0.0625))) end -- handle using an item last if btnp(2) then -- ” progress.seeninvhint = true progress.curitem -= 1 if progress.curitem == 0 then progress.curitem = #progress.inventory end elseif btnp(3) then -- ƒ progress.seeninvhint = true progress.curitem += 1 if progress.curitem > #progress.inventory then progress.curitem = 1 end elseif btnp(4) then -- Ž if self.touching_mechanism then progress.seenusehint = true self.touching_mechanism:onactivate() else local item = progress.inventory[progress.curitem] if item then item:use(self) end end end end firstjump = box(2, 7, 1, 1) firststaff = box(8, 7, 2, 1) function playeractor:draw() mobactor.draw(self) -- possibly draw instructional -- thoughts local hint = nil if not progress.seenjumphint and self:coll():overlaps(firstjump) then hint = "—" elseif not progress.seenstaffhint and self:coll():overlaps(firststaff) then hint = "Ž" elseif not progress.seenusehint and self.touching_mechanism then hint = "Ž" elseif not progress.seeninvhint and #progress.inventory > 1 then hint = "”ƒ" end if hint then local ax = self.pos.x * 8 local ay = self.pos.y * 8 circfill(ax + 4, ay - 1, 1, 7) circfill(ax + 8, ay - 5, 1, 7) -- make a cloud out of circles local cx, cy = ax + 4, ay - 13 circfill(cx + 5, cy - 0, 4, 7) circfill(cx - 5, cy + 0, 4, 7) circfill(cx - 0, cy - 2, 4, 7) circfill(cx + 0, cy + 2, 4, 7) printat({hint}, vec2(cx, cy), "mm") end end function playeractor:die() if self.is_dead then return end self.is_dead = true self:set_pose"dying" game:die(self) end -------------------------------- -- transient actor type -- used for performing collision -- against map tiles that aren't -- real actors; behavior can be -- changed using declare_tile transientactor = class(actor, { -- indicates that the map -- doesn't need to create and -- store a permanent instance is_transient = true, }) function transientactor:init(...) actor.init(self, ...) if not self.sprite then self.sprite = to_sprite( mget(self.pos.x, self.pos.y)) end end -------------------------------- -- associate actor behavior with -- particular map tiles _tiledefs = {} -- declare an actor type to be -- used for a map tile -- parent class can be given -- explicitly as "class"; if -- not, anything with update or -- reset or draw methods will -- use actor, and anything else -- will use transientactor function declare_tile(data) -- clean up data if necessary if data.sprite then data.sprite = to_sprite(data.sprite) end if data.poses then for name, sprref in pairs(data.poses) do data.poses[name] = to_sprite(sprref) end end -- which tiles? local sprite = data.sprite or (data.poses and data.poses.default) local for_tiles = data.for_tiles or sprite:get_tiles() -- what actor class? local cls = data.class data.class = nil if cls then -- do nothing elseif data.reset or data.update or data.draw or data.poses or -- todo check transparency too... (sprite and sprite.is_animated) then -- anything that expects to -- be called needs to at -- least be decor cls = decoractor else -- otherwise transient ok cls = transientactor end local newcls = class(cls, data) for _key, tileno in pairs(for_tiles) do if not _tiledefs[tileno] then _tiledefs[tileno] = class( data, { sprite = to_sprite(tileno) }) end end return newcls end -- todo no way to specify what map this goes on! _oneoff_actors = {} function oneoff_actor(data) setmetatable(data, data.class or actor) add(_oneoff_actors, data) return data end -------------------------------- -- decor: single-tile actors -- that never move, so can be -- mostly treated as part of -- the map, but still get to -- reset and update. -- this is an optimization for -- very simple tiles, to get -- them out of normal collision -- detection, which is slowww decoractor = class(actor, { __name = "decoractor", is_decor = true, _sprchange = false, }) function decoractor:set_sprite(s) actor.set_sprite(self, s) mset(self.pos.x, self.pos.y, self.sprite:current()) self._sprchange = true end function decoractor:reset() local t = 0 if self.enabled then t = self.sprite:current() end mset(self.pos.x, self.pos.y, t) end function decoractor:update() if curtime % animframedelay == 0 or self._sprchange then mset(self.pos.x, self.pos.y, self.sprite:current()) self._sprchange = false end end -------------------------------- -- particle -- super simple actor: a pixel -- of a given color. moves at -- the given velocity, destroys -- itself after some time particle = class(actor, { init = function(self, pos, col, ttl, vel) actor.init(self, pos) self.col = col self.ttl = ttl self.vel = vel or vec2() end, update = function(self) self.ttl -= 1 if self.ttl <= 0 then curzone:del_actor(self) end self.pos += self.vel end, draw = function(self) local p = self.pos * 8 pset(p.x, p.y, self.col) end, }) -------------------------------- -- sprite properties -- maps tileno to list of -- transparent colors _tiletrans = {} -- declare a set of tiles to -- have custom non-black -- transparent colors function declare_transparency(tiles) local trans = tiles.trans for tileno in all(tiles) do _tiletrans[tileno] = trans end end _spritedefs = {} sprite = class() function sprite:init(frames, skip) self.frames = frames self.skip = skip or 0 self.width = 1 self.height = 1 if type(frames[1]) == "table" then self.height = #frames else self.frames = {frames} end self.size = self.width * self.height self.is_animated = false for frames in all(self.frames) do if #frames > 1 then self.is_animated = true break end end end function sprite:get_tiles() local seen = {} local ret = {} for frames in all(self.frames) do for tileno in all(frames) do if not seen[tileno] then seen[tileno] = true add(ret, tileno) end end end return ret end function sprite:current(n, dt) n = n or 1 dt = dt or curtime -- todo this sucks; should anyone else even call it? local frames = self.frames[n] local animlen = #frames * animframedelay local time = dt % animlen local frame = flr(time / animframedelay) + 1 if self.frames.stop and dt >= animlen then frame = #frames end frame += self.skip if frame > #frames then frame -= #frames end return frames[frame] end function sprite:drawat(pos, dt, hflip, vflip) for n = 1, self.size do local tileno = self:current(n, dt) local trans = _tiletrans[tileno] if trans then palt(0, false) for color in all(trans) do palt(color, true) end end spr(tileno, pos.x * 8, (pos.y + n - 1) * 8, 1, 1, hflip, vflip) if trans then palt() end end end -- declare props for a sprite, -- to be used anywhere it's -- referenced, either on the -- map or in actors. args are -- one or more tiles (multiple -- will be animated), optional -- 'trans' list of transparent -- colors, and optional 'name' -- to use to refer to a sprite function declare_sprite(args) -- todo there's no way to register a custom sprite without making it a tile default -- todo no way to /override/ transparency per frame local skip = 0 for tileno in all(args) do _spritedefs[tileno] = sprite( args, skip) if args.name then _spritedefs[args.name] = _spritedefs[tileno] end skip += 1 end return _spritedefs[args[1]] end function declare_sprites(defs) foreach(defs, declare_sprite) end function to_sprite(val) if type(val) == "number" then return _spritedefs[val] or declare_sprite{val} elseif type(val) == "string" then return _spritedefs[val] elseif #val > 0 then return declare_sprite(val) else return val end end -------------------------------- -- some color stuff -- create color ramps from a -- list mapping each color to -- the next one function to_ramp(conv) local ret = {} for color = 0, 15 do local ramp = {} ret[color + 1] = ramp while color do add(ramp, color) color = conv[color + 1] end end return ret end blackramp = to_ramp{ nil, 0, 0, 1, 2, 1, 5, 6, 2, 8, 9, 3, 13, 5, 8, 14, } greenramp = to_ramp{ 1, 3, 3, 11, 3, 1, 10, 10, 9, 10, 11, nil, 11, 12, 9, 9, } -- use pal() to create a fade -- along a ramp. proportion -- should be 0 to 1 function apply_ramp_fade(ramp, proportion, mode) mode = mode or 1 pal() for color = 0, 15 do local colorramp = ramp[color + 1] local slot = flr(#colorramp * proportion + 1) pal(color, colorramp[slot], mode) end end -------------------------------- -- mapzone type -- defines a distinct area of -- the map mapzone = class() function mapzone:init(...) self.box = box(...) self.actors = {} -- mobile actors, ones not -- bound to a single tile self.mobs = {} -- decor can update and reset -- like any other actor, but -- doesn't participate in -- drawing, and acts like -- a plain tile for collision. -- also, these are indexed by -- coordinate, so tile() -- will return the decor self.decor = {} end -- todo it would be nice to have an interface here for manually changing a tile in a decor-aware way (either adding or removing) function mapzone:tile(pos) local decor = self.decor[pos.y * 128 + pos.x] if decor then return decor end local tileno = mget(pos.x, pos.y) if _tiledefs[tileno] then return _tiledefs[tileno](pos) end return transientactor(pos) end function mapzone:add_actor(actor) add(self.actors, actor) if actor.is_decor then self.decor[actor.pos.y * 128 + actor.pos.x] = actor elseif actor.is_mobile then add(self.mobs, actor) end -- todo lol if actor.is_player then player = actor end end function mapzone:del_actor(actor) del(self.actors, actor) if actor.is_decor then local x, y = actor.pos.x, actor.pos.y self.decor[y * 128 + x] = nil mset(x, y, 0) elseif actor.is_mobile then del(self.mobs, actor) end end function mapzone:reset() local mset, vec2 = mset, vec2 if not self.inited then self.inited = true cam.l, cam.t = self.box.l, self.box.t for x = self.box.l, self.box.r - 1 do for y = self.box.t, self.box.b - 1 do local tilecls = _tiledefs[mget(x, y)] if tilecls and not tilecls.is_transient then local actor = tilecls( vec2(x, y)) self:add_actor(actor) if actor.is_mobile then -- remove from actual map mset(x, y, 0) end end end end for actor in all(_oneoff_actors) do self:add_actor(actor) end end end function mapzone:draw(cam, flag) flag = flag or 0 camera(cam.l * 8, cam.t * 8) local x = flr(cam.l) local y = flr(cam.t) map(x, y, x * 8, y * 8, 17, 17, flag) end -------------------------------- -- scenes and layers -- (inspired by cocos2d) scene = class{ -- called when a scene becomes -- or stops being the active -- scene. note that it may be -- drawn even when not active onenter = function() end, onexit = function() end, -- used by scene transitions to -- start the music automatically -- at the right time get_music = function() end, } function scene:init(obj) merge(self, obj or {}) end curtime = 0 function scene:update() -- 64 * 9 * 5 * 7 -- should be divisible by -- most interesting numbers -- todo this makes no sense in a scene, but scenefader needs to pause it curtime = (curtime + 1) % 20160 for layer in all(self.layers) do if layer.update then layer:update() end end end function scene:draw(nocls) local pal, camera = pal, camera if not nocls then cls() end for layer in all(self.layers) do pal() camera() layer:draw() end end -- simple transitional scene -- that can fade from the -- current scene to another scenefader = class(scene) function scenefader:init(newscene, duration, ramp, onbetween) self.newscene = newscene self.oldscene = game.scene self.timer = 1 self.duration = duration self.ramp = ramp or blackramp self.onbetween = onbetween if self.oldscene then game:changemus(nil, self.duration) else self:doreverse() end end function scenefader:doreverse() self.reverse = true self.timer = 1 game:changemus(self.newscene:get_music(), self.duration) if self.onbetween then self:onbetween() end end function scenefader:onenter() end function scenefader:update() self.timer += 1 if self.timer >= self.duration then if not self.reverse then self:doreverse() elseif self.timer > 0 then self.timer -= 1 game:set_scene(self.newscene) end end end function scenefader:draw() rectfill(0, 0, 128, 128, 9) if self.reverse then self.newscene:draw() else self.oldscene:draw() end local prop = self.timer / self.duration if self.reverse then prop = 1 - prop end apply_ramp_fade(self.ramp, prop) end -- current camera, in tiles cam = box(0, 0, 16, 16) margin = 6 map_layer = { update_camera = function(self) local bounds = curzone.box local focus = player:coll() cam.l = max( min(cam.l, max(bounds.l, focus.l - margin)), min(bounds.r, focus.r + margin) - cam.w) cam.t = max( min(cam.t, max(bounds.t, focus.t - margin)), min(bounds.b, focus.b + margin) - cam.h) end, reset = function(self) curzone:reset() for actor in all(curzone.actors) do actor:reset() end self:update_camera() progress.savepoint = nil progress:backup() end, update = function(self) for actor in all(curzone.actors) do if actor.enabled then actor:update() end end self:update_camera() -- advance if player reaches right edge if player:coll().r == curzone.box.r then game:set_scene(scenefader( mainscene, 20, blackramp, function() -- todo probably need to, like, unload the current zone and then load the next one... that hasn't been an explicit step or anything so far -- todo and yet, i don't know why the map /zone/ contains all that information in the first place. should it be on the map layer, and the zone list is just a list of boxes? curzonen += 1 curzone = zones[curzonen] map_layer:reset() end )) end end, draw = function(self) curzone:draw(cam) pal() sort( curzone.actors, function (actor) return actor.z end) for actor in all(curzone.actors) do if actor.enabled and actor:coll():overlaps(cam) then actor:draw() end end end, } -- prompt shown on death deadscene = class(scene) function deadscene:init(wrapped) self.wrapped = wrapped end function deadscene:update() if btn(4) then game:doreset() elseif btn(5) and progress.savepoint then game:doresurrect() else self.wrapped:update() end end function deadscene:draw() self.wrapped:draw() pal() palt() local msg = {"Ž reset "} if progress.savepoint then add(msg, "— resurrect") end printat(msg, vec2(64, 64), "mm", 7, 7, 0) end -- singleton game = { pending_scene = nil, scene = nil, curmusic = -1, taskhdl = 1, tasks = {}, pending_tasks = {}, } function game:initialize() if self.curmusic then self:_music(self.curmusic) end -- create automatic decor for -- tiles with custom sprite -- transparency or animation for tileno, def in pairs(_spritedefs) do if type(tileno) == "number" and not _tiledefs[tileno] and -- todo actually... transparent can't be decoractor, it can't be drawn by map() (def.is_animated or _tiletrans[tileno]) then declare_tile{ class = decoractor, sprite = def, } end end -- initialize map map_layer:reset() end -- schedule a function to be -- called in the future function game:schedule(tics, callback) local handle = self.taskhdl self.taskhdl += 1 self.pending_tasks[handle] = { time = tics, callback = callback, } return handle end function game:update() for handle, task in pairs(self.tasks) do task.time -= 1 if task.time <= 0 then task.callback() self.tasks[handle] = nil end end if self.pending_scene then if self.scene then self.scene:onexit() end self.scene = self.pending_scene self.pending_scene = nil self.scene:onenter() end self.scene:update() -- add pending tasks at the very end, for consistency -- otherwise e.g. a task might schedule a second task, which would then play immediately merge(self.tasks, self.pending_tasks) self.pending_tasks = {} end function game:draw() self.scene:draw() end function game:set_scene(scene) self.pending_scene = scene end -- change the current music, -- with a fade. can fade -- between two tracks function game:changemus(track, fadelen) track = track or -1 if track == self.curmusic then return end -- todo doesn't handle being called again while in the middle of a fade, or while there's another fade scheduled if self.curmusic ~= -1 and track ~= -1 then self:_music(-1, fadelen) self:schedule(fadelen, function() self:_music(track, fadelen) end) else self:_music(track, fadelen) end self.curmusic = track end function game:_music(track, fadelen) if fadelen then fadelen = fadelen * 100 / 3 end music(track, fadelen) end -- death/reset handling function game:die() self:changemus(nil, 0) sfx(2) self:schedule(45, function() self:set_scene(deadscene(self.scene)) end) end function game:doresurrect() if not progress.savepoint then -- how did you even get here return end sfx(3) self:changemus(nil) self:set_scene(scenefader( mainscene, 10, greenramp, function() player.pos = progress.savepoint.pos player.is_dead = false player:set_pose"default" map_layer:update_camera() end )) end function game:doreset() -- this is just a regular reset of the map, plus reverting the player's -- progress self:changemus(nil) self:set_scene(scenefader( mainscene, 20, blackramp, function() -- revert progress first, since resetting the map creates a backup! progress:restore() map_layer:reset() end )) end function game:win() -- todo usual state change -- caveats apply: we're still -- in the middle of an update -- and something might, say, -- kill the player before it's -- done self:set_scene(winscene( self.scene)) end -------------------------------- -- pico-8 engine hooks function _init() game:initialize() end function _update() game:update() end function _draw() game:draw() end --============================-- --===== end engine code ======-- --============================-- -- main gameplay scene, map etc mainscene = scene{ layers = { -- background { update = function(self) end, draw = function(self) camera() rectfill(0, 0, 128, 128, 0) end, }, -- map map_layer, -- hud { draw = function(self) local gizmo = player.touching_mechanism if gizmo then color(isaaccolors[isaaccolor][3]) else color(7) end local t, l = 2, 2 rect(t + 1, l, t + 12, l + 13) rect(t, l + 1, t + 13, l + 12) rectfill(t + 2, l + 2, t + 11, l + 11, 0) local iconpos = vec2(t + 3, l + 3) * 0.125 if gizmo then if gizmo.usesprite:current() == 2 then pal( isaaccolors[1][1], isaaccolors[isaaccolor][1]) end gizmo.usesprite:drawat(iconpos) pal() else item = progress.inventory[progress.curitem] if item then item.sprite:drawat(iconpos) end end end, }, -- framerate { update = function() end, draw = function() local fps = flr(30 / stat(1) + 0.5) local color = 12 if fps < 30 then color = 8 end print(fps, 2, 128 - 5 - 2, color) end, }, }, } function mainscene:get_music() return 0 end titlescene = scene{ slowwalk = declare_sprite{ {1}, {16, 16, 16, 16, 17, 17, 17, 17}}, update = function(self) scene.update(self) if btn(4) or btn(5) then game:set_scene(scenefader( mainscene, 30, blackramp)) end end, draw = function(self) cls() --pal(7, isaaccolors[isaaccolor][1]) pal(5, isaaccolors[isaaccolor][4]) sspr(64, 96, 64, 32, 0, 16, 128, 64) pal() -- todo wtb paltrans type? for i = 1, 4 do pal( isaaccolors[1][i], isaaccolors[isaaccolor][i]) end self.slowwalk:drawat(vec2(0.5, 6)) pal() to_sprite(24):drawat(vec2(14.5, 6.5)) printat( {"ld36 edition"}, vec2(64, 72), "tm", isaaccolors[isaaccolor][4]) printat( {"press Ž or —"}, vec2(64, 96), "mm", 7) printat( {"Ž = z — = x enter for menu"}, vec2(64, 128), "bm", 5) end, get_music = function() return 20 end, onenter = function(self) game:changemus(self:get_music()) end, } game:set_scene(titlescene) winscene = class(scene, { init = function(self, wrapped) self.wrapped = wrapped scene.init(self) end, onenter = function(self) game:changemus(nil) sfx(9) game:schedule(60, function() game:set_scene(scenefader( endscene, 60, blackramp)) end) end, draw = function(self) self.wrapped:draw() end, }) endscene = scene{ timer = 0, onenter = function() -- used instead of get_music -- to avoid the fade in, -- since it's short and -- doesn't loop game:changemus(30) end, update = function(self) self.timer += 1 end, draw = function(self) cls() printat({ "you did it, isaac!", "", "you found the flurry, the", "legendary enchanted sabre.", "", "now you just need to, ah,", "get back out of here.", "", "good luck with that!", }, vec2(64, 8), "tm", 7) printat( {"\135 thanks for playing! \135"}, vec2(64, 80), "mm", 14, 2, 2) sspr(120, 48, 8, 16, 4, 108) printat( {"hastily made by eevee", "@eevee", "\138 http://eev.ee/"}, vec2(16, 124), "bl", 12) end, } menuitem(1, "reset room", function() game:doreset() end) -- todo hmm, wish i had an -- itemactor type items = { staff = { sprite = declare_sprite{48}, use = function(self, player) progress.seenstaffhint = true -- todo this concept requires -- a second save for when -- the player entered the -- room; otherwise they can -- screw themselves local pos = player.pos:copy() -- check that there's space -- todo well this isn't quite -- right local tile = curzone:tile(pos) -- todo this seems clumsy if tile.sprite:current() ~= 0 then -- todo play "nope" sound? return end -- remove existing savepoint if progress.savepoint then curzone:del_actor(progress.savepoint) progress.savepoint = nil end -- create new savepoint progress.savepoint = savepointactor(pos) curzone:add_actor(progress.savepoint) -- sparkles and jingles sfx(1) for angle = 0.125, 1, 0.125 do curzone:add_actor(particle( player.pos + vec2(0.5, 0.5), 11, 8, vec2(cos(angle), sin(angle)) * 0.125 )) end end, }, spellbook = { sprite = declare_sprite{50}, use = function(self, player) if player.floating then sfx(19) player.floating = false elseif player.ground then sfx(8) player.floating = true end end, } } progress = { inventory = {items.staff}, curitem = 1, savepoint = nil, -- called when entering a room to record your progress thusfar backup = function(self) self.savestate = { inventory = merge({}, self.inventory), curitem = self.curitem, } end, restore = function(self) self.inventory = merge({}, self.savestate.inventory) self.curitem = self.savestate.curitem -- savepoint is always gone after a restore self.savepoint = nil end, } gravity = 1/32 terminal_velocity = 1 zones = { mapzone(0, 0, 24, 16), mapzone(24, 0, 16, 16), mapzone(40, 0, 40, 24), mapzone(80, 0, 16, 24), mapzone(96, 0, 32, 24), mapzone(0, 16, 24, 32), mapzone(24, 16, 16, 16), mapzone(24, 32, 16, 16), mapzone(40, 24, 40, 24), mapzone(80, 24, 32, 24), mapzone(112, 24, 16, 24), } curzonen = 1 curzone = zones[curzonen] -- isaac (player) declare_tile{ class = playeractor, shape = box(0, 0.5, 1, 1.5), height = 2, poses = { default = {{1}, {17}}, walking = {{1}, {16, 17}}, jumping = {{1}, {16}}, falling = {{1}, {16}}, dying = {{1, 3, 4, 5, 6}, {17, 19, 20, 21, 22}, stop = true}, }, draw = function(self) for i = 1, 4 do pal( isaaccolors[1][i], isaaccolors[isaaccolor][i]) end playeractor.draw(self) pal() end, } -- randomize isaac's cloak and -- skin tone isaaccolors = { {13, 2, 12, 1}, -- purple + blue {13, 2, 14, 2}, -- purple + pink {12, 1, 11, 3}, -- blue + green {15, 9, 14, 2}, -- peach + pink {11, 3, 10, 9}, -- green + yellow {6, 5, 7, 6}, -- silver + white {9, 4, 13, 2}, -- orange + purple {1, 1, 8, 2}, -- navy + red } isaaccolor = flr(rnd(#isaaccolors)) + 1 -- save point savepointactor = class(actor, { sprite = declare_sprite{ 24, 24, 24, 24, 24, 25, 26, 27, 28, 29, }, is_savepoint = true, -- todo ugh this hierarchy is so bad, one-off actors like this should not -- be this confusing. but this code exists only in mobactor, which has -- physics, which this should not have -- so either i inherit actor and -- reimplement draw, or i inherit mobactor and blank out update draw = function(self) self.sprite:drawat( self.pos + vec2(0, 0.5), self.sprite_time, self.facing_right) end, reset = function(self) curzone:del_actor(self) end, }) -- spikes declare_tile{ sprite = 8, shape = box(0, 0.75, 1, 0.25), oncollide = function(self, actor, d) if d.y > 0 and actor.is_player then actor:die() end end, } -- wooden switch (platforms) declare_tile{ poses = { default = {56}, switched = {57}, }, usesprite = declare_sprite{2}, -- todo ugh, this tricks both -- declare_tile into giving us -- a decoractor, and collision -- into not skipping us oncollide = function() end, is_usable = true, reset = function(self) self.is_usable = true self:set_pose"default" end, onactivate = function(self) sfx(4) for _pos, decor in pairs(curzone.decor) do if decor.onuselever then decor:onuselever(true) end end self:set_pose"switched" self.is_usable = false end, } -- magical bridge declare_tile{ sprite = 42, shape = box(0, 0, 1, 0.25), timer = 0, reset = function(self) -- disabled by default self.enabled = false decoractor.reset(self) end, onuselever = function(self) -- todo should check for a -- blocker and refuse to -- materialize self.enabled = true self.timer = 25 end, update = function(self) decoractor.update(self) if not self.enabled or self.timer <= 0 then return end self.timer -= 1 if self.timer == 10 then sfx(5) end if self.timer <= 10 then end end, draw = function(self) -- we're decor so we already get drawn by map(), but that's ok, just draw atop ourselves if self.timer > 0 then apply_ramp_fade(blackramp, self.timer / 10, 0) self.sprite:drawat(self.pos) pal() end end, } -- laser eye declare_tile{ class = mobactor, poses = { default = {58}, awake = {59}, }, reset = function(self) mobactor.reset(self) self:sleep() end, sleep = function(self) self.sleep_timer = 0 self:set_pose"default" if self.laser then curzone:del_actor(self.laser) self.laser = nil end end, update = function(self) local pcoll = player:coll() local scoll = self:coll() local px = pcoll.l + pcoll.w / 2 local sx = scoll.l + scoll.w / 2 if abs(px - sx) < 2 then self:set_pose"awake" self.sleep_timer = 150 if not self.laser then self.laser = laseractor(self.pos + vec2(0, 1)) curzone:add_actor(self.laser) end elseif self.pose == "awake" then self.sleep_timer -= 1 if self.sleep_timer <= 0 then self:sleep() end end if self.pose == "awake" then local dx = 0.125 local d0 = self.pos.x - self.pos0.x if d0 > 4 then self.reverse = true elseif d0 < -4 then self.reverse = false end if self.reverse then dx *= -1 end self.pos.x += dx if self.laser then self.laser.pos.x += dx end end end, } laseractor = class(actor, { init = function(self, pos) actor.init(self, pos) local bottom = pos:copy() while pos.y < curzone.box.b - 1 do bottom.y += 1 local tile = curzone:tile(bottom) if tile:blocks(self) then break end end self.shape = box( 0.375, 0, 0.25, bottom.y - pos.y) end, update = function(self) local coll = self:coll() if curtime % 10 == 0 then local ang = rnd() * 0.5 curzone:add_actor(particle( vec2(coll.l, coll.b), 8, 8, vec2(cos(ang), sin(ang)) * 0.125)) end if coll:overlaps(player:coll()) then player:die() end end, draw = function(self) local coll = self:coll() rectfill(coll.l * 8, coll.t * 8, coll.r * 8 - 1, coll.b * 8 - 1, 8) end, }) -- wheel (stone doors) -- todo largely copy/pasted declare_tile{ poses = { default = {62}, turning = {62, 63}, }, usesprite = declare_sprite{2}, -- todo ugh, this tricks both -- declare_tile into giving us -- a decoractor, and collision -- into not skipping us oncollide = function() end, is_usable = true, update = function(self) -- todo this is what game's -- schedule() is meant to be -- for, but i don't want it -- to survive through a -- map reset if self.turning_timer then self.turning_timer -= 1 if self.turning_timer <= 0 then self.turning_timer = nil self:reset() end end decoractor.update(self) end, reset = function(self) self.is_usable = true self:set_pose"default" end, onactivate = function(self) sfx(18) -- todo lol well this is awful for actor in all(curzone.actors) do if actor.onusewheel then actor:onusewheel(true) end end self:set_pose"turning" self.is_usable = false self.turning_timer = 30 end, } -- stone door declare_tile{ class = mobactor, sprite = 39, reset = function(self) mobactor.reset(self) local x, y = self.pos0.x, self.pos0.y local h = 1 while y > 0 do if curzone:tile(vec2(x, y - 1)).sprite:current() == 38 then h += 1 y -= 1 else break end end self.pos = vec2(x, y) self.shape = box(0, 0, 1, h) end, update = function(self) if self.direction and curtime % 3 == 0 then local coll = self:coll() -- todo would love to check -- for any collider below, -- but, don't have a way to -- do that at the moment if self.direction > 0 and coll.b == flr(coll.b) and curzone:tile(vec2(coll.l, coll.b)):blocks(self) then self.direction = nil return end if self.direction < 0 and coll.h <= 1 then self.direction = nil self.close_timer = 120 return end self.shape.h += self.direction self.shape.b += self.direction elseif self.close_timer then self.close_timer -= 1 if self.close_timer <= 0 then self.close_timer = nil sfx(7) self.direction = 0.125 end end end, draw = function(self) local sx = self.pos.x * 8 local coll = self:coll() local sy = coll.b * 8 - 8 spr(39, sx, sy) local h = coll.h * 8 - 8 while h >= 8 do sy -= 8 h -= 8 spr(38, sx, sy) end if h > 0 then -- todo haha super ugly and -- hardcoded sspr(6*8, 24 - h, 8, h, sx, sy - h) end end, onusewheel = function(self) if not self.direction and not self.close_timer then sfx(7) self.direction = -0.125 end end, } -- door parts, only used as -- markers declare_tile{ class = decoractor, sprite = 38, enabled = false, } -- wooden bridge declare_tile{ sprite = 47, shape = box(0, 0.375, 1, 0.625), } -- spellbook declare_tile{ class = mobactor, sprite = 50, shape = box(0.25, 0.25, 0.5, 0.5), floating = true, -- todo whoops, i guess this -- is only automatic for decor reset = function(self) mobactor.reset(self) self.enabled = true end, oncollide = function(self, actor, d) if actor.is_player then sfx(6) add(progress.inventory, items.spellbook) self.enabled = false end end } -- flurry declare_tile{ class = mobactor, sprite = 53, shape = box(0.25, 0.25, 0.5, 0.5), floating = true, oncollide = function(self, actor, d) if actor.is_player then game:win() end end, } __gfx__ 00000000c0000000000ddd0000000000000000000000000000000000000000000000000044440444000000000000000000000000000000000044444022242242 00000000ca0000000ddddd00c0000000000000000000000000000000000000000000000004444440000000000000000000000000000000004444444424224224 007007001ccc0000dddd0000ca000000000000000000000000000000000000000000000000000000000000000000000000000000000000004424424422424224 000770001accc000dddddddd1ccc0000c000000000000000001cc000000000000000000000000000000000000000000000000000000000002442242422422424 0007700001caca00dddddddd1accc0000ca000000ccca0000001cca0000000000080000000000000000000000000000000000000000000004224242242242422 00700700041cccc0dddd000001caca0001ccc00001cccc000001cccc000000000060002000000000000000000000000000000000000000002424222224242222 000000000117dd000ddddd00041cccc001accc00001accc00001accc000000000566006000000000000000000000000000000000000000002422422424224224 00000000022dddd0000ddd00011ddd00001caca0001ccac00001ccac000000005556655600000000000000000000000000000000000000002242242222422422 002dddd0002dddd0002dddd0002dddd0041cccc0004ccca000041cca00000000033333000333330003333300033333000bb33300033bb30003333b0000000000 0011cc000011cc000011cc000011cc00011dddd0002dddd000121ccc00000000330003303300033033000330bb0003303300033033000b30330003b000000000 011ccdc0011ccdc0011ccdc00111cd000011cc000012ddd00012dddd000000003003003330030033b003003330030033300b0033300300b33003003b00000000 21ccdd1c211ccdc0211ccdc0011ccdc00111cd000011cd000011cdd0000000003033303330333033b033303330bb30333033b033303330bb3033303300000000 1cc2dd1c11ccdd1c11ccdd1c111ccdc0011ccdc00111cd000111cd000000000003300030033000300bb0003003300030033000b0033000300330003000000000 1cc2ddc01cc2dd1c1cc2dd1c11ccdd1c111ccdc0011ccdc00111cdc0000000000000333000003330000033300000bb30000033b0000033300000333000000000 020000d000200d000002d00000200d0011ccdd1c11ccdd1c111ccdc0000000000003300000033000000bb0000003300000033000000330000003300000000000 2000000d00200d00000d200000200d000220dd0011c0dd1c11ccdd1c0000000000030000000b0000000300000003000000030000000300000003000000000000 044444404444422244444224444444440444044455555555056d6650056d665006760600055505000effffe00000000000000000555555554444422265000056 424422442444224404444440444400402424242426d666650566665005666650606007075050050502eeee20000000000000000066d666652444224407655670 22242444222424440000000004400400222022202226d66505d66d5005d66d5000700606005005050000000000000000000000006666d6652224244400766700 2222444422224444000000000040004000000000222266d5056d6650056d665007000060050000500022220000000000000000006d6666d522224444eeeeeeee 422422444224224400000000000000000000000042246d650566665005666650000600000005000000000000000000000000000066666d6542662d44ef2222fe 4244222442442224000000000000000000000000424426650566d6500566d6506760076055500550000000000ffffff000000000666d66654d66d66402ffff20 4244422242444222000000000000000000000000424442d505d6665005d666507070760650505505000000002e7eeee22ffffff26d66d6d556d666d502feef20 24444222244442220000000000000000000000002444422505666d50005555000060070700500505000000002e7eeee22e7eeee2666666655555555502feef20 00004440077777701cccccc00ff00000000000000000000600000000000000000000000000000000444444444444444400000000000000000002000000000020 000442447757557711c33cc09f9f0e00000000000000006000000000000000004000000000000004446666444466664450000000000000050004000020000400 00042444777777771cccc3c099fffe00000000000000060000000000000000004400000000000044462222644622226455000000000000550020420004204200 00444240775575771cc3ccc0fffffeee00000000090060000000000000000000040000000000004062244226622ee22605000000000000500044404200444000 004400000777777011cc33c00fffeff00000000000960000000000000000000000500000000005002244442222eeee2200600000000006002404440000044400 04400000000077001cccccc0000effff0000000004490000555555555555555500252200002252002222222222e88e2200262200002262000024020000240240 44000000000070001ffffff00000ffff00000000440f90006d666d666d666d660244442002444420022442200228822002444420024444200000400000400002 40000000000700001111111000000ff00000000044f0000066666666666666662444444224444442002222000022220024444442244444420000200002000000 66666666606566660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 60000000066550600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 60000000000605060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 60000000000650550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 66666666000066560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00006000000000650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00006000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00006000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200200 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002202200 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024e2400 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eee4400 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e414100 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004444e40 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000444400 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff4f00 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffff0 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffff0 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004fff40 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f420 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004244420 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff442400 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff42400 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040400 12020000000032121212121212121212121212000000001212121212121212121212121212121212121202000000000000000022321212121212000012120000 00000000000002121200000012121212120200000000000032221212120200003232323232000000000000000000001212520000000000000000000012121212 12120000000000221212122232e23232121212808002021212121212121212121212121212121212121212000000000000000000002222322212000012320000 00000000020212121200000012121212121202020000000000002212121200000000000000000000000000000000021212120000000000000000000012121212 12120200000000001212220000620000221212121212121212121212121212121212121212121212121212420000000000000000000000000012000032000000 00000202121212121200000012121212121212120202020000000012121202020000000002020202000000e30000121212120000000000000000000212121212 12121200000000001222000000620000002212121212121212121232223222e22232121212121212121212000000000000000000000000000022000000000000 02021212121212121202000012121212121212121212120242424212121212120000000012121212020000000002121212120000000000000000001212121212 12121202000000001200000000720000000032121212121212123200000000620000222212121212121212424200000000000000000000000000000000000202 12121212121212121212000022121212121212121212121200000012121212120000000022121212120202020212121212125200000000000000001212121212 12121212000000021200000002020202000000221212121212120000000000620000000032121212121212000000000000000000000000000000000000021212 12121212121212121212000000121212121212121212122200000212121212120000000000121212121212121212121212121200000000000000001212121212 12121222000000121202000022121212020000002212121212220000000000620000000000221212121212024242000000000000000000000000000202121222 22323222121212121212000000121212121212121232220000001212121212220000000000141212121212121212121212121200000000000000001412121212 12123200000002121212000000223212120200000012121212000000000000620000000000001212121212120000000000000000000000000000002222322200 00000000221212121212020000121212121212222200000000021212121212000000000000001212e23222121212121212121200000000000000000012121212 12320000000012121212020000000022121200000032121212000000a20000620000000200002212121212120200000000000000000000000000000000000000 0000e300001212121212120000121212121222000000000002121212121232000000000000003222620000221412121212121252000000000000000014121212 12000000000212121212120000000000121202000000121212020000000000620000001200000012121212121200000000000000000000000000000000000000 00000000003212121212120000321212121200000000000212121212122200000000000000000000620000000022141212121212000000000000000000121212 12000000021212121212120200000000121212000000221212120000000000620000001200000012121212121252000000000000000000000000000000000000 00000000000012121212120000001212123200000000002232323222220000000000000000000000720000000000001212121212000000000000000000321212 12020000223212121212122200000002121212020000003222120200000000620000001202000012121212121212000000000000000000000000000000000000 00000000000012121212120200002212220000000200000000000000000000000000000000000000020202520000001412121212520000000000000000001212 12120000000022322232320000000012121212120000000000121202000000620000001212000032121212121212020000000000000000000000020200000000 00000000000012121212121200000012100000021202020000000000000000000000000000000002121212125200000012121212120000000000000000021212 1212020000000000000000000000021212121212000000001022223200e300720000831212000000121212121212120200000000000000000202121202020200 00000000000212121212121202000032000002121212120202000000000000000000000000000012121212121252000012121212125200000000530000121212 12121202020000000000000002021212121212120202000000000000000000020000121212020000121212121212121202028080800202021212121212121202 02020202021212121212121212020000020212121212121212020202020000008080800000000012121212121212520012121212121200000000f20002121212 12121212120202020202020212121212121212121212020202020202020202120202121212120202121212121212121212121212121212121212121212121212 12121212121212121212121212120202121212121212121212121212120202021212120202020212121212121212125212121212121252d2d2d2d2d212121212 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007700000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000770000000000000000000000000000000000005700000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000770000000000000000000000000000000000007500000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000550000777000007777000007777000000777005000777000000000 00000000000000000000000000000000000000000000000000000000000000000000000007770007777700077777700077777700007777700007777700000000 00000000000000000000000000000000000000000000000000000000000000000000000005770007775500055557700055557700077755700007775500000000 00000000000000000000000000000000000000000000000000000000000000000000000000770005777000007777700007777700077500500005777000000000 00000000000000000000000000000000000000000000000000000000000000000000000000770000577700077557700077557700077700000000577700000000 00000000000000000000000000000000000000000000000000000000000000000000000000770007777700077777700077777700057777700007777700000000 00000000000000000000000000000000000000000000000000000000000000000000000007777005777500057777770057777770005777500005777500000000 00000000000000000000000000000000000000000000000000000000000000000000000005555000555000005555550005555550000555000000555000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000070000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000070000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000070000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000777700000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000777700077700077700777000777007077700575500000000000 00000000000000000000000000000000000000000000000000000000000000000000000000007555700755570755507555707555705755570070000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000007000700777750577007000507777500700070070000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000007000700755500055707000707555000700070070000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000005777570577700777505777505777000700070057700000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000555050055500555000555000555000500050005500000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 __gff__ 000000000000000000000000000080800000000000000000000000000000000080804040a080008000008000008080800000000000000000000080800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 __map__ 21212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121222300003a0000222321212121212121212121212121212121 2121212121212121212121212121212121212121212121212121212121212121212121212121212121212222222222222221212123232222222322222221212121222223232223222222222222212121222223222221212121212121212121212121212223222200000000000000000022222121212121212121212121212121 2121212121212121212121212121212121212121212121212121212121212121212121212121212122220000000000000022212200000000000000000022232321000000000000000000000000232121010000000023212121212121212121212121220000000000000000000000000000002223222221212121212121212121 2121212121212121212121212121212121212121212121212121232223223a22232222212121212100000000000000000000210000000000000000000000000021000000000000000000000000002121000000000000222121212121212121212121000000000000000000000000000000000000000022222121212121212121 2121222322222121212121212121212121212121212121232222000000000000000000222223212101000000000000000000210000000000000020200000000022000000000000002a20000000002121202000000000002121212121212121212123000000202000000000000000000020202020242424242121212121212121 22220000000022222321212121222223222121212323220001000000000000000000000000002221000000000000202000002200200000000000222300000000000000000000002a0021000000002121212100000000002221212121212121212100000020212120202020202020202021212121000000002221212121212121 010000000000000000222322220000000023222200000000000000000000000000000000000000212020200000002222000000002200000000000000000000000000000000002a000021200000002121212100000000000021212121212121212100000022232121212121212121212323232121202024242421212121212121 0000002020000000000000000000000000000000000020202020202020202020202020000000002121212100000000000000002000000000000000000000000020200000002000000021210000002221212120000000000023212121212121212100000000002321212121212323230000002222222200000021212121212121 2020202121202000000000000000000020202020202021212121212121212121212121200000002121212300000000000000002200000000000000000000000023220000002300000021210000000021212121000000000000222121212121212100320000000023232323230000000000000000000000002021212121212121 21212121212121202020202a2a2a2a2a212121212121212121212121212121212121212100000021212100000000000000002000000000000000000000000000000000000000000000212100000000212121210000000000000021212121212121002f0000000000000000000000000020000000000000202121212121212121 21212121212121212121210000000000212121212121212121212121212121212121212120000021212100000000000000002300000000000000000000000000000000000000000000212100000000212121212a2a2a2a2a2a2a2121212121212120212020080808080808080808082021000000002020212121212121212121 2121212121232322212121000000000021212121212121212121212121212121212121212100002321210000000000000000000000000000000000000000000000000000000000000022210000000021212121000000000000002222222322232121212121212121212121212121212122000020202121212121212121212121 2121212222000000222322000000202021212121212121212121212121212121212121212100000021210000000000000000000000000000000000000000000000000000000000000000210000000021212121000000000000000000000000002121212121212121212122232222222200002021212121212121212121212121 2121230000003800000000000020212121212121212121212121212121212121212121212120000021210000000000000000000000000000000000000000000000000000000000000000212000000021212121000000000000000000000000002121212121212122222200000000000000202121212121212121212121212121 212108080820212020202020202121212121212121212121212121212121212121212121212120202121000000000000000000000000000000000000000000000000000000000000000021210000002121212100000000000000002a202020202121212121222200000000002020202020212121212121212121212121212121 2121212121212121212121212121212121212121212121212121212121212121212121212121212121230000000000000000000000000000000000000000000000000000000000000000212100000021212121000000000000002a08212121212121212223000000000020202121212121212121212121212121212121212121 21212121212121212121212121212121212121212121212121212121212121212121212121212121210000000000000000000000000000000000000000000000000000000000000000002121000000212121212a2a2a2a2a2a2a0821212121212121220000000000202021212121212223222121212121212121212222222221 2121212122222221212122222322212121212121212121212323232223212121212121212121212121000000000000000000000000000000000000000000000000000000000000000008212100000021212121000000000000002121212121212121000000000020212121212222230000002223222323222223220000000021 21222322000000232e2200000000222223212121212121210100000000222121212121212121212121000000000000000000000000000000000000000000000000000000000000000021212100000022212121000000000000002121212121212123000000000022222322220000000000000000000000000000000000000022 220000000000000026000000000000000022222e23212121000000000000222e23222e222221212121000000000000000000000000000000000000000000000000080808000000000821212100000000212121080000000000002121212121212200000020000000000000000000000020000000000000000000000820000000 0100003e00000000260000000000000000000026002221212000000000000026000026000023212121000008080000000000000000000000000000000000000808212121080000082121212120000000212121210000000000002121212121210100002021202008080000000008082021202008080000000008082121200000 00000000000000002700000000000000000000260000212121200000003e0026000026000000222121003821210800080808000000000000080000080008082121212121210808212121212121000000212121210000380000082121212121210000202121212121210808080821212121212121210808080821212121212000 2020202020000020202020200820082020000027000023212121200000000026000027000000002121082121212108212121080808080808210808210821212121212121212121212121212121002020212121210820212008212121212121212020212121212121212121212121212121212121212121212121212121212120 2121212121202021212121202020202121202020000000212121212020202026202020202000002121212121212121212121212121212121212121212121212121212121212121212121212121202121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121 212121212121212123222323222223222e22222200000021212121212121212621212121220000212121212121212121212e21212121212121212121212e212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121 2121212122232322000000000000000026000000000000212121212121212126212121230000202121212121222222232226222121212121212121212226222121222223222223232222212121212121212121212222232222232322222223222321212121212121212121212121212121212121232341212121212121212121 21212222000000000000000000003e0026000000000000212121212121212126212121000020212122222323000000000026002222212121212123220026002223000000000000000000212121212121212121220000000000000000000000000023212121212121212121212121212123232323000000232321212121212121 2123000000000000000000000000000027000000000020212121212122222226212122000021212101000000000000000026000000222323222200000026000000000000000000000000232121212121212123000000000000000000000000000000212121212121212121212121212101000000000000000021212121212121 2100000000000000202020202020202020200000002021212121212300000027212100000022222200000000000000000026000000000000000000000026000000000000000000200000002121212121212200000000202008080808080000080808212121212121212222232321212100000000000000000041212121212121 210000000020202021212121212121212121200000232321212121080808202121212020000000002000000000000000002700000000000000000000002738000000000000002a210000002121212121210000000020212121212121210000212121212121212122230000000022212125000000000000000000232121212121 2100000020212121212121212121212121212100000000212121212121212121212121212020000021000000242424000020202020202000000000002020210000000000000000210000002221212121210000242421212121212121210000222121212121212200000000000000232121000000000000000000002121212121 2100000022222121212121212121212121212100003e00212121212121212121212121212121202021200000000000000022222121212120202000002121230000000000000000212000000021212121210000000022232221212121210000002121212121220000000000000000002121000000000000000000004121212121 __sfx__ 010200000c0700c070110701307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 010c00001f3751c375233752330523305233050030500305003050030500305003050030500305003050030500305003050030500305003050030500305003050030500305003050030500305003050030500305 0108000017070170701707017070110701107011070110700e0700c0700e0710e0710e0710e0710e0710e07100000000000000000000000000000000000000000000000000000000000000000000000000000000 01020000186111861118621186211d631216312364126641296412d64130641346413764137641376413764137641376413764137641296412964124641246411d6411d641186311863111621116210c6110c611 01100000136550065000655006050c605006050060500605006050060500605006050060500605006050060500605006050060500605006050060500605006050060500605006050060500605006050060500605 01040000115741a504135741557415570005040050400504005040050400504005040050400504005040050400504005040050400504005040050400504005040050400504005040050400504005040050400504 0108000028075260752d0751700513005040050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005 010c0000246102b6102f61000616246102b6102f61000616006060060600606006060060600606006060060600606006060060600606006060060600606006060060600606006060060600606006060060600606 010c00000e774107740e7741377413770137701377013770007040070400704007040070400704007040070400704007040070400704007040070400704007040070400704007040070400704007040070400704 010c0000217701c7001d7701f770217701a70021770007001f7702177023770217002477024770247702477023700237002370023700237002370023700237000070000700007000070000700007000070000700 0110000005070050700507005070070700707005070050700b0700b0700b0700b0700907009070090700907005070050700507005070040700407002070020700707007070050700507002070020700007000070 011000001c0021c0021c0521c0521c0021c0021c0521c052000020000200002000021f0521f0521f0521f05200002000021d0521d0521f0521f05219002180021f0521f0521f0521d05218052180521800218002 01100000050700507005000050000407004070050000500007070070700707007070187430900007000070000907009070040700407005070050700200002000040700407004070040701a743187430000000000 01100000077430670305703057030c743077030070300703057030570305743057030c743057030b70300703077430670305703057030c743077030070300703057030570305743007430c743057030b70300703 01100000180521a0521f0521f0021f0521f0021f0521f0521f0021f0021f0521f0521d0521d0521f0521c05218052180021805218002180521a0521d0521a0521805218052180520e0021a0521a0521a05205002 011000000707007070070700707007070070700707007070050700507005070050700407004070020700207007070070700907009070050700507007070070700507005070050700507002070020700207002070 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 010c00003b0740000429074000043b0740000429074000043b0740000429074000040000400004000040000400004000040000400004000040000400004000040000400004000040000400004000040000400004 0106000013770107700c7700c7700c7700c7751370013700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 011000001103500005000050000513035110051103500005150301503500005000051303013035000050000510030100301003010035000050000500005000051003010030100301003500005000050000500005 011000001103500000000000000013035000001103500000150301503500000000001303013035000000000010035100351003510035130351303513035130351703517035170351703511035110351103511035 011000001703511035130350000017035110351303500000100301003500000000001003010035000000000017035110351303500000170351103513035000001003010035000000000010030100350000000000 011000001703511035130350000018035150351703500000170351103513035000001803515035170350000018035150351303511035170351303517035130051803515035130351103517035130351703513005 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 011000001c770007002170021700217702177021770007001d7001d7001f7001c7001d7701f7001f7701f7001d7701d7001a7701a7701a7001a7001a7001a70021770007001d770007001c7701c7700070000700 011000001a770007001c770007001d7701d77000700007001f7701f7001c770007001f7701c7001d770007001f7701f7701f7701f7701c7001c7000070000700187701a770187701877018770187701877018770 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 __music__ 01 0a424344 00 0c424d44 00 0c420d44 00 0a4b0d44 00 0f4b0d44 00 0f4e0d44 02 0c4e0d44 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 01 14424344 00 15424344 00 14424344 00 16424344 02 17424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 01 1e424344 04 1f424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344 00 41424344