blob: d409dbba833995a15a9127c8fc752066ac0dc670 [file]
#include <map>
#include <string>
#include <vector>
#include <cstdlib>
#include "platformer.hpp"
using namespace blit;
using std::floor;
Size screen_size(160, 120);
/* define storage for the framebuffer, spritesheet, and mask */
Pen __ss[128 * 128];
uint8_t __m[320 * 240];
/* create surfaces */
Surface m((uint8_t *)__m, PixelFormat::M, screen_size);
const int max_light_radius = 60;
uint8_t __mshad[(max_light_radius * 2 + 1) * (max_light_radius * 2 + 1)] __SECTION__(".m");
Surface mshad((uint8_t *)__mshad, PixelFormat::M, Size(max_light_radius * 2 + 1, max_light_radius * 2 + 1));
Point world_to_screen(const Vec2 &p);
Point world_to_screen(const Point &p);
Point screen_to_world(const Point &p);
void highlight_tile(Point p, Pen c);
Point tile(const Point &p);
Point player_origin();
void draw_layer(MapLayer &layer);
void draw_flags();
void render_light(Point pt, float radius, bool shadows);
void blur(uint8_t passes);
void bloom(uint8_t passes);
void load_assets();
/* create map */
enum TileFlags { SOLID = 1, WATER = 2, LADDER = 4 };
Map map(Rect(0, 0, 48, 24));
uint8_t player_animation[5] = { 208, 209, 210, 211, 212 };
float player_animation_frame = 0;
float clamp(float v, float min, float max) {
return v > min ? (v < max ? v : max) : min;
}
struct Player {
Vec2 vel;
Vec2 pos;
bool flip = false;
enum {
STILL,
WALKING,
JUMPING
};
std::map<uint8_t, std::vector<uint8_t>> animations;
float animation_frame = 0.0f;
Player() {
animations[STILL] = { 208, 208, 208, 208, 208, 208, 209, 208, 208, 208, 208, 208, 208, 208 };
animations[WALKING] = { 208, 209, 210, 211, 212 };
animations[JUMPING] = { 217 };
vel = Vec2(0, 0);
pos = Vec2(100, 32);
}
Rect aabb() {
return Rect(pos.x - 4, pos.y - 12, 7, 11);
}
uint8_t animation_sprite_index(uint8_t animation) {
uint8_t animation_length = animations[animation].size();
return animations[animation][uint32_t(animation_frame) % animation_length];
}
Point current_tile() {
return Point(pos.x / 8, pos.y / 8);
}
bool tile_under_solid() {
Point p = current_tile();
return map.has_flag(p, TileFlags::SOLID);
}
bool tile_under_ladder() {
Point p = current_tile();
return map.tile_index(p) == 7;
}
bool on_ground() {
if (vel.y < 0) return false;
Point p = current_tile();
return map.has_flag(Point(p.x, p.y + 1), TileFlags::SOLID) && ((int32_t(pos.y) % 8) == 7);
}
bool in_water() {
return false;
Point p = current_tile();
return map.has_flag(Point(p.x, p.y + 1), TileFlags::WATER);
}
/*
return a clipped camera point that doesn't allow the viewport to
leave the world bounds
*/
Point camera() {
static Rect b(screen_size.w / 2, screen_size.h / 2, map.bounds.w * 8 - screen.bounds.w, map.bounds.h * 8 - screen.bounds.h);
return b.clamp(Point(floor(pos.x), floor(pos.y)));
}
Rect viewport() {
Point c = camera();
return Rect(
c.x - screen.bounds.w / 2,
c.y - screen.bounds.h / 2,
screen.bounds.w,
screen.bounds.h
);
}
void update() {
static float max_speed_x = 2.0f;
static float ground_acceleration_x = 0.5f;
static float air_acceleration_x = 0.2f;
static float duration = 0.01f;
static Vec2 gravity(0, 9.8f * 5.0f); // normal gravity is boring!
if (pressed(Button::DPAD_LEFT)) {
vel.x = vel.x - (on_ground() ? ground_acceleration_x : air_acceleration_x);
}
if (pressed(Button::DPAD_RIGHT)) {
vel.x = vel.x + (on_ground() ? ground_acceleration_x : air_acceleration_x);
}
vel.x = clamp(vel.x, -max_speed_x, max_speed_x);
//player.vel = player.vel + (gravity * duration);
Vec2 future_player_pos = pos + vel;
Rect future_bb = Rect(future_player_pos.x - 4, future_player_pos.y - 12, 7, 11);
bool collision = false;
map.tiles_in_rect(future_bb, [&collision](Point tile_pt) -> void {
if (map.has_flag(tile_pt, TileFlags::SOLID)) {
collision = true;
}
});
if (!collision) {
pos = future_player_pos;
}
else {
vel.x = 0.0f;
vel.y = 0.0f;
}
}
void render() {
uint8_t animation = Player::STILL;
if (std::abs(vel.x) > 1) {
animation = Player::WALKING;
}
if (!on_ground()) {
animation = Player::JUMPING;
}
uint8_t si = animation_sprite_index(animation);
Point sp = world_to_screen(Point(pos.x - 4, pos.y - 7));
screen.sprite(si, sp, flip);
sp.y -= 8;
screen.sprite(si - 16, sp, flip);
Rect bb = aabb();
screen.pen = Pen(0, 255, 0);
screen.line(world_to_screen(bb.tl()), world_to_screen(bb.tr()));
screen.line(world_to_screen(bb.bl()), world_to_screen(bb.br()));
map.tiles_in_rect(bb, [&bb](Point tile_pt) -> void {
Point sp = world_to_screen(tile_pt * 8);
Rect rb(sp.x, sp.y, 8, 8);
screen.pen = Pen(0, 255, 0, 150);
if (map.has_flag(tile_pt, TileFlags::SOLID)) {
screen.pen = Pen(255, 0, 0, 150);
}
screen.rectangle(rb);
});
//map.tiles_in_rect(bb)
}
} player;
struct bat {
Vec2 pos;
Vec2 vel = Vec2(-2, 0);
uint8_t current_frame = 0;
std::array<uint8_t, 6> frames = {{ 96, 97, 98, 99, 98, 97 }};
void update() {
current_frame++;
current_frame %= frames.size();
Vec2 test_pos = pos + (Vec2::normalize(vel) * 8.0f);
if (map.has_flag(tile(Point(test_pos)), TileFlags::SOLID)) {
vel.x *= -1;
}
pos += vel;
}
};
bat bat1;
struct slime {
Vec2 pos;
Vec2 vel = Vec2(1, 0);
uint8_t current_frame = 0;
std::array<uint8_t, 4> frames = {{ 112, 113, 114, 113 }};
void update() {
current_frame++;
current_frame %= frames.size();
Vec2 test_pos = pos + (Vec2::normalize(vel) * 8.0f);
if (map.has_flag(tile(Point(test_pos)), TileFlags::SOLID)) {
vel.x *= -1;
}
pos += vel;
}
};
slime slime1;
void animation_timer_callback(Timer &timer) {
bat1.update();
slime1.update();
}
Timer t;
/* setup */
void init() {
load_assets();
bat1.pos = Vec2(200, 22);
slime1.pos = Vec2(50, 112);
t.init(animation_timer_callback, 50, -1);
t.start();
screen_size.w = 160;
screen_size.h = 120;
//engine::set_screen_mode(screen_mode::hires);
}
void render(uint32_t time) {
static int32_t x = 0; x++;
uint32_t ms_start = now();
screen.mask = nullptr;
screen.alpha = 255;
screen.pen = Pen(0, 0, 0);
screen.clear();
// mask out for lighting
mshad.alpha = 255;
mshad.pen = Pen(0);
mshad.clear();
m.alpha = 255;
m.pen = Pen(64);
m.clear();
// render lights
for (uint8_t y = 0; y < 24; y++) {
for (uint8_t x = 0; x < 48; x++) {
uint32_t ti = map.layers["effects"].tile_at(Point(x, y));
Point lp = Point(x * 8 + 4, y * 8 + 3);
if (ti == 37 || ti == 38) {
render_light(lp, 15.0f, false);
}
}
}
render_light(Point(player.pos.x, player.pos.y - 7), 60.0f, true);
// light up the "outside" this should be done with map flags
Rect r; m.pen = Pen(255);
r = Rect(world_to_screen(Point(0, 0)), world_to_screen(Point(112, 40))); m.rectangle(r);
r = Rect(world_to_screen(Point(0, 40)), world_to_screen(Point(80, 48))); m.rectangle(r);
r = Rect(world_to_screen(Point(0, 48)), world_to_screen(Point(72, 56))); m.rectangle(r);
r = Rect(world_to_screen(Point(0, 56)), world_to_screen(Point(48, 64))); m.rectangle(r);
r = Rect(world_to_screen(Point(0, 64)), world_to_screen(Point(32, 72))); m.rectangle(r);
bloom(3);
blur(1);
screen.alpha = 255;
screen.pen = Pen(39, 39, 54);
screen.clear();
// draw world
// layers: background, environment, effects, characters, objects
draw_layer(map.layers["background"]);
draw_layer(map.layers["environment"]);
draw_layer(map.layers["effects"]);
draw_layer(map.layers["objects"]);
// draw player
player.render();
// bat
Point sp = world_to_screen(Point(bat1.pos.x - 4, bat1.pos.y));
screen.sprite(bat1.frames[bat1.current_frame], sp, bat1.vel.x < 0 ? false : true);
// slime
sp = world_to_screen(Point(slime1.pos.x - 4, slime1.pos.y));
screen.sprite(slime1.frames[slime1.current_frame], sp, slime1.vel.x < 0 ? false : true);
// overlay water
screen.pen = Pen(56, 136, 205, 125);
for (uint8_t y = 0; y < 24; y++) {
for (uint8_t x = 0; x < 48; x++) {
Point pt = world_to_screen(Point(x * 8, y * 8));
uint32_t ti = map.tile_index(Point(x, y));
if (map.has_flag(Point(x, y), TileFlags::WATER)) {
screen.rectangle(Rect(pt.x, pt.y, 8, 8));
}
}
}
// invert the lighting mask
m.custom_modify(m.clip, [](uint8_t *p, int16_t c) -> void {
while (c--) {
*p = 255 - *p;
p++;
}
});
// blend over lighting
screen.mask = &m;
screen.pen = Pen(39 / 2, 39 / 2, 54 / 2);
screen.clear();
static int tick = 0;
tick++;
screen.mask = nullptr;
screen.alpha = 255;
screen.sprite(139, Point(2, 2));
screen.sprite(139, Point(12, 2));
screen.sprite(139, Point(22, 2));
// draw FPS meter
uint32_t ms_end = now();
screen.mask = nullptr;
screen.pen = Pen(255, 0, 0);
for (uint32_t i = 0; i < (ms_end - ms_start); i++) {
screen.pen = Pen(i * 5, 255 - (i * 5), 0);
screen.rectangle(Rect(i * 3 + 1, 117, 2, 2));
}
// highlight current player tile
// point pt2 = player.current_tile();
// highlight_tile(pt2, rgba(0, 255, 0, 100));
// draw map flags
// draw_flags();
}
/*
update() is called every 10ms, all effects should be
scaled to that duration
player velocity is in tiles per second, so if the players
'x' velocity is 1 then they move sideways by one tile per
second
one tile is considered to be 1 metre
*/
void update(uint32_t time) {
float duration = 0.01f; // == 10ms as a float
static float jump_velocity = 15.0f;
static Vec2 gravity(0, 9.8f * 5.0f); // normal gravity is boring!
static bool jumping = false;
player.update();
/*
// player is on the ground and not moving left or right, friction!
if (player.in_water()) {
if ((pressed(button::A) | pressed(button::DPAD_UP))) {
player.vel.y = 0;
}
if ((pressed(button::A) | pressed(button::DPAD_LEFT))) {
player.vel.x = 0;
}
if ((pressed(button::A) | pressed(button::DPAD_RIGHT))) {
player.vel.x = 0;
}
}
else {
if (pressed(button::DPAD_LEFT)) {
player.vel.x = player.vel.x - (player.on_ground() ? ground_acceleration_x : air_acceleration_x);
player.vel.x = std::max(-max_speed_x, player.vel.x);
player.flip = true;
}
if (pressed(button::DPAD_RIGHT)) {
player.vel.x = player.vel.x + (player.on_ground() ? ground_acceleration_x : air_acceleration_x);
player.vel.x = std::min(max_speed_x, player.vel.x);
player.flip = false;
}
if (player.on_ground()) {
jumping = false;
if (!pressed(button::DPAD_RIGHT) && !pressed(button::DPAD_LEFT)) {
player.vel.x = player.vel.x * 0.90;
}
if ((pressed(button::A) | pressed(button::DPAD_UP)) && !jumping) {
player.vel.y = -jump_velocity;
jumping = true;
}
}
}
//if player_on_ground() and math.abs(last_noise_x - player.pos.x) > 5 then
// step_noise()
// last_noise_x = player.pos.x
//end
point old_tile = tile(player_origin());
float water = player.in_water() ? 0.2f : 1.0f;
player.vel = player.vel + (gravity * duration * water);
point new_tile = tile(player_origin());
// collision detection and correction
// falling
if (player.tile_under_solid() && old_tile.y < new_tile.y) {
// player.pos.y = old_tile.y * 8 + 7;
player.vel.y = 0;
}
// moving left/right
if (!map.has_flag(old_tile, TileFlags::SOLID) && map.has_flag(new_tile, TileFlags::SOLID) && ((old_tile.x > new_tile.x) || (old_tile.x < new_tile.x))) {
player.pos.x = old_tile.x * 8 + 4;
player.vel.x = 0;
}
player.animation_frame += 0.1;
if (player.on_ground()) {
player.pos.y = floor(player.pos.y);
if (player.vel.y > 0) {
player.vel.y = 0;
}
}
else {
player_animation_frame = 2;
}
/*
if (tick_seed % 3 == 0) {
for (uint8_t y = 0; y < 16; y++) {
for (uint8_t x = 0; x < 32; x++) {
uint8_t ti = tile_index(point(x, y));
if (ti >= 5 && ti <= 7) {
set_tile_index(point(x, y), 5 + rand() % 3);
}
}
}
}*/
}
float orient2d(Vec2 p1, Vec2 p2, Vec2 p3) {
return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
}
std::vector<std::pair<Vec2, Vec2>> get_occluders(Point pt, float radius) {
std::vector<std::pair<Vec2, Vec2>> occluders;
Rect light_bounds(pt, pt);
light_bounds.inflate(max_light_radius);
map.tiles_in_rect(light_bounds, [&occluders, &pt](Point tile_pt) -> void {
if (map.has_flag(tile_pt, TileFlags::SOLID)) {
Rect rb(tile_pt.x * 8, tile_pt.y * 8, 8, 8);
rb.x -= pt.x;
rb.y -= pt.y;
Vec2 o(0, 0);
Vec2 fpt(pt.x, pt.y);
/*vec2 tl(rb.x - 0.5f, rb.y + 0.5f);// = rb.tl();
vec2 tr(rb.x + rb.w - 0.5f, rb.y + 0.5f);// = rb.tr();
vec2 bl(rb.x - 0.5f, rb.y + rb.h + 0.5f);// = rb.bl();
vec2 br(rb.x + rb.w - 0.5f, rb.y + rb.h + 0.5f);// = rb.br();
*/
Vec2 tl = Vec2(rb.tl().x - 1, rb.tl().y - 1);
Vec2 tr = Vec2(rb.tr().x - 1, rb.tr().y - 1);
Vec2 bl = Vec2(rb.bl().x - 1, rb.bl().y - 1);
Vec2 br = Vec2(rb.br().x - 1, rb.br().y - 1);
if (!map.has_flag(Point(tile_pt.x, tile_pt.y + 1), TileFlags::SOLID) && orient2d(bl, br, o) > 0) {
occluders.push_back(std::make_pair(bl, br));
}
if (!map.has_flag(Point(tile_pt.x - 1, tile_pt.y), TileFlags::SOLID) && orient2d(tl, bl, o) > 0) {
occluders.push_back(std::make_pair(tl, bl));
}
if (!map.has_flag(Point(tile_pt.x, tile_pt.y - 1), TileFlags::SOLID) && orient2d(tr, tl, o) > 0) {
occluders.push_back(std::make_pair(tr, tl));
}
if (!map.has_flag(Point(tile_pt.x + 1, tile_pt.y), TileFlags::SOLID) && orient2d(br, tr, o) > 0) {
occluders.push_back(std::make_pair(br, tr));
}
}
});
return occluders;
}
void render_light(Point pt, float radius, bool shadows = false) {
Point lpt(max_light_radius, max_light_radius);
mshad.alpha = 255;
mshad.pen = Pen(0);
mshad.clear();
// draw the light aura
mshad.alpha = (rand() % 10) + 40;
int steps = 20;
for (int j = steps; j > 0; j--) {
mshad.pen = Pen(255);
mshad.circle(lpt, (j * radius / steps));
}
if (shadows)
{
// cut out the shadows
mshad.alpha = 255;
mshad.pen = Pen(0);
float rs = radius * radius;
std::vector<std::pair<Vec2, Vec2>> occluders = get_occluders(pt, radius);
for (auto occluder : occluders) {
Vec2 p1 = occluder.first;
Vec2 p2 = occluder.second;
Vec2 fpt(pt.x, pt.y);
Vec2 rv1 = p1;
Vec2 rv2 = p2;
if ((std::abs(rv1.x) * std::abs(rv1.y)) < rs && (std::abs(rv2.x) * std::abs(rv2.y)) < rs) {
// (max_light_radius * 2) = cludge to ensure shadows are projected far enough
// actually we should project shadows to the bounds of the light bounding box
// there is no need to "guess" but that requires working out the intersection
// with the edge of the bounding box and optionally inserting points at the corners
// if required. a task for another day....
float c1 = (max_light_radius * 2) / float(std::max(std::abs(rv1.x), std::abs(rv1.y)));
float c2 = (max_light_radius * 2) / float(std::max(std::abs(rv2.x), std::abs(rv2.y)));
Vec2 p3 = rv1 * c1;
Vec2 p4 = rv2 * c2;
Point wp1 = p1 + lpt;
Point wp2 = p2 + lpt;
Point wp3 = p3 + lpt;
Point wp4 = p4 + lpt;
std::vector<Point> poly = {
wp1, wp3, wp4, wp2
};
mshad.triangle(wp1, wp2, wp3);
mshad.triangle(wp2, wp4, wp3);
//mshad.polygon(poly);
}
}
}
Point light_corner = world_to_screen(pt - Point(max_light_radius, max_light_radius));
m.custom_blend(&mshad, mshad.clip, light_corner, [](uint8_t *psrc, uint8_t *pdest, int16_t c) -> void {
while (c--) {
*pdest = *pdest ^ ((*pdest ^ *psrc) & -(*pdest < *psrc)); // integer `max` without branching
pdest++;
psrc++;
}
});
}
void blur(uint8_t passes) {
uint8_t last;
for (uint8_t pass = 0; pass < passes; pass++) {
uint8_t *p = (uint8_t *)m.data;
for (uint16_t y = 0; y < m.bounds.h; y++) {
last = *p;
p++;
for (uint16_t x = 1; x < m.bounds.w - 1; x++) {
*p = (*(p + 1) + last + *p + *p) >> 2;
last = *p;
p++;
}
p++;
}
}
// vertical
for (uint8_t pass = 0; pass < passes; pass++) {
for (uint16_t x = 0; x < m.bounds.w; x++) {
uint8_t *p = (uint8_t *)m.data + x;
last = *p;
p += m.bounds.w;
for (uint16_t y = 1; y < m.bounds.h - 1; y++) {
*p = (*(p + m.bounds.w) + last + *p + *p) >> 2;
last = *p;
p += m.bounds.w;
}
}
}
}
void bloom(uint8_t passes) {
for (uint8_t pass = 0; pass < passes; pass++) {
uint8_t *p = (uint8_t *)m.data + m.bounds.w;
for (uint16_t y = 1; y < m.bounds.h - 1; y++) {
p++;
for (uint16_t x = 1; x < m.bounds.w - 1; x++) {
uint8_t v1 = *p;
uint8_t v2 = *(p + 1);
uint8_t v3 = *(p + m.bounds.w);
*p++ = v1 > v2 ? (v1 > v3 ? v1 : v3) : (v2 > v3 ? v2 : v3);
}
p++;
}
p = (uint8_t *)m.data + (m.bounds.h * m.bounds.w) - 1 - m.bounds.w;
for (uint16_t y = 1; y < m.bounds.h - 1; y++) {
p--;
for (uint16_t x = 1; x < m.bounds.w - 1; x++) {
uint8_t v1 = *p;
uint8_t v2 = *(p - 1);
uint8_t v3 = *(p - m.bounds.w);
*p-- = v1 > v2 ? (v1 > v3 ? v1 : v3) : (v2 > v3 ? v2 : v3);
}
p--;
}
}
}
void load_assets() {
std::vector<uint8_t> layer_background = { 17,17,17,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,17,17,17,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,17,17,17,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,0,0,0,47,1,2,3,4,1,2,3,1,2,3,4,5,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,0,0,0,0,0,0,0,51,0,0,0,13,14,0,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,47,0,0,0,30,0,0,0,0,15,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,31,84,47,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,31,67,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,83,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,223,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,0,0,0,0,0,0,41,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,15,0,78,0,0,0,0,0,0,0,0,15,0,0,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,15,15,15,15,41,15,15,15,41,15,41,15,15,15,41,0,0,0,15,15,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,41,15,41,15,15,15,15,41,15,15,15,15,15,60,15,15,0,0,0,15,41,41,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,60,15,15,15,15,15,41,15,15,41,15,15,15,41,15,41,41,15,15,15,15,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,15,15,15,41,15,13,15,15,41,15,15,41,15,41,15,15,15,15,41,15,15,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,41,15,15,41,15,15,15,41,41,15,15,15,15,15,30,15,15,15,41,15,60,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,15,15,15,15,41,15,15,15,60,15,15,41,15,15,15,15,41,15,41,15,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };;
map.add_layer("background", layer_background);
std::vector<uint8_t> layer_environment = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,0,74,28,29,60,0,0,0,0,0,0,60,28,29,0,0,15,0,0,0,0,0,0,0,0,0,0,28,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,0,74,44,45,0,0,0,0,0,0,0,0,44,45,0,0,0,0,15,0,0,0,0,15,0,0,0,44,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,0,74,0,0,0,0,0,0,0,0,0,0,60,89,89,89,89,71,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,88,89,90,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,28,29,0,0,0,0,0,15,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,45,0,0,15,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,121,28,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,71,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,44,45,58,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,88,89,89,89,89,89,71,74,0,0,0,0,0,0,0,0,0,0,0,60,57,57,87,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,0,0,0,0,0,0,0,0,60,74,0,0,0,56,57,0,0,0,0,56,57,87,0,0,0,0,0,86,57,57,57,57,28,29,57,60,57,57,57,50,55,55,55,55,48,57,57,57,60,0,0,0,0,0,0,0,28,29,55,55,55,64,0,58,7,57,60,72,0,0,0,0,75,94,94,94,94,94,94,76,44,45,0,0,0,0,0,66,16,16,48,49,127,0,0,28,29,60,0,0,0,0,0,0,44,45,16,16,16,64,0,74,7,0,0,72,0,0,0,0,79,0,0,0,0,0,0,77,0,75,94,94,94,94,76,126,49,49,127,0,0,0,0,44,45,66,55,55,55,55,55,55,60,16,16,16,16,64,0,74,7,0,0,93,94,94,94,94,95,0,0,0,0,0,0,93,94,95,0,0,0,0,47,0,0,0,0,0,0,0,0,0,0,66,16,16,16,16,16,16,16,16,16,16,16,64,0,74,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,0,0,0,0,0,0,0,0,0,0,126,49,49,49,50,16,16,16,16,16,16,48,127,0,31,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,16,16,16,16,16,48,127,0,0,31,7,0,0,0,0,0,0,0,0,40,61,62,62,63,0,0,0,0,0,0,0,0,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,126,49,49,49,49,49,127,0,0,0,91,62,62,62,62,62,62,62,62,62,62,92,0,0,91,62,62,63,0,61,62,62,62,92,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,59,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
map.add_layer("environment", layer_environment);
map.layers["environment"].add_flags({ 8, 59, 31, 47, 28, 29, 44, 45, 60, 48, 49, 50, 64, 66, 80, 81, 82, 56, 57, 58, 72, 74, 88, 89, 90, 61, 62, 63, 77, 79, 93, 94, 95 }, TileFlags::SOLID);
map.layers["environment"].add_flags(7, TileFlags::LADDER);
map.layers["environment"].add_flags({ 16, 55, 223 }, TileFlags::WATER);
std::vector<uint8_t> layer_effects = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,0,0,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
map.add_layer("effects", layer_effects);
std::vector<uint8_t> layer_characters = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,182,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
map.add_layer("characters", layer_characters);
std::vector<uint8_t> layer_objects = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,39,0,0,0,0,0,0,0,0,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0,0,0,0,0,0,0,0,0,85,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
map.add_layer("objects", layer_objects);
screen.sprites = SpriteSheet::load(packed_data);
}
Point world_to_screen(const Vec2 &p) {
return Point(
p.x - player.camera().x + m.bounds.w / 2,
p.y - player.camera().y + m.bounds.h / 2
);
}
Point world_to_screen(const Point &p) {
return Point(
p.x - player.camera().x + m.bounds.w / 2,
p.y - player.camera().y + m.bounds.h / 2
);
}
Point screen_to_world(const Point &p) {
return Point(
p.x + player.camera().x - m.bounds.w / 2,
p.y + player.camera().y - m.bounds.h / 2
);
}
void highlight_tile(Point p, Pen c) {
screen.pen = c;
p.x *= 8;
p.y *= 8;
p = world_to_screen(p);
screen.rectangle(Rect(p.x, p.y, 8, 8));
}
Point player_origin() {
return Point(player.pos.x, player.pos.y);
}
Point tile(const Point &p) {
return Point(p.x / 8, p.y / 8);
}
void draw_layer(MapLayer &layer) {
Point tl = screen_to_world(Point(0, 0));
Point br = screen_to_world(Point(screen.bounds.w, screen.bounds.h));
Point tlt = tile(tl);
Point brt = tile(br);
for (uint8_t y = tlt.y; y <= brt.y; y++) {
for (uint8_t x = tlt.x; x <= brt.x; x++) {
Point pt = world_to_screen(Point(x * 8, y * 8));
int32_t ti = layer.map->tile_index(Point(x, y));
if (ti != -1) {
uint8_t si = layer.tiles[ti];
if (si != 0) {
screen.sprite(si, pt);
}
}
}
}
}
Pen flag_colours[] = {
Pen(255, 0, 0, 100),
Pen(0, 255, 0, 100),
Pen(0, 0, 255, 100)
};
void draw_flags() {
for (uint8_t y = 0; y < 24; y++) {
for (uint8_t x = 0; x < 48; x++) {
Point pt = world_to_screen(Point(x * 8, y * 8));
uint32_t ti = map.tile_index(Point(x, y));
uint8_t f = map.get_flags(Point(x, y));
for (uint8_t i = 0; i < 3; i++) {
if (f & (1 << i)) {
screen.pen = flag_colours[i];
screen.rectangle(Rect(pt.x, pt.y, 8, 8));
}
}
}
}
}