diff --git a/main_gbmeta/My_settings.h b/main_gbmeta/My_settings.h new file mode 100644 index 0000000..cf7eba5 --- /dev/null +++ b/main_gbmeta/My_settings.h @@ -0,0 +1,6 @@ +// Pokitto config required by PokittoLib + +//#define PROJ_SHOW_FPS_COUNTER +#define PROJ_SCREENMODE 13 +#define PROJ_MODE13 1 +#define PROJ_ENABLE_SOUND 1 diff --git a/main_gbmeta/constants.h b/main_gbmeta/constants.h new file mode 100644 index 0000000..08ae02b --- /dev/null +++ b/main_gbmeta/constants.h @@ -0,0 +1,582 @@ +/** + @file constants.h + + This file contains definitions of game constants that are not considered + part of game settings and whose change can ffect the game balance and + playability, e.g. physics constants. + + by Miloslav Ciz (drummyfish), 2019 + + Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) + plus a waiver of all other intellectual property. The goal of this work is + be and remain completely in the public domain forever, available for any use + whatsoever. +*/ + +#ifndef _SFG_CONSTANTS_H +#define _SFG_CONSTANTS_H + +/** + How quickly player moves, in squares per second. +*/ +#define SFG_PLAYER_MOVE_SPEED 7 + +/** + Gravity acceleration in squares / (second^2). +*/ +#define SFG_GRAVITY_ACCELERATION 30 + +/** + Initial upwards speed of player's jump, in squares per second. +*/ +#define SFG_PLAYER_JUMP_SPEED 5 + +/** + Melee and close-up attack range, in RCL_Units. +*/ +#define SFG_MELEE_RANGE 1600 + +/** + When a projectile is shot, it'll be offset by this distance (in RCL_Units) + from the shooter. +*/ + +#define SFG_PROJECTILE_SPAWN_OFFSET 256 + +/** + Player's melee hit range, in RCL_Units (RCL_UNITS_PER_SQUARE means full angle, + 180 degrees to both sides). +*/ +#define SFG_PLAYER_MELEE_ANGLE 512 + +/** + How quickly elevators and squeezers move, in RCL_Unit per second. +*/ +#define SFG_MOVING_WALL_SPEED 1024 + +/** + How quickly doors open and close, in RCL_Unit per second. +*/ +#define SFG_DOOR_OPEN_SPEED 2048 + +/** + Helper special state value. +*/ +#define SFG_CANT_SAVE 255 + +/** + Says the distance in RCL_Units at which level elements (items, monsters etc.) + are active. +*/ +#define SFG_LEVEL_ELEMENT_ACTIVE_DISTANCE (12 * 1024) + +/** + Rate at which AI will be updated, which also affects how fast enemies will + appear. +*/ +#define SFG_AI_FPS 4 + +/** + Says a probability (0 - 255) of the AI changing its state during one update + step. +*/ +#define SFG_AI_RANDOM_CHANGE_PROBABILITY 40 + +/** + Distance at which level elements (sprites) collide, in RCL_Unit (1024 per + square). +*/ +#define SFG_ELEMENT_COLLISION_RADIUS 1800 + +/** + Height, in RCL_Units, at which collisions happen with level elements + (sprites). +*/ +#define SFG_ELEMENT_COLLISION_HEIGHT 1024 + +/** + Distance at which explosion does damage and throws away the player, in + RCL_Units. Should be higher than SFG_ELEMENT_COLLISION_RADIUS so that + exploded rockets also hurt the target. +*/ +#define SFG_EXPLOSION_RADIUS 2000 + +/** + Distance in RCL_Units which the player is pushed away by an explosion. Watch + out, a slightly higher value can make player go through walls. Rather keep + this under RCL_UNITS_PER_SQUARE; +*/ +#define SFG_EXPLOSION_PUSH_AWAY_DISTANCE 1023 + +/** + How much damage triggers a barrel explosion. +*/ + +#define SFG_BARREL_EXPLOSION_DAMAGE_THRESHOLD 3 + +/** + Maximum player health. +*/ +#define SFG_PLAYER_MAX_HEALTH 125 + +/** + Start health of player. +*/ +#define SFG_PLAYER_START_HEALTH 100 + +/** + At which value health indicator shows a warning (red color). +*/ +#define SFG_PLAYER_HEALTH_WARNING_LEVEL 20 + +/** + Amount of health that is increased by taking a health kit. +*/ +#define SFG_HEALTH_KIT_VALUE 20 + +/** + How much randomness (positive and negative) will be added to damage + (e.g. by weapons, explosions, ...). This constant is is 0 to 255, 255 meaning + 100% of the base value. +*/ +#define SFG_DAMAGE_RANDOMNESS 64 + +/** + Height of monster collision BBox in RCL_Units. +*/ +#define SFG_MONSTER_COLLISION_HEIGHT 1024 + +/** + Specifies key repeat delay, in ms. +*/ +#define SFG_KEY_REPEAT_DELAY 500 + +/** + Specifies key repeat period, in ms. +*/ +#define SFG_KEY_REPEAT_PERIOD 150 + +/** + Angle in which multiple projectiles are spread, RCL_Units. +*/ +#define SFG_PROJECTILE_SPREAD_ANGLE 100 + +#define SFG_MAX_MONSTERS 64 + +#define SFG_MAX_PROJECTILES 12 + +#define SFG_MAX_DOORS 32 + +#define SFG_AMMO_BULLETS 0 +#define SFG_AMMO_ROCKETS 1 +#define SFG_AMMO_PLASMA 2 + +#define SFG_AMMO_TOTAL 3 + +#define SFG_AMMO_NONE SFG_AMMO_TOTAL + +#define SFG_AMMO_INCREASE_BULLETS 10 +#define SFG_AMMO_INCREASE_ROCKETS 5 +#define SFG_AMMO_INCREASE_PLASMA 8 + +#define SFG_AMMO_MAX_BULLETS 200 +#define SFG_AMMO_MAX_ROCKETS 100 +#define SFG_AMMO_MAX_PLASMA 150 + +/** + Duration of story text (intro/outro) in ms. +*/ +#define SFG_STORYTEXT_DURATION 15000 + +/** + Time in ms of the player death animation. +*/ +#define SFG_LOSE_ANIMATION_DURATION 2000 + +/** + Time in ms of the level win animation. +*/ +#define SFG_WIN_ANIMATION_DURATION 2500 + +/** + Time in ms of the level start stage. +*/ +#define SFG_LEVEL_START_DURATION 1500 + +/** + Vertical sprite size, in RCL_Units. +*/ +#define SFG_BASE_SPRITE_SIZE RCL_UNITS_PER_SQUARE + +// ---------------------------- +// derived constants + +#define SFG_GAME_RESOLUTION_X \ + (SFG_SCREEN_RESOLUTION_X / SFG_RESOLUTION_SCALEDOWN) + +#define SFG_GAME_RESOLUTION_Y \ + (SFG_SCREEN_RESOLUTION_Y / SFG_RESOLUTION_SCALEDOWN) + +#define SFG_MS_PER_FRAME (1000 / SFG_FPS) // ms per frame with target FPS + +#if SFG_MS_PER_FRAME == 0 + #undef SFG_MS_PER_FRAME + #define SFG_MS_PER_FRAME 1 +#endif + +#define SFG_KEY_REPEAT_DELAY_FRAMES \ + (SFG_KEY_REPEAT_DELAY / SFG_MS_PER_FRAME) + +#if SFG_KEY_REPEAT_DELAY_FRAMES == 0 + #undef SFG_KEY_REPEAT_DELAY_FRAMES + #define SFG_KEY_REPEAT_DELAY_FRAMES 1 +#endif + +#define SFG_KEY_REPEAT_PERIOD_FRAMES \ + (SFG_KEY_REPEAT_PERIOD / SFG_MS_PER_FRAME) + +#if SFG_KEY_REPEAT_PERIOD_FRAMES == 0 + #undef SFG_KEY_REPEAT_PERIOD_FRAMES + #define SFG_KEY_REPEAT_PERIOD_FRAMES 1 +#endif + +#define SFG_WEAPON_IMAGE_SCALE \ + (SFG_GAME_RESOLUTION_X / (SFG_TEXTURE_SIZE * 5)) + +#if SFG_WEAPON_IMAGE_SCALE == 0 + #undef SFG_WEAPON_IMAGE_SCALE + #define SFG_WEAPON_IMAGE_SCALE 1 +#endif + +#define SFG_WEAPONBOB_OFFSET_PIXELS \ + (SFG_WEAPONBOB_OFFSET * SFG_WEAPON_IMAGE_SCALE) + +#define SFG_WEAPON_IMAGE_POSITION_X \ + (SFG_GAME_RESOLUTION_X / 2 - (SFG_WEAPON_IMAGE_SCALE * SFG_TEXTURE_SIZE) / 2) + +#if SFG_GAME_RESOLUTION_Y > 70 + #define SFG_WEAPON_IMAGE_POSITION_Y \ + (SFG_GAME_RESOLUTION_Y - (SFG_WEAPON_IMAGE_SCALE * SFG_TEXTURE_SIZE)) +#elif SFG_GAME_RESOLUTION_Y > 50 + #define SFG_WEAPON_IMAGE_POSITION_Y (SFG_GAME_RESOLUTION_Y \ + - ((SFG_WEAPON_IMAGE_SCALE * 3 * SFG_TEXTURE_SIZE) / 4)) +#else + #define SFG_WEAPON_IMAGE_POSITION_Y \ + (SFG_GAME_RESOLUTION_Y - SFG_TEXTURE_SIZE / 2) +#endif + +#define SFG_PLAYER_TURN_UNITS_PER_FRAME \ + ((SFG_PLAYER_TURN_SPEED * RCL_UNITS_PER_SQUARE) / (360 * SFG_FPS)) + +#if SFG_PLAYER_TURN_UNITS_PER_FRAME == 0 + #undef SFG_PLAYER_TURN_UNITS_PER_FRAME + #define SFG_PLAYER_TURN_UNITS_PER_FRAME 1 +#endif + +#define SFG_PLAYER_MOVE_UNITS_PER_FRAME \ + ((SFG_PLAYER_MOVE_SPEED * RCL_UNITS_PER_SQUARE) / SFG_FPS) + +#if SFG_PLAYER_MOVE_UNITS_PER_FRAME == 0 + #undef SFG_PLAYER_MOVE_UNITS_PER_FRAME + #define SFG_PLAYER_MOVE_UNITS_PER_FRAME 1 +#endif + +#define SFG_GRAVITY_SPEED_INCREASE_PER_FRAME \ + ((SFG_GRAVITY_ACCELERATION * RCL_UNITS_PER_SQUARE) / (SFG_FPS * SFG_FPS)) + +#if SFG_GRAVITY_SPEED_INCREASE_PER_FRAME == 0 + #undef SFG_GRAVITY_SPEED_INCREASE_PER_FRAME + #define SFG_GRAVITY_SPEED_INCREASE_PER_FRAME 1 +#endif + +#define SFG_PLAYER_JUMP_OFFSET_PER_FRAME \ + (((SFG_PLAYER_JUMP_SPEED * RCL_UNITS_PER_SQUARE) / SFG_FPS) \ + - SFG_GRAVITY_SPEED_INCREASE_PER_FRAME / 2) + /* ^ This substraction corrects the initial veloc. so that the numeric curve + copies the analytical (smooth) curve. Without it the numeric curve goes + ABOVE and makes player jump higher with lower FPS. To make sense of this + try to solve the differential equation and plot it. */ + +#if SFG_PLAYER_JUMP_OFFSET_PER_FRAME == 0 + #undef SFG_PLAYER_JUMP_OFFSET_PER_FRAME + #define SFG_PLAYER_JUMP_OFFSET_PER_FRAME 1 +#endif + +#define SFG_HEADBOB_FRAME_INCREASE_PER_FRAME \ + (SFG_HEADBOB_SPEED / SFG_FPS) + +#if SFG_HEADBOB_FRAME_INCREASE_PER_FRAME == 0 + #undef SFG_HEADBOB_FRAME_INCREASE_PER_FRAME + #define SFG_HEADBOB_FRAME_INCREASE_PER_FRAME 1 +#endif + +#define SFG_HEADBOB_ENABLED (SFG_HEADBOB_SPEED > 0 && SFG_HEADBOB_OFFSET > 0) + +#define SFG_CAMERA_SHEAR_STEP_PER_FRAME \ + ((SFG_GAME_RESOLUTION_Y * SFG_CAMERA_SHEAR_SPEED) / SFG_FPS) + +#if SFG_CAMERA_SHEAR_STEP_PER_FRAME == 0 + #undef SFG_CAMERA_SHEAR_STEP_PER_FRAME + #define SFG_CAMERA_SHEAR_STEP_PER_FRAME 1 +#endif + +#define SFG_CAMERA_MAX_SHEAR_PIXELS \ + ((SFG_CAMERA_MAX_SHEAR * SFG_GAME_RESOLUTION_Y) / 1024) + +#define SFG_FONT_SIZE_SMALL \ + (SFG_GAME_RESOLUTION_X / (SFG_FONT_CHARACTER_SIZE * 50)) + +#if SFG_FONT_SIZE_SMALL == 0 + #undef SFG_FONT_SIZE_SMALL + #define SFG_FONT_SIZE_SMALL 1 +#endif + +#define SFG_FONT_SIZE_MEDIUM \ + (SFG_GAME_RESOLUTION_X / (SFG_FONT_CHARACTER_SIZE * 30)) + +#if SFG_FONT_SIZE_MEDIUM == 0 + #undef SFG_FONT_SIZE_MEDIUM + #define SFG_FONT_SIZE_MEDIUM 1 +#endif + +#define SFG_FONT_SIZE_BIG \ + (SFG_GAME_RESOLUTION_X / (SFG_FONT_CHARACTER_SIZE * 18)) + +#if SFG_FONT_SIZE_BIG == 0 + #undef SFG_FONT_SIZE_BIG + #define SFG_FONT_SIZE_BIG 1 +#endif + +#define SFG_Z_BUFFER_SIZE SFG_GAME_RESOLUTION_X + +/** + Step in which walls get higher, in raycastlib units. +*/ +#define SFG_WALL_HEIGHT_STEP (RCL_UNITS_PER_SQUARE / 4) + +#define SFG_CEILING_MAX_HEIGHT\ + (16 * RCL_UNITS_PER_SQUARE - RCL_UNITS_PER_SQUARE / 2 ) + +#define SFG_DOOR_UP_DOWN_MASK 0x20 +#define SFG_DOOR_LOCK(doorRecord) ((doorRecord) >> 6) +#define SFG_DOOR_VERTICAL_POSITION_MASK 0x1f +#define SFG_DOOR_HEIGHT_STEP (RCL_UNITS_PER_SQUARE / 0x1f) + +#define SFG_DOOR_INCREMENT_PER_FRAME \ + (SFG_DOOR_OPEN_SPEED / (SFG_DOOR_HEIGHT_STEP * SFG_FPS)) + +#if SFG_DOOR_INCREMENT_PER_FRAME == 0 + #undef SFG_DOOR_INCREMENT_PER_FRAME + #define SFG_DOOR_INCREMENT_PER_FRAME 1 +#endif + +#define SFG_MAX_ITEMS SFG_MAX_LEVEL_ELEMENTS + +#define SFG_MAX_SPRITE_SIZE SFG_GAME_RESOLUTION_X + +#define SFG_MAP_PIXEL_SIZE (SFG_GAME_RESOLUTION_Y / SFG_MAP_SIZE) + +#if SFG_MAP_PIXEL_SIZE == 0 + #undef SFG_MAP_PIXEL_SIZE + #define SFG_MAP_PIXEL_SIZE 1 +#endif + +#define SFG_AI_UPDATE_FRAME_INTERVAL \ + (SFG_FPS / SFG_AI_FPS) + +#if SFG_AI_UPDATE_FRAME_INTERVAL == 0 + #undef SFG_AI_UPDATE_FRAME_INTERVAL + #define SFG_AI_UPDATE_FRAME_INTERVAL 1 +#endif + +#define SFG_SPRITE_ANIMATION_FRAME_DURATION \ + (SFG_FPS / SFG_SPRITE_ANIMATION_SPEED) + +#if SFG_SPRITE_ANIMATION_FRAME_DURATION == 0 + #undef SFG_SPRITE_ANIMATION_FRAME_DURATION + #define SFG_SPRITE_ANIMATION_FRAME_DURATION 1 +#endif + +#define SFG_HUD_MARGIN (SFG_GAME_RESOLUTION_X / 40) + +#define SFG_HUD_BORDER_INDICATOR_WIDTH_PIXELS \ + (SFG_GAME_RESOLUTION_Y / SFG_HUD_BORDER_INDICATOR_WIDTH) + +#define SFG_HUD_BORDER_INDICATOR_DURATION_FRAMES \ + (SFG_HUD_BORDER_INDICATOR_DURATION / SFG_MS_PER_FRAME) + +#if SFG_HUD_BORDER_INDICATOR_DURATION_FRAMES == 0 + #define SFG_HUD_BORDER_INDICATOR_DURATION_FRAMES 1 +#endif + +#define SFG_BLINK_PERIOD_FRAMES (SFG_BLINK_PERIOD / SFG_MS_PER_FRAME) + +#define SFG_HUD_BAR_HEIGHT \ + (SFG_FONT_CHARACTER_SIZE * SFG_FONT_SIZE_MEDIUM + SFG_HUD_MARGIN * 2 + 1) + +// ---------------------------- +// monsters + +#define SFG_MONSTER_ATTACK_MELEE 0 +#define SFG_MONSTER_ATTACK_FIREBALL 1 +#define SFG_MONSTER_ATTACK_BULLET 2 +#define SFG_MONSTER_ATTACK_FIREBALL_BULLET 3 +#define SFG_MONSTER_ATTACK_PLASMA 4 +#define SFG_MONSTER_ATTACK_EXPLODE 5 +#define SFG_MONSTER_ATTACK_FIREBALL_PLASMA 6 + +#define SFG_MONSTER_ATTRIBUTE(attackType,aggressivity0to255,health0to255,spriteSize0to3) \ + ((uint16_t) ( \ + attackType | \ + ((aggressivity0to255 / 8) << 3) | \ + (spriteSize0to3 << 8) | \ + ((health0to255 / 4) << 10))) + +#define SFG_GET_MONSTER_ATTACK_TYPE(monsterNumber) \ + (SFG_monsterAttributeTable[monsterNumber] & 0x0007) + +#define SFG_GET_MONSTER_AGGRESSIVITY(monsterNumber) \ + (((SFG_monsterAttributeTable[monsterNumber] >> 3) & 0x1F) * 8) + +#define SFG_GET_MONSTER_SPRITE_SIZE(monsterNumber) \ + ((SFG_monsterAttributeTable[monsterNumber] >> 8) & 0x03) + +#define SFG_GET_MONSTER_MAX_HEALTH(monsterNumber) \ + (((SFG_monsterAttributeTable[monsterNumber] >> 10) & 0x3F) * 4) + +/** + Table of monster attributes, each as a 16bit word in format: + + MSB hhhhhhssaaaattt LSB + + ttt: attack type + aaaaa: aggressivity (frequence of attacks), 0 to 31 + ss: sprite size + hhhhhh: health, 0 to 63 +*/ +uint16_t SFG_monsterAttributeTable[SFG_MONSTERS_TOTAL] = +{ + /* spider */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_FIREBALL,40,61,2), + /* destr. */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_FIREBALL_BULLET,90,170,3), + /* warrior */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_MELEE,255,40,1), + /* plasma */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_PLASMA,56,92,1), + /* ender */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_FIREBALL_PLASMA,128,255,3), + /* turret */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_BULLET,32,23,0), + /* explod. */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_EXPLODE,255,36,1) +}; + +// ---------------------------- +// weapons and projectiles + +#define SFG_WEAPON_KNIFE 0 +#define SFG_WEAPON_SHOTGUN 1 +#define SFG_WEAPON_MACHINE_GUN 2 +#define SFG_WEAPON_ROCKET_LAUNCHER 3 +#define SFG_WEAPON_PLASMAGUN 4 +#define SFG_WEAPON_SOLUTION 5 + +#define SFG_WEAPONS_TOTAL 6 + +#define SFG_WEAPON_ATTRIBUTE(fireType,projectileCount,fireCooldownMs) \ + ((uint8_t) (fireType | ((projectileCount - 1) << 2) | ((fireCooldownMs / (SFG_MS_PER_FRAME * 16)) << 4))) + +#define SFG_GET_WEAPON_FIRE_TYPE(weaponNumber) \ + (SFG_weaponAttributeTable[weaponNumber] & 0x03) + +#define SFG_GET_WEAPON_FIRE_COOLDOWN_FRAMES(weaponNumber) \ + ((SFG_weaponAttributeTable[weaponNumber] >> 4) * 16) + +#define SFG_GET_WEAPON_PROJECTILE_COUNT(weaponNumber) \ + (((SFG_weaponAttributeTable[weaponNumber] >> 2) & 0x03) + 1) + +#define SFG_MIN_WEAPON_COOLDOWN_FRAMES 8 + +#define SFG_WEAPON_FIRE_TYPE_MELEE 0 +#define SFG_WEAPON_FIRE_TYPE_BULLET 1 +#define SFG_WEAPON_FIRE_TYPE_FIREBALL 2 +#define SFG_WEAPON_FIRE_TYPE_PLASMA 3 + +#define SFG_WEAPON_FIRE_TYPES_TOTAL 4 + +/** + Table of weapon attributes, each as a byte in format: + + MSB ccccnnff LSB + + ff: fire type + nn: number of projectiles - 1 + cccc: fire cooldown in frames, i.e. time after which the next shot can be + shot again, ccccc has to be multiplied by 16 to get the real value +*/ +SFG_PROGRAM_MEMORY uint8_t SFG_weaponAttributeTable[SFG_WEAPONS_TOTAL] = +{ + /* knife */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_MELEE,1,650), // DPS: 6.2 + /* shotgun */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_BULLET,2,1250), // DPS: 12.8 + /* m. gun */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_BULLET,1,700), // DPS: 11.4 + /* r. laun. */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_FIREBALL,1,850), // DPS: 28.2 + /* plasma */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_PLASMA,1,550), // DPS: 32.7 + /* solution */ SFG_WEAPON_ATTRIBUTE(SFG_WEAPON_FIRE_TYPE_PLASMA,4,1050) // DPS: 85.7 +}; + +SFG_PROGRAM_MEMORY uint8_t SFG_attackDamageTable[SFG_WEAPON_FIRE_TYPES_TOTAL] = +{ + /* melee */ 4, + /* bullet */ 8, + /* explostion (fireball) */ 24, + /* plasma */ 18 +}; + +#define SFG_PROJECTILE_EXPLOSION 0 +#define SFG_PROJECTILE_FIREBALL 1 +#define SFG_PROJECTILE_PLASMA 2 +#define SFG_PROJECTILE_DUST 3 +#define SFG_PROJECTILE_BULLET 4 +#define SFG_PROJECTILE_NONE 255 + +#define SFG_PROJECTILES_TOTAL 5 + +#define SFG_PROJECTILE_ATTRIBUTE(speedSquaresPerSec,timeToLiveMs) \ + ((uint8_t) \ + ((((speedSquaresPerSec / 4 == 0) && (speedSquaresPerSec != 0)) ? 1 : speedSquaresPerSec / 4) | \ + ((timeToLiveMs / (8 * SFG_MS_PER_FRAME)) << 3))) + +#define SFG_GET_PROJECTILE_SPEED_UPS(projectileNumber) \ + (((SFG_projectileAttributeTable[projectileNumber] & 0x07) * 4 * RCL_UNITS_PER_SQUARE) / SFG_FPS) + +#define SFG_GET_PROJECTILE_FRAMES_TO_LIVE(projectileNumber) \ + ((SFG_projectileAttributeTable[projectileNumber] >> 3) * 8) + +/** + Table of projectile attributes, each as a byte in format: + + MSB lllllsss LSB + + fff: half speed in game squares per second + lllll: eigth of frames to live +*/ + +#define LOW_FPS (SFG_FPS < 24) ///< low FPS needs low speeds, because collisions + +SFG_PROGRAM_MEMORY uint8_t SFG_projectileAttributeTable[SFG_PROJECTILES_TOTAL] = +{ + /* explosion */ SFG_PROJECTILE_ATTRIBUTE(0,400), + /* fireball */ SFG_PROJECTILE_ATTRIBUTE(10,1000), + +#if LOW_FPS + /* plasma */ SFG_PROJECTILE_ATTRIBUTE(17,500), +#else + /* plasma */ SFG_PROJECTILE_ATTRIBUTE(18,500), +#endif + + /* dust */ SFG_PROJECTILE_ATTRIBUTE(0,450), + +#if LOW_FPS + /* bullet */ SFG_PROJECTILE_ATTRIBUTE(17,1000) +#else + /* bullet */ SFG_PROJECTILE_ATTRIBUTE(28,1000) +#endif +}; + +#undef LOW_FPS + +#endif // guard diff --git a/main_gbmeta/demo.h b/main_gbmeta/demo.h new file mode 100644 index 0000000..02ec801 --- /dev/null +++ b/main_gbmeta/demo.h @@ -0,0 +1,587 @@ +/** + @file demo.h + + Simple demo support for Anarch, intended just for testing. This file is not + needed for the game, it's just an extra helper. + + by drummyfish, released under CC0 1.0 (public domain) +*/ + +#ifndef _DEMO_H +#define _DEMO_H + +#include + +#define UINT32_MAX_VALUE 0xffffffff + +typedef struct +{ + uint32_t frame; // UINT32_MAX_VALUE is the terminating record + uint16_t keyStates; + int16_t mouseOffset[2]; +} DemoRecord; + +#define DEMO_MAX_RECORDS 1000000 + +DemoRecord demoRec[DEMO_MAX_RECORDS]; +uint32_t demoRecLength = 0; + +// --------- RECORDING ---------- + +void demoRecordStep() +{ + DemoRecord record; + + record.keyStates = 0; + + uint32_t mask = 1; + + for (int i = 0; i < SFG_KEY_COUNT; ++i) + { + record.keyStates |= SFG_keyPressed(i) ? mask : 0; + mask <<= 1; + } + + record.mouseOffset[0] = 0; + record.mouseOffset[1] = 0; + + record.frame = SFG_game.frame; + + record.mouseOffset[0] = SFG_game.mouseOffset[0]; + record.mouseOffset[1] = SFG_game.mouseOffset[1]; + + if (demoRecLength < DEMO_MAX_RECORDS) + { + if ( + (demoRecLength == 0) || + ( + (record.keyStates != demoRec[demoRecLength - 1].keyStates) || + (record.mouseOffset[0] != demoRec[demoRecLength - 1].mouseOffset[0]) || + (record.mouseOffset[1] != demoRec[demoRecLength - 1].mouseOffset[1]) + )) + { + demoRec[demoRecLength] = record; + demoRecLength++; + } + } + else + printf("max demo records reached!\n"); +} + +// ---------- PLAYING ----------- + +static const DemoRecord demoPlay[] = +{ +{0,0,{0,0}},{63,16,{0,0}},{67,0,{0,0}},{78,16,{0,0}}, +{83,0,{0,0}},{147,4,{0,0}},{153,516,{0,0}},{174,516,{10,-2}}, +{175,516,{5,-2}},{176,516,{3,-1}},{177,516,{3,0}},{178,516,{20,-2}}, +{179,516,{21,0}},{180,516,{42,1}},{181,516,{19,1}},{182,516,{26,3}}, +{182,512,{26,3}},{183,512,{46,5}},{184,512,{21,3}},{185,512,{20,1}}, +{186,512,{34,6}},{187,512,{54,7}},{188,512,{18,3}},{189,512,{20,1}}, +{190,512,{0,0}},{192,512,{0,-1}},{193,513,{0,0}},{195,513,{-2,-7}}, +{196,513,{-4,-8}},{197,513,{-4,-6}},{198,513,{-14,-19}},{199,513,{-10,-14}}, +{200,513,{-19,-22}},{201,513,{-17,-15}},{202,1,{-21,-17}},{203,1,{-20,-17}}, +{204,1,{-25,-16}},{205,1,{-22,-15}},{206,1,{-33,-19}},{207,1,{-81,-49}}, +{208,1,{-50,-28}},{209,1,{-56,-30}},{210,1,{-123,-59}},{211,1,{-62,-31}}, +{212,257,{-104,-56}},{213,257,{-61,-31}},{215,257,{-125,-62}},{216,257,{-59,-28}}, +{217,257,{-58,-28}},{218,257,{-109,-58}},{219,257,{-34,-22}},{220,257,{-16,-11}}, +{220,289,{-16,-11}},{221,289,{-45,-31}},{222,289,{-33,-19}},{223,289,{-7,-7}}, +{225,289,{-1,-1}},{227,289,{0,0}},{228,417,{0,0}},{230,417,{-1,0}}, +{230,161,{-1,0}},{231,161,{1,-1}},{232,161,{0,-1}},{233,385,{0,-1}}, +{234,385,{0,-4}},{236,385,{-5,-12}},{236,257,{-5,-12}},{237,257,{-1,-3}}, +{238,257,{0,-1}},{239,257,{0,0}},{240,257,{0,-3}},{241,257,{1,-3}}, +{242,257,{0,0}},{243,1,{7,-4}},{243,33,{7,-4}},{244,33,{23,-5}}, +{245,33,{19,-2}},{246,33,{27,0}},{247,33,{11,0}},{248,33,{3,0}}, +{249,33,{12,0}},{250,33,{7,0}},{251,33,{45,1}},{252,33,{36,2}}, +{253,33,{40,2}},{254,33,{48,3}},{255,33,{28,0}},{256,32,{21,1}}, +{257,32,{54,0}},{258,32,{28,0}},{259,32,{71,-5}},{260,32,{32,-3}}, +{261,32,{34,0}},{262,32,{55,-3}},{263,32,{23,0}},{264,32,{16,0}}, +{265,0,{25,0}},{266,0,{16,-2}},{267,0,{13,-2}},{268,0,{42,-2}}, +{269,0,{21,-2}},{270,0,{42,-2}},{271,0,{7,-2}},{272,0,{18,-2}}, +{273,0,{37,-2}},{274,0,{21,-4}},{275,0,{9,-3}},{276,0,{3,-1}}, +{277,0,{0,0}},{278,0,{0,-1}},{279,0,{0,0}},{280,0,{-3,1}}, +{281,0,{0,-1}},{282,0,{0,-2}},{282,1,{0,-2}},{283,1,{0,-1}}, +{285,1,{-1,-1}},{286,1,{-1,-2}},{287,1,{-1,-1}},{288,1,{0,-1}}, +{289,1,{-1,0}},{290,1,{0,0}},{291,1,{2,-2}},{292,1,{16,-4}}, +{293,1,{22,0}},{294,1,{73,6}},{295,1,{47,2}},{296,257,{36,2}}, +{297,257,{91,8}},{298,257,{53,4}},{299,257,{56,4}},{299,385,{56,4}}, +{300,385,{58,2}},{301,385,{64,2}},{302,385,{61,0}},{302,384,{61,0}}, +{303,384,{111,2}},{304,384,{60,0}},{305,384,{59,0}},{306,385,{102,4}}, +{307,385,{67,0}},{308,385,{71,4}},{309,385,{146,4}},{310,385,{74,4}}, +{311,385,{76,2}},{312,385,{151,4}},{313,385,{77,2}},{314,385,{75,2}}, +{314,384,{75,2}},{315,384,{162,4}},{316,384,{0,0}},{317,384,{62,3}}, +{318,384,{82,2}},{319,384,{83,4}},{320,384,{80,2}},{321,384,{118,2}}, +{322,384,{72,2}},{323,384,{76,4}},{324,384,{178,12}},{325,384,{93,7}}, +{326,384,{91,7}},{327,384,{157,14}},{328,128,{80,7}},{329,128,{84,7}}, +{330,128,{170,14}},{330,0,{170,14}},{331,0,{85,7}},{332,0,{84,9}}, +{333,0,{85,9}},{333,512,{85,9}},{334,512,{61,6}},{335,512,{77,9}}, +{336,512,{59,6}},{337,512,{65,6}},{338,0,{157,16}},{339,0,{84,12}}, +{340,0,{79,12}},{341,0,{140,21}},{342,0,{72,9}},{343,0,{45,8}}, +{344,0,{130,16}},{345,0,{40,6}},{346,0,{24,2}},{347,0,{0,0}}, +{348,0,{2,0}},{349,0,{-6,1}},{350,0,{0,0}},{352,0,{1,-5}}, +{353,0,{0,0}},{354,0,{-9,-10}},{355,0,{-13,-10}},{356,0,{-13,-12}}, +{357,0,{-38,-22}},{358,0,{-18,-9}},{359,0,{-46,-27}},{359,256,{-46,-27}}, +{360,256,{-31,-15}},{361,256,{-30,-14}},{362,256,{-60,-26}},{363,256,{-33,-15}}, +{364,256,{-28,-12}},{365,256,{-61,-27}},{366,256,{-36,-17}},{368,257,{-36,-17}}, +{369,257,{-27,-14}},{370,257,{-30,-21}},{371,257,{0,0}},{372,257,{-3,-3}}, +{373,257,{0,0}},{374,129,{-1,-1}},{374,161,{-1,-1}},{375,161,{0,-1}}, +{376,161,{21,-12}},{377,161,{26,-4}},{378,161,{26,0}},{379,161,{44,3}}, +{380,161,{13,1}},{381,161,{5,1}},{382,33,{22,1}},{383,33,{8,1}}, +{384,33,{13,0}},{385,33,{66,4}},{386,1,{36,6}},{387,1,{29,5}}, +{388,0,{46,5}},{389,0,{0,0}},{391,0,{-13,1}},{392,0,{0,0}}, +{393,0,{0,-1}},{394,0,{3,0}},{395,0,{11,1}},{396,0,{26,9}}, +{397,0,{14,8}},{398,0,{19,10}},{399,4,{16,9}},{400,4,{1,2}}, +{401,4,{4,4}},{402,4,{17,15}},{403,4,{13,13}},{404,4,{15,13}}, +{405,4,{58,42}},{406,4,{43,24}},{407,4,{52,25}},{407,260,{52,25}}, +{408,260,{62,23}},{409,260,{64,23}},{409,256,{64,23}},{410,256,{141,50}}, +{411,256,{78,26}},{412,256,{68,21}},{413,256,{139,45}},{414,256,{76,21}}, +{415,256,{83,19}},{416,256,{153,38}},{417,256,{69,14}},{418,256,{155,36}}, +{419,256,{76,19}},{420,256,{80,19}},{421,256,{88,22}},{422,256,{177,41}}, +{423,384,{88,22}},{424,384,{178,44}},{425,384,{86,19}},{426,384,{76,21}}, +{427,384,{66,17}},{427,388,{66,17}},{428,388,{86,22}},{429,388,{85,22}}, +{430,388,{82,19}},{431,388,{174,44}},{432,388,{80,24}},{433,132,{154,43}}, +{434,132,{83,24}},{435,132,{80,21}},{436,132,{172,46}},{437,132,{86,24}}, +{437,644,{86,24}},{438,644,{167,46}},{439,644,{78,23}},{440,644,{86,22}}, +{441,644,{81,23}},{442,644,{146,43}},{443,644,{78,22}},{444,644,{137,37}}, +{445,644,{71,16}},{446,644,{73,19}},{447,640,{144,35}},{448,640,{73,18}}, +{449,640,{74,21}},{450,640,{69,18}},{451,640,{100,31}},{452,640,{30,12}}, +{453,640,{2,1}},{454,640,{-4,-1}},{455,640,{-24,1}},{456,640,{0,0}}, +{456,129,{0,0}},{457,129,{-1,-3}},{458,129,{-3,-5}},{459,385,{-22,-17}}, +{460,385,{-18,-13}},{461,385,{-22,-13}},{462,385,{-52,-36}},{463,385,{-32,-22}}, +{464,385,{0,0}},{465,385,{-33,-20}},{466,385,{-100,-50}},{467,385,{-53,-26}}, +{468,385,{-103,-46}},{469,385,{-49,-21}},{470,385,{-55,-26}},{471,385,{-58,-23}}, +{472,385,{-64,-26}},{473,385,{-133,-55}},{474,385,{-79,-30}},{475,385,{-82,-32}}, +{476,385,{-84,-35}},{477,385,{-173,-72}},{478,385,{-90,-38}},{479,385,{-89,-38}}, +{480,385,{-179,-73}},{481,385,{-85,-35}},{482,385,{-89,-40}},{483,385,{-193,-86}}, +{483,129,{-193,-86}},{484,129,{-98,-48}},{485,129,{-209,-95}},{486,129,{-107,-48}}, +{487,129,{-102,-46}},{488,129,{-176,-86}},{489,129,{-93,-43}},{490,129,{-85,-45}}, +{491,641,{-172,-90}},{492,641,{-81,-44}},{493,641,{-77,-42}},{494,641,{-166,-87}}, +{495,640,{-83,-43}},{496,640,{-81,-42}},{497,640,{-85,-43}},{498,640,{-86,-46}}, +{499,640,{-155,-79}},{500,640,{-62,-34}},{501,640,{-64,-36}},{502,640,{0,0}}, +{503,640,{-70,-37}},{504,640,{-67,-34}},{505,640,{-138,-62}},{506,640,{-70,-27}}, +{507,896,{-53,-21}},{508,384,{-122,-40}},{509,384,{-66,-22}},{510,384,{-72,-20}}, +{511,384,{-77,-22}},{512,384,{-74,-22}},{513,384,{-66,-19}},{514,384,{-61,-19}}, +{514,388,{-61,-19}},{515,388,{-72,-22}},{516,388,{-156,-42}},{517,388,{-87,-23}}, +{518,388,{-87,-25}},{519,388,{-154,-49}},{520,388,{-77,-25}},{521,388,{-72,-27}}, +{522,388,{-144,-53}},{523,388,{-50,-28}},{524,388,{-29,-23}},{525,384,{-8,-8}}, +{526,384,{-4,-5}},{527,384,{0,-2}},{528,384,{20,-31}},{529,384,{18,-19}}, +{530,128,{41,-29}},{530,640,{41,-29}},{531,640,{117,-54}},{532,640,{71,-24}}, +{533,640,{83,-23}},{533,641,{83,-23}},{534,641,{166,-37}},{535,641,{91,-13}}, +{536,641,{199,-13}},{537,641,{106,-3}},{538,641,{102,-3}},{539,641,{108,0}}, +{540,641,{95,2}},{541,641,{97,0}},{542,641,{96,2}},{543,129,{216,7}}, +{544,129,{121,5}},{544,385,{121,5}},{545,385,{117,5}},{546,385,{208,10}}, +{547,385,{91,4}},{548,385,{108,5}},{549,385,{195,9}},{550,385,{104,4}}, +{551,385,{108,5}},{552,385,{205,10}},{553,385,{109,5}},{554,385,{221,12}}, +{555,385,{111,7}},{556,385,{108,7}},{557,385,{192,12}},{558,385,{105,5}}, +{558,384,{105,5}},{559,384,{119,7}},{560,384,{258,12}},{561,384,{125,5}}, +{562,384,{103,7}},{563,384,{207,17}},{564,384,{93,7}},{565,384,{90,7}}, +{566,384,{219,17}},{567,384,{118,10}},{568,384,{119,12}},{569,384,{209,27}}, +{570,896,{100,12}},{571,896,{204,24}},{572,640,{105,12}},{573,640,{107,12}}, +{574,640,{108,15}},{575,640,{199,32}},{576,640,{102,14}},{577,640,{88,14}}, +{578,640,{0,0}},{579,640,{102,14}},{580,640,{99,14}},{581,640,{98,14}}, +{582,640,{120,22}},{582,641,{120,22}},{583,641,{16,4}},{584,641,{0,0}}, +{585,385,{-29,0}},{586,385,{-11,2}},{587,385,{-5,4}},{588,384,{-1,-1}}, +{589,384,{-17,-7}},{590,384,{-56,-22}},{591,384,{-41,-15}},{592,384,{-47,-18}}, +{593,384,{-53,-21}},{594,384,{-132,-52}},{595,384,{-76,-32}},{596,384,{-72,-27}}, +{597,384,{-153,-54}},{598,384,{-67,-22}},{599,384,{-69,-24}},{600,384,{-129,-47}}, +{601,384,{-77,-27}},{602,384,{-80,-27}},{603,384,{-172,-54}},{604,384,{-76,-24}}, +{605,384,{-136,-50}},{606,384,{-67,-24}},{607,384,{-76,-27}},{608,384,{-142,-48}}, +{609,384,{-77,-22}},{610,384,{-75,-22}},{610,385,{-75,-22}},{611,385,{-135,-43}}, +{612,385,{-62,-24}},{613,385,{-42,-20}},{614,385,{-26,-22}},{615,385,{0,0}}, +{616,385,{18,17}},{617,385,{-4,-4}},{618,385,{0,0}},{619,129,{0,0}}, +{620,129,{-1,-1}},{621,129,{0,0}},{622,129,{0,-2}},{623,129,{2,-3}}, +{624,129,{8,-9}},{625,129,{0,0}},{626,129,{1,-2}},{627,129,{0,-1}}, +{628,129,{4,-4}},{629,129,{14,-9}},{630,129,{47,-10}},{631,129,{31,-4}}, +{632,129,{16,-2}},{633,129,{52,-2}},{634,129,{45,4}},{635,129,{56,4}}, +{636,129,{142,16}},{637,641,{80,9}},{638,641,{169,24}},{639,641,{90,14}}, +{640,641,{100,20}},{641,641,{111,22}},{642,641,{250,56}},{643,641,{120,25}}, +{644,641,{106,35}},{645,641,{14,6}},{646,129,{2,1}},{647,129,{-43,-9}}, +{648,129,{-17,1}},{648,385,{-17,1}},{649,385,{-1,3}},{650,385,{-36,-29}}, +{651,385,{-47,-25}},{652,385,{0,0}},{653,385,{-165,-92}},{654,385,{-90,-48}}, +{655,385,{-88,-48}},{656,385,{-190,-92}},{657,385,{-96,-43}},{658,385,{-93,-40}}, +{658,384,{-93,-40}},{659,384,{-185,-78}},{660,384,{-93,-40}},{661,384,{-98,-46}}, +{662,384,{-193,-83}},{663,384,{-99,-41}},{664,384,{-96,-36}},{665,384,{-170,-67}}, +{666,384,{-91,-33}},{667,384,{-65,-31}},{668,384,{-136,-65}},{669,385,{-75,-34}}, +{670,385,{-63,-31}},{671,385,{-95,-56}},{672,385,{-26,-20}},{673,385,{-5,-5}}, +{674,385,{34,33}},{675,385,{0,7}},{676,129,{3,-6}},{677,129,{56,-21}}, +{678,641,{37,-5}},{679,641,{53,2}},{680,641,{67,11}},{681,641,{68,14}}, +{682,641,{163,29}},{683,641,{89,14}},{684,641,{91,17}},{685,641,{184,32}}, +{686,641,{90,17}},{687,641,{93,19}},{688,641,{178,39}},{689,641,{91,19}}, +{690,641,{0,0}},{691,641,{85,16}},{692,641,{205,45}},{693,641,{77,21}}, +{694,641,{143,33}},{695,641,{46,13}},{696,641,{53,11}},{697,641,{130,23}}, +{698,129,{62,9}},{699,129,{68,9}},{700,129,{24,3}},{701,129,{0,0}}, +{702,129,{6,-1}},{703,129,{-6,6}},{704,129,{6,-15}},{705,129,{2,-13}}, +{706,129,{-5,-14}},{706,385,{-5,-14}},{707,385,{-9,-22}},{708,385,{-44,-50}}, +{709,385,{-41,-36}},{710,385,{-44,-35}},{711,385,{-120,-86}},{712,385,{-71,-44}}, +{713,385,{-76,-39}},{714,385,{-166,-82}},{715,385,{-84,-40}},{716,385,{-80,-39}}, +{717,385,{-160,-74}},{718,384,{-79,-37}},{719,384,{-170,-70}},{720,384,{-84,-35}}, +{721,384,{-156,-66}},{722,384,{-64,-29}},{723,384,{-69,-31}},{724,384,{-109,-60}}, +{725,384,{-52,-30}},{725,385,{-52,-30}},{726,385,{-40,-27}},{727,385,{-34,-26}}, +{728,385,{16,16}},{729,385,{0,0}},{730,385,{-12,-15}},{731,385,{-5,-5}}, +{732,385,{0,-1}},{733,129,{0,0}},{734,129,{0,-1}},{735,129,{33,-16}}, +{736,129,{44,-9}},{737,129,{107,-12}},{738,129,{36,0}},{739,641,{56,4}}, +{740,641,{134,14}},{741,641,{85,14}},{742,641,{92,19}},{743,641,{185,37}}, +{744,641,{87,17}},{745,641,{76,16}},{746,641,{146,31}},{747,641,{70,14}}, +{747,129,{70,14}},{748,129,{57,13}},{749,129,{62,11}},{750,129,{0,0}}, +{751,129,{1,-1}},{752,129,{-15,10}},{753,129,{4,-10}},{754,129,{0,-21}}, +{755,385,{-22,-64}},{756,385,{-19,-38}},{757,385,{-29,-37}},{758,385,{-78,-85}}, +{759,385,{-56,-46}},{760,385,{-119,-84}},{761,385,{-65,-41}},{762,385,{-71,-44}}, +{763,385,{-146,-90}},{764,385,{-79,-47}},{765,385,{0,0}},{766,385,{-72,-39}}, +{766,129,{-72,-39}},{767,129,{-142,-82}},{768,129,{-43,-34}},{768,641,{-43,-34}}, +{769,641,{-17,-19}},{770,641,{-6,-5}},{771,641,{0,-1}},{772,641,{3,12}}, +{773,641,{4,-9}},{774,641,{21,-22}},{775,641,{38,-26}},{776,641,{111,-32}}, +{777,641,{74,-5}},{778,641,{159,4}},{779,641,{89,4}},{780,641,{85,7}}, +{781,641,{124,13}},{782,129,{33,1}},{783,129,{6,1}},{784,129,{0,0}}, +{785,129,{-10,1}},{786,385,{-16,10}},{787,385,{-2,-3}},{788,385,{-3,-3}}, +{789,385,{-41,-20}},{790,385,{-74,-30}},{791,385,{-45,-20}},{792,385,{-56,-24}}, +{793,385,{-68,-27}},{794,385,{-159,-64}},{795,385,{-93,-38}},{796,385,{-92,-35}}, +{797,385,{-179,-67}},{798,385,{-85,-33}},{799,385,{-169,-62}},{800,385,{-87,-30}}, +{801,385,{-87,-35}},{802,385,{0,0}},{803,385,{-185,-74}},{804,385,{-96,-38}}, +{805,385,{-84,-35}},{806,385,{-173,-67}},{807,385,{-76,-32}},{808,385,{-128,-60}}, +{809,385,{-73,-29}},{810,385,{-145,-56}},{811,897,{-67,-27}},{812,897,{-69,-26}}, +{813,641,{-73,-25}},{814,641,{-152,-56}},{815,641,{-75,-30}},{816,641,{-153,-51}}, +{817,641,{-75,-27}},{817,640,{-75,-27}},{818,640,{-75,-24}},{819,640,{-77,-27}}, +{820,640,{-77,-22}},{822,640,{-78,-22}},{823,640,{-145,-41}},{824,640,{-74,-22}}, +{825,640,{-75,-20}},{826,640,{-156,-39}},{827,640,{-141,-34}},{828,640,{-75,-17}}, +{828,644,{-75,-17}},{829,644,{-60,-14}},{830,644,{-71,-10}},{831,644,{-140,-22}}, +{832,644,{-77,-10}},{832,132,{-77,-10}},{833,132,{-81,-13}},{834,388,{-138,-24}}, +{835,388,{-74,-15}},{836,388,{-146,-27}},{837,388,{-71,-12}},{837,384,{-71,-12}}, +{838,384,{-71,-10}},{839,384,{-71,-12}},{840,384,{-53,-11}},{841,384,{-68,-15}}, +{842,384,{-55,-12}},{843,384,{-110,-28}},{844,384,{-57,-16}},{845,384,{-73,-26}}, +{846,384,{-18,-9}},{847,384,{0,0}},{848,385,{-6,-6}},{849,385,{4,3}}, +{850,385,{0,0}},{851,129,{-1,-1}},{852,129,{6,-11}},{853,129,{15,-11}}, +{854,129,{52,-24}},{855,129,{34,-9}},{856,129,{34,-5}},{857,129,{96,-5}}, +{858,129,{45,-3}},{859,129,{58,-3}},{860,129,{129,-3}},{861,129,{73,0}}, +{862,129,{67,0}},{863,129,{124,0}},{864,129,{43,2}},{865,129,{62,2}}, +{866,129,{133,9}},{866,641,{133,9}},{867,641,{64,4}},{868,641,{65,4}}, +{869,641,{129,13}},{870,641,{65,4}},{871,641,{59,6}},{871,129,{59,6}}, +{872,129,{111,6}},{873,129,{29,1}},{874,129,{26,1}},{875,129,{71,-2}}, +{876,129,{53,0}},{877,129,{56,0}},{878,129,{59,1}},{879,129,{68,4}}, +{880,129,{50,2}},{881,129,{47,0}},{882,129,{39,0}},{883,129,{23,1}}, +{884,129,{1,0}},{885,129,{-3,0}},{886,129,{-8,1}},{887,129,{-2,1}}, +{888,129,{-3,-1}},{888,385,{-3,-1}},{889,385,{-10,-2}},{890,385,{-42,-6}}, +{891,385,{-39,-9}},{891,384,{-39,-9}},{892,384,{-52,-12}},{893,384,{-125,-26}}, +{894,384,{-63,-14}},{895,384,{-64,-12}},{896,384,{-61,-15}},{897,384,{-73,-13}}, +{898,384,{-71,-10}},{899,384,{-151,-24}},{900,384,{-74,-12}},{901,384,{-68,-12}}, +{902,384,{-131,-21}},{903,384,{-67,-12}},{904,384,{-110,-21}},{905,384,{-60,-12}}, +{906,384,{-52,-12}},{907,384,{-103,-23}},{908,384,{-58,-16}},{909,384,{-46,-14}}, +{910,384,{-103,-27}},{911,384,{-56,-19}},{912,384,{-60,-24}},{913,384,{-11,-8}}, +{913,385,{-11,-8}},{914,385,{0,0}},{915,385,{3,2}},{916,385,{0,0}}, +{917,129,{19,-6}},{918,129,{37,-7}},{919,129,{50,-3}},{920,129,{53,8}}, +{921,129,{59,13}},{922,129,{62,16}},{923,129,{140,38}},{924,641,{69,14}}, +{925,641,{58,13}},{926,641,{13,3}},{927,641,{29,3}},{928,641,{101,13}}, +{929,641,{61,9}},{930,641,{64,11}},{931,641,{150,28}},{932,641,{74,14}}, +{933,641,{74,12}},{934,641,{72,18}},{935,641,{24,5}},{936,641,{2,1}}, +{937,641,{-33,-4}},{938,641,{-8,0}},{939,129,{-7,-7}},{940,385,{-27,-23}}, +{941,385,{-43,-30}},{942,385,{-126,-76}},{943,385,{-83,-46}},{944,385,{-85,-48}}, +{945,385,{-162,-84}},{946,385,{-82,-38}},{947,385,{-78,-37}},{948,385,{-124,-65}}, +{949,385,{-46,-30}},{950,385,{-46,-35}},{951,385,{-32,-28}},{952,385,{-43,-37}}, +{953,385,{-45,-34}},{954,129,{-31,-22}},{955,129,{-32,-25}},{956,129,{-22,-20}}, +{957,129,{-2,-2}},{958,641,{0,0}},{959,641,{0,-2}},{960,641,{0,0}}, +{961,641,{46,-33}},{962,641,{32,-15}},{963,641,{102,-18}},{964,641,{58,0}}, +{965,641,{66,0}},{966,641,{67,0}},{967,641,{77,4}},{968,641,{82,4}}, +{969,641,{173,12}},{970,641,{85,4}},{971,641,{63,4}},{972,641,{88,6}}, +{973,641,{65,2}},{974,641,{53,2}},{975,641,{154,9}},{976,641,{81,9}}, +{977,641,{84,7}},{978,641,{119,11}},{979,641,{68,4}},{980,641,{69,4}}, +{981,641,{31,0}},{982,641,{37,0}},{983,641,{32,-4}},{984,641,{7,-2}}, +{985,641,{1,-1}},{986,129,{-15,6}},{987,129,{-2,-7}},{988,129,{-11,-20}}, +{989,129,{-18,-28}},{990,129,{-22,-26}},{991,129,{0,0}},{991,385,{0,0}}, +{992,385,{-63,-53}},{993,385,{-43,-32}},{994,385,{-93,-64}},{995,385,{-51,-33}}, +{996,385,{-51,-30}},{997,385,{-107,-65}},{998,385,{-59,-36}},{999,385,{-53,-35}}, +{1000,129,{-93,-63}},{1001,129,{-29,-25}},{1001,641,{-29,-25}},{1002,641,{-5,-5}}, +{1003,641,{-2,-2}},{1004,641,{6,8}},{1005,641,{0,0}},{1006,641,{24,-16}}, +{1007,641,{32,-15}},{1008,641,{94,-16}},{1009,641,{50,-3}},{1010,641,{47,0}}, +{1011,641,{56,2}},{1012,641,{112,13}},{1012,129,{112,13}},{1013,129,{30,3}}, +{1014,129,{7,1}},{1015,129,{0,0}},{1016,385,{-1,0}},{1017,385,{-7,3}}, +{1018,385,{0,0}},{1019,385,{-1,-2}},{1021,385,{-23,-15}},{1022,385,{-22,-11}}, +{1023,385,{-33,-13}},{1024,385,{-88,-40}},{1025,385,{-55,-23}},{1026,385,{-58,-24}}, +{1027,385,{-59,-26}},{1028,385,{-41,-16}},{1029,385,{-29,-17}},{1029,641,{-29,-17}}, +{1030,641,{-54,-32}},{1031,641,{-18,-13}},{1032,641,{-1,0}},{1033,641,{11,11}}, +{1034,641,{1,3}},{1035,641,{7,-6}},{1036,641,{78,-22}},{1037,641,{48,-9}}, +{1038,641,{45,-5}},{1039,641,{99,0}},{1040,641,{56,2}},{1041,641,{67,6}}, +{1042,641,{85,8}},{1043,641,{0,0}},{1044,129,{-14,4}},{1045,129,{-8,10}}, +{1046,129,{-2,-6}},{1047,385,{-34,-21}},{1048,385,{-44,-20}},{1049,385,{-118,-30}}, +{1050,385,{-67,-15}},{1051,385,{-63,-14}},{1052,385,{-121,-24}},{1053,385,{-46,-11}}, +{1054,385,{-52,-12}},{1055,385,{-100,-27}},{1055,257,{-100,-27}},{1056,257,{-48,-13}}, +{1057,257,{-59,-15}},{1058,257,{-104,-30}},{1059,257,{-42,-11}},{1060,1,{-63,-21}}, +{1061,1,{-25,-10}},{1062,1,{-13,-7}},{1062,0,{-13,-7}},{1063,0,{-10,-5}}, +{1064,0,{0,0}},{1065,0,{7,9}},{1066,0,{-2,-4}},{1067,0,{-1,-1}}, +{1068,0,{0,0}},{1069,0,{0,-2}},{1070,0,{0,-4}},{1071,0,{3,-4}}, +{1072,0,{25,-19}},{1073,0,{27,-14}},{1074,1,{36,-11}},{1075,1,{41,-11}}, +{1076,1,{6,-2}},{1077,1,{5,-3}},{1078,1,{6,-3}},{1079,1,{9,-3}}, +{1080,1,{14,-5}},{1081,1,{48,-12}},{1082,1,{40,-7}},{1083,1,{51,-5}}, +{1084,1,{95,-9}},{1085,1,{28,-4}},{1086,1,{11,-2}},{1087,1,{42,-7}}, +{1088,257,{34,-7}},{1089,257,{83,-9}},{1090,257,{45,-5}},{1091,257,{38,-5}}, +{1092,257,{57,-10}},{1093,257,{21,-8}},{1094,257,{13,-5}},{1095,257,{9,-3}}, +{1096,257,{26,-6}},{1097,257,{29,-4}},{1098,257,{77,-5}},{1099,257,{34,-3}}, +{1100,256,{34,-3}},{1102,256,{11,0}},{1103,256,{31,-4}},{1104,256,{18,-4}}, +{1105,256,{33,-5}},{1106,256,{18,-4}},{1107,256,{26,-2}},{1108,256,{33,-6}}, +{1109,256,{16,-2}},{1110,256,{7,-2}},{1111,256,{2,-1}},{1112,256,{7,-2}}, +{1113,260,{3,-1}},{1114,260,{5,-2}},{1115,260,{8,0}},{1116,260,{3,0}}, +{1117,260,{30,-2}},{1118,260,{21,-2}},{1119,256,{47,-2}},{1120,256,{25,-2}}, +{1121,256,{28,-4}},{1122,256,{61,-4}},{1123,256,{39,-3}},{1124,256,{37,0}}, +{1125,256,{80,-5}},{1126,256,{21,-2}},{1127,256,{35,-4}},{1128,256,{16,-4}}, +{1129,256,{5,-3}},{1130,256,{25,-6}},{1131,260,{18,-4}},{1132,260,{15,-2}}, +{1133,260,{13,-1}},{1134,260,{5,-2}},{1135,260,{9,-1}},{1136,260,{0,0}}, +{1139,260,{-1,0}},{1140,260,{0,0}},{1140,4,{0,0}},{1145,4,{-1,-1}}, +{1146,4,{-3,-1}},{1147,516,{-3,-1}},{1148,516,{-2,-1}},{1149,516,{-1,0}}, +{1150,516,{0,0}},{1152,516,{-1,-2}},{1153,516,{0,-2}},{1154,516,{-1,0}}, +{1155,516,{-1,-4}},{1155,4,{-1,-4}},{1156,4,{0,0}},{1157,4,{0,-1}}, +{1157,260,{0,-1}},{1158,260,{0,-2}},{1159,260,{0,-3}},{1162,260,{0,-7}}, +{1163,260,{0,-3}},{1164,4,{0,-6}},{1165,4,{4,-13}},{1166,4,{2,-6}}, +{1166,260,{2,-6}},{1167,260,{7,-16}},{1168,260,{3,-5}},{1169,260,{3,-6}}, +{1170,260,{1,-4}},{1171,260,{5,-9}},{1172,260,{3,-5}},{1173,4,{3,-5}}, +{1174,4,{0,0}},{1175,4,{10,-9}},{1176,4,{2,-3}},{1176,260,{2,-3}}, +{1177,260,{3,-5}},{1178,260,{-1,-2}},{1178,256,{-1,-2}},{1179,256,{-4,-8}}, +{1180,256,{-6,-8}},{1181,256,{-13,-12}},{1182,256,{-9,-9}},{1183,256,{-9,-6}}, +{1184,256,{-54,-34}},{1185,256,{-45,-25}},{1186,256,{-107,-56}},{1187,384,{-47,-23}}, +{1188,384,{-38,-17}},{1189,384,{-37,-22}},{1190,384,{-12,-6}},{1191,384,{-15,-9}}, +{1192,384,{-7,-4}},{1193,384,{0,0}},{1195,384,{0,-1}},{1196,384,{-3,-3}}, +{1197,384,{-2,-1}},{1198,384,{0,0}},{1201,384,{13,0}},{1202,384,{82,15}}, +{1203,384,{54,11}},{1204,384,{78,21}},{1205,384,{38,12}},{1206,384,{40,12}}, +{1207,384,{120,39}},{1208,384,{68,23}},{1209,384,{76,26}},{1210,384,{64,23}}, +{1211,388,{48,19}},{1212,388,{42,16}},{1213,388,{63,23}},{1214,388,{117,45}}, +{1215,388,{62,23}},{1216,388,{64,23}},{1216,644,{64,23}},{1217,644,{128,49}}, +{1218,644,{71,24}},{1219,644,{119,48}},{1220,644,{63,23}},{1221,644,{59,22}}, +{1222,644,{131,49}},{1223,644,{71,26}},{1224,644,{78,29}},{1225,644,{151,58}}, +{1226,644,{75,26}},{1227,644,{69,26}},{1228,644,{137,54}},{1229,644,{69,25}}, +{1230,644,{69,26}},{1231,644,{144,52}},{1232,644,{69,26}},{1233,644,{132,47}}, +{1234,644,{63,23}},{1235,644,{71,26}},{1236,644,{143,52}},{1237,640,{70,23}}, +{1238,640,{71,26}},{1239,640,{76,23}},{1240,640,{146,42}},{1241,640,{79,21}}, +{1242,640,{77,21}},{1243,640,{140,38}},{1244,640,{74,21}},{1245,640,{117,39}}, +{1246,640,{59,18}},{1247,640,{19,12}},{1248,897,{0,0}},{1249,897,{-9,-6}}, +{1250,385,{-6,-4}},{1251,385,{-5,-5}},{1252,385,{-4,-5}},{1253,384,{-4,-1}}, +{1254,384,{-13,-2}},{1255,384,{-25,-6}},{1256,384,{-67,-23}},{1257,384,{-47,-16}}, +{1259,384,{-103,-27}},{1260,384,{-44,-9}},{1261,384,{-101,-21}},{1262,384,{-55,-10}}, +{1263,384,{-60,-12}},{1264,384,{-127,-28}},{1265,384,{-66,-15}},{1266,384,{-67,-15}}, +{1267,384,{-126,-24}},{1268,384,{-66,-12}},{1269,384,{-62,-12}},{1270,384,{-128,-21}}, +{1271,384,{-64,-12}},{1272,384,{-66,-15}},{1273,384,{-131,-26}},{1274,384,{-61,-12}}, +{1275,384,{-127,-29}},{1276,384,{-52,-12}},{1277,384,{-58,-14}},{1278,384,{-83,-26}}, +{1279,384,{-24,-10}},{1280,384,{-22,-11}},{1280,385,{-22,-11}},{1281,385,{-21,-15}}, +{1282,385,{-5,-4}},{1283,385,{5,4}},{1284,385,{0,0}},{1287,385,{37,-20}}, +{1288,385,{29,-8}},{1289,128,{36,-3}},{1290,128,{99,15}},{1291,128,{56,15}}, +{1292,640,{120,41}},{1293,640,{70,26}},{1294,640,{68,26}},{1295,640,{140,52}}, +{1296,640,{73,26}},{1297,640,{68,26}},{1298,640,{134,49}},{1299,640,{62,23}}, +{1300,640,{57,20}},{1301,640,{118,41}},{1302,640,{58,21}},{1303,640,{60,18}}, +{1304,640,{133,44}},{1305,640,{65,21}},{1306,640,{73,23}},{1307,641,{150,47}}, +{1308,641,{73,23}},{1309,641,{65,21}},{1310,641,{124,42}},{1311,641,{52,15}}, +{1312,641,{54,18}},{1313,641,{115,36}},{1314,641,{60,18}},{1315,641,{118,34}}, +{1316,641,{40,14}},{1317,641,{46,11}},{1318,129,{34,8}},{1319,129,{0,0}}, +{1321,129,{-2,0}},{1322,129,{0,0}},{1322,385,{0,0}},{1323,385,{0,-1}}, +{1324,385,{0,-2}},{1325,385,{-3,-12}},{1326,385,{-12,-23}},{1327,385,{-41,-57}}, +{1328,385,{-28,-33}},{1329,385,{-56,-62}},{1330,385,{-30,-28}},{1331,385,{-33,-33}}, +{1332,385,{-70,-63}},{1333,385,{-32,-28}},{1334,385,{-35,-29}},{1335,385,{-76,-67}}, +{1336,385,{-35,-29}},{1337,385,{-69,-56}},{1338,385,{-35,-26}},{1339,385,{-43,-32}}, +{1340,385,{-39,-28}},{1341,385,{-75,-49}},{1342,385,{-37,-24}},{1343,385,{-37,-26}}, +{1344,385,{-74,-54}},{1345,385,{-38,-31}},{1346,385,{-70,-57}},{1347,385,{-35,-28}}, +{1348,385,{-24,-22}},{1349,385,{-32,-26}},{1350,385,{-34,-26}},{1351,385,{-35,-28}}, +{1352,385,{-75,-55}},{1353,385,{-35,-24}},{1354,385,{-35,-26}},{1355,385,{-74,-50}}, +{1356,385,{-34,-26}},{1357,385,{-70,-49}},{1358,385,{-37,-26}},{1359,385,{-37,-24}}, +{1360,385,{-34,-23}},{1361,385,{-36,-26}},{1362,385,{-19,-13}},{1363,385,{-35,-24}}, +{1364,385,{-63,-42}},{1365,385,{-33,-26}},{1366,385,{-32,-24}},{1367,385,{-66,-49}}, +{1368,129,{-24,-22}},{1369,129,{-18,-14}},{1370,129,{-29,-31}},{1371,129,{-13,-16}}, +{1372,129,{-10,-14}},{1373,129,{-1,-1}},{1374,129,{0,0}},{1374,641,{0,0}}, +{1375,641,{3,-8}},{1376,641,{19,-11}},{1377,641,{63,-14}},{1378,641,{34,0}}, +{1379,641,{45,4}},{1380,641,{44,5}},{1381,641,{3,0}},{1382,129,{0,0}}, +{1383,129,{-2,0}},{1383,385,{-2,0}},{1384,385,{-3,1}},{1385,385,{0,0}}, +{1386,385,{-1,-3}},{1387,385,{-2,-4}},{1388,385,{-15,-18}},{1389,385,{-19,-15}}, +{1390,385,{-24,-20}},{1391,385,{-57,-43}},{1392,385,{-29,-21}},{1393,385,{-25,-16}}, +{1394,385,{-36,-25}},{1395,385,{-24,-20}},{1396,385,{-37,-24}},{1397,385,{-29,-23}}, +{1398,385,{-30,-23}},{1399,385,{-35,-26}},{1400,129,{-58,-50}},{1401,129,{-17,-19}}, +{1402,129,{-20,-22}},{1403,129,{-18,-16}},{1404,129,{0,0}},{1404,641,{0,0}}, +{1405,641,{-1,-2}},{1406,641,{0,-7}},{1407,641,{9,-29}},{1408,641,{9,-13}}, +{1409,641,{6,-7}},{1410,641,{27,-20}},{1411,641,{22,-12}},{1412,641,{24,-12}}, +{1412,129,{24,-12}},{1413,129,{40,-16}},{1414,129,{16,-9}},{1415,129,{10,-6}}, +{1416,129,{6,-7}},{1417,129,{13,-16}},{1418,129,{9,-12}},{1418,385,{9,-12}}, +{1419,385,{5,-7}},{1420,385,{1,-4}},{1421,385,{6,-9}},{1422,385,{3,-5}}, +{1423,385,{2,-6}},{1424,385,{11,-18}},{1425,385,{7,-15}},{1426,385,{7,-13}}, +{1426,897,{7,-13}},{1427,641,{3,-7}},{1428,641,{10,-19}},{1429,641,{3,-5}}, +{1430,641,{8,-13}},{1431,641,{6,-5}},{1432,641,{7,-9}},{1433,641,{13,-14}}, +{1434,641,{15,-12}},{1435,641,{0,0}},{1436,641,{31,-19}},{1437,641,{14,-9}}, +{1438,641,{17,-7}},{1439,641,{33,-16}},{1440,641,{6,-6}},{1441,641,{0,-1}}, +{1442,641,{0,0}},{1443,641,{5,-7}},{1443,640,{5,-7}},{1444,640,{0,-1}}, +{1446,640,{-1,-2}},{1447,640,{-3,-8}},{1448,640,{-32,-47}},{1449,640,{-29,-35}}, +{1450,640,{-33,-33}},{1451,640,{-74,-74}},{1452,640,{-32,-30}},{1452,896,{-32,-30}}, +{1453,896,{-16,-16}},{1454,896,{-55,-49}},{1455,896,{-38,-34}},{1456,640,{-72,-55}}, +{1457,640,{-38,-26}},{1458,640,{-47,-31}},{1459,640,{-86,-47}},{1460,640,{-41,-20}}, +{1461,640,{-36,-19}},{1462,640,{-56,-32}},{1462,512,{-56,-32}},{1463,512,{-28,-16}}, +{1464,512,{-42,-20}},{1465,512,{-72,-34}},{1466,512,{-40,-20}},{1467,512,{-37,-20}}, +{1467,768,{-37,-20}},{1468,768,{-28,-16}},{1469,768,{-7,-6}},{1470,768,{-4,-4}}, +{1471,768,{-7,-6}},{1472,768,{0,0}},{1473,768,{-3,-3}},{1474,768,{-5,-5}}, +{1475,257,{-1,-1}},{1476,257,{-3,-3}},{1477,257,{-1,-1}},{1478,257,{0,-4}}, +{1479,257,{1,-6}},{1480,385,{11,-13}},{1481,385,{7,-9}},{1482,385,{13,-12}}, +{1483,385,{28,-24}},{1484,385,{21,-11}},{1485,385,{24,-10}},{1486,385,{62,-15}}, +{1487,385,{34,-7}},{1488,385,{29,-4}},{1488,384,{29,-4}},{1489,384,{31,-6}}, +{1490,384,{31,-4}},{1491,384,{34,-5}},{1492,384,{38,-6}},{1493,384,{25,-2}}, +{1494,384,{13,-4}},{1495,384,{45,-6}},{1496,384,{26,-4}},{1497,384,{26,-6}}, +{1498,384,{45,-6}},{1498,388,{45,-6}},{1499,388,{18,-2}},{1500,388,{32,-2}}, +{1501,388,{16,-2}},{1502,388,{7,0}},{1503,388,{15,-2}},{1504,644,{9,-2}}, +{1505,644,{17,0}},{1506,644,{6,0}},{1507,644,{3,0}},{1508,644,{0,-1}}, +{1509,644,{0,0}},{1510,644,{-3,1}},{1511,644,{0,0}},{1512,644,{-3,-1}}, +{1513,644,{-4,-1}},{1514,644,{-12,-5}},{1515,644,{-20,-9}},{1516,644,{-80,-37}}, +{1517,644,{-54,-24}},{1518,644,{-58,-21}},{1519,644,{-112,-39}},{1520,644,{-52,-16}}, +{1521,644,{-51,-14}},{1522,644,{-117,-32}},{1523,644,{-69,-20}},{1524,644,{0,0}}, +{1525,644,{-159,-49}},{1526,644,{-84,-25}},{1527,644,{-149,-46}},{1528,644,{-78,-22}}, +{1529,644,{-68,-22}},{1530,644,{-151,-44}},{1531,644,{-72,-20}},{1532,644,{-63,-21}}, +{1533,644,{-152,-39}},{1533,900,{-152,-39}},{1534,900,{-80,-22}},{1535,900,{-80,-20}}, +{1536,900,{-155,-32}},{1537,388,{-66,-15}},{1538,388,{-77,-15}},{1539,388,{-138,-29}}, +{1540,388,{-72,-17}},{1541,388,{-78,-20}},{1542,388,{-149,-36}},{1543,388,{-81,-20}}, +{1544,388,{-159,-35}},{1545,388,{-78,-17}},{1546,388,{-55,-16}},{1546,384,{-55,-16}}, +{1547,384,{-49,-13}},{1548,384,{-72,-17}},{1549,384,{-72,-22}},{1550,384,{-78,-22}}, +{1551,384,{-107,-34}},{1552,384,{-58,-19}},{1553,384,{-67,-19}},{1554,384,{-91,-29}}, +{1555,384,{-49,-16}},{1556,384,{-36,-13}},{1557,384,{-38,-13}},{1558,384,{-50,-14}}, +{1559,384,{-29,-10}},{1559,256,{-29,-10}},{1560,256,{-38,-18}},{1561,256,{0,0}}, +{1562,513,{4,3}},{1563,513,{2,5}},{1564,513,{12,-10}},{1565,513,{32,-18}}, +{1566,513,{19,-7}},{1567,513,{16,-4}},{1568,513,{35,-3}},{1569,513,{45,0}}, +{1570,513,{53,2}},{1571,513,{116,6}},{1572,513,{59,2}},{1573,641,{48,4}}, +{1574,641,{93,6}},{1575,641,{43,2}},{1576,641,{36,4}},{1577,641,{44,3}}, +{1578,641,{11,1}},{1579,641,{2,0}},{1580,641,{0,0}},{1581,641,{-1,0}}, +{1581,129,{-1,0}},{1582,129,{-4,2}},{1583,257,{-1,-1}},{1584,257,{0,0}}, +{1585,257,{-11,-4}},{1586,257,{-52,-21}},{1587,257,{-41,-13}},{1588,257,{-49,-16}}, +{1589,257,{-112,-39}},{1590,257,{-42,-16}},{1591,257,{-98,-36}},{1592,257,{-48,-18}}, +{1593,257,{-47,-18}},{1594,257,{-85,-35}},{1595,257,{-36,-17}},{1596,257,{-13,-8}}, +{1597,257,{-7,-7}},{1598,257,{-2,-2}},{1599,257,{2,5}},{1600,257,{2,-3}}, +{1601,1,{38,-18}},{1602,1,{23,-4}},{1603,1,{28,-4}},{1603,129,{28,-4}}, +{1604,129,{34,-5}},{1605,129,{90,-5}},{1606,129,{50,0}},{1607,129,{59,0}}, +{1608,641,{122,4}},{1609,641,{58,2}},{1610,641,{51,4}},{1611,641,{96,4}}, +{1612,641,{47,2}},{1613,641,{55,2}},{1614,641,{81,4}},{1615,641,{20,0}}, +{1616,641,{37,-3}},{1617,641,{11,-3}},{1618,641,{1,-2}},{1619,641,{0,0}}, +{1619,385,{0,0}},{1622,385,{0,-1}},{1623,385,{-10,-24}},{1624,385,{-13,-16}}, +{1625,385,{-22,-22}},{1626,385,{-68,-61}},{1627,385,{-41,-34}},{1628,385,{-83,-63}}, +{1629,385,{-40,-27}},{1630,385,{-32,-21}},{1631,385,{-67,-40}},{1632,385,{-39,-22}}, +{1633,385,{-39,-24}},{1634,385,{-95,-48}},{1635,385,{-42,-25}},{1636,385,{-87,-45}}, +{1637,385,{-18,-13}},{1638,385,{-21,-15}},{1639,385,{-21,-13}},{1640,385,{-10,-11}}, +{1641,385,{-7,-6}},{1642,385,{-15,-12}},{1643,385,{-5,-5}},{1645,385,{-2,-2}}, +{1646,385,{0,0}},{1647,385,{2,-6}},{1648,385,{42,-22}},{1649,385,{37,-11}}, +{1650,385,{92,-9}},{1651,385,{53,0}},{1652,385,{65,2}},{1653,385,{143,14}}, +{1654,385,{79,11}},{1655,385,{73,11}},{1656,385,{102,13}},{1657,385,{26,3}}, +{1658,385,{0,0}},{1659,385,{25,2}},{1660,385,{128,11}},{1661,385,{67,6}}, +{1662,385,{72,9}},{1663,385,{54,9}},{1664,257,{59,6}},{1665,257,{87,10}}, +{1666,257,{52,6}},{1667,257,{33,1}},{1668,257,{23,1}},{1668,256,{23,1}}, +{1669,256,{41,1}},{1670,256,{29,-2}},{1671,256,{31,-9}},{1672,256,{35,-13}}, +{1673,256,{37,-11}},{1674,256,{68,-21}},{1674,257,{68,-21}},{1675,257,{39,-11}}, +{1676,257,{38,-11}},{1677,257,{79,-17}},{1678,257,{34,-5}},{1679,257,{45,-7}}, +{1680,257,{78,-9}},{1681,257,{40,-5}},{1682,385,{34,-7}},{1683,385,{33,-9}}, +{1684,384,{5,-3}},{1685,384,{7,-4}},{1686,384,{37,-11}},{1687,384,{23,-6}}, +{1688,384,{26,-6}},{1689,384,{30,-5}},{1690,384,{24,-2}},{1691,384,{16,-2}}, +{1692,384,{11,0}},{1693,384,{20,1}},{1694,384,{39,8}},{1695,384,{16,4}}, +{1696,384,{0,0}},{1696,388,{0,0}},{1697,388,{16,7}},{1698,388,{18,11}}, +{1699,388,{0,0}},{1701,388,{2,2}},{1702,388,{9,10}},{1703,388,{13,11}}, +{1704,388,{15,11}},{1705,388,{46,33}},{1706,644,{28,18}},{1707,644,{42,21}}, +{1708,644,{4,6}},{1709,644,{0,0}},{1710,644,{1,1}},{1711,644,{0,0}}, +{1712,644,{0,3}},{1713,644,{0,2}},{1714,644,{-3,7}},{1715,644,{-3,2}}, +{1716,644,{-2,2}},{1717,644,{-22,16}},{1718,644,{-17,8}},{1719,644,{-17,6}}, +{1720,644,{-47,16}},{1721,644,{-29,5}},{1722,644,{-31,1}},{1723,644,{-75,1}}, +{1724,644,{-48,-5}},{1725,644,{-55,-7}},{1726,644,{-111,-25}},{1727,644,{-57,-12}}, +{1728,644,{-104,-28}},{1729,644,{-43,-13}},{1730,644,{-58,-19}},{1731,644,{-50,-18}}, +{1732,644,{-65,-27}},{1733,644,{-25,-12}},{1734,644,{-5,-4}},{1735,644,{0,0}}, +{1736,644,{3,3}},{1737,644,{0,0}},{1739,644,{0,-2}},{1740,644,{32,-21}}, +{1740,900,{32,-21}},{1741,900,{25,-6}},{1742,900,{38,-5}},{1743,900,{31,-2}}, +{1744,900,{48,0}},{1745,900,{34,2}},{1746,900,{68,6}},{1747,900,{34,2}}, +{1748,900,{45,8}},{1748,644,{45,8}},{1749,644,{112,22}},{1750,644,{62,11}}, +{1751,644,{64,13}},{1752,644,{117,25}},{1753,644,{60,13}},{1754,644,{115,30}}, +{1755,644,{57,13}},{1756,644,{62,18}},{1757,644,{125,39}},{1758,644,{62,18}}, +{1759,644,{51,17}},{1760,644,{109,34}},{1761,644,{54,15}},{1762,644,{57,16}}, +{1763,132,{122,39}},{1764,132,{59,16}},{1765,132,{59,18}},{1766,132,{104,26}}, +{1767,132,{53,15}},{1768,132,{51,15}},{1769,132,{63,20}},{1770,132,{12,6}}, +{1771,132,{0,0}},{1771,164,{0,0}},{1772,164,{-10,-7}},{1773,164,{2,4}}, +{1774,676,{3,4}},{1775,676,{0,3}},{1776,676,{0,0}},{1778,676,{4,9}}, +{1779,676,{5,8}},{1780,676,{6,6}},{1781,676,{17,14}},{1782,644,{7,3}}, +{1783,640,{33,11}},{1784,640,{22,5}},{1785,640,{32,2}},{1786,640,{62,3}}, +{1787,640,{42,0}},{1788,640,{45,0}},{1789,640,{82,-3}},{1790,768,{39,0}}, +{1792,769,{63,0}},{1793,257,{30,0}},{1794,257,{25,1}},{1795,257,{54,3}}, +{1796,257,{23,0}},{1797,769,{16,1}},{1798,769,{42,5}},{1799,769,{26,1}}, +{1800,769,{29,5}},{1801,769,{55,11}},{1802,257,{21,3}},{1803,257,{5,2}}, +{1804,257,{40,8}},{1805,257,{20,3}},{1806,257,{23,3}},{1807,257,{7,1}}, +{1808,257,{0,0}},{1809,385,{1,0}},{1810,385,{13,1}},{1811,385,{9,1}}, +{1812,384,{16,2}},{1813,384,{13,1}},{1814,384,{9,1}},{1815,384,{17,2}}, +{1816,384,{4,2}},{1817,384,{3,1}},{1818,384,{0,0}},{1819,896,{0,0}}, +{1824,896,{-1,0}},{1825,640,{-2,0}},{1826,640,{0,0}},{1830,640,{9,-2}}, +{1831,640,{15,-4}},{1832,640,{34,-3}},{1833,640,{98,-7}},{1834,640,{59,-3}}, +{1835,640,{53,-3}},{1836,640,{115,-7}},{1837,641,{54,-5}},{1838,641,{124,-10}}, +{1839,513,{67,-5}},{1840,513,{70,-3}},{1841,513,{110,-7}},{1842,1,{28,-4}}, +{1842,257,{28,-4}},{1843,257,{1,-1}},{1844,257,{0,0}},{1845,257,{-14,3}}, +{1846,257,{-8,3}},{1847,257,{-2,1}},{1848,257,{-1,-1}},{1849,256,{-15,-7}}, +{1850,256,{-46,-17}},{1851,256,{-28,-10}},{1852,256,{-66,-19}},{1853,256,{-47,-11}}, +{1854,256,{-45,-11}},{1855,256,{-107,-19}},{1856,256,{-57,-7}},{1857,256,{-46,-11}}, +{1858,256,{-78,-17}},{1859,256,{-33,-9}},{1860,256,{-99,-21}},{1861,256,{-49,-12}}, +{1862,256,{-95,-20}},{1863,256,{-42,-9}},{1864,256,{-32,-8}},{1865,256,{-25,-10}}, +{1866,256,{-54,-18}},{1867,256,{-23,-10}},{1868,256,{-63,-27}},{1869,257,{-15,-7}}, +{1870,257,{-24,-10}},{1871,257,{-24,-8}},{1872,257,{-39,-16}},{1873,257,{-20,-8}}, +{1874,257,{-10,-8}},{1875,257,{-2,-2}},{1876,257,{-8,-8}},{1877,257,{-5,-5}}, +{1878,257,{-3,-3}},{1880,257,{0,0}},{1881,385,{0,0}},{1882,385,{22,-12}}, +{1883,385,{27,-8}},{1884,385,{0,0}},{1885,385,{26,-8}},{1886,385,{18,-4}}, +{1887,385,{28,-4}},{1888,385,{106,2}},{1889,385,{70,7}},{1890,385,{76,7}}, +{1891,385,{142,16}},{1892,385,{45,6}},{1893,385,{51,6}},{1894,385,{65,11}}, +{1895,385,{73,11}},{1896,385,{85,19}},{1897,385,{169,38}},{1898,385,{82,21}}, +{1899,384,{59,13}},{1900,384,{132,27}},{1901,384,{73,11}},{1902,384,{77,12}}, +{1903,384,{85,14}},{1904,256,{85,14}},{1905,256,{164,31}},{1906,256,{72,14}}, +{1907,256,{43,12}},{1908,256,{102,26}},{1909,256,{57,15}},{1910,256,{37,16}}, +{1911,256,{61,30}},{1912,256,{10,7}},{1913,0,{0,1}},{1914,0,{-11,-8}}, +{1915,0,{-7,-6}},{1916,0,{0,0}},{1917,0,{-4,8}},{1918,0,{-6,7}}, +{1919,0,{0,0}},{1920,0,{-10,8}},{1921,0,{-26,19}},{1922,0,{-6,3}}, +{1923,0,{-19,11}},{1924,0,{-18,6}},{1925,0,{-20,8}},{1926,0,{-41,14}}, +{1927,0,{-27,7}},{1928,0,{-30,7}},{1929,0,{-29,4}},{1930,0,{-1,0}}, +{1931,0,{-2,0}},{1932,0,{0,0}},{1933,16384,{0,0}},{1934,16384,{0,1}}, +{1940,0,{0,1}},{1968,4,{0,1}},{1970,0,{0,1}},{1975,4,{0,1}}, +{1978,0,{0,1}},{1984,4,{0,1}},{1986,0,{0,1}},{1992,4,{0,1}}, +{1995,0,{0,1}},{2000,4,{0,1}},{2003,0,{0,1}},{2006,4,{0,1}}, +{2011,0,{0,1}},{2019,16,{0,1}},{4294967295,0,{0,0}} +}; + +DemoRecord playRecord; +uint32_t playRecordIndex = 0; +int8_t playEnd = 0; + +void demoPlayStep() +{ + if (playRecordIndex == 0) + playRecord = demoPlay[playRecordIndex]; + + if (playEnd) + return; + + DemoRecord nextRecord = demoPlay[playRecordIndex + 1]; + + playEnd = nextRecord.frame == UINT32_MAX_VALUE; + + if (playEnd) + { + puts("demo end reached"); + } + else if (SFG_game.frame >= nextRecord.frame) + { + playRecord = nextRecord; + playRecordIndex++; + } +} + +int8_t demoKeyPressed(uint8_t key) +{ + return (playRecord.keyStates & (((uint16_t) 0x01) << key)) != 0; +} + +void demoGetMouseOffset(int16_t *x, int16_t *y) +{ + *x = playRecord.mouseOffset[0]; + *y = playRecord.mouseOffset[1]; +} + +void demoRecordPrint() +{ + printf("recorded demo:"); + + for (uint32_t i = 0; i < demoRecLength; ++i) + { + DemoRecord record = demoRec[i]; + + if (i % 4 == 0) + putchar('\n'); + + printf("{%lu,%d,{%d,%d}},",record.frame,record.keyStates,record.mouseOffset[0],record.mouseOffset[1]); + } + + printf("{%lu,0,{0,0}}",UINT32_MAX_VALUE); // terminate demo +} + +#endif // guard diff --git a/main_gbmeta/game.h b/main_gbmeta/game.h new file mode 100755 index 0000000..7676678 --- /dev/null +++ b/main_gbmeta/game.h @@ -0,0 +1,4862 @@ +/** + @file game.h + + Main source file of Anarch the game that puts together all the pieces. main + game logic is implemented here. + + Physics notes (you can break this when messing with constants): + + - Lowest ceiling under which player can fit is 4 height steps. + - Widest hole over which player can run without jumping is 1 square. + - Widest hole over which the player can jump is 3 squares. + - Highest step a player can walk onto without jumping is 2 height steps. + - Highest step a player can jump onto is 3 height steps. + + by Miloslav Ciz (drummyfish), 2019 + + Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) + plus a waiver of all other intellectual property. The goal of this work is + be and remain completely in the public domain forever, available for any use + whatsoever. +*/ + +#ifndef _SFG_GAME_H +#define _SFG_GAME_H + +#include // Needed for fixed width types, can easily be replaced. + +/* + The following keys are mandatory to be implemented on any platform in order + for the game to be playable. Enums are bloat. +*/ +#define SFG_KEY_UP 0 +#define SFG_KEY_RIGHT 1 +#define SFG_KEY_DOWN 2 +#define SFG_KEY_LEFT 3 +#define SFG_KEY_A 4 ///< fire, confirm +#define SFG_KEY_B 5 ///< cancel, strafe, look up/down +#define SFG_KEY_C 6 ///< menu, jump, switch weapons + +/* + The following keys are optional for a platform to implement. They just make + the controls more comfortable. +*/ +#define SFG_KEY_JUMP 7 +#define SFG_KEY_STRAFE_LEFT 8 +#define SFG_KEY_STRAFE_RIGHT 9 +#define SFG_KEY_MAP 10 +#define SFG_KEY_TOGGLE_FREELOOK 11 +#define SFG_KEY_NEXT_WEAPON 12 +#define SFG_KEY_PREVIOUS_WEAPON 13 +#define SFG_KEY_MENU 14 +#define SFG_KEY_CYCLE_WEAPON 15 + +#define SFG_KEY_COUNT 16 ///< Number of keys. + +/* ============================= PORTING =================================== */ + +/* When porting, do the following: + - Include this file (and possibly other optional files, like sounds.h) in + your main_*.c frontend source. + - Implement the following functions in your frontend source. + - Call SFG_init() from your frontend initialization code. + - Call SFG_mainLoopBody() from within your frontend main loop. */ + +#ifndef SFG_LOG + #define SFG_LOG(str) {} ///< Can be redefined to log game messages. +#endif + +#ifndef SFG_CPU_LOAD + #define SFG_CPU_LOAD(percent) {} ///< Can be redefined to check CPU load in %. +#endif + +#ifndef SFG_GAME_STEP_COMMAND + #define SFG_GAME_STEP_COMMAND {} /**< Will be called each simlation step (good + for creating deterministic behavior such as + demos (SFG_mainLoopBody() calls potentially + multiple simulation steps). */ +#endif + +/** + Returns 1 (0) if given key is pressed (not pressed). At least the mandatory + keys have to be implemented, the optional keys don't have to ever return 1. + See the key constant definitions to see which ones are mandatory. +*/ +int8_t SFG_keyPressed(uint8_t key); + +/** + Optinal function for mouse/joystick/analog controls, gets mouse x and y offset + in pixels from the game screen center (to achieve classic FPS mouse controls + the platform should center the mouse after this call). If the platform isn't + using a mouse, this function can simply return [0,0] offset at each call, or + even do nothing at all (leave the variables as are). +*/ +void SFG_getMouseOffset(int16_t *x, int16_t *y); + +/** + Returns time in milliseconds sice program start. +*/ +uint32_t SFG_getTimeMs(); + +/** + Sleep (yield CPU) for specified amount of ms. This is used to relieve CPU + usage. If your platform doesn't need this or handles it in other way, this + function can do nothing. +*/ +void SFG_sleepMs(uint16_t timeMs); + +/** + Set specified screen pixel. ColorIndex is the index of the game's palette. + The function doesn't have to (and shouldn't, for the sake of performance) + check whether the coordinates are within screen bounds. +*/ +static inline void SFG_setPixel(uint16_t x, uint16_t y, uint8_t colorIndex); + +/** + Play given sound effect (SFX). This function may or may not use the sound + samples provided in sounds.h, and it may or may not ignore the (logarithmic) + volume parameter (0 to 255). Depending on the platform, the function can play + completely different samples or even e.g. just beeps. If the platform can't + play sounds, this function implementation can simply be left empty. This + function doesn't have to implement safety measures, the back end takes cares + of them. +*/ +void SFG_playSound(uint8_t soundIndex, uint8_t volume); + +#define SFG_MUSIC_TURN_OFF 0 +#define SFG_MUSIC_TURN_ON 1 +#define SFG_MUSIC_NEXT 2 + +/** + Informs the frontend how music should play, e.g. turn on/off, change track, + ... See SFG_MUSIC_* constants. Playing music is optional and the frontend may + ignore this. If a frontend wants to implement music, it can use the bytebeat + provided in sounds.h or use its own. +*/ +void SFG_setMusic(uint8_t value); + +#define SFG_EVENT_VIBRATE 0 ///< the controller should vibrate (or blink etc.) +#define SFG_EVENT_PLAYER_HURT 1 +#define SFG_EVENT_PLAYER_DIES 2 +#define SFG_EVENT_LEVEL_STARTS 3 +#define SFG_EVENT_LEVEL_WON 4 +#define SFG_EVENT_MONSTER_DIES 5 +#define SFG_EVENT_PLAYER_TAKES_ITEM 6 +#define SFG_EVENT_EXPLOSION 7 +#define SFG_EVENT_PLAYER_TELEPORTS 8 +#define SFG_EVENT_PLAYER_CHANGES_WEAPON 9 + +/** + This is an optional function that informs the frontend about special events + which may trigger something special on the platform, such as a controller + vibration, logging etc. The implementation of this function may be left empty. +*/ +void SFG_processEvent(uint8_t event, uint8_t data); + +#define SFG_SAVE_SIZE 12 ///< size of the save in bytes + +/** + Optional function for permanently saving the game state. Platforms that don't + have permanent storage (HDD, EEPROM etc.) may let this function simply do + nothing. If implemented, the function should save the passed data into its + permanent storage, e.g. a file, a cookie etc. +*/ +void SFG_save(uint8_t data[SFG_SAVE_SIZE]); + +/** + Optional function for retrieving game data that were saved to permanent + storage. Platforms without permanent storage may let this function do nothing. + If implemented, the function should fill the passed array with data from + permanent storage, e.g. a file, a cookie etc. + + If this function is called before SFG_save was ever called and no data is + present in permanent memory, this function should do nothing (leave the data + array as is). + + This function should return 1 if saving/loading is possible or 0 if not (this + will be used by the game to detect saving/loading capability). +*/ +uint8_t SFG_load(uint8_t data[SFG_SAVE_SIZE]); + +/* ========================================================================= */ + +/** + Main game loop body, call this inside your platform's specific main loop. + Returns 1 if the game continues or 0 if the game was exited and program should + halt. This functions handles reaching the target FPS and sleeping for + relieving CPU, so don't do this. +*/ +uint8_t SFG_mainLoopBody(); + +/** + Initializes the game, call this in the platform's initialization code. +*/ +void SFG_init(); + +#include "settings.h" + +#if SFG_ARDUINO + #include + + #define SFG_PROGRAM_MEMORY const PROGMEM + #define SFG_PROGRAM_MEMORY_U8(addr) pgm_read_byte(addr) +#else + #define SFG_PROGRAM_MEMORY static const + #define SFG_PROGRAM_MEMORY_U8(addr) ((uint8_t) (*(addr))) +#endif + +#include "images.h" // don't change the order of these includes +#include "levels.h" +#include "texts.h" +#include "palette.h" + +#if SFG_TEXTURE_DISTANCE == 0 + #define RCL_COMPUTE_WALL_TEXCOORDS 0 +#endif + +#define RCL_PIXEL_FUNCTION SFG_pixelFunc +#define RCL_TEXTURE_VERTICAL_STRETCH 0 + +#define RCL_CAMERA_COLL_HEIGHT_BELOW 800 +#define RCL_CAMERA_COLL_HEIGHT_ABOVE 200 + +#define RCL_HORIZONTAL_FOV SFG_FOV_HORIZONTAL +#define RCL_VERTICAL_FOV SFG_FOV_VERTICAL + +#include "raycastlib.h" + +#include "constants.h" + +typedef struct +{ + uint8_t coords[2]; + uint8_t state; /**< door state in format: + + MSB ccbaaaaa LSB + + aaaaa: current door height (how much they're open) + b: whether currently going up (0) or down (1) + cc: by which card (key) the door is unlocked, 00 + means no card (unlocked), 1 means card 0 etc. */ +} SFG_DoorRecord; + +#define SFG_SPRITE_SIZE(size0to3) \ + (((size0to3 + 3) * SFG_BASE_SPRITE_SIZE) / 4) + +#define SFG_SPRITE_SIZE_PIXELS(size0to3) \ + ((SFG_SPRITE_SIZE(size0to3) * SFG_GAME_RESOLUTION_Y) / RCL_UNITS_PER_SQUARE) + +#define SFG_SPRITE_SIZE_TO_HEIGHT_ABOVE_GROUND(size0to3) \ + (SFG_SPRITE_SIZE(size0to3) / 2) + +/** + Holds information about one instance of a level item (a type of level element, + e.g. pickable items, decorations etc.). The format is following: + + MSB abbbbbbb LSB + + a: active flag, 1 means the item is nearby to player and is active + bbbbbbb: index to elements array of the current level, pointing to element + representing this item +*/ +typedef uint8_t SFG_ItemRecord; + +#define SFG_ITEM_RECORD_ACTIVE_MASK 0x80 + +#define SFG_ITEM_RECORD_LEVEL_ELEMENT(itemRecord) \ + (SFG_currentLevel.levelPointer->elements[itemRecord & \ + ~SFG_ITEM_RECORD_ACTIVE_MASK]) + +typedef struct +{ + uint8_t stateType; /**< Holds state (lower 4 bits) and type of monster (upper + 4 bits). */ + uint8_t coords[2]; /**< monster position, in 1/4s of a square */ + uint8_t health; +} SFG_MonsterRecord; + +#define SFG_MR_STATE(mr) ((mr).stateType & SFG_MONSTER_MASK_STATE) +#define SFG_MR_TYPE(mr) \ + (SFG_MONSTER_INDEX_TO_TYPE(((mr).stateType & SFG_MONSTER_MASK_TYPE) >> 4)) + +#define SFG_MONSTER_COORD_TO_RCL_UNITS(c) ((RCL_UNITS_PER_SQUARE / 8) + c * 256) +#define SFG_MONSTER_COORD_TO_SQUARES(c) (c / 4) + +#define SFG_ELEMENT_COORD_TO_RCL_UNITS(c) \ + (c * RCL_UNITS_PER_SQUARE + RCL_UNITS_PER_SQUARE / 2) + +#define SFG_MONSTER_MASK_STATE 0x0f +#define SFG_MONSTER_MASK_TYPE 0xf0 + +#define SFG_MONSTER_STATE_INACTIVE 0 ///< Not nearby, not actively updated. +#define SFG_MONSTER_STATE_IDLE 1 +#define SFG_MONSTER_STATE_ATTACKING 2 +#define SFG_MONSTER_STATE_HURTING 3 +#define SFG_MONSTER_STATE_DYING 4 +#define SFG_MONSTER_STATE_GOING_N 5 +#define SFG_MONSTER_STATE_GOING_NE 6 +#define SFG_MONSTER_STATE_GOING_E 7 +#define SFG_MONSTER_STATE_GOING_SE 8 +#define SFG_MONSTER_STATE_GOING_S 9 +#define SFG_MONSTER_STATE_GOING_SW 10 +#define SFG_MONSTER_STATE_GOING_W 11 +#define SFG_MONSTER_STATE_GOING_NW 12 +#define SFG_MONSTER_STATE_DEAD 13 + +typedef struct +{ + uint8_t type; + uint8_t doubleFramesToLive; /**< This number times two (because 255 could be + too little at high FPS) says after how many + frames the projectile is destroyed. */ + uint16_t position[3]; /**< Current position, stored as u16 to save space, as + that is exactly enough to store position on 64x64 + map. */ + int16_t direction[3]; /**< Added to position each game step. */ +} SFG_ProjectileRecord; + +#define SFG_GAME_STATE_INIT 0 ///< first state, waiting for key releases +#define SFG_GAME_STATE_PLAYING 1 +#define SFG_GAME_STATE_WIN 2 +#define SFG_GAME_STATE_LOSE 3 +#define SFG_GAME_STATE_INTRO 4 +#define SFG_GAME_STATE_OUTRO 5 +#define SFG_GAME_STATE_MAP 6 +#define SFG_GAME_STATE_LEVEL_START 7 +#define SFG_GAME_STATE_MENU 8 + +#define SFG_MENU_ITEM_CONTINUE 0 +#define SFG_MENU_ITEM_MAP 1 +#define SFG_MENU_ITEM_PLAY 2 +#define SFG_MENU_ITEM_LOAD 3 +#define SFG_MENU_ITEM_SOUND 4 +#define SFG_MENU_ITEM_SHEAR 5 +#define SFG_MENU_ITEM_EXIT 6 + +#define SFG_MENU_ITEM_NONE 255 + +/* + GLOBAL VARIABLES +=============================================================================== +*/ + +/** + Groups global variables related to the game as such in a single struct. There + are still other global structs for player, level etc. +*/ +struct +{ + uint8_t state; ///< Current game state. + uint32_t stateChangeTime; ///< Time in ms at which the state was changed. + uint8_t currentRandom; ///< for RNG + uint8_t spriteAnimationFrame; + uint8_t soundsPlayedThisFrame; /**< Each bit says whether given sound was + played this frame, prevents playing too many + sounds at once. */ + RCL_RayConstraints rayConstraints; + uint8_t keyStates[SFG_KEY_COUNT]; /**< Pressed states of keys, each value + stores the number of frames for which the + key has been held. */ + uint8_t zBuffer[SFG_Z_BUFFER_SIZE]; + uint8_t textureAverageColors[SFG_WALL_TEXTURE_COUNT]; /**< Contains average + color for each wall texture. */ + int8_t backgroundScaleMap[SFG_GAME_RESOLUTION_Y]; + uint16_t backgroundScroll; + uint8_t spriteSamplingPoints[SFG_MAX_SPRITE_SIZE]; /**< Helper for + precomputing sprite + sampling positions for + drawing. */ + uint32_t frameTime; ///< time (in ms) of the current frame start + uint32_t frame; ///< frame number + uint8_t selectedMenuItem; + uint8_t selectedLevel; ///< level to play selected in the main menu + uint8_t antiSpam; ///< Prevents log message spamming. + uint8_t settings; /**< dynamic game settings (can be changed at runtime), + bit meaning: + + MSB -------- LSB + |||| + |||\_ sound (SFX) + ||\__ music + |\___ shearing + \____ freelook (shearing not sliding back) */ + uint8_t blink; ///< Says whether blinkg is currently on or off. + uint8_t saved; /**< Helper variable to know if game was saved. Can be + 0 (not saved), 1 (just saved) or 255 (can't save).*/ + uint8_t save[SFG_SAVE_SIZE]; /**< Stores the game save state that's kept in + the persistent memory. + + The save format is binary and platform independent. + The save contains game settings, game progress and a + saved position. The format is as follows: + + 0 4b highest level that has been reached + 0 4b level number of the saved position (15: no save) + 1 8b game settings (SFG_game.settings) + 2 8b health at saved position + 3 8b bullet ammo at saved position + 4 8b rocket ammo at saved position + 5 8b plasma ammo at saved position + 6 32b little endian total play time, in 10ths of sec + 10 16b little endian total enemies killed from start */ + uint8_t continues; ///< Whether the game continues or was exited. +} SFG_game; + +#define SFG_SAVE_TOTAL_TIME (SFG_game.save[6] + SFG_game.save[7] * 256 + \ + SFG_game.save[8] * 65536 + SFG_game.save[9] * 4294967296) + +/** + Stores player state. +*/ +struct +{ + RCL_Camera camera; + int8_t squarePosition[2]; + RCL_Vector2D direction; + RCL_Unit verticalSpeed; + RCL_Unit previousVerticalSpeed; /**< Vertical speed in previous frame, needed + for determining whether player is in the + air. */ + uint16_t headBobFrame; + uint8_t weapon; ///< currently selected weapon + uint8_t health; + uint32_t weaponCooldownFrames; ///< frames left for weapon cooldow + uint32_t lastHurtFrame; + uint32_t lastItemTakenFrame; + uint8_t ammo[SFG_AMMO_TOTAL]; + uint8_t cards; /**< Lowest 3 bits say which access cards + have been taken., the next 3 bits say + which cards should be blinking in the HUD, + the last 2 bits are a blink reset counter. */ + uint8_t justTeleported; + int8_t previousWeaponDirection; ///< Direction (+/0/-) of previous weapon. +} SFG_player; + +/** + Stores the current level and helper precomputed vaues for better performance. +*/ +struct +{ + const SFG_Level *levelPointer; + uint8_t levelNumber; + const uint8_t* textures[7]; ///< textures the level is using + uint32_t timeStart; + uint32_t frameStart; + uint32_t completionTime10sOfS; ///< completion time in 10th of second + uint8_t floorColor; + uint8_t ceilingColor; + + SFG_DoorRecord doorRecords[SFG_MAX_DOORS]; + uint8_t doorRecordCount; + uint8_t checkedDoorIndex; ///< Says which door are currently being checked. + + SFG_ItemRecord itemRecords[SFG_MAX_ITEMS]; ///< Holds level items. + uint8_t itemRecordCount; + uint8_t checkedItemIndex; ///< Same as checkedDoorIndex, but for items. + + SFG_MonsterRecord monsterRecords[SFG_MAX_MONSTERS]; + uint8_t monsterRecordCount; + uint8_t checkedMonsterIndex; + + SFG_ProjectileRecord projectileRecords[SFG_MAX_PROJECTILES]; + uint8_t projectileRecordCount; + uint8_t bossCount; + uint8_t monstersDead; + uint8_t backgroundImage; + uint8_t teleporterCount; + uint16_t mapRevealMask; /**< Bits say which parts of the map have been + revealed. */ + uint8_t itemCollisionMap[(SFG_MAP_SIZE * SFG_MAP_SIZE) / 8]; + /**< Bit array, for each map square says whether there + is a colliding item or not. */ +} SFG_currentLevel; + +#if SFG_ARDUINO +/** + Copy of the current level that is stored in RAM. This is only done on Arduino + because accessing it in program memory (PROGMEM) directly would be a pain. + Because of this Arduino needs more RAM. +*/ +SFG_Level SFG_ramLevel; +#endif + +/** + Helper function for accessing the itemCollisionMap bits. +*/ +void SFG_getItemCollisionMapIndex( + uint8_t x, uint8_t y, uint16_t *byte, uint8_t *bit) +{ + uint16_t index = y * SFG_MAP_SIZE + x; + + *byte = index / 8; + *bit = index % 8; +} + +void SFG_setItemCollisionMapBit(uint8_t x, uint8_t y, uint8_t value) +{ + uint16_t byte; + uint8_t bit; + + SFG_getItemCollisionMapIndex(x,y,&byte,&bit); + + SFG_currentLevel.itemCollisionMap[byte] &= ~(0x01 << bit); + SFG_currentLevel.itemCollisionMap[byte] |= (value & 0x01) << bit; +} + +uint8_t SFG_getItemCollisionMapBit(uint8_t x, uint8_t y) +{ + uint16_t byte; + uint8_t bit; + + SFG_getItemCollisionMapIndex(x,y,&byte,&bit); + return (SFG_currentLevel.itemCollisionMap[byte] >> bit) & 0x01; +} + +#if SFG_DITHERED_SHADOW +static const uint8_t SFG_ditheringPatterns[] = +{ + 0,0,0,0, + 0,0,0,0, + + 0,0,0,0, + 0,1,0,0, + + 0,0,0,0, + 0,1,0,1, + + 1,0,1,0, + 0,1,0,0, + + 1,0,1,0, + 0,1,0,1, + + 1,0,1,0, + 0,1,1,1, + + 1,1,1,1, + 0,1,0,1, + + 1,1,1,1, + 0,1,1,1, + + 1,1,1,1, + 1,1,1,1 +}; +#endif + +/* + FUNCTIONS +=============================================================================== +*/ + +/** + Returns a pseudorandom byte. This is a very simple congrent generator, its + parameters have been chosen so that each number (0-255) is included in the + output exactly once! +*/ +uint8_t SFG_random() +{ + SFG_game.currentRandom *= 13; + SFG_game.currentRandom += 7; + + return SFG_game.currentRandom; +} + +void SFG_playGameSound(uint8_t soundIndex, uint8_t volume) +{ + if (!(SFG_game.settings & 0x01)) + return; + + uint8_t mask = 0x01 << soundIndex; + + if (!(SFG_game.soundsPlayedThisFrame & mask)) + { + SFG_playSound(soundIndex,volume); + SFG_game.soundsPlayedThisFrame |= mask; + } +} + +/** + Returns a damage value for specific attack type (SFG_WEAPON_FIRE_TYPE_...), + with added randomness (so the values will differ). For explosion pass + SFG_WEAPON_FIRE_TYPE_FIREBALL. +*/ +uint8_t SFG_getDamageValue(uint8_t attackType) +{ + if (attackType >= SFG_WEAPON_FIRE_TYPES_TOTAL) + return 0; + + int32_t value = SFG_attackDamageTable[attackType]; // has to be signed + int32_t maxAdd = (value * SFG_DAMAGE_RANDOMNESS) / 256; + + value = value + (maxAdd / 2) - (SFG_random() * maxAdd / 256); + + if (value < 0) + value = 0; + + return value; +} + +/** + Saves game data to persistent storage. +*/ +void SFG_gameSave() +{ + if (SFG_game.saved == SFG_CANT_SAVE) + return; + + SFG_LOG("saving game data"); + + SFG_save(SFG_game.save); +} + +/** + Loads game data from persistent storage. +*/ +void SFG_gameLoad() +{ + if (SFG_game.saved == SFG_CANT_SAVE) + return; + + SFG_LOG("loading game data"); + + uint8_t result = SFG_load(SFG_game.save); + + if (result == 0) + SFG_game.saved = SFG_CANT_SAVE; +} + +/** + Returns ammo type for given weapon. +*/ +uint8_t SFG_weaponAmmo(uint8_t weapon) +{ + if (weapon == SFG_WEAPON_KNIFE) + return SFG_AMMO_NONE; + if (weapon == SFG_WEAPON_MACHINE_GUN || + weapon == SFG_WEAPON_SHOTGUN) + return SFG_AMMO_BULLETS; + else if (weapon == SFG_WEAPON_ROCKET_LAUNCHER) + return SFG_AMMO_ROCKETS; + else + return SFG_AMMO_PLASMA; +} + +RCL_Unit SFG_taxicabDistance( + RCL_Unit x0, RCL_Unit y0, RCL_Unit z0, RCL_Unit x1, RCL_Unit y1, RCL_Unit z1) +{ + return (RCL_abs(x0 - x1) + RCL_abs(y0 - y1) + RCL_abs(z0 - z1)); +} + +uint8_t SFG_isInActiveDistanceFromPlayer(RCL_Unit x, RCL_Unit y, RCL_Unit z) +{ + return SFG_taxicabDistance( + x,y,z,SFG_player.camera.position.x,SFG_player.camera.position.y, + SFG_player.camera.height) <= SFG_LEVEL_ELEMENT_ACTIVE_DISTANCE; +} + +/** + Function called when a level end to compute the stats etc. +*/ +void SFG_levelEnds() +{ + SFG_currentLevel.completionTime10sOfS = (SFG_MS_PER_FRAME * + (SFG_game.frame - SFG_currentLevel.frameStart)) / 100; + + SFG_currentLevel.monstersDead = 0; + + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + if (SFG_currentLevel.monsterRecords[i].health == 0) + SFG_currentLevel.monstersDead++; + + uint32_t totalTime = SFG_SAVE_TOTAL_TIME; + + if ((SFG_currentLevel.levelNumber == 0) || (totalTime != 0)) + { + SFG_LOG("Updating save totals."); + + totalTime += SFG_currentLevel.completionTime10sOfS; + + for (uint8_t i = 0; i < 4; ++i) + { + SFG_game.save[6 + i] = totalTime % 256; + totalTime /= 256; + } + + SFG_game.save[10] += SFG_currentLevel.monstersDead % 256; + SFG_game.save[11] += SFG_currentLevel.monstersDead / 256; + } + + SFG_game.save[0] = + (SFG_game.save[0] & 0x0f) | ((SFG_currentLevel.levelNumber + 1) << 4); + + SFG_game.save[2] = SFG_player.health; + SFG_game.save[3] = SFG_player.ammo[0]; + SFG_game.save[4] = SFG_player.ammo[1]; + SFG_game.save[5] = SFG_player.ammo[2]; +} + +static inline uint8_t SFG_RCLUnitToZBuffer(RCL_Unit x) +{ + x /= (RCL_UNITS_PER_SQUARE / 8); + + uint8_t okay = x < 256; + + return okay * (x + 1) - 1; +} + +const uint8_t *SFG_getMonsterSprite( + uint8_t monsterType, uint8_t state, uint8_t frame) +{ + uint8_t index = + state == SFG_MONSTER_STATE_DEAD ? 18 : 17; + // ^ makes the compiled binary smaller compared to returning pointers directly + + if ((state != SFG_MONSTER_STATE_DYING) && (state != SFG_MONSTER_STATE_DEAD)) + switch (monsterType) + { + case SFG_LEVEL_ELEMENT_MONSTER_SPIDER: + switch (state) + { + case SFG_MONSTER_STATE_ATTACKING: index = 1; break; + case SFG_MONSTER_STATE_IDLE: index = 0; break; + default: index = frame ? 0 : 2; break; + } + break; + + case SFG_LEVEL_ELEMENT_MONSTER_WARRIOR: + index = state != SFG_MONSTER_STATE_ATTACKING ? 6 : 7; + break; + + case SFG_LEVEL_ELEMENT_MONSTER_DESTROYER: + switch (state) + { + case SFG_MONSTER_STATE_ATTACKING: index = 4; break; + case SFG_MONSTER_STATE_IDLE: index = 3; break; + default: index = frame ? 3 : 5; break; + } + break; + + case SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT: + index = state != SFG_MONSTER_STATE_ATTACKING ? 8 : 9; + break; + + case SFG_LEVEL_ELEMENT_MONSTER_ENDER: + switch (state) + { + case SFG_MONSTER_STATE_ATTACKING: index = 12; break; + case SFG_MONSTER_STATE_IDLE: index = 10; break; + default: index = frame ? 10 : 11; break; + } + break; + + case SFG_LEVEL_ELEMENT_MONSTER_TURRET: + switch (state) + { + case SFG_MONSTER_STATE_ATTACKING: index = 15; break; + case SFG_MONSTER_STATE_IDLE: index = 13; break; + default: index = frame ? 13 : 14; break; + } + break; + + case SFG_LEVEL_ELEMENT_MONSTER_EXPLODER: + default: + index = 16; + break; + } + + return SFG_monsterSprites + index * SFG_TEXTURE_STORE_SIZE; +} + +/** + Says whether given key is currently pressed (down). This should be preferred + to SFG_keyPressed(). +*/ +uint8_t SFG_keyIsDown(uint8_t key) +{ + return SFG_game.keyStates[key] != 0; +} + +/** + Says whether given key has been pressed in the current frame. +*/ +uint8_t SFG_keyJustPressed(uint8_t key) +{ + return (SFG_game.keyStates[key]) == 1; +} + +/** + Says whether a key is being repeated after being held for certain time. +*/ +uint8_t SFG_keyRepeated(uint8_t key) +{ + return + ((SFG_game.keyStates[key] >= SFG_KEY_REPEAT_DELAY_FRAMES) || + (SFG_game.keyStates[key] == 255)) && + (SFG_game.frame % SFG_KEY_REPEAT_PERIOD_FRAMES == 0); +} + +uint16_t SFG_keyRegisters(uint8_t key) +{ + return SFG_keyJustPressed(key) || SFG_keyRepeated(key); +} + +#if SFG_RESOLUTION_SCALEDOWN == 1 + #define SFG_setGamePixel SFG_setPixel +#else + +/** + Sets the game pixel (a pixel that can potentially be bigger than the screen + pixel). +*/ +static inline void SFG_setGamePixel(uint16_t x, uint16_t y, uint8_t colorIndex) +{ + uint16_t screenY = y * SFG_RESOLUTION_SCALEDOWN; + uint16_t screenX = x * SFG_RESOLUTION_SCALEDOWN; + + for (uint16_t j = screenY; j < screenY + SFG_RESOLUTION_SCALEDOWN; ++j) + for (uint16_t i = screenX; i < screenX + SFG_RESOLUTION_SCALEDOWN; ++i) + SFG_setPixel(i,j,colorIndex); +} +#endif + +void SFG_recomputePLayerDirection() +{ + SFG_player.camera.direction = + RCL_wrap(SFG_player.camera.direction,RCL_UNITS_PER_SQUARE); + + SFG_player.direction = RCL_angleToDirection(SFG_player.camera.direction); + + SFG_player.direction.x = + (SFG_player.direction.x * SFG_PLAYER_MOVE_UNITS_PER_FRAME) + / RCL_UNITS_PER_SQUARE; + + SFG_player.direction.y = + (SFG_player.direction.y * SFG_PLAYER_MOVE_UNITS_PER_FRAME) + / RCL_UNITS_PER_SQUARE; + + SFG_game.backgroundScroll = + ((SFG_player.camera.direction * 8) * SFG_GAME_RESOLUTION_Y) + / RCL_UNITS_PER_SQUARE; +} + +#if SFG_BACKGROUND_BLUR != 0 +uint8_t SFG_backgroundBlurIndex = 0; + +static const int8_t SFG_backgroundBlurOffsets[8] = + { + 0 * SFG_BACKGROUND_BLUR, + 16 * SFG_BACKGROUND_BLUR, + 7 * SFG_BACKGROUND_BLUR, + 17 * SFG_BACKGROUND_BLUR, + 1 * SFG_BACKGROUND_BLUR, + 4 * SFG_BACKGROUND_BLUR, + 15 * SFG_BACKGROUND_BLUR, + 9 * SFG_BACKGROUND_BLUR, + }; +#endif + +static inline uint8_t SFG_fogValueDiminish(RCL_Unit depth) +{ + return depth / SFG_FOG_DIMINISH_STEP; +} + +static inline uint8_t + SFG_getTexelFull(uint8_t textureIndex,RCL_Unit u, RCL_Unit v) +{ + return + SFG_getTexel( + textureIndex != 255 ? + SFG_currentLevel.textures[textureIndex] : + (SFG_wallTextures + SFG_currentLevel.levelPointer->doorTextureIndex + * SFG_TEXTURE_STORE_SIZE), u / 32, v / 32); +} + +static inline uint8_t SFG_getTexelAverage(uint8_t textureIndex) +{ + return + textureIndex != 255 ? + SFG_game.textureAverageColors[ + SFG_currentLevel.levelPointer->textureIndices[textureIndex]] + : + ( + SFG_game.textureAverageColors[ + SFG_currentLevel.levelPointer->doorTextureIndex] + + 1 // to distinguish from normal walls + ); +} + +void SFG_pixelFunc(RCL_PixelInfo *pixel) +{ + uint8_t color; + uint8_t shadow = 0; + + if (pixel->isHorizon && pixel->depth > RCL_UNITS_PER_SQUARE * 16) + { + color = SFG_TRANSPARENT_COLOR; + } + else if (pixel->isWall) + { + uint8_t textureIndex = + pixel->isFloor ? + ( + ((pixel->hit.type & SFG_TILE_PROPERTY_MASK) != SFG_TILE_PROPERTY_DOOR) ? + (pixel->hit.type & 0x7) + : + ( + (pixel->texCoords.y > RCL_UNITS_PER_SQUARE) ? + (pixel->hit.type & 0x7) : 255 + ) + ): + ((pixel->hit.type & 0x38) >> 3); + +#if SFG_TEXTURE_DISTANCE != 0 + RCL_Unit textureV = pixel->texCoords.y; + + if ((pixel->hit.type & SFG_TILE_PROPERTY_MASK) == + SFG_TILE_PROPERTY_SQUEEZER) + textureV += pixel->wallHeight; +#endif + + color = + textureIndex != SFG_TILE_TEXTURE_TRANSPARENT ? + ( +#if SFG_TEXTURE_DISTANCE >= 65535 + SFG_getTexelFull(textureIndex,pixel->texCoords.x,textureV) +#elif SFG_TEXTURE_DISTANCE == 0 + SFG_getTexelAverage(textureIndex) +#else + pixel->depth <= SFG_TEXTURE_DISTANCE ? + SFG_getTexelFull(textureIndex,pixel->texCoords.x,textureV) : + SFG_getTexelAverage(textureIndex) +#endif + ) + : + SFG_TRANSPARENT_COLOR; + + shadow = pixel->hit.direction >> 1; + } + else + { + color = pixel->isFloor ? + (SFG_currentLevel.floorColor) : + (pixel->height < SFG_CEILING_MAX_HEIGHT ? + SFG_currentLevel.ceilingColor : SFG_TRANSPARENT_COLOR); + } + + if (color != SFG_TRANSPARENT_COLOR) + { +#if SFG_DITHERED_SHADOW + uint8_t fogShadow = (pixel->depth * 8) / SFG_FOG_DIMINISH_STEP; + + uint8_t fogShadowPart = fogShadow & 0x07; + + fogShadow /= 8; + + uint8_t xMod4 = pixel->position.x & 0x03; + uint8_t yMod2 = pixel->position.y & 0x01; + + shadow += + fogShadow + SFG_ditheringPatterns[fogShadowPart * 8 + yMod2 * 4 + xMod4]; +#else + shadow += SFG_fogValueDiminish(pixel->depth); +#endif + +#if SFG_ENABLE_FOG + color = palette_minusValue(color,shadow); +#endif + } + else + { +#if SFG_DRAW_LEVEL_BACKGROUND + color = SFG_getTexel(SFG_backgroundImages + + SFG_currentLevel.backgroundImage * SFG_TEXTURE_STORE_SIZE, + SFG_game.backgroundScaleMap[((pixel->position.x + #if SFG_BACKGROUND_BLUR != 0 + + SFG_backgroundBlurOffsets[SFG_backgroundBlurIndex] + #endif + ) * SFG_RAYCASTING_SUBSAMPLE + SFG_game.backgroundScroll) % SFG_GAME_RESOLUTION_Y], + (SFG_game.backgroundScaleMap[(pixel->position.y // ^ TODO: get rid of mod? + #if SFG_BACKGROUND_BLUR != 0 + + SFG_backgroundBlurOffsets[SFG_backgroundBlurIndex + 1] + #endif + ) % SFG_GAME_RESOLUTION_Y]) + ); + + #if SFG_BACKGROUND_BLUR != 0 + SFG_backgroundBlurIndex = (SFG_backgroundBlurIndex + 1) % 8; + #endif +#else + color = 1; +#endif + } + +#if SFG_RAYCASTING_SUBSAMPLE == 1 + // the other version will probably get optimized to this, but just in case + SFG_setGamePixel(pixel->position.x,pixel->position.y,color); +#else + RCL_Unit screenX = pixel->position.x * SFG_RAYCASTING_SUBSAMPLE; + + for (int_fast8_t i = 0; i < SFG_RAYCASTING_SUBSAMPLE; ++i) + { + SFG_setGamePixel(screenX,pixel->position.y,color); + screenX++; + } +#endif +} + +/** + Draws image on screen, with transparency. This is faster than sprite drawing. + For performance sake drawing near screen edges is not pixel perfect. +*/ +void SFG_blitImage( + const uint8_t *image, + int16_t posX, + int16_t posY, + uint8_t scale) +{ + if (scale == 0) + return; + + uint16_t x0 = posX, + x1, + y0 = posY, + y1; + + uint8_t u0 = 0, v0 = 0; + + if (posX < 0) + { + x0 = 0; + u0 = (-1 * posX) / scale; + } + + posX += scale * SFG_TEXTURE_SIZE; + + uint16_t limitX = SFG_GAME_RESOLUTION_X - scale; + uint16_t limitY = SFG_GAME_RESOLUTION_Y - scale; + + x1 = posX >= 0 ? + (posX <= limitX ? posX : limitX) + : 0; + + if (x1 >= SFG_GAME_RESOLUTION_X) + x1 = SFG_GAME_RESOLUTION_X - 1; + + if (posY < 0) + { + y0 = 0; + v0 = (-1 * posY) / scale; + } + + posY += scale * SFG_TEXTURE_SIZE; + + y1 = posY >= 0 ? + (posY <= limitY ? posY : limitY) + : 0; + + if (y1 >= SFG_GAME_RESOLUTION_Y) + y1 = SFG_GAME_RESOLUTION_Y - 1; + + uint8_t v = v0; + + for (uint16_t y = y0; y < y1; y += scale) + { + uint8_t u = u0; + + for (uint16_t x = x0; x < x1; x += scale) + { + uint8_t color = SFG_getTexel(image,u,v); + + if (color != SFG_TRANSPARENT_COLOR) + { + uint16_t sY = y; + + for (uint8_t j = 0; j < scale; ++j) + { + uint16_t sX = x; + + for (uint8_t i = 0; i < scale; ++i) + { + SFG_setGamePixel(sX,sY,color); + sX++; + } + + sY++; + } + } + u++; + } + v++; + } +} + +void SFG_drawScaledSprite( + const uint8_t *image, + int16_t centerX, + int16_t centerY, + int16_t size, + uint8_t minusValue, + RCL_Unit distance) +{ + if ((size > SFG_MAX_SPRITE_SIZE) || (size == 0)) + return; + + uint16_t halfSize = size / 2; + + int16_t topLeftX = centerX - halfSize; + int16_t topLeftY = centerY - halfSize; + + int16_t x0, u0; + + if (topLeftX < 0) + { + u0 = -1 * topLeftX; + x0 = 0; + } + else + { + u0 = 0; + x0 = topLeftX; + } + + int16_t x1 = topLeftX + size - 1; + + if (x1 >= SFG_GAME_RESOLUTION_X) + x1 = SFG_GAME_RESOLUTION_X - 1; + + int16_t y0, v0; + + if (topLeftY < 0) + { + v0 = -1 * topLeftY; + y0 = 0; + } + else + { + v0 = 0; + y0 = topLeftY; + } + + int16_t y1 = topLeftY + size - 1; + + if (y1 >= SFG_GAME_RESOLUTION_Y) + y1 = SFG_GAME_RESOLUTION_Y - 1; + + if ((x0 > x1) || (y0 > y1) || (u0 >= size) || (v0 >= size)) // outside screen? + return; + + int16_t u1 = u0 + (x1 - x0); + int16_t v1 = v0 + (y1 - y0); + + // precompute sampling positions: + + int16_t uMin = RCL_min(u0,u1); + int16_t vMin = RCL_min(v0,v1); + int16_t uMax = RCL_max(u0,u1); + int16_t vMax = RCL_max(v0,v1); + + int16_t precompFrom = RCL_min(uMin,vMin); + int16_t precompTo = RCL_max(uMax,vMax); + + precompFrom = RCL_max(0,precompFrom); + precompTo = RCL_min(SFG_MAX_SPRITE_SIZE - 1,precompTo); + + #define PRECOMP_SCALE 512 + + int16_t precompStepScaled = ((SFG_TEXTURE_SIZE) * PRECOMP_SCALE) / size; + int16_t precompPosScaled = precompFrom * precompStepScaled; + + for (int16_t i = precompFrom; i <= precompTo; ++i) + { + SFG_game.spriteSamplingPoints[i] = precompPosScaled / PRECOMP_SCALE; + precompPosScaled += precompStepScaled; + } + + #undef PRECOMP_SCALE + + uint8_t zDistance = SFG_RCLUnitToZBuffer(distance); + + for (int16_t x = x0, u = u0; x <= x1; ++x, ++u) + { + if (SFG_game.zBuffer[x] >= zDistance) + { + int8_t columnTransparent = 1; + + for (int16_t y = y0, v = v0; y <= y1; ++y, ++v) + { + uint8_t color = + SFG_getTexel(image,SFG_game.spriteSamplingPoints[u], + SFG_game.spriteSamplingPoints[v]); + + if (color != SFG_TRANSPARENT_COLOR) + { +#if SFG_DIMINISH_SPRITES + color = palette_minusValue(color,minusValue); +#endif + columnTransparent = 0; + + SFG_setGamePixel(x,y,color); + } + } + + if (!columnTransparent) + SFG_game.zBuffer[x] = zDistance; + } + } +} + +RCL_Unit SFG_texturesAt(int16_t x, int16_t y) +{ + uint8_t p; + + SFG_TileDefinition tile = + SFG_getMapTile(SFG_currentLevel.levelPointer,x,y,&p); + + return + SFG_TILE_FLOOR_TEXTURE(tile) | (SFG_TILE_CEILING_TEXTURE(tile) << 3) | p; + // ^ store both textures (floor and ceiling) and properties in one number +} + +RCL_Unit SFG_movingWallHeight +( + RCL_Unit low, + RCL_Unit high, + uint32_t time +) +{ + RCL_Unit height = high - low; + RCL_Unit halfHeight = height / 2; + + RCL_Unit sinArg = + (time * ((SFG_MOVING_WALL_SPEED * RCL_UNITS_PER_SQUARE) / 1000)) / height; + + return + low + halfHeight + (RCL_sin(sinArg) * halfHeight) / RCL_UNITS_PER_SQUARE; +} + +RCL_Unit SFG_floorHeightAt(int16_t x, int16_t y) +{ + uint8_t properties; + + SFG_TileDefinition tile = + SFG_getMapTile(SFG_currentLevel.levelPointer,x,y,&properties); + + RCL_Unit doorHeight = 0; + + if (properties == SFG_TILE_PROPERTY_DOOR) + { + for (uint8_t i = 0; i < SFG_currentLevel.doorRecordCount; ++i) + { + SFG_DoorRecord *door = &(SFG_currentLevel.doorRecords[i]); + + if ((door->coords[0] == x) && (door->coords[1] == y)) + { + doorHeight = door->state & SFG_DOOR_VERTICAL_POSITION_MASK; + + doorHeight = doorHeight != (0xff & SFG_DOOR_VERTICAL_POSITION_MASK) ? + doorHeight * SFG_DOOR_HEIGHT_STEP : RCL_UNITS_PER_SQUARE; + + break; + } + } + } + else if (properties == SFG_TILE_PROPERTY_ELEVATOR) + { + RCL_Unit height = + SFG_TILE_FLOOR_HEIGHT(tile) * SFG_WALL_HEIGHT_STEP; + + return SFG_movingWallHeight( + height, + height + SFG_TILE_CEILING_HEIGHT(tile) * SFG_WALL_HEIGHT_STEP, + SFG_game.frameTime - SFG_currentLevel.timeStart); + } + + return SFG_TILE_FLOOR_HEIGHT(tile) * SFG_WALL_HEIGHT_STEP - doorHeight; +} + +/** + Like SFG_floorCollisionHeightAt, but takes into account colliding items on + the map, so the squares that have these items are higher. The former function + is for rendering, this one is for collision checking. +*/ +RCL_Unit SFG_floorCollisionHeightAt(int16_t x, int16_t y) +{ + return SFG_floorHeightAt(x,y) + + SFG_getItemCollisionMapBit(x,y) * RCL_UNITS_PER_SQUARE; +} + +void SFG_getPlayerWeaponInfo( + uint8_t *ammoType, uint8_t *projectileCount, uint8_t *canShoot) +{ + *ammoType = SFG_weaponAmmo(SFG_player.weapon); + + *projectileCount = SFG_GET_WEAPON_PROJECTILE_COUNT(SFG_player.weapon); + +#if SFG_INFINITE_AMMO + *canShoot = 1; +#else + *canShoot = + (*ammoType == SFG_AMMO_NONE || + SFG_player.ammo[*ammoType] >= *projectileCount); +#endif +} + +void SFG_playerRotateWeapon(uint8_t next) +{ + uint8_t initialWeapon = SFG_player.weapon; + int8_t increment = next ? 1 : -1; + + while (1) + { + SFG_player.weapon = + (SFG_WEAPONS_TOTAL + SFG_player.weapon + increment) % SFG_WEAPONS_TOTAL; + + if (SFG_player.weapon == initialWeapon) + break; + + uint8_t ammo, projectileCount, canShoot; + + SFG_getPlayerWeaponInfo(&ammo,&projectileCount,&canShoot); + + if (canShoot) + break; + } +} + +void SFG_initPlayer() +{ + RCL_initCamera(&SFG_player.camera); + + SFG_player.camera.resolution.x = + SFG_GAME_RESOLUTION_X / SFG_RAYCASTING_SUBSAMPLE; + + SFG_player.camera.resolution.y = SFG_GAME_RESOLUTION_Y - SFG_HUD_BAR_HEIGHT; + + SFG_player.camera.position.x = RCL_UNITS_PER_SQUARE / 2 + + SFG_currentLevel.levelPointer->playerStart[0] * RCL_UNITS_PER_SQUARE; + + SFG_player.camera.position.y = RCL_UNITS_PER_SQUARE / 2 + + SFG_currentLevel.levelPointer->playerStart[1] * RCL_UNITS_PER_SQUARE; + + SFG_player.squarePosition[0] = + SFG_player.camera.position.x / RCL_UNITS_PER_SQUARE; + + SFG_player.squarePosition[1] = + SFG_player.camera.position.y / RCL_UNITS_PER_SQUARE; + + SFG_player.camera.height = + SFG_floorHeightAt( + SFG_currentLevel.levelPointer->playerStart[0], + SFG_currentLevel.levelPointer->playerStart[1]) + + RCL_CAMERA_COLL_HEIGHT_BELOW; + + SFG_player.camera.direction = + SFG_currentLevel.levelPointer->playerStart[2] * + (RCL_UNITS_PER_SQUARE / 256); + + SFG_recomputePLayerDirection(); + + SFG_player.previousVerticalSpeed = 0; + + SFG_player.headBobFrame = 0; + + SFG_player.weapon = SFG_WEAPON_KNIFE; + + SFG_player.weaponCooldownFrames = 0; + SFG_player.lastHurtFrame = SFG_game.frame; + SFG_player.lastItemTakenFrame = SFG_game.frame; + + SFG_player.health = SFG_PLAYER_START_HEALTH; + + SFG_player.previousWeaponDirection = 0; + + SFG_player.cards = +#if SFG_UNLOCK_DOOR + 0x07; +#else + 0; +#endif + + SFG_player.justTeleported = 0; + + for (uint8_t i = 0; i < SFG_AMMO_TOTAL; ++i) + SFG_player.ammo[i] = 0; +} + +RCL_Unit SFG_ceilingHeightAt(int16_t x, int16_t y) +{ + uint8_t properties; + SFG_TileDefinition tile = + SFG_getMapTile(SFG_currentLevel.levelPointer,x,y,&properties); + + if (properties == SFG_TILE_PROPERTY_ELEVATOR) + return SFG_CEILING_MAX_HEIGHT; + + uint8_t height = SFG_TILE_CEILING_HEIGHT(tile); + + return properties != SFG_TILE_PROPERTY_SQUEEZER ? + ( + height != SFG_TILE_CEILING_MAX_HEIGHT ? + ((SFG_TILE_FLOOR_HEIGHT(tile) + height) * SFG_WALL_HEIGHT_STEP) : + SFG_CEILING_MAX_HEIGHT + ) : + SFG_movingWallHeight( + SFG_TILE_FLOOR_HEIGHT(tile) * SFG_WALL_HEIGHT_STEP, + (SFG_TILE_CEILING_HEIGHT(tile) + SFG_TILE_FLOOR_HEIGHT(tile)) + * SFG_WALL_HEIGHT_STEP, + SFG_game.frameTime - SFG_currentLevel.timeStart); +} + +/** + Gets sprite (image and sprite size) for given item. +*/ +void SFG_getItemSprite( + uint8_t elementType, const uint8_t **sprite, uint8_t *spriteSize) +{ + *spriteSize = 0; + *sprite = SFG_itemSprites + (elementType - 1) * SFG_TEXTURE_STORE_SIZE; + + switch (elementType) + { + case SFG_LEVEL_ELEMENT_TREE: + case SFG_LEVEL_ELEMENT_RUIN: + case SFG_LEVEL_ELEMENT_LAMP: + case SFG_LEVEL_ELEMENT_TELEPORTER: + *spriteSize = 2; + break; + + case SFG_LEVEL_ELEMENT_TERMINAL: + *spriteSize = 1; + break; + + case SFG_LEVEL_ELEMENT_FINISH: + case SFG_LEVEL_ELEMENT_COLUMN: + *spriteSize = 3; + break; + + case SFG_LEVEL_ELEMENT_CARD0: + case SFG_LEVEL_ELEMENT_CARD1: + case SFG_LEVEL_ELEMENT_CARD2: + *sprite = SFG_itemSprites + + (SFG_LEVEL_ELEMENT_CARD0 - 1) * SFG_TEXTURE_STORE_SIZE; + break; + + case SFG_LEVEL_ELEMENT_BLOCKER: + *sprite = 0; + break; + + default: + break; + } +} + +/** + Says whether given item type collides, i.e. stops player from moving. +*/ +uint8_t SFG_itemCollides(uint8_t elementType) +{ + return + elementType == SFG_LEVEL_ELEMENT_BARREL || + elementType == SFG_LEVEL_ELEMENT_TREE || + elementType == SFG_LEVEL_ELEMENT_TERMINAL || + elementType == SFG_LEVEL_ELEMENT_COLUMN || + elementType == SFG_LEVEL_ELEMENT_RUIN || + elementType == SFG_LEVEL_ELEMENT_BLOCKER || + elementType == SFG_LEVEL_ELEMENT_LAMP; +} + +void SFG_setGameState(uint8_t state) +{ + SFG_LOG("changing game state"); + SFG_game.state = state; + SFG_game.stateChangeTime = SFG_game.frameTime; +} + +void SFG_setAndInitLevel(uint8_t levelNumber) +{ + SFG_LOG("setting and initializing level"); + + const SFG_Level *level; + +#if SFG_ARDUINO + memcpy_P(&SFG_ramLevel,SFG_levels[levelNumber],sizeof(SFG_Level)); + level = &SFG_ramLevel; +#else + level = SFG_levels[levelNumber]; +#endif + + SFG_game.currentRandom = 0; + + if (SFG_game.saved != SFG_CANT_SAVE) + SFG_game.saved = 0; + + SFG_currentLevel.levelNumber = levelNumber; + SFG_currentLevel.monstersDead = 0; + SFG_currentLevel.backgroundImage = level->backgroundImage; + SFG_currentLevel.levelPointer = level; + SFG_currentLevel.bossCount = 0; + SFG_currentLevel.floorColor = level->floorColor; + SFG_currentLevel.ceilingColor = level->ceilingColor; + SFG_currentLevel.completionTime10sOfS = 0; + + for (uint8_t i = 0; i < 7; ++i) + SFG_currentLevel.textures[i] = + SFG_wallTextures + level->textureIndices[i] * SFG_TEXTURE_STORE_SIZE; + + SFG_LOG("initializing doors"); + + SFG_currentLevel.checkedDoorIndex = 0; + SFG_currentLevel.doorRecordCount = 0; + SFG_currentLevel.projectileRecordCount = 0; + SFG_currentLevel.teleporterCount = 0; + SFG_currentLevel.mapRevealMask = +#if SFG_REVEAL_MAP + 0xffff; +#else + 0; +#endif + + for (uint8_t j = 0; j < SFG_MAP_SIZE; ++j) + { + for (uint8_t i = 0; i < SFG_MAP_SIZE; ++i) + { + uint8_t properties; + + SFG_getMapTile(level,i,j,&properties); + + if ((properties & SFG_TILE_PROPERTY_MASK) == SFG_TILE_PROPERTY_DOOR) + { + SFG_DoorRecord *d = + &(SFG_currentLevel.doorRecords[SFG_currentLevel.doorRecordCount]); + + d->coords[0] = i; + d->coords[1] = j; + d->state = 0x00; + + SFG_currentLevel.doorRecordCount++; + } + + if (SFG_currentLevel.doorRecordCount >= SFG_MAX_DOORS) + { + SFG_LOG("warning: too many doors!"); + break; + } + } + + if (SFG_currentLevel.doorRecordCount >= SFG_MAX_DOORS) + break; + } + + SFG_LOG("initializing level elements"); + + SFG_currentLevel.itemRecordCount = 0; + SFG_currentLevel.checkedItemIndex = 0; + + SFG_currentLevel.monsterRecordCount = 0; + SFG_currentLevel.checkedMonsterIndex = 0; + + SFG_MonsterRecord *monster; + + for (uint16_t i = 0; i < ((SFG_MAP_SIZE * SFG_MAP_SIZE) / 8); ++i) + SFG_currentLevel.itemCollisionMap[i] = 0; + + for (uint8_t i = 0; i < SFG_MAX_LEVEL_ELEMENTS; ++i) + { + const SFG_LevelElement *e = &(SFG_currentLevel.levelPointer->elements[i]); + + if (e->type != SFG_LEVEL_ELEMENT_NONE) + { + if (SFG_LEVEL_ELEMENT_TYPE_IS_MOSTER(e->type)) + { + monster = + &(SFG_currentLevel.monsterRecords[SFG_currentLevel.monsterRecordCount]); + + monster->stateType = (SFG_MONSTER_TYPE_TO_INDEX(e->type) << 4) + | SFG_MONSTER_STATE_INACTIVE; + + monster->health = + SFG_GET_MONSTER_MAX_HEALTH(SFG_MONSTER_TYPE_TO_INDEX(e->type)); + + monster->coords[0] = e->coords[0] * 4 + 2; + monster->coords[1] = e->coords[1] * 4 + 2; + + SFG_currentLevel.monsterRecordCount++; + + if (e->type == SFG_LEVEL_ELEMENT_MONSTER_ENDER) + SFG_currentLevel.bossCount++; + } + else if ((e->type < SFG_LEVEL_ELEMENT_LOCK0) || + (e->type > SFG_LEVEL_ELEMENT_LOCK2)) + { + SFG_currentLevel.itemRecords[SFG_currentLevel.itemRecordCount] = i; + SFG_currentLevel.itemRecordCount++; + + if (e->type == SFG_LEVEL_ELEMENT_TELEPORTER) + SFG_currentLevel.teleporterCount++; + + if (SFG_itemCollides(e->type)) + SFG_setItemCollisionMapBit(e->coords[0],e->coords[1],1); + } + else + { + uint8_t properties; + + SFG_getMapTile(level,e->coords[0],e->coords[1],&properties); + + if ((properties & SFG_TILE_PROPERTY_MASK) == SFG_TILE_PROPERTY_DOOR) + { + // find the door record and lock the door: + for (uint16_t j = 0; j < SFG_currentLevel.doorRecordCount; ++j) + { + SFG_DoorRecord *d = &(SFG_currentLevel.doorRecords[j]); + + if (d->coords[0] == e->coords[0] && d->coords[1] == e->coords[1]) + { + d->state |= (e->type - SFG_LEVEL_ELEMENT_LOCK0 + 1) << 6; + break; + } + } + } + else + { + SFG_LOG("warning: lock not put on door tile!"); + } + } + } + } + + SFG_currentLevel.timeStart = SFG_game.frameTime; + SFG_currentLevel.frameStart = SFG_game.frame; + + SFG_game.spriteAnimationFrame = 0; + + SFG_initPlayer(); + SFG_setGameState(SFG_GAME_STATE_LEVEL_START); + SFG_setMusic(SFG_MUSIC_NEXT); + SFG_processEvent(SFG_EVENT_LEVEL_STARTS,levelNumber); +} + +void SFG_init() +{ + SFG_LOG("initializing game") + + SFG_game.frame = 0; + SFG_game.frameTime = 0; + SFG_game.currentRandom = 0; + SFG_game.continues = 1; + + RCL_initRayConstraints(&SFG_game.rayConstraints); + SFG_game.rayConstraints.maxHits = SFG_RAYCASTING_MAX_HITS; + SFG_game.rayConstraints.maxSteps = SFG_RAYCASTING_MAX_STEPS; + + SFG_game.antiSpam = 0; + + SFG_LOG("computing average texture colors") + + for (uint8_t i = 0; i < SFG_WALL_TEXTURE_COUNT; ++i) + { + /** For simplicity, we round colors so that there is only 64 of them, and + we count them up to 256. */ + + uint8_t colorHistogram[64]; + + for (uint8_t j = 0; j < 64; ++j) + colorHistogram[j] = 0; + + for (uint8_t y = 0; y < SFG_TEXTURE_SIZE; ++y) + for (uint8_t x = 0; x < SFG_TEXTURE_SIZE; ++x) + { + uint8_t color = + SFG_getTexel(SFG_wallTextures + i * SFG_TEXTURE_STORE_SIZE,x,y) / 4; + + colorHistogram[color] += 1; + + if (colorHistogram[color] == 255) + break; + } + + uint8_t maxIndex = 0; + + for (uint8_t j = 0; j < 64; ++j) + { + if (colorHistogram[j] == 255) + { + maxIndex = j; + break; + } + + if (colorHistogram[j] > colorHistogram[maxIndex]) + maxIndex = j; + } + + SFG_game.textureAverageColors[i] = maxIndex * 4; + } + + for (uint16_t i = 0; i < SFG_GAME_RESOLUTION_Y; ++i) + SFG_game.backgroundScaleMap[i] = + (i * SFG_TEXTURE_SIZE) / SFG_GAME_RESOLUTION_Y; + + for (uint8_t i = 0; i < SFG_KEY_COUNT; ++i) + SFG_game.keyStates[i] = 0; + + SFG_game.backgroundScroll = 0; + SFG_currentLevel.levelPointer = 0; + SFG_game.selectedMenuItem = 0; + SFG_game.selectedLevel = 0; + SFG_game.settings = 0x03; + SFG_game.saved = 0; + + // create a default save data: + + for (uint16_t i = 0; i < SFG_SAVE_SIZE; ++i) + SFG_game.save[i] = 0; + + SFG_game.save[0] = 0; + SFG_game.save[1] = SFG_game.settings; + + SFG_gameLoad(); // attempt to load settings + + if (SFG_game.saved != SFG_CANT_SAVE) + { + SFG_LOG("settings loaded"); + SFG_game.settings = SFG_game.save[1]; + } + else + { + SFG_LOG("saving/loading not possible"); + SFG_game.save[0] = (SFG_NUMBER_OF_LEVELS - 1) | 0xf0; // revealed all levels + } + + SFG_setMusic((SFG_game.settings & 0x02) ? + SFG_MUSIC_TURN_ON : SFG_MUSIC_TURN_OFF); + +#if SFG_START_LEVEL == 0 + SFG_setGameState(SFG_GAME_STATE_INIT); +#else + SFG_setAndInitLevel(SFG_START_LEVEL - 1); +#endif +} + +/** + Adds new projectile to the current level, return 1 if added, 0 if not (max + count reached). +*/ +uint8_t SFG_createProjectile(SFG_ProjectileRecord projectile) +{ + if (SFG_currentLevel.projectileRecordCount >= SFG_MAX_PROJECTILES) + return 0; + + SFG_currentLevel.projectileRecords[SFG_currentLevel.projectileRecordCount] = + projectile; + + SFG_currentLevel.projectileRecordCount++; + + return 1; +} + +/** + Launches projectile of given type from given position in given direction + (has to be normalized), with given offset (so as to not collide with the + shooting entity). Returns the same value as SFG_createProjectile. +*/ +uint8_t SFG_launchProjectile( + uint8_t type, + RCL_Vector2D shootFrom, + RCL_Unit shootFromHeight, + RCL_Vector2D direction, + RCL_Unit verticalSpeed, + RCL_Unit offsetDistance + ) +{ + if (type == SFG_PROJECTILE_NONE) + return 0; + + SFG_ProjectileRecord p; + + p.type = type; + p.doubleFramesToLive = + RCL_nonZero(SFG_GET_PROJECTILE_FRAMES_TO_LIVE(type) / 2); + + p.position[0] = + shootFrom.x + (direction.x * offsetDistance) / RCL_UNITS_PER_SQUARE; + p.position[1] = + shootFrom.y + (direction.y * offsetDistance) / RCL_UNITS_PER_SQUARE; + p.position[2] = shootFromHeight; + + p.direction[0] = + (direction.x * SFG_GET_PROJECTILE_SPEED_UPS(type)) / RCL_UNITS_PER_SQUARE; + p.direction[1] = + (direction.y * SFG_GET_PROJECTILE_SPEED_UPS(type)) / RCL_UNITS_PER_SQUARE; + p.direction[2] = verticalSpeed; + + return SFG_createProjectile(p); +} + +/** + Pushes a given position away from a center by given distance, with collisions. + Returns 1 if push away happened, otherwise 0. +*/ +uint8_t SFG_pushAway( + RCL_Unit pos[3], + RCL_Unit centerX, + RCL_Unit centerY, + RCL_Unit preferredDirection, + RCL_Unit distance) +{ + RCL_Vector2D fromCenter; + + fromCenter.x = pos[0] - centerX; + fromCenter.y = pos[1] - centerY; + + RCL_Unit l = RCL_len(fromCenter); + + if (l < 128) + { + fromCenter = RCL_angleToDirection(preferredDirection); + l = RCL_UNITS_PER_SQUARE; + } + + RCL_Vector2D offset; + + offset.x = (fromCenter.x * distance) / l; + offset.y = (fromCenter.y * distance) / l; + + RCL_Camera c; + + RCL_initCamera(&c); + + c.position.x = pos[0]; + c.position.y = pos[1]; + c.height = pos[2]; + + RCL_moveCameraWithCollision(&c,offset,0,SFG_floorCollisionHeightAt, + SFG_ceilingHeightAt,1,1); + + pos[0] = c.position.x; + pos[1] = c.position.y; + pos[2] = c.height; + + return 1; +} + +uint8_t SFG_pushPlayerAway( + RCL_Unit centerX, RCL_Unit centerY, RCL_Unit distance) +{ + RCL_Unit p[3]; + + p[0] = SFG_player.camera.position.x; + p[1] = SFG_player.camera.position.y; + p[2] = SFG_player.camera.height; + + uint8_t result = SFG_pushAway(p,centerX,centerY, + SFG_player.camera.direction - RCL_UNITS_PER_SQUARE / 2, + distance); + + SFG_player.camera.position.x = p[0]; + SFG_player.camera.position.y = p[1]; + SFG_player.camera.height = p[2]; + + return result; +} + +/** + Helper function to resolve collision with level element. The function supposes + the collision already does happen and only resolves it. Returns adjusted move + offset. +*/ +RCL_Vector2D SFG_resolveCollisionWithElement( + RCL_Vector2D position, RCL_Vector2D moveOffset, RCL_Vector2D elementPos) +{ + RCL_Unit dx = RCL_abs(elementPos.x - position.x); + RCL_Unit dy = RCL_abs(elementPos.y - position.y); + + if (dx > dy) + { + // colliding from left/right + + if ((moveOffset.x > 0) == (position.x < elementPos.x)) + moveOffset.x = 0; + // ^ only stop if heading towards element, to avoid getting stuck + } + else + { + // colliding from up/down + + if ((moveOffset.y > 0) == (position.y < elementPos.y)) + moveOffset.y = 0; + } + + return moveOffset; +} + +/** + Adds or substracts player's health during the playing state due to taking + damage (negative value) or getting healed. Negative value will be corrected by + SFG_PLAYER_DAMAGE_MULTIPLIER in this function. +*/ +void SFG_playerChangeHealth(int8_t healthAdd) +{ + if (SFG_game.state != SFG_GAME_STATE_PLAYING) + return; // don't hurt during level starting phase + + if (healthAdd < 0) + { + healthAdd = + RCL_min(-1, + (((RCL_Unit) healthAdd) * SFG_PLAYER_DAMAGE_MULTIPLIER) / + RCL_UNITS_PER_SQUARE); + + SFG_player.lastHurtFrame = SFG_game.frame; + SFG_processEvent(SFG_EVENT_VIBRATE,0); + SFG_processEvent(SFG_EVENT_PLAYER_HURT,-1 * healthAdd); + } + + int16_t health = SFG_player.health; + health += healthAdd; + health = RCL_clamp(health,0,SFG_PLAYER_MAX_HEALTH); + + SFG_player.health = health; +} + +uint8_t SFG_distantSoundVolume(RCL_Unit x, RCL_Unit y, RCL_Unit z) +{ + RCL_Unit distance = SFG_taxicabDistance(x,y,z, + SFG_player.camera.position.x, + SFG_player.camera.position.y, + SFG_player.camera.height); + + if (distance >= SFG_SFX_MAX_DISTANCE) + return 0; + + uint32_t result = 255 - (distance * 255) / SFG_SFX_MAX_DISTANCE; + + return (result * result) / 256; +} + +/** + Same as SFG_playerChangeHealth but for monsters. +*/ +void SFG_monsterChangeHealth(SFG_MonsterRecord *monster, int8_t healthAdd) +{ + int16_t health = monster->health; + + health += healthAdd; + health = RCL_clamp(health,0,255); + monster->health = health; + + if (healthAdd < 0) + { + // play hurt sound + + uint8_t volume = SFG_distantSoundVolume( + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]), + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]), + SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1]))); + + SFG_playGameSound(5,volume); + + if (monster->health == 0) + SFG_playGameSound(2,volume); + } +} + +void SFG_removeItem(uint8_t index) +{ + SFG_LOG("removing item"); + + for (uint16_t j = index; j < SFG_currentLevel.itemRecordCount - 1; ++j) + SFG_currentLevel.itemRecords[j] = + SFG_currentLevel.itemRecords[j + 1]; + + SFG_currentLevel.itemRecordCount--; +} + +/** + Helper function, returns a pointer to level element representing item with + given index, but only if the item is active (otherwise 0 is returned). +*/ +static inline const SFG_LevelElement *SFG_getActiveItemElement(uint8_t index) +{ + SFG_ItemRecord item = SFG_currentLevel.itemRecords[index]; + + if ((item & SFG_ITEM_RECORD_ACTIVE_MASK) == 0) + return 0; + + return &(SFG_currentLevel.levelPointer->elements[item & + ~SFG_ITEM_RECORD_ACTIVE_MASK]); +} + +static inline const SFG_LevelElement *SFG_getLevelElement(uint8_t index) +{ + SFG_ItemRecord item = SFG_currentLevel.itemRecords[index]; + + return &(SFG_currentLevel.levelPointer->elements[item & + ~SFG_ITEM_RECORD_ACTIVE_MASK]); +} + +void SFG_createExplosion(RCL_Unit, RCL_Unit, RCL_Unit); // forward decl + +void SFG_explodeBarrel(uint8_t itemIndex, RCL_Unit x, RCL_Unit y, RCL_Unit z) +{ + const SFG_LevelElement *e = SFG_getLevelElement(itemIndex); + SFG_setItemCollisionMapBit(e->coords[0],e->coords[1],0); + SFG_removeItem(itemIndex); + SFG_createExplosion(x,y,z); +} + +void SFG_createExplosion(RCL_Unit x, RCL_Unit y, RCL_Unit z) +{ + SFG_ProjectileRecord explosion; + + SFG_playGameSound(2,SFG_distantSoundVolume(x,y,z)); + SFG_processEvent(SFG_EVENT_EXPLOSION,0); + + explosion.type = SFG_PROJECTILE_EXPLOSION; + + explosion.position[0] = x; + explosion.position[1] = y; + explosion.position[2] = z; + + explosion.direction[0] = 0; + explosion.direction[1] = 0; + explosion.direction[2] = 0; + + explosion.doubleFramesToLive = RCL_nonZero( + SFG_GET_PROJECTILE_FRAMES_TO_LIVE(SFG_PROJECTILE_EXPLOSION) / 2); + + SFG_createProjectile(explosion); + + uint8_t damage = SFG_getDamageValue(SFG_WEAPON_FIRE_TYPE_FIREBALL); + + if (SFG_taxicabDistance(x,y,z,SFG_player.camera.position.x, + SFG_player.camera.position.y,SFG_player.camera.height) + <= SFG_EXPLOSION_RADIUS) + { + SFG_playerChangeHealth(-1 * damage); + SFG_pushPlayerAway(x,y,SFG_EXPLOSION_PUSH_AWAY_DISTANCE); + } + + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + { + SFG_MonsterRecord *monster = &(SFG_currentLevel.monsterRecords[i]); + + uint16_t state = SFG_MR_STATE(*monster); + + if ((state == SFG_MONSTER_STATE_INACTIVE) || + (state == SFG_MONSTER_STATE_DEAD)) + continue; + + RCL_Unit monsterHeight = + SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1])) + + RCL_UNITS_PER_SQUARE / 2; + + if (SFG_taxicabDistance( + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]), + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]),monsterHeight, + x,y,z) <= SFG_EXPLOSION_RADIUS) + { + SFG_monsterChangeHealth(monster, + -1 * SFG_getDamageValue(SFG_WEAPON_FIRE_TYPE_FIREBALL)); + } + } + + // explode nearby barrels + + if (damage >= SFG_BARREL_EXPLOSION_DAMAGE_THRESHOLD) + for (uint16_t i = 0; i < SFG_currentLevel.itemRecordCount; ++i) + { + SFG_ItemRecord item = SFG_currentLevel.itemRecords[i]; + + /* We DON'T check just active barrels but all, otherwise it looks weird + that out of sight barrels in a line didn't explode.*/ + + SFG_LevelElement element = SFG_ITEM_RECORD_LEVEL_ELEMENT(item); + + if (element.type != SFG_LEVEL_ELEMENT_BARREL) + continue; + + RCL_Unit elementX = + element.coords[0] * RCL_UNITS_PER_SQUARE + RCL_UNITS_PER_SQUARE / 2; + + RCL_Unit elementY = + element.coords[1] * RCL_UNITS_PER_SQUARE + RCL_UNITS_PER_SQUARE / 2; + + RCL_Unit elementHeight = + SFG_floorHeightAt(element.coords[0],element.coords[1]); + + if (SFG_taxicabDistance( + x,y,z,elementX,elementY,elementHeight) <= SFG_EXPLOSION_RADIUS) + { + SFG_explodeBarrel(i,elementX,elementY,elementHeight); + i--; + } + } +} + +void SFG_createDust(RCL_Unit x, RCL_Unit y, RCL_Unit z) +{ + SFG_ProjectileRecord dust; + + dust.type = SFG_PROJECTILE_DUST; + + dust.position[0] = x; + dust.position[1] = y; + dust.position[2] = z; + + dust.direction[0] = 0; + dust.direction[1] = 0; + dust.direction[2] = 0; + + dust.doubleFramesToLive = + RCL_nonZero(SFG_GET_PROJECTILE_FRAMES_TO_LIVE(SFG_PROJECTILE_DUST) / 2); + + SFG_createProjectile(dust); +} + +void SFG_getMonsterWorldPosition(SFG_MonsterRecord *monster, RCL_Unit *x, + RCL_Unit *y, RCL_Unit *z) +{ + *x = SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]); + *y = SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]); + *z = SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1])) + + RCL_UNITS_PER_SQUARE / 2; +} + +void SFG_monsterPerformAI(SFG_MonsterRecord *monster) +{ + uint8_t state = SFG_MR_STATE(*monster); + uint8_t type = SFG_MR_TYPE(*monster); + uint8_t monsterNumber = SFG_MONSTER_TYPE_TO_INDEX(type); + uint8_t attackType = SFG_GET_MONSTER_ATTACK_TYPE(monsterNumber); + + int8_t coordAdd[2]; + + coordAdd[0] = 0; + coordAdd[1] = 0; + + uint8_t notRanged = + (attackType == SFG_MONSTER_ATTACK_MELEE) || + (attackType == SFG_MONSTER_ATTACK_EXPLODE); + + uint8_t monsterSquare[2] = + { + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1]) + }; + + RCL_Unit currentHeight = + SFG_floorCollisionHeightAt(monsterSquare[0],monsterSquare[1]); + + if ( // sometimes randomly attack + !notRanged && + (SFG_random() < + SFG_GET_MONSTER_AGGRESSIVITY(SFG_MONSTER_TYPE_TO_INDEX(type))) + ) + { + if (SFG_random() % 4 != 0) + { + // attack + + state = SFG_MONSTER_STATE_ATTACKING; + + if (type != SFG_LEVEL_ELEMENT_MONSTER_WARRIOR) + { + RCL_Vector2D pos; + RCL_Vector2D dir; + + pos.x = SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]); + pos.y = SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]); + + dir.x = SFG_player.camera.position.x - pos.x + - 128 * SFG_MONSTER_AIM_RANDOMNESS + + SFG_random() * SFG_MONSTER_AIM_RANDOMNESS; + + dir.y = SFG_player.camera.position.y - pos.y + - 128 * SFG_MONSTER_AIM_RANDOMNESS + + SFG_random() * SFG_MONSTER_AIM_RANDOMNESS; + + dir = RCL_normalize(dir); + + uint8_t projectile; + + switch (SFG_GET_MONSTER_ATTACK_TYPE(monsterNumber)) + { + case SFG_MONSTER_ATTACK_FIREBALL: + projectile = SFG_PROJECTILE_FIREBALL; + break; + + case SFG_MONSTER_ATTACK_BULLET: + projectile = SFG_PROJECTILE_BULLET; + break; + + case SFG_MONSTER_ATTACK_PLASMA: + projectile = SFG_PROJECTILE_PLASMA; + break; + + case SFG_MONSTER_ATTACK_FIREBALL_BULLET: + projectile = (SFG_random() < 128) ? + SFG_PROJECTILE_FIREBALL : + SFG_PROJECTILE_BULLET; + break; + + case SFG_MONSTER_ATTACK_FIREBALL_PLASMA: + projectile = (SFG_random() < 128) ? + SFG_PROJECTILE_FIREBALL : + SFG_PROJECTILE_PLASMA; + break; + + default: + projectile = SFG_PROJECTILE_NONE; + break; + } + + if (projectile == SFG_PROJECTILE_BULLET) + SFG_playGameSound(0, + SFG_distantSoundVolume( + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]), + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]), + currentHeight) + ); + + SFG_launchProjectile( + projectile, + pos, + currentHeight + RCL_UNITS_PER_SQUARE / 2, + dir, + 0, + SFG_PROJECTILE_SPAWN_OFFSET + ); + } + } + else + state = SFG_MONSTER_STATE_IDLE; + } + else if (state == SFG_MONSTER_STATE_IDLE) + { + if (notRanged) + { + // non-ranged monsters walk towards player + + RCL_Unit pX, pY, pZ; + SFG_getMonsterWorldPosition(monster,&pX,&pY,&pZ); + + uint8_t isClose = // close to player? + SFG_taxicabDistance(pX,pY,pZ, + SFG_player.camera.position.x, + SFG_player.camera.position.y, + SFG_player.camera.height) <= SFG_MELEE_RANGE; + + if (!isClose) + { + // walk towards player + + if (monsterSquare[0] > SFG_player.squarePosition[0]) + { + if (monsterSquare[1] > SFG_player.squarePosition[1]) + state = SFG_MONSTER_STATE_GOING_NW; + else if (monsterSquare[1] < SFG_player.squarePosition[1]) + state = SFG_MONSTER_STATE_GOING_SW; + else + state = SFG_MONSTER_STATE_GOING_W; + } + else if (monsterSquare[0] < SFG_player.squarePosition[0]) + { + if (monsterSquare[1] > SFG_player.squarePosition[1]) + state = SFG_MONSTER_STATE_GOING_NE; + else if (monsterSquare[1] < SFG_player.squarePosition[1]) + state = SFG_MONSTER_STATE_GOING_SE; + else + state = SFG_MONSTER_STATE_GOING_E; + } + else + { + if (monsterSquare[1] > SFG_player.squarePosition[1]) + state = SFG_MONSTER_STATE_GOING_N; + else if (monsterSquare[1] < SFG_player.squarePosition[1]) + state = SFG_MONSTER_STATE_GOING_S; + } + } + else // is close + { + // melee, close-up attack + + if (attackType == SFG_MONSTER_ATTACK_MELEE) + { + // melee attack + + state = SFG_MONSTER_STATE_ATTACKING; + + SFG_playerChangeHealth( + -1 * SFG_getDamageValue(SFG_WEAPON_FIRE_TYPE_MELEE)); + + SFG_playGameSound(3,255); + } + else // SFG_MONSTER_ATTACK_EXPLODE + { + // explode + + SFG_createExplosion(pX,pY,pZ); + monster->health = 0; + } + } + } + else // ranged monsters + { + // choose walk direction randomly + + switch (SFG_random() % 8) + { + case 0: state = SFG_MONSTER_STATE_GOING_E; break; + case 1: state = SFG_MONSTER_STATE_GOING_W; break; + case 2: state = SFG_MONSTER_STATE_GOING_N; break; + case 3: state = SFG_MONSTER_STATE_GOING_S; break; + case 4: state = SFG_MONSTER_STATE_GOING_NE; break; + case 5: state = SFG_MONSTER_STATE_GOING_NW; break; + case 6: state = SFG_MONSTER_STATE_GOING_SE; break; + case 7: state = SFG_MONSTER_STATE_GOING_SW; break; + default: break; + } + } + } + else if (state == SFG_MONSTER_STATE_ATTACKING) + { + state = SFG_MONSTER_STATE_IDLE; + } + else + { + int8_t add = 1; + + if (attackType == SFG_MONSTER_ATTACK_MELEE) + add = 2; + else if (attackType == SFG_MONSTER_ATTACK_EXPLODE) + add = 3; + + if (state == SFG_MONSTER_STATE_GOING_E || + state == SFG_MONSTER_STATE_GOING_NE || + state == SFG_MONSTER_STATE_GOING_SE) + coordAdd[0] = add; + else if (state == SFG_MONSTER_STATE_GOING_W || + state == SFG_MONSTER_STATE_GOING_SW || + state == SFG_MONSTER_STATE_GOING_NW) + coordAdd[0] = -1 * add; + + if (state == SFG_MONSTER_STATE_GOING_N || + state == SFG_MONSTER_STATE_GOING_NE || + state == SFG_MONSTER_STATE_GOING_NW) + coordAdd[1] = -1 * add; + else if (state == SFG_MONSTER_STATE_GOING_S || + state == SFG_MONSTER_STATE_GOING_SE || + state == SFG_MONSTER_STATE_GOING_SW) + coordAdd[1] = add; + + if ((coordAdd[0] != 0 || coordAdd[1] != 0) && SFG_random() < + SFG_MONSTER_SOUND_PROBABILITY) + SFG_playGameSound(5, + SFG_distantSoundVolume( + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]), + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]), + currentHeight) / 2); + + state = SFG_MONSTER_STATE_IDLE; + } + + int16_t newPos[2]; + + newPos[0] = monster->coords[0] + coordAdd[0]; + newPos[1] = monster->coords[1] + coordAdd[1]; + + int8_t collision = 0; + + if (newPos[0] < 0 || newPos[0] >= 256 || newPos[1] < 0 || newPos[1] >= 256) + { + collision = 1; + } + else + { + uint8_t movingDiagonally = (coordAdd[0] != 0) && (coordAdd[1] != 0); + + // when moving diagonally, we need to check extra tiles + + for (uint8_t i = 0; i < (1 + movingDiagonally); ++i) + { + newPos[0] = monster->coords[0] + (i != 1) * coordAdd[0]; + + RCL_Unit newHeight = + SFG_floorCollisionHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(newPos[0]), + SFG_MONSTER_COORD_TO_SQUARES(newPos[1])); + + collision = + RCL_abs(currentHeight - newHeight) > RCL_CAMERA_COLL_STEP_HEIGHT; + + if (!collision) + collision = (SFG_ceilingHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(newPos[0]), + SFG_MONSTER_COORD_TO_SQUARES(newPos[1])) - newHeight) < + SFG_MONSTER_COLLISION_HEIGHT; + + if (collision) + break; + } + + newPos[0] = monster->coords[0] + coordAdd[0]; + } + + if (collision) + { + state = SFG_MONSTER_STATE_IDLE; + // ^ will force the monster to choose random direction in the next update + + newPos[0] = monster->coords[0]; + newPos[1] = monster->coords[1]; + } + + monster->stateType = state | (monsterNumber << 4); + monster->coords[0] = newPos[0]; + monster->coords[1] = newPos[1];; +} + +static inline uint8_t SFG_elementCollides( + RCL_Unit pointX, + RCL_Unit pointY, + RCL_Unit pointZ, + RCL_Unit elementX, + RCL_Unit elementY, + RCL_Unit elementHeight +) +{ + return + SFG_taxicabDistance(pointX,pointY,pointZ,elementX,elementY,elementHeight) + <= SFG_ELEMENT_COLLISION_RADIUS; +} + +/** + Checks collision of a projectile with level element at given position. +*/ +uint8_t SFG_projectileCollides(SFG_ProjectileRecord *projectile, + RCL_Unit x, RCL_Unit y, RCL_Unit z) +{ + if (!SFG_elementCollides(x,y,z, + projectile->position[0],projectile->position[1],projectile->position[2])) + return 0; + + if ((projectile->type == SFG_PROJECTILE_EXPLOSION) || + (projectile->type == SFG_PROJECTILE_DUST)) + return 0; + + /* For directional projectiles we only register a collision if its direction + is "towards" the element so that the shooter doesn't get shot by his own + projectile. */ + + RCL_Vector2D projDir, toElement; + + projDir.x = projectile->direction[0]; + projDir.y = projectile->direction[1]; + + toElement.x = x - projectile->position[0]; + toElement.y = y - projectile->position[1]; + + return RCL_vectorsAngleCos(projDir,toElement) >= 0; +} + +/** + Updates a frame of the currently loaded level, i.e. enemies, projectiles, + aimations etc., with the exception of player. +*/ +void SFG_updateLevel() +{ + // update projectiles: + + uint8_t substractFrames = + ((SFG_game.frame - SFG_currentLevel.frameStart) & 0x01) ? 1 : 0; + /* ^ only substract frames to live every other frame because a maximum of + 256 frames would be too few */ + + for (int8_t i = 0; i < SFG_currentLevel.projectileRecordCount; ++i) + { // ^ has to be signed + SFG_ProjectileRecord *p = &(SFG_currentLevel.projectileRecords[i]); + + uint8_t attackType = 255; + + if (p->type == SFG_PROJECTILE_BULLET) + attackType = SFG_WEAPON_FIRE_TYPE_BULLET; + else if (p->type == SFG_PROJECTILE_PLASMA) + attackType = SFG_WEAPON_FIRE_TYPE_PLASMA; + + RCL_Unit pos[3] = {0,0,0}; /* we have to convert from uint16_t because of + under/overflows */ + uint8_t eliminate = 0; + + for (uint8_t j = 0; j < 3; ++j) + { + pos[j] = p->position[j]; + pos[j] += p->direction[j]; + + if ( // projectile outside map? + (pos[j] < 0) || + (pos[j] >= (SFG_MAP_SIZE * RCL_UNITS_PER_SQUARE))) + { + eliminate = 1; + break; + } + } + + if (p->doubleFramesToLive == 0) // no more time to live? + { + eliminate = 1; + } + else if ( + (p->type != SFG_PROJECTILE_EXPLOSION) && + (p->type != SFG_PROJECTILE_DUST)) + { + if (SFG_projectileCollides( // collides with player? + p, + SFG_player.camera.position.x, + SFG_player.camera.position.y, + SFG_player.camera.height)) + { + eliminate = 1; + + SFG_playerChangeHealth(-1 * SFG_getDamageValue(attackType)); + } + + /* Check collision with the map (we don't use SFG_floorCollisionHeightAt + because collisions with items have to be done differently for + projectiles). */ + + if (!eliminate && + ((SFG_floorHeightAt(pos[0] / RCL_UNITS_PER_SQUARE,pos[1] / + RCL_UNITS_PER_SQUARE) >= pos[2]) + || + (SFG_ceilingHeightAt(pos[0] / RCL_UNITS_PER_SQUARE,pos[1] / + RCL_UNITS_PER_SQUARE) <= pos[2])) + ) + eliminate = 1; + + // check collision with active level elements + + if (!eliminate) // monsters + for (uint16_t j = 0; j < SFG_currentLevel.monsterRecordCount; ++j) + { + SFG_MonsterRecord *m = &(SFG_currentLevel.monsterRecords[j]); + + uint8_t state = SFG_MR_STATE(*m); + + if ((state != SFG_MONSTER_STATE_INACTIVE) && + (state != SFG_MONSTER_STATE_DEAD)) + { + if (SFG_projectileCollides(p, + SFG_MONSTER_COORD_TO_RCL_UNITS(m->coords[0]), + SFG_MONSTER_COORD_TO_RCL_UNITS(m->coords[1]), + SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(m->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(m->coords[1])) + )) + { + eliminate = 1; + SFG_monsterChangeHealth(m,-1 * SFG_getDamageValue(attackType)); + break; + } + } + } + + if (!eliminate) // items (can't check itemCollisionMap because of barrels) + for (uint16_t j = 0; j < SFG_currentLevel.itemRecordCount; ++j) + { + const SFG_LevelElement *e = SFG_getActiveItemElement(j); + + if (e != 0 && SFG_itemCollides(e->type)) + { + RCL_Unit x = SFG_ELEMENT_COORD_TO_RCL_UNITS(e->coords[0]); + RCL_Unit y = SFG_ELEMENT_COORD_TO_RCL_UNITS(e->coords[1]); + RCL_Unit z = SFG_floorHeightAt(e->coords[0],e->coords[1]); + + if (SFG_projectileCollides(p,x,y,z)) + { + if ( + (e->type == SFG_LEVEL_ELEMENT_BARREL) && + (SFG_getDamageValue(attackType) >= + SFG_BARREL_EXPLOSION_DAMAGE_THRESHOLD) + ) + { + SFG_explodeBarrel(j,x,y,z); + } + + eliminate = 1; + break; + } + } + } + } + + if (eliminate) + { + if (p->type == SFG_PROJECTILE_FIREBALL) + SFG_createExplosion(p->position[0],p->position[1],p->position[2]); + else if (p->type == SFG_PROJECTILE_BULLET) + SFG_createDust(p->position[0],p->position[1],p->position[2]); + else if (p->type == SFG_PROJECTILE_PLASMA) + SFG_playGameSound(4,SFG_distantSoundVolume(pos[0],pos[1],pos[2])); + + // remove the projectile + + for (uint8_t j = i; j < SFG_currentLevel.projectileRecordCount - 1; ++j) + SFG_currentLevel.projectileRecords[j] = + SFG_currentLevel.projectileRecords[j + 1]; + + SFG_currentLevel.projectileRecordCount--; + + i--; + } + else + { + p->position[0] = pos[0]; + p->position[1] = pos[1]; + p->position[2] = pos[2]; + } + + p->doubleFramesToLive -= substractFrames; + } + + // handle door: + if (SFG_currentLevel.doorRecordCount > 0) // has to be here + { + /* Check door on whether a player is standing nearby. For performance + reasons we only check a few doors and move to others in the next + frame. */ + + if (SFG_currentLevel.checkedDoorIndex == 0) + { + uint8_t count = SFG_player.cards >> 6; + + SFG_player.cards = (count <= 1) ? + (SFG_player.cards & 0x07) : + ((SFG_player.cards & 0x7f) | ((count - 1) << 6)); + } + + for (uint16_t i = 0; + i < RCL_min(SFG_ELEMENT_DISTANCES_CHECKED_PER_FRAME, + SFG_currentLevel.doorRecordCount); + ++i) + { + SFG_DoorRecord *door = + &(SFG_currentLevel.doorRecords[SFG_currentLevel.checkedDoorIndex]); + + uint8_t upDownState = door->state & SFG_DOOR_UP_DOWN_MASK; + + uint8_t newUpDownState = 0; + + uint8_t lock = SFG_DOOR_LOCK(door->state); + + if ( // player near door? + (door->coords[0] >= (SFG_player.squarePosition[0] - 1)) && + (door->coords[0] <= (SFG_player.squarePosition[0] + 1)) && + (door->coords[1] >= (SFG_player.squarePosition[1] - 1)) && + (door->coords[1] <= (SFG_player.squarePosition[1] + 1))) + { + if (lock == 0) + { + newUpDownState = SFG_DOOR_UP_DOWN_MASK; + } + else + { + lock = 1 << (lock - 1); + + if (SFG_player.cards & lock) // player has the card? + newUpDownState = SFG_DOOR_UP_DOWN_MASK; + else + SFG_player.cards = + (SFG_player.cards & 0x07) | (lock << 3) | (2 << 6); + } + } + + if (upDownState != newUpDownState) + SFG_playGameSound(1,255); + + door->state = (door->state & ~SFG_DOOR_UP_DOWN_MASK) | newUpDownState; + + SFG_currentLevel.checkedDoorIndex++; + + if (SFG_currentLevel.checkedDoorIndex >= SFG_currentLevel.doorRecordCount) + SFG_currentLevel.checkedDoorIndex = 0; + } + + // move door up/down: + for (uint32_t i = 0; i < SFG_currentLevel.doorRecordCount; ++i) + { + SFG_DoorRecord *door = &(SFG_currentLevel.doorRecords[i]); + + int8_t height = door->state & SFG_DOOR_VERTICAL_POSITION_MASK; + + height = (door->state & SFG_DOOR_UP_DOWN_MASK) ? + RCL_min(0x1f,height + SFG_DOOR_INCREMENT_PER_FRAME) : + RCL_max(0x00,height - SFG_DOOR_INCREMENT_PER_FRAME); + + door->state = (door->state & ~SFG_DOOR_VERTICAL_POSITION_MASK) | height; + } + } + + // handle items, in a similar manner to door: + if (SFG_currentLevel.itemRecordCount > 0) // has to be here + { + // check item distances: + + for (uint16_t i = 0; + i < RCL_min(SFG_ELEMENT_DISTANCES_CHECKED_PER_FRAME, + SFG_currentLevel.itemRecordCount); + ++i) + { + SFG_ItemRecord item = + SFG_currentLevel.itemRecords[SFG_currentLevel.checkedItemIndex]; + + item &= ~SFG_ITEM_RECORD_ACTIVE_MASK; + + SFG_LevelElement e = + SFG_currentLevel.levelPointer->elements[item]; + + if ( + SFG_isInActiveDistanceFromPlayer( + e.coords[0] * RCL_UNITS_PER_SQUARE + RCL_UNITS_PER_SQUARE / 2, + e.coords[1] * RCL_UNITS_PER_SQUARE + RCL_UNITS_PER_SQUARE / 2, + SFG_floorHeightAt(e.coords[0],e.coords[1]) + RCL_UNITS_PER_SQUARE / 2) + ) + item |= SFG_ITEM_RECORD_ACTIVE_MASK; + + SFG_currentLevel.itemRecords[SFG_currentLevel.checkedItemIndex] = item; + + SFG_currentLevel.checkedItemIndex++; + + if (SFG_currentLevel.checkedItemIndex >= SFG_currentLevel.itemRecordCount) + SFG_currentLevel.checkedItemIndex = 0; + } + } + + // similarly handle monsters: + if (SFG_currentLevel.monsterRecordCount > 0) // has to be here + { + // check monster distances: + + for (uint16_t i = 0; + i < RCL_min(SFG_ELEMENT_DISTANCES_CHECKED_PER_FRAME, + SFG_currentLevel.monsterRecordCount); + ++i) + { + SFG_MonsterRecord *monster = + &(SFG_currentLevel.monsterRecords[SFG_currentLevel.checkedMonsterIndex]); + + if ( // far away from the player? + !SFG_isInActiveDistanceFromPlayer( + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]), + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]), + SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1])) + + RCL_UNITS_PER_SQUARE / 2 + ) + ) + { + monster->stateType = + (monster->stateType & SFG_MONSTER_MASK_TYPE) | + SFG_MONSTER_STATE_INACTIVE; + } + else if (SFG_MR_STATE(*monster) == SFG_MONSTER_STATE_INACTIVE) + { + monster->stateType = + (monster->stateType & SFG_MONSTER_MASK_TYPE) | + (monster->health != 0 ? + SFG_MONSTER_STATE_IDLE : SFG_MONSTER_STATE_DEAD); + } + + SFG_currentLevel.checkedMonsterIndex++; + + if (SFG_currentLevel.checkedMonsterIndex >= + SFG_currentLevel.monsterRecordCount) + SFG_currentLevel.checkedMonsterIndex = 0; + } + } + + // update AI and handle dead monsters: + if ((SFG_game.frame - SFG_currentLevel.frameStart) % + SFG_AI_UPDATE_FRAME_INTERVAL == 0) + { + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + { + SFG_MonsterRecord *monster = &(SFG_currentLevel.monsterRecords[i]); + uint8_t state = SFG_MR_STATE(*monster); + + if ((state == SFG_MONSTER_STATE_INACTIVE) || + (state == SFG_MONSTER_STATE_DEAD)) + continue; + + if (state == SFG_MONSTER_STATE_DYING) + { + if (SFG_MR_TYPE(*monster) == SFG_LEVEL_ELEMENT_MONSTER_ENDER) + { + SFG_currentLevel.bossCount--; + + // last boss killed gives player a key card + + if (SFG_currentLevel.bossCount == 0) + { + SFG_LOG("boss killed, giving player a card"); + SFG_player.cards |= 0x04; + } + } + + monster->stateType = + (monster->stateType & 0xf0) | SFG_MONSTER_STATE_DEAD; + } + else if (monster->health == 0) + { + monster->stateType = (monster->stateType & SFG_MONSTER_MASK_TYPE) | + SFG_MONSTER_STATE_DYING; + + SFG_processEvent(SFG_EVENT_MONSTER_DIES,SFG_MR_TYPE(*monster)); + + if (SFG_MR_TYPE(*monster) == SFG_LEVEL_ELEMENT_MONSTER_EXPLODER) + SFG_createExplosion( + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]), + SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]), + SFG_floorCollisionHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0])) + + RCL_UNITS_PER_SQUARE / 2); + } + else + { +#if SFG_PREVIEW_MODE == 0 + SFG_monsterPerformAI(monster); +#endif + } + } + } +} + +/** + Maps square position on the map to a bit in map reveal mask. +*/ +static inline uint16_t SFG_getMapRevealBit(uint8_t squareX, uint8_t squareY) +{ + return 1 << ((squareY / 16) * 4 + squareX / 16); +} + +/** + Checks a 3D point visibility from player's position (WITHOUT considering + facing direction). +*/ +static inline uint8_t SFG_spriteIsVisible(RCL_Vector2D pos, RCL_Unit height, + uint8_t spriteSize) +{ + return + RCL_castRay3D( + SFG_player.camera.position, + SFG_player.camera.height, + pos, + height, + SFG_floorHeightAt, + SFG_ceilingHeightAt, + SFG_game.rayConstraints + ) == RCL_UNITS_PER_SQUARE; +} + +/** + Returns a tangent in RCL_Unit of vertical autoaim, given current game state. +*/ +RCL_Unit SFG_autoaimVertically() +{ + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + { + SFG_MonsterRecord m = SFG_currentLevel.monsterRecords[i]; + + if (SFG_MR_STATE(m) == SFG_MONSTER_STATE_INACTIVE) + continue; + + RCL_Vector2D worldPosition, toMonster; + + worldPosition.x = SFG_MONSTER_COORD_TO_RCL_UNITS(m.coords[0]); + worldPosition.y = SFG_MONSTER_COORD_TO_RCL_UNITS(m.coords[1]); + + toMonster.x = worldPosition.x - SFG_player.camera.position.x; + toMonster.y = worldPosition.y - SFG_player.camera.position.y; + + if (RCL_abs( + RCL_vectorsAngleCos(SFG_player.direction,toMonster) + - RCL_UNITS_PER_SQUARE) < SFG_VERTICAL_AUTOAIM_ANGLE_THRESHOLD) + { + uint8_t spriteSize = SFG_GET_MONSTER_SPRITE_SIZE( + SFG_MONSTER_TYPE_TO_INDEX(SFG_MR_TYPE(m))); + + RCL_Unit worldHeight = + SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(m.coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(m.coords[1])) + + + SFG_SPRITE_SIZE_TO_HEIGHT_ABOVE_GROUND(spriteSize); + + if (SFG_spriteIsVisible(worldPosition,worldHeight,spriteSize)) + { + RCL_Unit distance = RCL_len(toMonster); + + return ((worldHeight - SFG_player.camera.height) * RCL_UNITS_PER_SQUARE) + / distance; + } + } + } + + return 0; +} + +/** + Draws text on screen using the bitmap font stored in assets. +*/ +void SFG_drawText( + const char *text, + uint16_t x, + uint16_t y, + uint8_t size, + uint8_t color, + uint16_t maxLength, + uint16_t limitX) +{ + if (size == 0) + size = 1; + + if (limitX == 0) + limitX = 65535; + + if (maxLength == 0) + maxLength = 65535; + + uint16_t pos = 0; + + uint16_t currentX = x; + uint16_t currentY = y; + + while (pos < maxLength && text[pos] != 0) // for each character + { + uint16_t character = SFG_font[SFG_charToFontIndex(text[pos])]; + + for (uint8_t i = 0; i < SFG_FONT_CHARACTER_SIZE; ++i) // for each line + { + currentY = y; + + for (uint8_t j = 0; j < SFG_FONT_CHARACTER_SIZE; ++j) // for each row + { + if (character & 0x8000) + for (uint8_t k = 0; k < size; ++k) + for (uint8_t l = 0; l < size; ++l) + { + uint16_t drawX = currentX + k; + uint16_t drawY = currentY + l; + + if (drawX < SFG_GAME_RESOLUTION_X && + drawY < SFG_GAME_RESOLUTION_Y) + SFG_setGamePixel(drawX,drawY,color); + } + + currentY += size; + character = character << 1; + } + + currentX += size; + } + + currentX += size; // space + + if (currentX > limitX) + { + currentX = x; + y += (SFG_FONT_CHARACTER_SIZE + 1) * size; + } + + pos++; + } +} + +void SFG_drawLevelStartOverlay() +{ + uint8_t stage = ((SFG_game.frameTime - SFG_game.stateChangeTime) * 4) / + SFG_LEVEL_START_DURATION; + + // fade in: + + for (uint16_t y = 0; y < SFG_GAME_RESOLUTION_Y; ++y) + for (uint16_t x = 0; x < SFG_GAME_RESOLUTION_X; ++x) + { + uint8_t draw = 0; + + switch (stage) + { + case 0: draw = 1; break; + case 1: draw = (x % 2) || (y % 2); break; + case 2: draw = (x % 2) == (y % 2); break; + case 3: draw = (x % 2) && (y % 2); break; + default: break; + } + + if (draw) + SFG_setGamePixel(x,y,0); + } + + if (SFG_game.saved == 1) + SFG_drawText(SFG_TEXT_SAVED,SFG_HUD_MARGIN,SFG_HUD_MARGIN, + SFG_FONT_SIZE_MEDIUM,7,255,0); +} + +/** + Sets player's height to match the floor height below him. +*/ +void SFG_updatePlayerHeight() +{ + SFG_player.camera.height = + SFG_floorCollisionHeightAt( + SFG_player.squarePosition[0],SFG_player.squarePosition[1]) + + RCL_CAMERA_COLL_HEIGHT_BELOW; +} + +/** + Part of SFG_gameStep() for SFG_GAME_STATE_PLAYING. +*/ +void SFG_gameStepPlaying() +{ + if ( + (SFG_keyIsDown(SFG_KEY_C) && SFG_keyIsDown(SFG_KEY_DOWN)) || + SFG_keyIsDown(SFG_KEY_MENU)) + { + SFG_setGameState(SFG_GAME_STATE_MENU); + SFG_playGameSound(3,SFG_MENU_CLICK_VOLUME); + return; + } + + SFG_updateLevel(); + + int8_t recomputeDirection = SFG_currentLevel.frameStart == SFG_game.frame; + + RCL_Vector2D moveOffset; + + moveOffset.x = 0; + moveOffset.y = 0; + + int8_t strafe = 0; + + uint8_t currentWeapon = SFG_player.weapon; + +#if SFG_HEADBOB_ENABLED + int8_t bobbing = 0; +#endif + + int8_t shearing = 0; + + if (SFG_player.weaponCooldownFrames > 0) + SFG_player.weaponCooldownFrames--; + + if (SFG_keyJustPressed(SFG_KEY_TOGGLE_FREELOOK)) + SFG_game.settings = (SFG_game.settings & 0x04) ? + (SFG_game.settings & ~0x0c) : (SFG_game.settings | 0x0c); + + int8_t canSwitchWeapon = SFG_player.weaponCooldownFrames == 0; + + if (SFG_keyJustPressed(SFG_KEY_NEXT_WEAPON) && canSwitchWeapon) + SFG_playerRotateWeapon(1); + else if (SFG_keyJustPressed(SFG_KEY_PREVIOUS_WEAPON) && canSwitchWeapon) + SFG_playerRotateWeapon(0); + else if (SFG_keyJustPressed(SFG_KEY_CYCLE_WEAPON) && + SFG_player.previousWeaponDirection) + SFG_playerRotateWeapon(SFG_player.previousWeaponDirection > 0); + + uint8_t shearingOn = SFG_game.settings & 0x04; + + if (SFG_keyIsDown(SFG_KEY_B)) + { + if (shearingOn) // B + U/D: shearing (if on) + { + if (SFG_keyIsDown(SFG_KEY_UP)) + { + SFG_player.camera.shear = + RCL_min(SFG_CAMERA_MAX_SHEAR_PIXELS, + SFG_player.camera.shear + SFG_CAMERA_SHEAR_STEP_PER_FRAME); + + shearing = 1; + } + else if (SFG_keyIsDown(SFG_KEY_DOWN)) + { + SFG_player.camera.shear = + RCL_max(-1 * SFG_CAMERA_MAX_SHEAR_PIXELS, + SFG_player.camera.shear - SFG_CAMERA_SHEAR_STEP_PER_FRAME); + + shearing = 1; + } + } + + if (!SFG_keyIsDown(SFG_KEY_C)) + { // B + L/R: strafing + if (SFG_keyIsDown(SFG_KEY_LEFT)) + strafe = -1; + else if (SFG_keyIsDown(SFG_KEY_RIGHT)) + strafe = 1; + } + } + + if (SFG_keyIsDown(SFG_KEY_C)) // C + A/B/L/R: weapon switching + { + if ((SFG_keyJustPressed(SFG_KEY_LEFT) || SFG_keyJustPressed(SFG_KEY_A)) && + canSwitchWeapon) + SFG_playerRotateWeapon(0); + else if ( + (SFG_keyJustPressed(SFG_KEY_RIGHT) || SFG_keyJustPressed(SFG_KEY_B)) && + canSwitchWeapon) + SFG_playerRotateWeapon(1); + } + else if (!SFG_keyIsDown(SFG_KEY_B)) // L/R: turning + { + if (SFG_keyIsDown(SFG_KEY_LEFT)) + { + SFG_player.camera.direction -= SFG_PLAYER_TURN_UNITS_PER_FRAME; + recomputeDirection = 1; + } + else if (SFG_keyIsDown(SFG_KEY_RIGHT)) + { + SFG_player.camera.direction += SFG_PLAYER_TURN_UNITS_PER_FRAME; + recomputeDirection = 1; + } + } + + if (!SFG_keyIsDown(SFG_KEY_B) || !shearingOn) // U/D: movement + { + if (SFG_keyIsDown(SFG_KEY_UP)) + { + moveOffset.x += SFG_player.direction.x; + moveOffset.y += SFG_player.direction.y; +#if SFG_HEADBOB_ENABLED + bobbing = 1; +#endif + } + else if (SFG_keyIsDown(SFG_KEY_DOWN)) + { + moveOffset.x -= SFG_player.direction.x; + moveOffset.y -= SFG_player.direction.y; +#if SFG_HEADBOB_ENABLED + bobbing = 1; +#endif + } + } + + int16_t mouseX = 0, mouseY = 0; + + SFG_getMouseOffset(&mouseX,&mouseY); + + if (mouseX != 0) // mouse turning + { + SFG_player.camera.direction += + (mouseX * SFG_MOUSE_SENSITIVITY_HORIZONTAL) / 128; + + recomputeDirection = 1; + } + + if ((mouseY != 0) && shearingOn) // mouse shearing + SFG_player.camera.shear = + RCL_max(RCL_min( + SFG_player.camera.shear - + (mouseY * SFG_MOUSE_SENSITIVITY_VERTICAL) / 128, + SFG_CAMERA_MAX_SHEAR_PIXELS), + -1 * SFG_CAMERA_MAX_SHEAR_PIXELS); + + if (recomputeDirection) + SFG_recomputePLayerDirection(); + + if (SFG_keyIsDown(SFG_KEY_STRAFE_LEFT)) + strafe = -1; + else if (SFG_keyIsDown(SFG_KEY_STRAFE_RIGHT)) + strafe = 1; + + if (strafe != 0) + { + moveOffset.x += strafe * SFG_player.direction.y; + moveOffset.y -= strafe * SFG_player.direction.x; + } + +#if SFG_PREVIEW_MODE + if (SFG_keyIsDown(SFG_KEY_B)) + SFG_player.verticalSpeed = SFG_PLAYER_MOVE_UNITS_PER_FRAME; + else if (SFG_keyIsDown(SFG_KEY_C)) + SFG_player.verticalSpeed = -1 * SFG_PLAYER_MOVE_UNITS_PER_FRAME; + else + SFG_player.verticalSpeed = 0; +#else + RCL_Unit verticalOffset = + ( + ( + SFG_keyIsDown(SFG_KEY_JUMP) || + (SFG_keyIsDown(SFG_KEY_UP) && SFG_keyIsDown(SFG_KEY_C)) + ) && + (SFG_player.verticalSpeed == 0) && + (SFG_player.previousVerticalSpeed == 0)) ? + SFG_PLAYER_JUMP_OFFSET_PER_FRAME : // jump + (SFG_player.verticalSpeed - SFG_GRAVITY_SPEED_INCREASE_PER_FRAME); +#endif + + if (!shearing && SFG_player.camera.shear != 0 && !(SFG_game.settings & 0x08)) + { + // gradually shear back to zero + + SFG_player.camera.shear = + (SFG_player.camera.shear > 0) ? + RCL_max(0,SFG_player.camera.shear - SFG_CAMERA_SHEAR_STEP_PER_FRAME) : + RCL_min(0,SFG_player.camera.shear + SFG_CAMERA_SHEAR_STEP_PER_FRAME); + } + +#if SFG_HEADBOB_ENABLED && !SFG_PREVIEW_MODE + if (bobbing) + { + SFG_player.headBobFrame += SFG_HEADBOB_FRAME_INCREASE_PER_FRAME; + } + else if (SFG_player.headBobFrame != 0) + { + // smoothly stop bobbing + + uint8_t quadrant = (SFG_player.headBobFrame % RCL_UNITS_PER_SQUARE) / + (RCL_UNITS_PER_SQUARE / 4); + + /* When in quadrant in which sin is going away from zero, switch to the + same value of the next quadrant, so that bobbing starts to go towards + zero immediately. */ + + if (quadrant % 2 == 0) + SFG_player.headBobFrame = + ((quadrant + 1) * RCL_UNITS_PER_SQUARE / 4) + + (RCL_UNITS_PER_SQUARE / 4 - SFG_player.headBobFrame % + (RCL_UNITS_PER_SQUARE / 4)); + + RCL_Unit currentFrame = SFG_player.headBobFrame; + RCL_Unit nextFrame = SFG_player.headBobFrame + 16; + + // only stop bobbing when we pass a frame at which sin crosses zero + SFG_player.headBobFrame = + (currentFrame / (RCL_UNITS_PER_SQUARE / 2) == + nextFrame / (RCL_UNITS_PER_SQUARE / 2)) ? + nextFrame : 0; + } +#endif + + RCL_Unit previousHeight = SFG_player.camera.height; + + // handle player collision with level elements: + + // monsters: + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + { + SFG_MonsterRecord *m = &(SFG_currentLevel.monsterRecords[i]); + + uint8_t state = SFG_MR_STATE(*m); + + if (state == SFG_MONSTER_STATE_INACTIVE || state == SFG_MONSTER_STATE_DEAD) + continue; + + RCL_Vector2D mPos; + + mPos.x = SFG_MONSTER_COORD_TO_RCL_UNITS(m->coords[0]); + mPos.y = SFG_MONSTER_COORD_TO_RCL_UNITS(m->coords[1]); + + if ( + SFG_elementCollides( + SFG_player.camera.position.x, + SFG_player.camera.position.y, + SFG_player.camera.height, + mPos.x, + mPos.y, + SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(m->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(m->coords[1])) + ) + ) + { + moveOffset = SFG_resolveCollisionWithElement( + SFG_player.camera.position,moveOffset,mPos); + } + } + + uint8_t collidesWithTeleporter = 0; + + /* item collisions with player (only those that don't stop player's movement, + as those are handled differently, via itemCollisionMap): */ + for (int16_t i = 0; i < SFG_currentLevel.itemRecordCount; ++i) + // ^ has to be int16_t (signed) + { + if (!(SFG_currentLevel.itemRecords[i] & SFG_ITEM_RECORD_ACTIVE_MASK)) + continue; + + const SFG_LevelElement *e = SFG_getActiveItemElement(i); + + if (e != 0) + { + RCL_Vector2D ePos; + + ePos.x = SFG_ELEMENT_COORD_TO_RCL_UNITS(e->coords[0]); + ePos.y = SFG_ELEMENT_COORD_TO_RCL_UNITS(e->coords[1]); + + if (!SFG_itemCollides(e->type) && + SFG_elementCollides( + SFG_player.camera.position.x, + SFG_player.camera.position.y, + SFG_player.camera.height, + ePos.x, + ePos.y, + SFG_floorHeightAt(e->coords[0],e->coords[1])) + ) + { + uint8_t eliminate = 1; + + uint8_t onlyKnife = 1; + + for (uint8_t j = 0; j < SFG_AMMO_TOTAL; ++j) + if (SFG_player.ammo[j] != 0) + { + onlyKnife = 0; + break; + } + + switch (e->type) + { + case SFG_LEVEL_ELEMENT_HEALTH: + if (SFG_player.health < SFG_PLAYER_MAX_HEALTH) + SFG_playerChangeHealth(SFG_HEALTH_KIT_VALUE); + else + eliminate = 0; + break; + +#define addAmmo(type) \ + if (SFG_player.ammo[SFG_AMMO_##type] < SFG_AMMO_MAX_##type) \ + {\ + SFG_player.ammo[SFG_AMMO_##type] = RCL_min(SFG_AMMO_MAX_##type,\ + SFG_player.ammo[SFG_AMMO_##type] + SFG_AMMO_INCREASE_##type);\ + if (onlyKnife) SFG_playerRotateWeapon(1); \ + }\ + else\ + eliminate = 0; + + case SFG_LEVEL_ELEMENT_BULLETS: + addAmmo(BULLETS) + break; + + case SFG_LEVEL_ELEMENT_ROCKETS: + addAmmo(ROCKETS) + break; + + case SFG_LEVEL_ELEMENT_PLASMA: + addAmmo(PLASMA) + break; + +#undef addAmmo + + case SFG_LEVEL_ELEMENT_CARD0: + case SFG_LEVEL_ELEMENT_CARD1: + case SFG_LEVEL_ELEMENT_CARD2: + SFG_player.cards |= 1 << (e->type - SFG_LEVEL_ELEMENT_CARD0); + break; + + case SFG_LEVEL_ELEMENT_TELEPORTER: + collidesWithTeleporter = 1; + eliminate = 0; + break; + + case SFG_LEVEL_ELEMENT_FINISH: + SFG_levelEnds(); + SFG_setGameState(SFG_GAME_STATE_WIN); + SFG_playGameSound(2,255); + SFG_processEvent(SFG_EVENT_VIBRATE,0); + SFG_processEvent( + SFG_EVENT_LEVEL_WON,SFG_currentLevel.levelNumber + 1); + eliminate = 0; + break; + + default: + eliminate = 0; + break; + } + + if (eliminate) // take the item + { +#if !SFG_PREVIEW_MODE + SFG_removeItem(i); + SFG_player.lastItemTakenFrame = SFG_game.frame; + i--; + SFG_playGameSound(3,255); + SFG_processEvent(SFG_EVENT_PLAYER_TAKES_ITEM,e->type); +#endif + } + else if ( + e->type == SFG_LEVEL_ELEMENT_TELEPORTER && + SFG_currentLevel.teleporterCount > 1 && + !SFG_player.justTeleported) + { + // teleport to random destination teleporter + + uint8_t teleporterNumber = + SFG_random() % (SFG_currentLevel.teleporterCount - 1) + 1; + + for (uint16_t j = 0; j < SFG_currentLevel.itemRecordCount; ++j) + { + SFG_LevelElement e2 = + SFG_currentLevel.levelPointer->elements + [SFG_currentLevel.itemRecords[j] & + ~SFG_ITEM_RECORD_ACTIVE_MASK]; + + if ((e2.type == SFG_LEVEL_ELEMENT_TELEPORTER) && (j != i)) + teleporterNumber--; + + if (teleporterNumber == 0) + { + SFG_player.camera.position.x = + SFG_ELEMENT_COORD_TO_RCL_UNITS(e2.coords[0]); + + SFG_player.camera.position.y = + SFG_ELEMENT_COORD_TO_RCL_UNITS(e2.coords[1]); + + SFG_player.camera.height = + SFG_floorHeightAt(e2.coords[0],e2.coords[1]) + + RCL_CAMERA_COLL_HEIGHT_BELOW; + + SFG_currentLevel.itemRecords[j] |= SFG_ITEM_RECORD_ACTIVE_MASK; + /* ^ we have to make the new teleporter immediately active so + that it will immediately collide */ + + SFG_player.justTeleported = 1; + + SFG_playGameSound(4,255); + SFG_processEvent(SFG_EVENT_PLAYER_TELEPORTS,0); + + break; + } + } + } + } + } + } // item collision check + + if (!collidesWithTeleporter) + SFG_player.justTeleported = 0; + +#if SFG_PREVIEW_MODE + SFG_player.camera.position.x += + SFG_PREVIEW_MODE_SPEED_MULTIPLIER * moveOffset.x; + + SFG_player.camera.position.y += + SFG_PREVIEW_MODE_SPEED_MULTIPLIER * moveOffset.y; + + SFG_player.camera.height += + SFG_PREVIEW_MODE_SPEED_MULTIPLIER * SFG_player.verticalSpeed; +#else + RCL_moveCameraWithCollision(&(SFG_player.camera),moveOffset, + verticalOffset,SFG_floorCollisionHeightAt,SFG_ceilingHeightAt,1,1); + + SFG_player.previousVerticalSpeed = SFG_player.verticalSpeed; + + RCL_Unit limit = RCL_max(RCL_max(0,verticalOffset),SFG_player.verticalSpeed); + + SFG_player.verticalSpeed = + RCL_min(limit,SFG_player.camera.height - previousHeight); + /* ^ By "limit" we assure height increase caused by climbing a step doesn't + add vertical velocity. */ +#endif + +#if SFG_PREVIEW_MODE == 0 + if ( + SFG_keyIsDown(SFG_KEY_A) && + !SFG_keyIsDown(SFG_KEY_C) && + (SFG_player.weaponCooldownFrames == 0)) + { + /* Player attack/shoot/fire, this has to be done AFTER the player is moved, + otherwise he could shoot himself while running forward. */ + + uint8_t ammo, projectileCount, canShoot; + + SFG_getPlayerWeaponInfo(&ammo,&projectileCount,&canShoot); + + if (canShoot) + { + uint8_t sound; + + switch (SFG_player.weapon) + { + case SFG_WEAPON_KNIFE: sound = 255; break; + case SFG_WEAPON_ROCKET_LAUNCHER: + case SFG_WEAPON_SHOTGUN: sound = 2; break; + case SFG_WEAPON_PLASMAGUN: + case SFG_WEAPON_SOLUTION: sound = 4; break; + default: sound = 0; break; + } + + if (sound != 255) + SFG_playGameSound(sound,255); + + if (ammo != SFG_AMMO_NONE) + SFG_player.ammo[ammo] -= projectileCount; + + uint8_t projectile; + + switch (SFG_GET_WEAPON_FIRE_TYPE(SFG_player.weapon)) + { + case SFG_WEAPON_FIRE_TYPE_PLASMA: + projectile = SFG_PROJECTILE_PLASMA; + break; + + case SFG_WEAPON_FIRE_TYPE_FIREBALL: + projectile = SFG_PROJECTILE_FIREBALL; + break; + + case SFG_WEAPON_FIRE_TYPE_BULLET: + projectile = SFG_PROJECTILE_BULLET; + break; + + case SFG_WEAPON_FIRE_TYPE_MELEE: + projectile = SFG_PROJECTILE_NONE; + break; + + default: + projectile = 255; + break; + } + + if (projectile != SFG_PROJECTILE_NONE) + { + uint16_t angleAdd = SFG_PROJECTILE_SPREAD_ANGLE / (projectileCount + 1); + + RCL_Unit direction = + (SFG_player.camera.direction - SFG_PROJECTILE_SPREAD_ANGLE / 2) + + angleAdd; + + RCL_Unit projectileSpeed = SFG_GET_PROJECTILE_SPEED_UPS(projectile); + + /* Vertical speed will be either determined by autoaim (if shearing is + off) or the camera shear value. */ + RCL_Unit verticalSpeed = (SFG_game.settings & 0x04) ? + (SFG_player.camera.shear * projectileSpeed * 2) / // only approximate + SFG_CAMERA_MAX_SHEAR_PIXELS + : + (projectileSpeed * SFG_autoaimVertically()) / RCL_UNITS_PER_SQUARE; + + for (uint8_t i = 0; i < projectileCount; ++i) + { + SFG_launchProjectile( + projectile, + SFG_player.camera.position, + SFG_player.camera.height, + RCL_angleToDirection(direction), + verticalSpeed, + SFG_PROJECTILE_SPAWN_OFFSET + ); + + direction += angleAdd; + } + } + else + { + // player's melee attack + + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + { + SFG_MonsterRecord *m = &(SFG_currentLevel.monsterRecords[i]); + + uint8_t state = SFG_MR_STATE(*m); + + if ((state == SFG_MONSTER_STATE_INACTIVE) || + (state == SFG_MONSTER_STATE_DEAD)) + continue; + + RCL_Unit pX, pY, pZ; + SFG_getMonsterWorldPosition(m,&pX,&pY,&pZ); + + if (SFG_taxicabDistance(pX,pY,pZ, + SFG_player.camera.position.x, + SFG_player.camera.position.y, + SFG_player.camera.height) > SFG_MELEE_RANGE) + continue; + + RCL_Vector2D toMonster; + + toMonster.x = pX - SFG_player.camera.position.x; + toMonster.y = pY - SFG_player.camera.position.y; + + if (RCL_vectorsAngleCos(SFG_player.direction,toMonster) >= + (RCL_UNITS_PER_SQUARE - SFG_PLAYER_MELEE_ANGLE)) + { + SFG_monsterChangeHealth(m, + -1 * SFG_getDamageValue(SFG_WEAPON_FIRE_TYPE_MELEE)); + + SFG_createDust(pX,pY,pZ); + + break; + } + } + } + + SFG_player.weaponCooldownFrames = + RCL_max( + SFG_GET_WEAPON_FIRE_COOLDOWN_FRAMES(SFG_player.weapon), + SFG_MIN_WEAPON_COOLDOWN_FRAMES); + + SFG_getPlayerWeaponInfo(&ammo,&projectileCount,&canShoot); + + if (!canShoot) + { + // No more ammo, switch to the second strongest weapon. + + SFG_playerRotateWeapon(1); + + uint8_t previousWeapon = SFG_player.weapon; + + SFG_playerRotateWeapon(0); + + if (previousWeapon > SFG_player.weapon) + SFG_playerRotateWeapon(1); + } + } // endif: has enough ammo? + } // attack +#endif // SFG_PREVIEW_MODE == 0 + + SFG_player.squarePosition[0] = + SFG_player.camera.position.x / RCL_UNITS_PER_SQUARE; + + SFG_player.squarePosition[1] = + SFG_player.camera.position.y / RCL_UNITS_PER_SQUARE; + + SFG_currentLevel.mapRevealMask |= + SFG_getMapRevealBit( + SFG_player.squarePosition[0], + SFG_player.squarePosition[1]); + + uint8_t properties; + + SFG_getMapTile(SFG_currentLevel.levelPointer,SFG_player.squarePosition[0], + SFG_player.squarePosition[1],&properties); + + if ( // squeezer check + (properties == SFG_TILE_PROPERTY_SQUEEZER) && + ((SFG_ceilingHeightAt( + SFG_player.squarePosition[0],SFG_player.squarePosition[1]) - + SFG_floorHeightAt( + SFG_player.squarePosition[0],SFG_player.squarePosition[1])) + < + (RCL_CAMERA_COLL_HEIGHT_ABOVE + RCL_CAMERA_COLL_HEIGHT_BELOW))) + { + SFG_LOG("player is squeezed"); + SFG_player.health = 0; + } + + if (SFG_player.weapon != currentWeapon) // if weapon switched, start cooldown + { + + if (SFG_player.weapon == (currentWeapon + 1) % SFG_WEAPONS_TOTAL) + SFG_player.previousWeaponDirection = -1; + else if (currentWeapon == (SFG_player.weapon + 1) % SFG_WEAPONS_TOTAL) + SFG_player.previousWeaponDirection = 1; + else + SFG_player.previousWeaponDirection = 0; + + SFG_player.weaponCooldownFrames = + SFG_GET_WEAPON_FIRE_COOLDOWN_FRAMES(SFG_player.weapon) / 2; + } + +#if SFG_IMMORTAL == 0 + if (SFG_player.health == 0) + { + SFG_LOG("player dies"); + SFG_levelEnds(); + SFG_processEvent(SFG_EVENT_VIBRATE,0); + SFG_processEvent(SFG_EVENT_PLAYER_DIES,0); + SFG_setGameState(SFG_GAME_STATE_LOSE); + } +#endif +} + +/** + This function defines which items are displayed in the menu. +*/ +uint8_t SFG_getMenuItem(uint8_t index) +{ + uint8_t current = 0; + + while (1) // find first legitimate item + { + if ( // skip non-legitimate items + ((current <= SFG_MENU_ITEM_MAP) && (SFG_currentLevel.levelPointer == 0)) + || ((current == SFG_MENU_ITEM_LOAD) && ((SFG_game.save[0] >> 4) == 0x0f))) + { + current++; + continue; + } + + if (index == 0) + return (current <= (SFG_MENU_ITEM_EXIT - (SFG_CAN_EXIT ? 0 : 1)) + ) ? current : SFG_MENU_ITEM_NONE; + + current++; + index--; + } + + return SFG_MENU_ITEM_NONE; +} + +void SFG_gameStepMenu() +{ + uint8_t menuItems = 0; + + while (SFG_getMenuItem(menuItems) != SFG_MENU_ITEM_NONE) + menuItems++; + + uint8_t item = SFG_getMenuItem(SFG_game.selectedMenuItem); + + if (SFG_keyRegisters(SFG_KEY_DOWN) && + (SFG_game.selectedMenuItem < menuItems - 1)) + { + SFG_game.selectedMenuItem++; + SFG_playGameSound(3,SFG_MENU_CLICK_VOLUME); + } + else if (SFG_keyRegisters(SFG_KEY_UP) && (SFG_game.selectedMenuItem > 0)) + { + SFG_game.selectedMenuItem--; + SFG_playGameSound(3,SFG_MENU_CLICK_VOLUME); + } + else if (SFG_keyJustPressed(SFG_KEY_A)) + { + switch (item) + { + case SFG_MENU_ITEM_PLAY: + for (uint8_t i = 6; i < SFG_SAVE_SIZE; ++i) // reset totals in save + SFG_game.save[i] = 0; + + if (SFG_game.selectedLevel == 0) + { + SFG_currentLevel.levelNumber = 0; // to draw intro, not outro + SFG_setGameState(SFG_GAME_STATE_INTRO); + } + else + SFG_setAndInitLevel(SFG_game.selectedLevel); + + break; + + case SFG_MENU_ITEM_LOAD: + { + SFG_gameLoad(); + + uint8_t saveBackup[SFG_SAVE_SIZE]; + + for (uint8_t i = 0; i < SFG_SAVE_SIZE; ++i) + saveBackup[i] = SFG_game.save[i]; + + SFG_setAndInitLevel(SFG_game.save[0] >> 4); + + for (uint8_t i = 0; i < SFG_SAVE_SIZE; ++i) + SFG_game.save[i] = saveBackup[i]; + + SFG_player.health = SFG_game.save[2]; + SFG_player.ammo[0] = SFG_game.save[3]; + SFG_player.ammo[1] = SFG_game.save[4]; + SFG_player.ammo[2] = SFG_game.save[5]; + + SFG_playerRotateWeapon(1); // this chooses weapon with ammo available + break; + } + + case SFG_MENU_ITEM_CONTINUE: + SFG_setGameState(SFG_GAME_STATE_PLAYING); + break; + + case SFG_MENU_ITEM_MAP: + SFG_setGameState(SFG_GAME_STATE_MAP); + break; + + case SFG_MENU_ITEM_SOUND: + SFG_LOG("sound changed"); + + SFG_game.settings = + (SFG_game.settings & ~0x03) | ((SFG_game.settings + 1) & 0x03); + + SFG_playGameSound(3,SFG_MENU_CLICK_VOLUME); + + if ((SFG_game.settings & 0x02) != + ((SFG_game.settings - 1) & 0x02)) + SFG_setMusic((SFG_game.settings & 0x02) ? + SFG_MUSIC_TURN_ON : SFG_MUSIC_TURN_OFF); + + SFG_game.save[1] = SFG_game.settings; + SFG_gameSave(); + + break; + + case SFG_MENU_ITEM_SHEAR: + { + uint8_t current = (SFG_game.settings >> 2) & 0x03; + + current++; + + if (current == 2) // option that doesn't make sense, skip + current++; + + SFG_game.settings = + (SFG_game.settings & ~0x0c) | ((current & 0x03) << 2); + + SFG_game.save[1] = SFG_game.settings; + SFG_gameSave(); + + break; + } + + case SFG_MENU_ITEM_EXIT: + SFG_game.continues = 0; + break; + + default: + break; + } + } + else if (item == SFG_MENU_ITEM_PLAY) + { + if (SFG_keyRegisters(SFG_KEY_RIGHT) && + (SFG_game.selectedLevel < (SFG_game.save[0] & 0x0f))) + { + SFG_game.selectedLevel++; + SFG_playGameSound(3,SFG_MENU_CLICK_VOLUME); + } + else if (SFG_keyRegisters(SFG_KEY_LEFT) && SFG_game.selectedLevel > 0) + { + SFG_game.selectedLevel--; + SFG_playGameSound(3,SFG_MENU_CLICK_VOLUME); + } + } +} + +/** + Performs one game step (logic, physics, menu, ...), happening SFG_MS_PER_FRAME + after the previous step. +*/ +void SFG_gameStep() +{ + SFG_GAME_STEP_COMMAND + + SFG_game.soundsPlayedThisFrame = 0; + + SFG_game.blink = (SFG_game.frame / SFG_BLINK_PERIOD_FRAMES) % 2; + + for (uint8_t i = 0; i < SFG_KEY_COUNT; ++i) + if (!SFG_keyPressed(i)) + SFG_game.keyStates[i] = 0; + else if (SFG_game.keyStates[i] < 255) + SFG_game.keyStates[i]++; + + if ((SFG_currentLevel.frameStart - SFG_game.frame) % + SFG_SPRITE_ANIMATION_FRAME_DURATION == 0) + SFG_game.spriteAnimationFrame++; + + switch (SFG_game.state) + { + case SFG_GAME_STATE_PLAYING: + SFG_gameStepPlaying(); + break; + + case SFG_GAME_STATE_MENU: + SFG_gameStepMenu(); + break; + + case SFG_GAME_STATE_LOSE: + { + // player die animation (lose) + + SFG_updateLevel(); // let monsters and other things continue moving + SFG_updatePlayerHeight(); // in case player is on elevator + + int32_t t = SFG_game.frameTime - SFG_game.stateChangeTime; + + RCL_Unit h = SFG_floorHeightAt(SFG_player.squarePosition[0], + SFG_player.squarePosition[1]); + + SFG_player.camera.height = + RCL_max(h,h + ((SFG_LOSE_ANIMATION_DURATION - t) * + RCL_CAMERA_COLL_HEIGHT_BELOW) / SFG_LOSE_ANIMATION_DURATION); + + SFG_player.camera.shear = + RCL_min(SFG_CAMERA_MAX_SHEAR_PIXELS / 4, + (t * (SFG_CAMERA_MAX_SHEAR_PIXELS / 4)) / SFG_LOSE_ANIMATION_DURATION); + + if (t > SFG_LOSE_ANIMATION_DURATION && + (SFG_keyIsDown(SFG_KEY_A) || SFG_keyIsDown(SFG_KEY_B))) + { + for (uint8_t i = 6; i < SFG_SAVE_SIZE; ++i) + SFG_game.save[i] = 0; + + SFG_setAndInitLevel(SFG_currentLevel.levelNumber); + } + + break; + } + + case SFG_GAME_STATE_WIN: + { + // win animation + + SFG_updateLevel(); + + int32_t t = SFG_game.frameTime - SFG_game.stateChangeTime; + + if (t > SFG_WIN_ANIMATION_DURATION) + { + if (SFG_currentLevel.levelNumber == (SFG_NUMBER_OF_LEVELS - 1)) + { + if (SFG_keyIsDown(SFG_KEY_A)) + SFG_setGameState(SFG_GAME_STATE_OUTRO); + } + else if (SFG_keyIsDown(SFG_KEY_RIGHT) || + SFG_keyIsDown(SFG_KEY_LEFT)) + { + SFG_setAndInitLevel(SFG_currentLevel.levelNumber + 1); + + SFG_player.health = SFG_game.save[2]; + SFG_player.ammo[0] = SFG_game.save[3]; + SFG_player.ammo[1] = SFG_game.save[4]; + SFG_player.ammo[2] = SFG_game.save[5]; + + if (SFG_keyIsDown(SFG_KEY_RIGHT) && SFG_game.saved != SFG_CANT_SAVE) + { + // save the current position + SFG_gameSave(); + SFG_game.saved = 1; + } + } + } + + break; + } + + case SFG_GAME_STATE_MAP: + if (SFG_keyIsDown(SFG_KEY_B)) + SFG_setGameState(SFG_GAME_STATE_MENU); + + break; + + case SFG_GAME_STATE_INTRO: + if (SFG_keyJustPressed(SFG_KEY_A) || SFG_keyJustPressed(SFG_KEY_B)) + SFG_setAndInitLevel(0); + + break; + + case SFG_GAME_STATE_OUTRO: + if (((SFG_game.frameTime - SFG_game.stateChangeTime) > + SFG_STORYTEXT_DURATION) && (SFG_keyIsDown(SFG_KEY_A) || + SFG_keyIsDown(SFG_KEY_B))) + { + SFG_setGameState(SFG_GAME_STATE_MENU); + SFG_playGameSound(3,SFG_MENU_CLICK_VOLUME); + } + + break; + + case SFG_GAME_STATE_LEVEL_START: + { + SFG_updateLevel(); + SFG_updatePlayerHeight(); // in case player is on elevator + + if (SFG_currentLevel.levelNumber > (SFG_game.save[0] & 0x0f)) + { + SFG_game.save[0] = // save progress + (SFG_game.save[0] & 0xf0) | SFG_currentLevel.levelNumber; + SFG_gameSave(); + } + + int16_t x = 0, y = 0; + + SFG_getMouseOffset(&x,&y); // this keeps centering the mouse + + if ((SFG_game.frameTime - SFG_game.stateChangeTime) >= + SFG_LEVEL_START_DURATION) + SFG_setGameState(SFG_GAME_STATE_PLAYING); + + break; + } + + default: + break; + } +} + +void SFG_fillRectangle( + uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t color) +{ + if ((x + width > SFG_GAME_RESOLUTION_X) || + (y + height > SFG_GAME_RESOLUTION_Y)) + return; + + for (uint16_t j = y; j < y + height; ++j) + for (uint16_t i = x; i < x + width; ++i) + SFG_setGamePixel(i,j,color); +} + +static inline void SFG_clearScreen(uint8_t color) +{ + SFG_fillRectangle(0,0,SFG_GAME_RESOLUTION_X, + SFG_GAME_RESOLUTION_Y,color); +} + +/** + Draws fullscreen map of the current level. +*/ +void SFG_drawMap() +{ + SFG_clearScreen(0); + + uint16_t maxJ = + (SFG_MAP_PIXEL_SIZE * SFG_MAP_SIZE) < SFG_GAME_RESOLUTION_Y ? + (SFG_MAP_SIZE) : (SFG_GAME_RESOLUTION_Y / SFG_MAP_PIXEL_SIZE); + + uint16_t maxI = + (SFG_MAP_PIXEL_SIZE * SFG_MAP_SIZE) < SFG_GAME_RESOLUTION_X ? + (SFG_MAP_SIZE) : (SFG_GAME_RESOLUTION_X / SFG_MAP_PIXEL_SIZE); + + uint16_t topLeftX = + (SFG_GAME_RESOLUTION_X - (maxI * SFG_MAP_PIXEL_SIZE)) / 2; + + uint16_t topLeftY = + (SFG_GAME_RESOLUTION_Y - (maxJ * SFG_MAP_PIXEL_SIZE)) / 2; + + uint16_t x; + uint16_t y = topLeftY; + + uint8_t playerColor = + SFG_game.blink ? SFG_MAP_PLAYER_COLOR1 : SFG_MAP_PLAYER_COLOR2; + + for (int16_t j = 0; j < maxJ; ++j) + { + x = topLeftX; + + for (int16_t i = maxI - 1; i >= 0; --i) + { + uint8_t color = 0; // init with non-revealed color + + if (SFG_currentLevel.mapRevealMask & SFG_getMapRevealBit(i,j)) + { + uint8_t properties; + + SFG_TileDefinition tile = + SFG_getMapTile(SFG_currentLevel.levelPointer,i,j,&properties); + + color = playerColor; // start with player color + + if (i != SFG_player.squarePosition[0] || + j != SFG_player.squarePosition[1]) + { + if (properties == SFG_TILE_PROPERTY_ELEVATOR) + color = SFG_MAP_ELEVATOR_COLOR; + else if (properties == SFG_TILE_PROPERTY_SQUEEZER) + color = SFG_MAP_SQUEEZER_COLOR; + else if (properties == SFG_TILE_PROPERTY_DOOR) + color = SFG_MAP_DOOR_COLOR; + else + { + color = 0; + + uint8_t c = SFG_TILE_CEILING_HEIGHT(tile) / 4; + + if (c != 0) + color = (SFG_TILE_FLOOR_HEIGHT(tile) % 8 + 3) * 8 + c - 1; + } + } + } + + for (int_fast16_t k = 0; k < SFG_MAP_PIXEL_SIZE; ++k) + for (int_fast16_t l = 0; l < SFG_MAP_PIXEL_SIZE; ++l) + SFG_setGamePixel(x + l, y + k,color); + + x += SFG_MAP_PIXEL_SIZE; + } + + y += SFG_MAP_PIXEL_SIZE; + } +} + +/** + Draws fullscreen story text (intro/outro). +*/ +void SFG_drawStoryText() +{ + const char *text = SFG_outroText; + uint16_t textColor = 23; + uint8_t clearColor = 9; + uint8_t sprite = 18; + + if (SFG_currentLevel.levelNumber != (SFG_NUMBER_OF_LEVELS - 1)) // intro? + { + text = SFG_introText; + textColor = 7; + clearColor = 0; + sprite = SFG_game.blink * 2; + } + + SFG_clearScreen(clearColor); + + if (SFG_GAME_RESOLUTION_Y > 50) + SFG_blitImage(SFG_monsterSprites + sprite * SFG_TEXTURE_STORE_SIZE, + (SFG_GAME_RESOLUTION_X - SFG_TEXTURE_SIZE * SFG_FONT_SIZE_SMALL) / 2, + SFG_GAME_RESOLUTION_Y - (SFG_TEXTURE_SIZE + 3) * SFG_FONT_SIZE_SMALL, + SFG_FONT_SIZE_SMALL); + + uint16_t textLen = 0; + + while (text[textLen] != 0) + textLen++; + + uint16_t drawLen = + RCL_min(textLen, + ((SFG_game.frameTime - SFG_game.stateChangeTime) * textLen) / + SFG_STORYTEXT_DURATION + 1); + +#define CHAR_SIZE (SFG_FONT_SIZE_SMALL * (SFG_FONT_CHARACTER_SIZE + 1)) +#define LINE_LENGTH (SFG_GAME_RESOLUTION_X / CHAR_SIZE) +#define MAX_LENGTH (((SFG_GAME_RESOLUTION_Y / CHAR_SIZE) / 2) * LINE_LENGTH ) + + uint16_t drawShift = (drawLen < MAX_LENGTH) ? 0 : + (((drawLen - MAX_LENGTH) / LINE_LENGTH) * LINE_LENGTH); + +#undef CHAR_SIZE +#undef LINE_LENGTH +#undef MAX_LENGTH + + text += drawShift; + drawLen -= drawShift; + + SFG_drawText(text,SFG_HUD_MARGIN,SFG_HUD_MARGIN,SFG_FONT_SIZE_SMALL,textColor, + drawLen,SFG_GAME_RESOLUTION_X - SFG_HUD_MARGIN); +} + +/** + Draws a number as text on screen, returns the number of characters drawn. +*/ +uint8_t SFG_drawNumber( + int16_t number, + uint16_t x, + uint16_t y, + uint8_t size, + uint8_t color) +{ + char text[7]; + + text[6] = 0; // terminate the string + + int8_t positive = 1; + + if (number < 0) + { + positive = 0; + number *= -1; + } + + int8_t position = 5; + + while (1) + { + text[position] = '0' + number % 10; + number /= 10; + + position--; + + if (number == 0 || position == 0) + break; + } + + if (!positive) + { + text[position] = '-'; + position--; + } + + SFG_drawText(text + position + 1,x,y,size,color,0,0); + + return 5 - position; +} + +/** + Draws a screen border that indicates something is happening, e.g. being hurt + or taking an item. +*/ +void SFG_drawIndicationBorder(uint16_t width, uint8_t color) +{ + for (int_fast16_t j = 0; j < width; ++j) + { + uint16_t j2 = SFG_GAME_RESOLUTION_Y - 1 - j; + + for (int_fast16_t i = 0; i < SFG_GAME_RESOLUTION_X; ++i) + { + if ((i & 0x01) == (j & 0x01)) + { + SFG_setGamePixel(i,j,color); + SFG_setGamePixel(i,j2,color); + } + } + } + + for (int_fast16_t i = 0; i < width; ++i) + { + uint16_t i2 = SFG_GAME_RESOLUTION_X - 1 - i; + + for (int_fast16_t j = width; j < SFG_GAME_RESOLUTION_Y - width; ++j) + { + if ((i & 0x01) == (j & 0x01)) + { + SFG_setGamePixel(i,j,color); + SFG_setGamePixel(i2,j,color); + } + } + } +} + +/** + Draws the player weapon, includes handling the shoot animation. +*/ +void SFG_drawWeapon(int16_t bobOffset) +{ + uint32_t animationLength = + RCL_max(SFG_MIN_WEAPON_COOLDOWN_FRAMES, + SFG_GET_WEAPON_FIRE_COOLDOWN_FRAMES(SFG_player.weapon)); + + uint32_t shotAnimationFrame = + animationLength - SFG_player.weaponCooldownFrames; + + bobOffset -= SFG_HUD_BAR_HEIGHT; + + uint8_t fireType = SFG_GET_WEAPON_FIRE_TYPE(SFG_player.weapon); + + if (shotAnimationFrame < animationLength) + { + if (fireType == SFG_WEAPON_FIRE_TYPE_MELEE) + { + bobOffset = shotAnimationFrame < animationLength / 2 ? 0 : + 2 * SFG_WEAPONBOB_OFFSET_PIXELS ; + } + else + { + bobOffset += + ((animationLength - shotAnimationFrame) * SFG_WEAPON_IMAGE_SCALE * 20) + / animationLength; + + if ( + ((fireType == SFG_WEAPON_FIRE_TYPE_FIREBALL) || + (fireType == SFG_WEAPON_FIRE_TYPE_BULLET)) && + shotAnimationFrame < animationLength / 2) + SFG_blitImage(SFG_effectSprites, + SFG_WEAPON_IMAGE_POSITION_X, + SFG_WEAPON_IMAGE_POSITION_Y - + (SFG_TEXTURE_SIZE / 3) * SFG_WEAPON_IMAGE_SCALE + bobOffset, + SFG_WEAPON_IMAGE_SCALE); + } + } + + SFG_blitImage(SFG_weaponImages + SFG_player.weapon * SFG_TEXTURE_STORE_SIZE, + SFG_WEAPON_IMAGE_POSITION_X, + SFG_WEAPON_IMAGE_POSITION_Y + bobOffset - 1, + SFG_WEAPON_IMAGE_SCALE); +} + +uint16_t SFG_textLen(const char *text) +{ + uint16_t result = 0; + + while (text[result] != 0) + result++; + + return result; +} + +static inline uint16_t SFG_characterSize(uint8_t textSize) +{ + return (SFG_FONT_CHARACTER_SIZE + 1) * textSize; +} + +static inline uint16_t + SFG_textHorizontalSize(const char *text, uint8_t textSize) +{ + return (SFG_textLen(text) * SFG_characterSize(textSize)); +} + +void SFG_drawMenu() +{ + #define BACKGROUND_SCALE (SFG_GAME_RESOLUTION_X / (4 * SFG_TEXTURE_SIZE ) ) + + #if BACKGROUND_SCALE == 0 + #undef BACKGROUND_SCALE + #define BACKGROUND_SCALE 1 + #endif + + #define SCROLL_PIXELS_PER_FRAME ((64 * SFG_GAME_RESOLUTION_X) / (8 * SFG_FPS)) + + #if SCROLL_PIXELS_PER_FRAME == 0 + #undef SCROLL_PIXELS_PER_FRAME + #define SCROLL_PIXELS_PER_FRAME 1 + #endif + + #define SELECTION_START_X ((SFG_GAME_RESOLUTION_X - 12 * SFG_FONT_SIZE_MEDIUM\ + * (SFG_FONT_CHARACTER_SIZE + 1)) / 2) + + uint16_t scroll = (SFG_game.frame * SCROLL_PIXELS_PER_FRAME) / 64; + + for (uint16_t y = 0; y < SFG_GAME_RESOLUTION_Y; ++y) + for (uint16_t x = 0; x < SFG_GAME_RESOLUTION_X; ++x) + SFG_setGamePixel(x,y, + (y >= (SFG_TEXTURE_SIZE * BACKGROUND_SCALE)) ? 0 : + SFG_getTexel(SFG_backgroundImages,((x + scroll) / BACKGROUND_SCALE) + % SFG_TEXTURE_SIZE,y / BACKGROUND_SCALE)); + + uint16_t y = SFG_characterSize(SFG_FONT_SIZE_MEDIUM); + + SFG_blitImage(SFG_logoImage, + SFG_GAME_RESOLUTION_X / 2 - 16 * SFG_FONT_SIZE_MEDIUM,y, + SFG_FONT_SIZE_MEDIUM); + +#if SFG_GAME_RESOLUTION_Y > 50 + y += 32 * SFG_FONT_SIZE_MEDIUM + SFG_characterSize(SFG_FONT_SIZE_MEDIUM); +#else + y = 2; +#endif + + uint8_t i = 0; + + while (1) // draw menu items + { + uint8_t item = SFG_getMenuItem(i); + + if (item == SFG_MENU_ITEM_NONE) + break; + +#if SFG_GAME_RESOLUTION_Y < 70 + // with low resolution only display the selected item + + if (i != SFG_game.selectedMenuItem) + { + i++; + continue; + } +#endif + + const char *text = SFG_menuItemTexts[item]; + uint8_t textLen = SFG_textLen(text); + + uint16_t drawX = (SFG_GAME_RESOLUTION_X - + SFG_textHorizontalSize(text,SFG_FONT_SIZE_MEDIUM)) / 2; + + uint8_t textColor = 7; + + if (i != SFG_game.selectedMenuItem) + textColor = 23; + else + SFG_fillRectangle( // menu item highlight + SELECTION_START_X, + y - SFG_FONT_SIZE_MEDIUM, + SFG_GAME_RESOLUTION_X - SELECTION_START_X * 2, + SFG_characterSize(SFG_FONT_SIZE_MEDIUM),2); + + SFG_drawText(text,drawX,y,SFG_FONT_SIZE_MEDIUM,textColor,0,0); + + if ((item == SFG_MENU_ITEM_PLAY || item == SFG_MENU_ITEM_SOUND + || item == SFG_MENU_ITEM_SHEAR) && + ((i != SFG_game.selectedMenuItem) || SFG_game.blink)) + { + uint32_t x = + drawX + SFG_characterSize(SFG_FONT_SIZE_MEDIUM) * (textLen + 1); + + uint8_t c = 93; + + if (item == SFG_MENU_ITEM_PLAY) + SFG_drawNumber(SFG_game.selectedLevel + 1,x,y,SFG_FONT_SIZE_MEDIUM,c); + else if (item == SFG_MENU_ITEM_SHEAR) + { + uint8_t n = (SFG_game.settings >> 2) & 0x03; + + SFG_drawNumber(n == 3 ? 2 : n,x,y,SFG_FONT_SIZE_MEDIUM,c); + } + else + { + char settingText[3] = " "; + + settingText[0] = (SFG_game.settings & 0x01) ? 'S' : ' '; + settingText[1] = (SFG_game.settings & 0x02) ? 'M' : ' '; + + SFG_drawText(settingText,x,y,SFG_FONT_SIZE_MEDIUM,c,0,0); + } + } + + y += SFG_characterSize(SFG_FONT_SIZE_MEDIUM) + SFG_FONT_SIZE_MEDIUM; + i++; + } + + SFG_drawText(SFG_VERSION_STRING " CC0",SFG_HUD_MARGIN,SFG_GAME_RESOLUTION_Y - + SFG_HUD_MARGIN - SFG_FONT_SIZE_SMALL * SFG_FONT_CHARACTER_SIZE, + SFG_FONT_SIZE_SMALL,4,0,0); + + #if SFG_OS_IS_MALWARE + if (SFG_game.blink) + SFG_drawText(SFG_MALWARE_WARNING,SFG_HUD_MARGIN,SFG_HUD_MARGIN, + SFG_FONT_SIZE_MEDIUM,95,0,0); + #endif + + #undef MAX_ITEMS + #undef BACKGROUND_SCALE + #undef SCROLL_PIXELS_PER_FRAME +} + +void SFG_drawWinOverlay() +{ + uint32_t t = RCL_min(SFG_WIN_ANIMATION_DURATION, + SFG_game.frameTime - SFG_game.stateChangeTime); + + uint32_t t2 = RCL_min(t,SFG_WIN_ANIMATION_DURATION / 4); + + #define STRIP_HEIGHT (SFG_GAME_RESOLUTION_Y / 2) + #define INNER_STRIP_HEIGHT ((STRIP_HEIGHT * 3) / 4) + #define STRIP_START ((SFG_GAME_RESOLUTION_Y - STRIP_HEIGHT) / 2) + + RCL_Unit l = (t2 * STRIP_HEIGHT * 4) / SFG_WIN_ANIMATION_DURATION; + + for (uint16_t y = STRIP_START; y < STRIP_START + l; ++y) + for (uint16_t x = 0; x < SFG_GAME_RESOLUTION_X; ++x) + SFG_setGamePixel(x,y, + RCL_abs(y - (SFG_GAME_RESOLUTION_Y / 2)) <= (INNER_STRIP_HEIGHT / 2) ? + 0 : 172); + + char textLine[] = "level done"; + + uint16_t y = SFG_GAME_RESOLUTION_Y / 2 - + ((STRIP_HEIGHT + INNER_STRIP_HEIGHT) / 2) / 2; + + uint16_t x = (SFG_GAME_RESOLUTION_X - + SFG_textHorizontalSize(textLine,SFG_FONT_SIZE_BIG)) / 2; + + SFG_drawText(textLine,x,y,SFG_FONT_SIZE_BIG,7 + SFG_game.blink * 95,255,0); + + uint32_t timeTotal = SFG_SAVE_TOTAL_TIME; + + // don't show totals in level 1: + uint8_t blink = (SFG_game.blink) && (SFG_currentLevel.levelNumber != 0) + && (timeTotal != 0); + + if (t >= (SFG_WIN_ANIMATION_DURATION / 2)) + { + y += (SFG_FONT_SIZE_BIG + SFG_FONT_SIZE_MEDIUM) * SFG_FONT_CHARACTER_SIZE; + x = SFG_HUD_MARGIN; + + #define CHAR_SIZE (SFG_FONT_SIZE_SMALL * SFG_FONT_CHARACTER_SIZE) + + uint32_t time = blink ? timeTotal : SFG_currentLevel.completionTime10sOfS; + + x += SFG_drawNumber(time / 10,x,y,SFG_FONT_SIZE_SMALL,7) * + CHAR_SIZE + SFG_FONT_SIZE_SMALL; + + char timeRest[5] = ".X s"; + + timeRest[1] = '0' + (time % 10); + + SFG_drawText(timeRest,x,y,SFG_FONT_SIZE_SMALL,7,4,0); + + x = SFG_HUD_MARGIN; + y += (SFG_FONT_SIZE_BIG + SFG_FONT_SIZE_MEDIUM) * SFG_FONT_CHARACTER_SIZE; + + if (blink) + { + x += (SFG_drawNumber(SFG_game.save[10] + SFG_game.save[11] * 256,x,y, + SFG_FONT_SIZE_SMALL,7) + 1) * CHAR_SIZE; + } + else + { + x += SFG_drawNumber(SFG_currentLevel.monstersDead,x,y, + SFG_FONT_SIZE_SMALL,7) * CHAR_SIZE; + + SFG_drawText("/",x,y,SFG_FONT_SIZE_SMALL,7,1,0); + + x += CHAR_SIZE; + + x += (SFG_drawNumber(SFG_currentLevel.monsterRecordCount,x,y, + SFG_FONT_SIZE_SMALL,7) + 1) * CHAR_SIZE; + } + + SFG_drawText(SFG_TEXT_KILLS,x,y,SFG_FONT_SIZE_SMALL,7,255,0); + + if ((t >= (SFG_WIN_ANIMATION_DURATION - 1)) && + (SFG_currentLevel.levelNumber != (SFG_NUMBER_OF_LEVELS - 1))) + { + y += (SFG_FONT_SIZE_BIG + SFG_FONT_SIZE_MEDIUM) * SFG_FONT_CHARACTER_SIZE; + + SFG_drawText(SFG_TEXT_SAVE_PROMPT, + (SFG_GAME_RESOLUTION_X - SFG_textHorizontalSize(SFG_TEXT_SAVE_PROMPT, + SFG_FONT_SIZE_MEDIUM)) / 2,y,SFG_FONT_SIZE_MEDIUM,7,255,0); + } + + #undef CHAR_SIZE + } + + #undef STRIP_HEIGHT + #undef STRIP_START + #undef INNER_STRIP_HEIGHT +} + +void SFG_draw() +{ +#if SFG_BACKGROUND_BLUR != 0 + SFG_backgroundBlurIndex = 0; +#endif + + if (SFG_game.state == SFG_GAME_STATE_MENU) + { + SFG_drawMenu(); + return; + } + + if (SFG_game.state == SFG_GAME_STATE_INTRO || + SFG_game.state == SFG_GAME_STATE_OUTRO) + { + SFG_drawStoryText(); + return; + } + + if (SFG_keyIsDown(SFG_KEY_MAP) || (SFG_game.state == SFG_GAME_STATE_MAP)) + { + SFG_drawMap(); + } + else + { + for (int_fast16_t i = 0; i < SFG_Z_BUFFER_SIZE; ++i) + SFG_game.zBuffer[i] = 255; + + int16_t weaponBobOffset = 0; + +#if SFG_HEADBOB_ENABLED + RCL_Unit headBobOffset = 0; + +#if SFG_HEADBOB_SHEAR != 0 + int16_t headBobShearOffset = 0; +#endif + + if (SFG_game.state != SFG_GAME_STATE_LOSE) + { + RCL_Unit bobSin = RCL_sin(SFG_player.headBobFrame); + + headBobOffset = (bobSin * SFG_HEADBOB_OFFSET) / RCL_UNITS_PER_SQUARE; + +#if SFG_HEADBOB_SHEAR != 0 + headBobShearOffset = (bobSin * SFG_HEADBOB_SHEAR) / RCL_UNITS_PER_SQUARE; + SFG_player.camera.shear += headBobShearOffset; +#endif + + weaponBobOffset = + (bobSin * SFG_WEAPONBOB_OFFSET_PIXELS) / (RCL_UNITS_PER_SQUARE) + + SFG_WEAPONBOB_OFFSET_PIXELS; + } + else + { + // player die animation + + int32_t t = SFG_game.frameTime - SFG_game.stateChangeTime; + + weaponBobOffset = (SFG_WEAPON_IMAGE_SCALE * SFG_TEXTURE_SIZE * t) / + SFG_LOSE_ANIMATION_DURATION; + } + + // add head bob just for the rendering (we'll will substract it back later) + + SFG_player.camera.height += headBobOffset; +#endif // headbob enabled? + + RCL_renderComplex( + SFG_player.camera, + SFG_floorHeightAt, + SFG_ceilingHeightAt, + SFG_texturesAt, + SFG_game.rayConstraints); + + // draw sprites: + + // monster sprites: + for (int_fast16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + { + SFG_MonsterRecord m = SFG_currentLevel.monsterRecords[i]; + uint8_t state = SFG_MR_STATE(m); + + if (state != SFG_MONSTER_STATE_INACTIVE) + { + RCL_Vector2D worldPosition; + + worldPosition.x = SFG_MONSTER_COORD_TO_RCL_UNITS(m.coords[0]); + worldPosition.y = SFG_MONSTER_COORD_TO_RCL_UNITS(m.coords[1]); + + uint8_t spriteSize = SFG_GET_MONSTER_SPRITE_SIZE( + SFG_MONSTER_TYPE_TO_INDEX(SFG_MR_TYPE(m))); + + RCL_Unit worldHeight = + SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(m.coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(m.coords[1])) + + SFG_SPRITE_SIZE_TO_HEIGHT_ABOVE_GROUND(spriteSize); + + RCL_PixelInfo p = + RCL_mapToScreen(worldPosition,worldHeight,SFG_player.camera); + + if (p.depth > 0 && + SFG_spriteIsVisible(worldPosition,worldHeight,spriteSize)) + { + const uint8_t *s = + SFG_getMonsterSprite( + SFG_MR_TYPE(m), + state, + SFG_game.spriteAnimationFrame & 0x01); + + SFG_drawScaledSprite(s, + p.position.x * SFG_RAYCASTING_SUBSAMPLE,p.position.y, + RCL_perspectiveScaleVertical( + SFG_SPRITE_SIZE_PIXELS(spriteSize), + p.depth), + p.depth / (RCL_UNITS_PER_SQUARE * 2),p.depth); + } + } + } + + // item sprites: + for (int_fast16_t i = 0; i < SFG_currentLevel.itemRecordCount; ++i) + if (SFG_currentLevel.itemRecords[i] & SFG_ITEM_RECORD_ACTIVE_MASK) + { + RCL_Vector2D worldPosition; + + SFG_LevelElement e = + SFG_currentLevel.levelPointer->elements[ + SFG_currentLevel.itemRecords[i] & ~SFG_ITEM_RECORD_ACTIVE_MASK]; + + worldPosition.x = + SFG_ELEMENT_COORD_TO_RCL_UNITS(e.coords[0]); + + worldPosition.y = + SFG_ELEMENT_COORD_TO_RCL_UNITS(e.coords[1]); + + const uint8_t *sprite; + uint8_t spriteSize; + + SFG_getItemSprite(e.type,&sprite,&spriteSize); + + if (sprite != 0) + { + RCL_Unit worldHeight = SFG_floorHeightAt(e.coords[0],e.coords[1]) + + SFG_SPRITE_SIZE_TO_HEIGHT_ABOVE_GROUND(spriteSize); + + RCL_PixelInfo p = + RCL_mapToScreen(worldPosition,worldHeight,SFG_player.camera); + + if (p.depth > 0 && + SFG_spriteIsVisible(worldPosition,worldHeight,spriteSize)) + SFG_drawScaledSprite(sprite,p.position.x * SFG_RAYCASTING_SUBSAMPLE, + p.position.y, + RCL_perspectiveScaleVertical(SFG_SPRITE_SIZE_PIXELS(spriteSize), + p.depth),p.depth / (RCL_UNITS_PER_SQUARE * 2),p.depth); + } + } + + // projectile sprites: + for (uint8_t i = 0; i < SFG_currentLevel.projectileRecordCount; ++i) + { + SFG_ProjectileRecord *proj = &(SFG_currentLevel.projectileRecords[i]); + + if (proj->type == SFG_PROJECTILE_BULLET) + continue; // bullets aren't drawn + + RCL_Vector2D worldPosition; + + worldPosition.x = proj->position[0]; + worldPosition.y = proj->position[1]; + + RCL_PixelInfo p = + RCL_mapToScreen(worldPosition,proj->position[2],SFG_player.camera); + + const uint8_t *s = + SFG_effectSprites + proj->type * SFG_TEXTURE_STORE_SIZE; + + int16_t spriteSize = SFG_SPRITE_SIZE_PIXELS(0); + + if (proj->type == SFG_PROJECTILE_EXPLOSION || + proj->type == SFG_PROJECTILE_DUST) + { + int16_t doubleFramesToLive = + RCL_nonZero(SFG_GET_PROJECTILE_FRAMES_TO_LIVE(proj->type) / 2); + + // grow the explosion/dust sprite as an animation + spriteSize = ( + SFG_SPRITE_SIZE_PIXELS(2) * + RCL_sin( + ((doubleFramesToLive - + proj->doubleFramesToLive) * RCL_UNITS_PER_SQUARE / 4) + / doubleFramesToLive) + ) / RCL_UNITS_PER_SQUARE; + } + + if (p.depth > 0 && + SFG_spriteIsVisible(worldPosition,proj->position[2],spriteSize)) + SFG_drawScaledSprite(s, + p.position.x * SFG_RAYCASTING_SUBSAMPLE,p.position.y, + RCL_perspectiveScaleVertical(spriteSize,p.depth), + SFG_fogValueDiminish(p.depth), + p.depth); + } + +#if SFG_HEADBOB_ENABLED + // after rendering sprites substract back the head bob offset + SFG_player.camera.height -= headBobOffset; + +#if SFG_HEADBOB_SHEAR != 0 + SFG_player.camera.shear -= headBobShearOffset; +#endif + +#endif // head bob enabled? + +#if SFG_PREVIEW_MODE == 0 + SFG_drawWeapon(weaponBobOffset); +#endif + + // draw HUD: + + // bar + + uint8_t color = 61; + + for (uint16_t j = SFG_GAME_RESOLUTION_Y - SFG_HUD_BAR_HEIGHT; + j < SFG_GAME_RESOLUTION_Y; ++j) + { + for (uint16_t i = 0; i < SFG_GAME_RESOLUTION_X; ++i) + SFG_setGamePixel(i,j,color); + + color = 48; + } + + #define TEXT_Y (SFG_GAME_RESOLUTION_Y - SFG_HUD_MARGIN - \ + SFG_FONT_CHARACTER_SIZE * SFG_FONT_SIZE_MEDIUM) + + SFG_drawNumber( // health + SFG_player.health, + SFG_HUD_MARGIN, + TEXT_Y, + SFG_FONT_SIZE_MEDIUM, + SFG_player.health > SFG_PLAYER_HEALTH_WARNING_LEVEL ? 6 : 175); + + SFG_drawNumber( // ammo + SFG_player.weapon != SFG_WEAPON_KNIFE ? + SFG_player.ammo[SFG_weaponAmmo(SFG_player.weapon)] : 0, + SFG_GAME_RESOLUTION_X - SFG_HUD_MARGIN - + (SFG_FONT_CHARACTER_SIZE + 1) * SFG_FONT_SIZE_MEDIUM * 3, + TEXT_Y, + SFG_FONT_SIZE_MEDIUM, + 6); + + for (uint8_t i = 0; i < 3; ++i) // access cards + if ( + ((SFG_player.cards >> i) | ((SFG_player.cards >> (i + 3)) + & SFG_game.blink)) & 0x01) + SFG_fillRectangle( + SFG_HUD_MARGIN + (SFG_FONT_CHARACTER_SIZE + 1) * + SFG_FONT_SIZE_MEDIUM * (5 + i), + TEXT_Y, + SFG_FONT_SIZE_MEDIUM * SFG_FONT_CHARACTER_SIZE, + SFG_FONT_SIZE_MEDIUM * SFG_FONT_CHARACTER_SIZE, + i == 0 ? 93 : (i == 1 ? 124 : 60)); + + #undef TEXT_Y + + // border indicator + + if ((SFG_game.frame - SFG_player.lastHurtFrame + <= SFG_HUD_BORDER_INDICATOR_DURATION_FRAMES) || + (SFG_game.state == SFG_GAME_STATE_LOSE)) + SFG_drawIndicationBorder(SFG_HUD_BORDER_INDICATOR_WIDTH_PIXELS, + SFG_HUD_HURT_INDICATION_COLOR); + else if (SFG_game.frame - SFG_player.lastItemTakenFrame + <= SFG_HUD_BORDER_INDICATOR_DURATION_FRAMES) + SFG_drawIndicationBorder(SFG_HUD_BORDER_INDICATOR_WIDTH_PIXELS, + SFG_HUD_ITEM_TAKEN_INDICATION_COLOR); + + if (SFG_game.state == SFG_GAME_STATE_WIN) + SFG_drawWinOverlay(); + else if (SFG_game.state == SFG_GAME_STATE_LEVEL_START) + SFG_drawLevelStartOverlay(); + } +} + +uint8_t SFG_mainLoopBody() +{ + /* Standard deterministic game loop, independed of actual achieved FPS. + Each game logic (physics) frame is performed with the SFG_MS_PER_FRAME + delta time. */ + + if (SFG_game.state != SFG_GAME_STATE_INIT) + { + uint32_t timeNow = SFG_getTimeMs(); + +#if SFG_TIME_MULTIPLIER != 1024 + timeNow = (timeNow * SFG_TIME_MULTIPLIER) / 1024; +#endif + + int32_t timeSinceLastFrame = timeNow - SFG_game.frameTime; + + if (timeSinceLastFrame >= SFG_MS_PER_FRAME) + { + uint8_t steps = 0; + + uint8_t wasFirstFrame = SFG_game.frame == 0; + + while (timeSinceLastFrame >= SFG_MS_PER_FRAME) + { + uint8_t previousWeapon = SFG_player.weapon; + + SFG_game.frameTime += SFG_MS_PER_FRAME; + + SFG_gameStep(); + + if (SFG_player.weapon != previousWeapon) + SFG_processEvent(SFG_EVENT_PLAYER_CHANGES_WEAPON,SFG_player.weapon); + + timeSinceLastFrame -= SFG_MS_PER_FRAME; + + SFG_game.frame++; + steps++; + } + + if ((steps > 1) && (SFG_game.antiSpam == 0) && (!wasFirstFrame)) + { + SFG_LOG("failed to reach target FPS! consider setting a lower value") + SFG_game.antiSpam = 30; + } + + if (SFG_game.antiSpam > 0) + SFG_game.antiSpam--; + + // render only once + SFG_draw(); + + if (SFG_game.frame % 16 == 0) + SFG_CPU_LOAD(((SFG_getTimeMs() - timeNow) * 100) / SFG_MS_PER_FRAME); + } + else + { + // wait, relieve CPU + SFG_sleepMs(RCL_max(1, + (3 * (SFG_game.frameTime + SFG_MS_PER_FRAME - timeNow)) / 4)); + } + } + else if (!SFG_keyPressed(SFG_KEY_A) && !SFG_keyPressed(SFG_KEY_B)) + { + /* At the beginning we have to wait for the release of the keys in order not + to immediatelly confirm a menu item. */ + SFG_setGameState(SFG_GAME_STATE_MENU); + } + + return SFG_game.continues; +} + +#undef SFG_SAVE_TOTAL_TIME + +#endif // guard diff --git a/main_gbmeta/images.h b/main_gbmeta/images.h new file mode 100644 index 0000000..fac3efb --- /dev/null +++ b/main_gbmeta/images.h @@ -0,0 +1,1397 @@ +/** + @file assets.h + + This file containts assets to be used in the game. Textures are stored by + columns for cache friendliness (as rendering also happens by columns), + 4 bits per pixel, which means an index to 16 color subpalette stored at the + beginning of the image. Images can be converted to this format with the + provided pything script: + + python img2array.py -t -c -x32 -y32 -ppalette565.png image.png + + by Miloslav Ciz (drummyfish), 2019 + + Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) + plus a waiver of all other intellectual property. The goal of this work is + be and remain completely in the public domain forever, available for any use + whatsoever. +*/ + +#ifndef _SFG_IMAGES_H +#define _SFG_IMAGES_H + +#define SFG_TEXTURE_SIZE 32 + +#define SFG_TEXTURE_STORE_SIZE (16 + (SFG_TEXTURE_SIZE * SFG_TEXTURE_SIZE) / 2) + +/** + Color index which will in textures and sprites be considered transparent. +*/ +#define SFG_TRANSPARENT_COLOR 175 + +/** + Special index of an implicit texture that consists of only transparent pixels. +*/ +#define SFG_TRANSPARENT_TEXTURE 255 + +static inline uint8_t SFG_getTexel(const uint8_t *texture, uint8_t x, uint8_t y) +{ + x &= 0x1f; + y &= 0x1f; + + return SFG_PROGRAM_MEMORY_U8 (texture + + ((SFG_PROGRAM_MEMORY_U8(texture + 16 + (x * SFG_TEXTURE_SIZE + y) / 2) >> + (4 * (y % 2 == 0))) & 0x0f)); +} + +#define SFG_WALL_TEXTURE_COUNT 16 + +SFG_PROGRAM_MEMORY uint8_t + SFG_wallTextures[SFG_WALL_TEXTURE_COUNT * SFG_TEXTURE_STORE_SIZE] = +{ +// 0, white wooden planks +4,21,5,3,20,0,2,26,6,18,57,65,1,16,17,49,0,1,0,3,32,1,33,0,161,64,1,16,64,3,3, +32,0,17,16,9,32,1,17,1,161,65,1,16,78,132,35,32,0,17,16,7,32,1,32,17,240,49,0, +16,57,99,87,206,0,18,16,6,33,0,16,1,177,48,0,0,97,0,2,0,0,17,32,6,32,1,0,1,178, +48,0,0,48,0,2,0,0,17,32,7,32,17,1,0,178,48,1,0,49,0,1,0,0,1,16,3,32,18,0,0,194, +48,0,0,48,0,18,4,64,17,32,4,35,0,3,0,194,48,0,0,49,0,34,4,0,17,32,6,130,50,32, +40,242,48,1,0,49,0,18,0,0,2,32,12,85,85,85,85,81,48,2,0,49,0,33,3,0,2,16,3,32,0, +32,2,98,48,1,0,49,0,34,19,0,18,17,3,32,0,32,0,194,48,2,0,0,0,34,3,4,2,16,3,16,0, +32,32,226,48,2,0,48,0,33,19,0,18,33,3,0,16,32,32,178,48,1,1,50,1,34,3,4,17,16,3, +0,16,32,16,162,48,1,64,50,1,34,7,3,1,17,3,0,16,32,16,184,2,2,2,2,48,18,3,0,0,17, +3,0,17,32,16,94,93,93,89,112,0,18,3,0,0,16,3,0,2,32,16,48,48,48,3,0,0,17,4,0,0, +17,3,0,1,32,16,48,48,0,3,1,1,18,3,0,0,32,7,16,1,32,16,48,0,1,0,1,50,34,3,0,1,33, +3,16,1,20,32,112,48,0,16,1,49,34,3,64,16,33,3,4,2,4,16,48,49,0,16,0,49,34,3,64, +0,32,3,16,1,0,0,48,49,0,16,65,48,34,3,49,0,17,3,16,2,0,0,48,49,1,32,0,49,34,3, +64,0,16,19,16,2,1,0,113,49,17,16,0,48,32,3,0,0,16,19,16,1,2,0,97,66,17,32,64,48, +33,19,34,2,0,137,16,1,18,0,97,49,17,16,66,64,32,3,84,212,105,69,16,1,17,0,97,49, +18,16,50,48,16,19,51,48,51,51,16,1,16,0,98,50,1,19,66,48,32,3,0,1,0,3,32,1,33,0, +177,49,2,16,66,64,16,3,0,1,0,7,32,1,16,1,82,64,1,16,50,0,16,35,0,1,0,9,33,2,32, +0,161,64,1,20,48,0,0,32 +, // 1, skyscraper window +4,5,3,6,2,81,0,59,48,128,138,131,66,44,137,129,16,176,208,176,44,33,0,0,1,43,1, +13,0,32,29,0,0,176,0,0,12,64,0,17,0,32,0,17,1,32,13,11,0,176,0,208,4,65,0,0,0, +34,1,16,1,32,16,0,23,32,0,2,40,66,2,194,230,140,34,208,2,176,17,0,119,76,66,34, +34,34,34,34,34,34,34,34,34,116,64,0,72,194,51,51,51,51,17,49,51,19,19,49,51,12, +34,36,17,210,49,17,16,17,1,17,17,16,17,1,17,42,1,17,17,2,49,154,116,244,229,164, +233,85,49,16,17,14,1,16,2,69,17,104,79,117,149,88,94,137,49,17,17,36,0,0,196,69, +48,137,119,69,84,79,88,85,49,17,1,4,92,244,0,34,0,69,85,95,127,116,86,89,49,17, +17,36,0,0,17,32,1,169,88,229,228,74,85,85,49,19,1,4,0,0,0,2,49,90,153,85,85,169, +95,85,49,16,17,4,2,0,0,39,48,68,85,233,138,37,133,136,49,17,17,36,0,32,0,4,17, +122,150,84,133,230,136,136,49,1,17,10,0,0,0,44,48,35,51,51,51,51,51,35,49,17,1, +66,0,13,0,4,17,51,3,211,3,3,35,2,49,17,17,34,0,0,0,37,49,167,42,70,106,69,102, +102,49,0,17,36,2,34,68,244,48,39,119,79,69,150,102,102,49,17,17,68,64,34,16,76, +49,119,2,127,120,102,102,102,49,17,19,5,0,1,1,74,49,114,119,4,152,102,104,102, +49,17,17,75,0,0,208,28,49,119,39,116,248,104,134,102,49,16,17,34,0,0,0,10,17,39, +114,37,169,104,136,86,49,16,17,4,0,0,1,43,49,114,126,232,74,102,104,134,49,1,0, +34,0,32,0,116,17,119,122,102,88,102,102,102,49,16,17,66,0,0,1,36,49,17,17,17,17, +17,17,17,1,1,1,64,0,0,32,184,49,17,49,17,17,19,51,17,17,17,19,178,0,34,44,66,34, +71,39,34,180,36,66,34,2,32,32,192,17,19,66,192,0,16,176,66,34,34,34,200,36,34, +34,36,68,44,221,192,0,0,10,32,0,16,1,34,16,16,0,11,0,16,13,64,0,0,10,0,0,0,1,34, +0,1,1,2,16,0,1,176,27,0,11,33,0,17,0,112,0,1,17,113,16,0 +, // 2, pink high-tech wall +83,4,12,5,84,20,61,85,13,6,11,3,7,14,15,0,34,32,34,0,32,2,170,34,170,160,170, +160,17,17,17,17,34,34,32,34,42,34,170,2,42,42,170,170,17,17,17,17,34,34,34,36, +34,160,36,32,160,160,42,10,49,17,17,17,34,34,34,42,34,0,0,0,0,0,0,4,49,49,17,17, +34,34,2,10,36,32,17,17,81,17,81,23,59,59,59,17,0,0,0,0,2,0,84,84,96,0,0,0,59,59, +49,19,102,102,102,102,96,32,20,86,0,102,102,102,145,59,59,19,34,34,34,36,96,32, +21,86,5,85,85,23,59,59,49,19,34,34,34,42,96,64,21,86,5,85,69,71,145,155,49,49, +34,34,66,37,96,128,84,86,5,85,91,23,49,49,49,19,34,34,0,0,0,0,0,0,4,84,69,87, +145,155,49,49,34,38,6,102,102,102,102,96,68,84,84,23,145,145,145,51,34,38,2,37, +88,32,68,69,69,85,85,71,49,145,49,51,40,134,2,34,130,64,21,69,85,84,21,23,145, +145,147,51,36,38,4,68,68,64,84,85,85,84,20,71,145,145,49,51,37,38,2,66,68,32,69, +85,85,85,69,87,145,145,147,51,40,134,5,84,72,64,20,65,69,68,20,71,145,193,147, +51,36,70,2,72,136,112,68,65,20,84,20,87,145,145,51,57,40,134,8,133,132,32,84,84, +17,84,68,87,195,147,147,51,40,134,8,88,136,112,21,17,17,68,17,23,147,51,51,51, +36,134,4,133,136,112,81,17,17,68,65,87,147,147,51,57,40,134,0,0,0,0,0,0,65,20, +68,71,147,57,147,57,39,120,102,102,102,102,102,102,1,17,84,71,153,51,57,57,40, +119,135,119,96,112,17,22,1,17,68,183,147,57,51,51,37,120,135,120,96,112,177,22, +1,17,17,87,153,147,57,57,37,136,136,135,96,32,65,22,1,20,91,71,60,57,57,57,0,0, +0,0,96,112,84,22,96,0,0,0,57,57,60,57,102,102,102,102,104,128,75,181,102,102, +102,102,60,57,51,60,39,119,135,119,120,112,180,84,180,181,75,183,57,60,57,57,34, +136,135,215,231,116,119,119,119,119,119,119,60,51,60,60,37,120,135,114,119,135, +125,120,116,212,68,114,60,60,57,57,34,117,136,135,135,120,132,136,136,136,136, +71,57,57,57,153 +, // 3, partly mossy concrete wall +4,3,5,36,20,37,76,12,11,19,77,130,13,35,2,0,2,0,0,80,32,0,0,1,5,37,1,64,4,25,19, +145,0,32,96,32,0,16,48,24,115,48,65,53,48,16,113,11,2,0,0,0,0,0,0,152,3,48,49, +48,51,19,1,17,0,32,16,48,0,16,0,8,0,0,1,67,0,23,19,17,2,0,5,48,0,16,0,24,115,65, +113,85,67,16,0,17,2,0,18,0,0,0,0,6,4,0,0,67,48,19,145,17,0,0,3,80,80,0,0,1,3,80, +19,3,83,16,9,1,2,0,210,0,0,16,0,1,148,3,1,48,51,16,17,17,19,0,16,48,0,16,0,24,5, +64,113,51,3,49,1,11,2,0,0,34,0,0,0,8,85,3,1,67,84,3,112,17,0,36,5,4,32,96,0,8,4, +4,3,52,83,16,17,1,34,0,2,32,0,0,7,1,3,32,49,3,51,119,49,113,4,32,96,66,0,0,0,7, +5,84,1,51,67,112,0,30,2,32,98,32,10,0,0,8,68,32,64,5,3,49,0,14,2,2,96,0,0,96,0, +6,5,80,49,48,51,112,1,27,0,32,2,0,1,96,0,1,51,0,1,3,51,27,0,27,2,0,96,32,0,0,6, +8,0,48,3,3,48,208,24,1,2,32,98,4,32,0,0,6,4,36,3,0,51,0,16,17,34,194,96,34,0,96, +0,6,50,48,1,83,67,144,0,8,0,42,2,36,0,0,162,8,5,32,65,64,48,23,1,1,2,32,100,34, +6,0,12,8,68,50,1,0,3,16,112,1,36,34,2,0,0,0,0,8,0,0,0,48,0,23,7,17,2,42,4,32,42, +0,0,8,5,64,64,35,0,135,0,1,2,64,98,44,6,0,32,8,48,48,1,85,0,17,0,49,2,32,3,2,0, +4,0,8,5,64,0,0,4,0,112,1,4,34,98,2,6,98,32,8,85,36,48,67,5,1,0,11,2,32,98,192, +160,4,52,8,4,0,1,4,0,0,112,113,2,194,2,0,0,0,2,1,5,85,64,211,4,48,0,1,2,32,0,42, +0,21,4,8,64,68,45,4,48,0,23,27,2,32,96,0,0,16,0,1,5,80,0,85,3,16,0,1,2,194,0,0, +0,16,48,17,84,85,0,48,64,144,25,17,0,32,96,0,0,0,64,13,3,68,0,5,48,16,0,17 +, // 4, wooden chess pattern +20,12,11,21,2,43,19,73,1,83,81,10,9,34,42,65,86,82,91,85,89,249,149,153,66,34, +40,34,34,114,34,36,0,0,0,48,48,35,0,2,33,18,39,17,17,66,17,18,0,0,5,48,3,96,3, +50,33,34,40,33,33,113,17,18,96,0,6,48,3,99,3,50,33,34,23,33,18,129,17,18,80,3,5, +48,3,99,3,54,33,33,23,18,17,114,17,18,80,0,5,48,3,99,0,54,33,34,20,34,33,114,33, +18,80,0,2,48,51,163,3,54,65,34,20,34,33,65,33,18,80,3,2,48,0,163,0,54,33,34,20, +34,17,66,33,18,0,0,2,3,0,67,0,53,177,34,20,34,17,130,33,18,0,0,2,51,0,211,0,5, +33,34,36,34,17,114,18,18,80,0,6,3,0,99,0,53,33,34,20,18,33,113,17,18,0,3,2,48,3, +99,0,6,65,33,20,18,33,65,17,18,0,0,2,0,0,96,0,6,34,34,20,17,33,129,17,18,0,0,5, +0,0,99,0,1,33,34,36,17,33,130,17,18,3,3,53,48,0,35,0,6,65,17,20,17,17,66,17,18, +80,85,86,5,85,224,85,85,68,68,72,66,68,132,68,36,66,34,20,34,34,66,34,36,96,0,5, +5,80,80,85,82,65,34,20,33,34,65,18,18,3,3,53,48,3,83,0,5,65,34,20,18,34,65,18, +34,51,51,54,51,3,80,5,5,66,34,20,18,34,65,18,18,51,51,53,51,3,80,5,5,66,34,20, +17,33,65,17,18,0,51,54,51,3,80,5,5,65,34,20,17,17,65,17,34,51,51,53,51,3,80,0,0, +65,34,20,17,17,65,17,18,0,51,54,48,51,80,0,0,66,34,20,17,18,65,17,18,3,51,54,48, +51,80,5,5,65,34,20,17,33,65,17,18,3,51,54,51,51,32,0,5,65,34,20,17,33,65,17,18, +3,51,54,51,51,80,1,5,65,34,20,17,33,65,34,34,3,51,59,48,51,80,5,85,65,34,20,17, +17,66,34,36,3,51,52,48,3,83,1,5,65,34,20,17,17,68,17,20,3,51,54,48,48,35,48,5, +65,33,20,34,17,66,17,18,3,0,52,51,51,35,48,5,65,33,20,17,17,65,18,18,3,51,54,51, +0,35,48,5,32,80,106,0,80,101,6,2,85,85,92,86,86,160,5,82 +, // 5, red brick wall +13,5,6,21,93,101,4,100,11,7,19,3,106,178,0,0,33,17,22,37,48,8,33,3,54,33,64,0,1, +20,5,70,37,0,88,37,85,88,32,64,4,17,64,0,65,20,0,70,32,51,56,37,85,8,33,0,4,17, +83,51,81,20,96,70,32,3,52,38,51,8,33,3,4,18,83,51,81,20,85,70,38,6,4,32,51,8,33, +3,4,18,64,51,81,20,85,69,38,0,4,38,3,52,33,83,5,17,67,51,81,20,101,70,38,0,4,38, +83,4,17,83,0,17,67,51,81,20,101,68,38,0,4,38,69,68,17,86,80,18,69,85,65,36,101, +68,32,85,4,34,17,17,33,86,83,18,18,34,34,36,0,88,33,0,4,34,34,18,33,83,0,18,17, +17,17,36,0,84,35,3,56,34,64,76,17,83,48,98,112,0,119,36,0,68,35,0,4,34,133,4,18, +3,48,98,113,0,17,36,0,85,33,0,4,34,133,100,17,81,48,98,112,0,1,36,0,86,35,0,8, +33,165,68,17,67,53,98,113,0,1,36,85,86,35,0,4,33,69,106,17,64,53,98,112,0,1,20, +85,86,35,0,4,33,133,68,17,64,53,18,112,0,1,20,5,86,35,0,4,33,166,84,17,64,53,18, +112,0,1,20,5,86,35,3,4,33,69,10,17,80,53,18,112,0,1,36,85,86,35,0,52,34,69,100, +33,83,5,18,112,0,113,40,5,84,33,64,8,33,69,4,33,69,68,18,112,0,1,36,0,22,33,0,4, +33,0,52,17,34,34,18,112,0,1,34,34,145,34,41,146,33,0,4,17,17,17,18,113,17,1,36, +99,22,38,80,49,33,69,4,32,0,4,98,112,17,17,36,51,6,32,80,4,33,69,106,35,3,53,98, +112,0,17,36,51,6,33,3,52,33,69,72,35,51,53,18,16,0,17,37,51,6,33,3,52,17,69,84, +35,51,53,98,112,0,17,37,51,6,33,1,52,17,69,100,35,51,48,98,113,17,17,21,3,6,35, +3,52,17,67,4,35,51,48,98,112,0,17,16,51,6,35,3,53,17,69,100,33,49,19,97,112,0, +17,37,51,6,35,3,4,17,212,4,33,3,51,98,1,0,1,36,3,6,35,3,52,18,34,34,33,3,48,177, +34,153,146,36,51,54,33,3,52,34,49,17,33,3,48,98,70,102,17,36,0,6 +, // 6, grass-covered concrete wall, tiles with skyscraper window +36,37,43,35,4,3,107,34,131,50,42,5,106,110,114,26,3,131,51,128,58,52,0,5,84,56, +84,2,0,48,66,0,48,128,5,5,10,112,0,68,0,48,85,68,4,144,32,1,6,32,17,0,7,116,80, +0,85,153,36,13,0,1,0,0,16,1,1,0,54,115,3,160,110,234,55,1,208,40,1,0,170,96,0, +39,115,51,51,144,0,51,144,0,0,16,0,2,17,16,17,208,11,187,20,0,2,43,64,32,17,16, +0,44,17,1,0,16,3,1,0,2,0,3,64,0,0,32,32,0,1,16,17,0,1,3,2,96,32,37,64,0,2,0,2, +32,17,16,1,1,0,0,34,128,32,0,1,16,16,32,0,32,1,0,0,0,16,8,0,2,2,2,2,0,32,2,32,0, +34,1,19,48,5,96,0,2,0,32,0,17,1,2,0,16,1,18,16,65,16,0,32,0,1,2,2,4,0,8,32,2,1, +39,18,4,1,32,0,208,0,0,0,1,16,0,2,0,0,18,19,48,0,16,13,0,1,0,32,18,16,0,0,0,16, +1,0,0,16,65,16,0,0,33,1,16,0,54,0,38,0,6,64,0,129,0,0,0,0,1,0,0,0,9,63,50,2,2,8, +2,32,0,18,0,17,0,1,17,96,0,5,80,32,0,0,0,0,18,69,80,0,1,16,48,1,0,32,153,206,32, +2,2,32,17,4,64,96,32,0,17,0,224,0,131,64,0,0,0,1,0,4,8,0,0,16,16,1,18,96,0,2,2, +0,34,32,2,0,0,5,0,0,96,2,0,32,0,2,0,2,0,17,0,0,0,85,34,32,0,0,0,0,0,2,0,1,16,48, +0,33,2,68,0,2,2,0,16,0,32,32,32,38,1,32,0,0,34,6,0,0,48,3,0,8,0,0,0,18,16,0,0, +98,0,32,0,0,0,33,32,0,32,0,17,17,0,0,0,33,32,0,0,4,49,18,0,2,16,2,1,66,0,98,2,0, +0,0,34,0,17,1,0,0,0,17,0,17,33,2,0,12,126,199,112,39,0,16,6,21,0,16,16,0,16,32, +32,167,51,63,62,172,151,113,0,0,2,0,1,17,48,16,16,48,69,4,51,64,64,0,16,8,96,27, +16,16,16,62,57,149,0,4,51,0,1,4,7,80,2,0,17,1,51,8,52,0,68,0,32,0,4,68,36,16,32 +, // 7, steel door +4,80,3,17,5,59,6,69,58,50,60,2,68,74,70,67,1,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,22,102,70,102,70,102,70,102,70,100,102,100,102,100,102,97,16,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1,16,0,32,0,32,0,32,0,32,2,0,2,0,2,0,1,19,189,187,221,189, +219,219,219,187,187,187,219,189,189,189,177,17,51,51,51,51,51,51,51,51,51,51,51, +51,51,51,49,19,136,136,136,133,133,85,95,34,34,44,47,34,194,34,40,19,136,34,34, +34,2,34,34,34,32,34,32,2,2,2,34,19,130,40,140,136,192,197,192,112,112,64,0,0,7, +4,7,19,146,136,200,92,80,122,90,160,0,64,0,7,0,4,0,19,146,149,136,200,84,122, +202,0,0,64,0,0,7,14,0,19,146,153,153,197,94,170,80,112,0,64,0,112,0,4,0,19,146, +37,156,133,112,5,0,0,224,224,0,112,112,4,0,19,146,153,153,87,160,0,7,160,0,64,0, +0,0,4,4,19,146,149,41,149,4,7,80,160,10,71,0,0,7,4,0,19,146,153,146,87,0,170,87, +0,7,64,0,7,0,4,4,19,146,89,204,87,4,167,80,7,0,224,0,0,0,4,0,19,146,153,156,90, +160,122,80,0,14,64,0,0,112,116,4,19,146,149,153,85,116,170,192,0,112,64,112,0,0, +4,0,19,146,41,92,138,84,122,90,0,0,71,0,7,0,4,4,19,146,153,204,80,126,90,202, +224,0,64,0,0,0,4,0,19,146,143,85,32,4,170,90,160,0,71,0,7,7,14,0,19,130,136,140, +128,116,122,202,112,10,64,0,112,0,4,0,19,130,40,200,92,14,170,80,0,170,74,112,0, +112,116,0,19,136,34,34,34,2,2,0,0,32,34,34,34,34,2,34,19,136,136,136,133,34,85, +85,85,37,194,47,34,242,34,34,17,51,51,51,51,51,51,51,51,51,51,51,51,51,51,49,27, +189,221,187,219,219,219,187,221,187,187,221,189,189,189,177,22,102,70,102,70, +102,70,102,70,102,70,100,102,100,102,97,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,16,0, +32,0,32,0,32,0,32,0,32,2,0,2,0,1,1,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 +, // 8, white skull on blue +6,5,4,59,60,62,218,14,3,13,85,139,74,63,12,15,17,17,17,17,17,18,147,69,72,17,17, +17,17,17,17,17,16,16,1,1,16,18,35,51,50,17,1,1,16,16,1,17,16,0,0,0,0,18,36,99, +82,16,16,0,0,0,0,17,0,0,0,0,0,18,37,51,82,17,0,0,0,0,0,1,16,0,0,0,0,18,35,179, +50,17,16,0,0,0,0,1,0,0,0,0,0,18,35,51,66,17,16,0,0,0,0,17,16,0,0,0,1,226,37,67, +84,40,17,0,0,0,0,1,0,0,0,17,42,34,85,83,85,67,33,16,0,0,0,17,0,0,1,18,34,51,34, +34,68,75,98,129,16,0,0,17,16,0,17,162,51,130,34,34,38,198,52,66,129,0,1,17,17, +17,42,36,98,33,17,17,34,51,51,68,98,33,17,17,130,34,36,68,33,17,17,23,121,34,52, +68,51,66,34,34,68,84,53,85,33,0,0,121,151,34,37,85,67,69,221,51,51,68,52,82,16, +0,0,126,151,18,34,133,91,69,84,99,51,107,52,66,0,16,16,247,119,17,34,40,60,67, +51,68,83,99,51,50,1,1,17,0,1,33,18,40,51,51,52,85,75,52,52,66,0,17,17,0,1,33,18, +40,51,68,51,69,51,84,53,82,1,0,16,247,119,17,34,40,70,69,51,51,85,84,52,82,16,0, +0,126,151,18,34,132,70,69,84,99,85,68,52,52,33,0,0,121,151,34,36,52,60,52,85,51, +130,34,35,107,33,17,17,23,121,34,99,107,195,66,34,34,17,17,42,102,98,33,17,17, +34,54,102,102,98,33,17,17,16,0,17,162,68,130,34,34,36,76,102,98,33,0,1,17,0,0,1, +18,35,69,34,34,85,67,194,161,16,0,0,17,16,0,0,17,42,35,69,67,68,75,33,16,0,0,0, +17,0,0,0,0,1,226,35,99,54,42,17,0,0,0,0,1,0,0,0,0,0,18,35,51,66,17,16,0,0,0,0, +17,16,0,0,0,0,18,37,51,82,17,16,0,0,0,0,1,0,0,0,0,0,18,45,51,66,17,0,0,0,0,0,1, +16,0,0,0,0,18,36,99,50,16,16,0,0,0,0,17,16,16,1,1,16,18,35,68,50,17,16,16,16,16, +1,17,17,17,17,17,17,18,148,85,88,17,17,17,17,17,17,17 +, // 9, red lava with stones +3,4,12,11,83,94,102,92,91,14,93,15,19,20,100,0,3,82,2,83,32,67,84,1,17,17,16,5, +32,17,20,0,2,48,0,67,117,118,36,0,33,33,0,5,33,17,17,19,69,64,17,20,67,86,82,36, +17,1,0,53,1,17,17,64,56,1,17,17,0,130,50,117,131,64,4,39,0,17,17,0,32,1,17,17,3, +82,4,68,39,85,34,98,36,16,0,3,0,0,1,16,3,82,1,16,0,35,53,106,83,51,51,54,85,68, +36,3,53,32,49,17,16,0,54,34,66,35,37,86,67,85,85,34,38,66,1,17,17,0,82,64,64,0, +3,101,0,32,3,34,102,103,65,1,17,3,84,1,17,0,3,83,18,17,0,67,34,68,85,52,0,69,48, +17,17,19,69,0,17,17,20,3,112,0,2,53,51,114,1,17,17,16,69,65,17,17,16,3,80,3,0,4, +46,98,64,17,17,32,115,1,17,18,0,53,64,17,17,16,50,86,34,0,0,0,35,1,0,0,0,37,65, +17,17,17,2,34,119,85,67,66,34,0,51,130,50,98,64,17,17,17,2,35,68,51,85,102,98, +35,51,50,86,102,35,34,2,16,3,132,0,0,4,34,82,35,20,0,66,85,39,120,34,4,2,80,1, +17,4,53,52,0,17,4,3,83,64,2,37,81,69,16,77,17,16,69,16,0,18,16,0,84,16,0,67,66, +38,49,17,17,32,53,32,17,17,17,0,82,0,33,16,3,102,32,0,0,4,84,0,18,17,17,0,84,1, +17,17,4,182,98,64,0,3,84,1,17,17,17,0,83,1,17,17,4,99,37,83,50,50,32,0,33,17,16, +0,83,1,17,33,2,36,0,34,114,118,84,16,17,0,0,3,83,1,17,16,67,49,1,16,4,38,103,51, +64,84,68,53,32,0,17,0,55,32,17,17,0,39,50,39,85,37,82,166,98,36,16,64,34,1,17, +17,16,55,32,0,36,0,4,54,34,117,66,51,84,1,17,17,16,82,0,0,2,17,4,39,64,18,82, +118,98,64,1,17,4,84,16,17,17,18,4,84,4,0,20,53,102,82,32,0,4,84,0,33,17,16,2,32, +1,17,64,39,51,69,85,117,53,156,65,1,18,50,38,36,17,17,16,34,0,0,20,67,102,101, +115,51,51,130,101,101,32,17,4,84,1,17,33,16,38,148,19,56,56 +, // 10, transparent window +175,4,5,3,59,13,49,60,74,62,61,50,83,2,69,12,17,17,33,17,81,17,17,33,17,17,17, +17,18,34,34,17,59,17,17,17,17,17,17,17,17,17,177,17,18,34,82,33,51,51,51,51,51, +51,51,51,51,51,59,81,18,34,33,17,49,182,102,102,102,102,102,102,102,107,18,33, +18,34,34,33,51,0,0,0,0,116,16,0,0,10,50,37,18,34,34,33,51,0,0,0,0,116,16,0,0,10, +50,17,18,34,21,33,51,0,0,0,0,84,16,0,0,10,50,33,17,243,51,52,51,0,0,0,0,20,16,0, +0,10,50,145,18,17,17,21,51,0,0,0,0,20,32,0,0,10,50,149,18,49,81,17,51,0,0,0,0, +116,112,0,0,1,50,37,82,17,113,17,51,18,51,140,140,71,72,140,136,200,50,37,82,49, +17,225,51,18,68,68,68,121,116,68,68,71,50,33,82,18,18,17,51,0,0,0,0,212,208,0,0, +12,50,17,18,37,34,17,51,0,0,0,0,20,16,0,0,9,50,17,18,18,37,30,51,0,0,0,0,116,32, +0,0,2,50,145,18,34,34,33,51,0,0,0,0,116,16,0,0,2,50,37,18,34,18,17,51,0,0,0,0, +116,16,0,0,10,50,145,18,37,33,18,51,0,0,0,0,116,16,0,0,10,57,145,82,33,18,225, +51,0,0,0,0,20,16,0,0,10,57,145,18,18,17,21,51,0,0,0,0,212,208,0,0,13,50,149,18, +37,18,17,51,18,68,68,68,121,116,68,68,71,50,37,18,34,33,17,51,18,60,200,140,71, +76,136,136,200,50,37,18,34,81,30,51,0,0,0,0,244,16,0,0,1,50,149,18,34,33,17,51, +0,0,0,0,20,32,0,0,10,50,33,18,18,17,17,51,0,0,0,0,116,32,0,0,2,50,33,17,243,51, +52,51,0,0,0,0,20,16,0,0,10,50,17,18,17,17,17,51,0,0,0,0,84,16,0,0,10,50,33,82, +17,33,31,51,0,0,0,0,116,16,0,0,2,50,33,18,17,17,17,49,182,102,102,102,102,102, +102,102,107,34,81,18,37,17,17,19,50,34,34,34,34,34,34,34,34,35,81,18,34,17,17, +59,34,34,34,34,34,34,34,34,34,181,17,18,18,81,21,17,17,17,17,33,17,17,17,21,17, +17,17,18,34,34,18 +, // 11, white steel blocks +6,5,7,4,3,85,71,78,0,0,0,0,0,0,0,0,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, +68,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,52,34,0,34,34,2,34,34,34,34,34, +0,34,34,34,0,17,0,17,0,0,0,1,16,0,0,0,0,0,1,16,17,17,0,20,0,0,0,0,0,0,0,0,0,0,1, +64,0,17,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,17,17,17,17,17,17,17,17,81,17,17,17,17,17, +17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,1,17,16,0,0,0,0,0,0,0,0,0,0,0,0,17,0, +0,1,1,0,0,6,0,0,0,0,0,0,0,0,17,34,0,34,0,34,34,34,34,34,34,34,34,32,2,34,17,0, +17,0,1,16,0,0,0,0,0,17,0,0,0,0,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,0,0,0,0,1,0, +0,0,0,0,0,0,16,0,17,17,17,17,17,81,17,22,0,0,0,1,17,1,17,17,17,19,0,0,0,0,0,2,0, +0,0,1,0,0,0,0,113,21,16,0,0,0,0,2,0,0,0,1,0,0,0,0,0,19,0,0,0,0,0,2,0,0,0,1,0,0, +0,0,1,17,34,34,32,2,34,34,0,0,0,2,34,34,0,34,0,17,0,0,0,0,0,17,0,0,0,0,0,1,16, +16,17,17,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,17,0,1,0,0,0,0,0,0,0,0,0,0,0,17,17, +17,17,17,17,17,17,81,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,1, +17,16,0,0,0,0,0,0,0,0,1,0,1,16,17,0,0,1,1,0,0,6,0,0,0,16,0,0,0,0,17,34,0,34,0, +34,0,34,34,34,34,34,34,32,2,34,17,0,17,1,1,16,0,0,0,0,0,17,0,1,16,0,17,0,20,0,0, +0,0,0,0,0,0,0,0,1,64,1,17,0,0,0,0,0,0,0,1,0,0,0,0,16,0,17,17,17,17,17,17,17,17, +17,17,21,17,17,17,17,17,17,19,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51 +, // 12, gray square-tiled wall +4,5,3,13,50,6,12,21,85,20,14,11,19,22,84,0,17,17,17,17,17,17,17,18,17,17,17,17, +17,17,17,20,17,3,16,8,17,16,0,18,17,16,1,1,0,3,16,18,16,1,16,1,0,49,17,48,17,1, +3,6,0,17,3,2,16,16,0,16,16,24,16,16,17,0,0,23,16,0,0,2,16,1,3,17,1,16,16,18,19, +0,0,0,49,1,1,2,16,48,17,6,17,17,0,0,16,16,16,119,16,19,0,2,17,16,17,17,17,26,16, +50,17,49,0,19,0,0,0,2,16,17,49,17,129,17,16,2,16,3,16,0,0,1,6,2,16,17,16,1,17, +17,16,2,17,0,17,1,0,0,0,18,17,49,24,17,17,129,16,6,16,113,49,3,16,0,0,98,17,17, +17,16,49,0,96,9,16,16,0,0,1,49,0,18,17,17,17,17,17,16,1,2,81,1,0,32,0,16,16,2, +17,161,129,1,0,48,0,4,16,0,48,16,0,49,1,2,17,17,17,49,17,0,0,16,16,0,16,16,0,0, +48,2,80,17,17,17,19,17,48,0,16,16,0,0,0,17,6,2,32,48,32,6,0,34,32,98,2,34,34,38, +2,34,34,34,21,81,21,85,81,21,81,86,85,21,17,17,21,81,17,27,17,17,16,19,0,48,1,0, +16,0,0,0,48,0,0,2,19,17,49,0,17,1,17,2,22,1,0,1,1,48,0,2,16,17,0,0,48,0,49,2,80, +6,0,0,16,1,48,2,16,48,0,0,16,16,112,50,16,0,0,1,0,16,16,148,17,1,49,0,0,49,0,28, +16,0,0,48,3,0,0,2,16,0,3,1,0,0,17,18,16,3,0,0,0,0,0,50,17,113,1,3,0,0,48,2,16,0, +0,0,0,6,0,2,16,0,0,0,0,48,0,18,16,0,0,0,0,0,0,2,17,0,0,0,0,0,3,2,208,0,3,0,48,0, +0,4,17,112,48,19,16,0,0,18,17,0,0,0,0,0,16,100,16,17,9,1,1,16,1,2,22,0,0,0,0,0, +0,2,16,1,0,16,3,0,48,0,16,0,0,0,0,224,0,4,16,48,3,1,0,0,16,50,16,3,0,48,0,3,0, +52,16,16,1,16,0,0,0,2,16,16,0,0,2,2,1,4,68,66,32,34,36,34,34,36,34,36,34,34,68, +68,68,68 +, // 13, scifi door +3,2,4,9,0,74,200,10,75,41,160,48,120,17,34,50,68,68,68,68,68,68,68,68,70,102, +102,102,102,102,102,102,85,85,153,85,85,153,85,85,85,136,136,136,136,136,136, +136,149,153,153,147,147,57,55,57,125,238,88,135,127,85,119,119,51,147,51,51,51, +55,147,55,215,125,215,119,119,119,119,119,68,68,68,68,68,68,68,70,102,102,102, +102,102,102,102,102,0,0,0,0,0,0,0,5,2,34,34,34,34,34,34,34,53,92,65,85,19,48,0, +81,32,11,160,0,1,18,34,1,48,83,64,0,83,16,0,1,34,1,178,34,1,2,34,33,53,84,65,0, +4,49,80,1,0,11,160,34,43,16,2,1,52,196,49,85,28,51,51,161,26,186,16,0,11,17,17, +161,51,51,51,51,51,51,49,16,1,17,17,17,17,17,17,16,53,85,49,85,19,21,0,34,32,0, +16,0,1,2,34,1,53,5,48,0,83,16,34,34,34,32,18,34,1,2,34,17,49,85,49,0,4,16,34,34, +34,32,16,34,43,2,32,161,51,68,49,85,28,16,34,34,34,32,16,0,11,0,17,0,51,67,51, +51,51,16,34,34,34,32,17,17,17,1,16,34,52,49,49,17,19,16,34,34,34,32,16,0,1,0,17, +2,51,5,48,0,84,16,34,34,34,32,18,34,10,2,1,17,48,5,49,5,84,16,34,34,34,32,16,32, +10,2,32,161,48,85,49,21,28,53,2,34,34,0,16,0,11,16,34,17,49,19,67,68,195,17,80, +177,16,1,161,171,177,0,0,177,51,52,17,51,67,51,17,16,1,26,0,17,161,17,17,16,53, +92,48,85,196,48,0,1,32,11,18,0,186,18,34,1,48,83,48,5,52,48,0,33,34,1,18,32,27, +18,34,33,53,84,49,85,68,17,80,1,0,11,16,0,186,0,2,1,52,196,51,76,67,19,51,161, +26,186,17,171,161,1,17,161,0,0,0,0,0,0,0,0,2,34,34,34,34,34,34,34,68,68,68,68, +68,68,68,102,102,102,102,102,102,102,102,102,51,147,51,51,51,55,147,125,125,119, +119,119,119,119,119,119,149,153,153,147,147,121,55,62,119,238,88,135,127,85,119, +119,85,85,153,85,85,153,85,85,152,136,136,136,136,136,136,136,68,68,68,68,68,68, +68,68,102,102,102,102,102,102,102,102 +, // 14, concrete wall, tiles with skyscraper window +5,4,3,2,6,44,131,66,50,51,45,81,132,28,138,1,1,97,81,193,39,32,17,17,16,44,16, +21,17,33,5,17,17,97,17,17,23,49,17,0,17,33,17,0,16,33,21,28,17,97,17,81,19,48, +17,17,17,34,16,1,16,33,1,17,9,33,17,18,47,50,18,130,255,248,34,81,18,97,0,17, +153,55,50,34,34,34,34,34,34,34,34,34,34,147,49,17,63,114,68,68,68,68,0,64,68,4, +4,64,68,24,34,35,0,82,64,0,1,0,16,0,0,1,0,16,0,46,16,0,0,18,64,16,1,17,0,0,13,0, +0,1,0,31,16,1,18,59,0,16,0,0,0,0,0,0,0,0,0,35,17,17,115,59,65,17,0,0,0,0,0,0,0, +0,16,19,183,51,161,34,17,16,0,0,0,0,0,0,0,0,0,35,17,17,0,33,16,0,0,0,0,0,0,0,0, +4,208,19,17,17,17,18,64,0,0,0,0,0,0,0,0,1,0,19,18,17,17,41,65,16,0,0,0,0,0,0,0, +0,0,35,17,33,17,19,0,16,0,0,0,0,0,0,0,16,0,30,17,17,17,39,65,0,0,0,0,0,0,0,0,0, +16,50,17,21,17,19,0,21,17,0,0,0,0,0,0,0,0,34,17,17,17,43,64,0,0,0,0,0,0,0,0,29, +0,35,18,34,51,51,65,21,1,0,0,0,0,0,0,0,0,51,49,34,1,55,64,0,0,0,0,0,0,0,0,0,4, +27,17,16,16,62,64,16,1,0,0,0,0,0,0,0,0,54,17,17,81,7,64,0,160,0,1,0,0,0,0,1,0, +34,17,17,17,30,0,16,16,16,0,0,0,0,0,1,0,19,17,17,16,38,64,0,0,160,16,0,0,0,208, +16,209,34,17,33,17,147,0,16,17,0,0,16,0,16,0,1,0,50,17,17,16,35,64,0,0,0,0,0,0, +0,16,16,16,49,17,17,33,111,64,0,64,0,0,4,68,0,0,0,4,98,17,34,40,50,34,57,41,34, +99,35,50,34,18,33,33,129,0,4,50,129,17,1,193,50,34,34,34,143,35,34,34,35,51,39, +85,113,17,17,22,33,17,1,16,34,1,1,161,22,17,1,21,49,17,17,30,17,17,17,16,34,17, +16,16,18,10,17,16,97,12,17,22,32,17,0,17,145,17,16,0,144,1,17 +, // 15, computer tech wall +52,59,53,220,38,141,54,143,75,76,77,61,74,5,66,95,48,0,0,0,10,17,0,0,0,0,38,0,0, +0,0,51,16,0,2,1,17,17,0,0,16,0,38,0,0,0,0,3,10,0,0,0,17,1,17,17,17,16,34,0,1,0, +0,0,7,0,0,0,17,49,81,33,33,32,34,48,1,48,0,0,2,0,0,0,17,1,1,17,17,16,38,0,0,0,0, +0,0,0,0,83,0,17,1,33,33,35,18,0,0,80,0,0,0,0,3,0,0,17,17,17,17,16,2,83,2,0,7,0, +0,85,19,19,3,17,17,33,33,32,2,17,0,32,0,0,0,0,48,0,1,16,1,0,16,0,34,17,17,0,0,0, +0,1,2,16,0,24,0,80,1,0,82,1,12,2,0,0,16,16,5,16,0,1,1,0,9,17,34,17,30,18,32,8, +16,0,96,0,0,17,17,17,17,17,34,80,85,16,32,1,0,2,2,0,0,17,68,68,68,68,34,5,85,1, +39,0,0,6,0,176,0,17,68,68,68,68,34,85,5,1,114,3,0,6,0,0,10,25,68,68,68,68,38,11, +85,1,114,3,0,6,0,0,0,17,68,68,68,68,34,0,48,1,2,3,2,6,0,0,0,17,68,68,68,68,34,0, +0,1,2,0,0,2,112,0,0,17,68,68,68,68,38,0,0,1,2,112,0,0,7,112,80,17,68,68,68,68, +38,0,0,21,34,0,0,16,32,0,0,19,34,34,34,34,34,5,0,80,34,177,17,227,0,53,1,17,16, +3,1,1,50,19,51,224,32,24,128,17,32,16,1,16,1,0,16,16,2,51,28,50,32,8,16,1,0,80, +0,21,0,0,16,1,146,51,137,6,0,1,0,1,16,0,17,17,0,0,17,16,34,17,144,32,0,3,0,0,17, +0,1,1,13,240,3,17,35,24,0,0,3,3,0,0,81,16,0,1,15,240,51,0,35,0,3,0,0,1,48,0,0, +195,0,17,0,0,5,49,34,0,3,0,160,3,0,0,5,48,206,17,4,208,109,0,2,48,0,112,2,3,57, +0,0,0,1,17,13,208,221,51,18,17,0,176,3,3,19,0,5,16,0,1,3,0,49,19,50,17,1,0,51,1, +144,0,48,0,0,17,0,0,0,48,34,49,48,0,0,3,48,0,0,0,10,17,0,0,0,0,38,0,0,0,0,51 +}; + +SFG_PROGRAM_MEMORY uint8_t SFG_itemSprites[13 * SFG_TEXTURE_STORE_SIZE] = +{ +// 0, barrel +175,6,106,29,100,84,7,92,2,43,10,11,46,4,28,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0, +15,240,0,0,0,0,0,0,255,248,255,255,255,255,255,255,248,143,255,255,255,255,255, +255,143,248,248,255,255,143,136,136,130,136,136,136,136,136,136,136,143,168,66, +136,136,137,136,146,146,130,153,153,146,146,143,66,168,170,226,34,130,41,73,41, +66,137,34,34,153,41,146,226,168,186,34,34,155,149,187,186,162,170,84,153,34,146, +36,158,170,234,34,233,229,93,170,171,85,91,43,78,68,66,146,36,187,121,228,237, +69,90,181,85,85,93,91,132,77,66,36,73,158,89,18,68,69,187,85,183,119,122,181, +187,68,66,68,18,222,93,18,68,77,161,197,28,119,119,170,26,94,34,36,18,213,93, +193,20,21,177,17,81,87,119,123,183,84,52,44,20,222,93,17,17,23,17,17,21,119,117, +17,81,65,35,65,28,213,93,49,17,26,21,186,167,119,225,17,17,113,34,49,49,222,93, +60,19,106,97,106,119,115,49,97,193,118,35,67,19,222,93,18,102,101,102,102,103, +117,86,22,54,113,50,35,18,213,93,18,198,99,118,102,119,119,119,119,183,54,99,38, +25,190,93,102,102,195,166,203,119,119,123,190,101,108,50,51,99,181,93,54,54,51, +117,22,19,87,187,229,53,51,34,33,28,222,125,51,51,51,58,49,28,17,49,21,227,19, +19,51,17,158,185,195,51,51,49,174,81,17,85,117,17,17,193,28,76,155,186,51,195, +51,17,61,91,187,181,49,52,49,28,20,28,154,170,25,236,30,49,49,17,49,193,17,17, +28,20,19,28,184,170,25,225,193,17,17,17,17,193,17,17,17,20,19,30,184,138,60,238, +236,193,193,193,17,195,65,17,17,225,68,62,175,250,34,34,34,34,34,36,225,228,34, +34,34,34,34,36,175,251,0,0,0,0,0,0,4,64,0,0,0,0,0,0,191,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 1, health +175,7,5,6,2,94,0,69,4,53,71,93,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,68,64,0,4,68,68,64,0,0,0,0,0,0,0,4,17,17,20,68,65,17,17,20, +0,0,0,0,0,0,0,65,18,35,49,17,19,50,35,56,64,0,0,0,0,0,4,17,55,119,119,119,119, +119,119,50,70,0,0,0,0,0,4,34,119,41,41,41,41,41,39,114,134,0,0,0,0,0,4,34,114, +146,146,146,146,146,149,115,38,0,0,0,0,0,68,19,161,17,17,17,17,17,53,163,54,0,0, +0,0,4,34,35,163,17,17,17,17,17,21,163,38,0,0,0,0,4,108,41,161,21,85,85,85,177, +53,162,134,0,0,0,0,4,4,34,163,21,85,85,85,177,21,162,70,0,0,0,0,4,4,194,161,49, +49,91,17,49,53,168,96,0,0,0,0,4,0,66,163,19,17,91,19,19,21,168,96,0,0,0,0,4,0, +66,161,49,49,91,17,49,53,168,96,0,0,0,0,4,4,194,163,19,17,91,19,19,21,168,96,0, +0,0,0,4,4,34,161,21,85,85,85,177,53,162,70,0,0,0,0,4,108,41,163,21,85,85,85,177, +21,162,134,0,0,0,0,6,34,35,161,17,17,17,17,17,53,163,38,0,0,0,0,0,102,19,163,17, +17,17,17,17,21,163,54,0,0,0,0,0,4,34,121,41,41,41,41,41,37,115,38,0,0,0,0,0,4, +34,119,146,146,146,146,146,151,114,134,0,0,0,0,0,4,19,55,119,119,119,119,119, +119,50,70,0,0,0,0,0,0,98,50,35,40,136,130,50,35,40,96,0,0,0,0,0,0,6,136,136,134, +102,104,136,136,134,0,0,0,0,0,0,0,0,102,102,96,0,6,102,102,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,0,0,0,0,0,0,0,0,0,0,0 +, // 2, ammo: bullets +175,124,168,125,2,5,21,194,19,17,112,113,190,3,4,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,170,170,170,0,0,0,0,0,0,0,0,0,0,0,0,170,136,72,218, +0,0,0,0,0,2,34,34,34,34,32,10,104,102,214,73,32,0,0,0,0,34,119,119,119,119,34, +36,68,68,68,71,32,0,0,0,0,33,17,17,17,25,183,119,238,231,119,23,32,0,0,0,0,35, +17,17,20,68,183,119,238,231,119,23,32,0,0,0,0,35,17,20,72,132,183,119,238,231, +119,23,32,0,0,0,0,35,17,70,134,109,179,51,255,243,51,49,32,0,0,0,0,35,17,20,74, +170,179,119,85,81,17,49,32,0,0,0,0,35,17,26,168,132,179,113,85,81,17,49,32,0,0, +0,0,35,17,70,134,109,179,113,92,193,17,49,32,0,0,0,0,35,17,26,150,245,179,17, +204,81,17,49,32,0,0,0,0,35,17,20,137,153,179,17,197,81,17,49,32,0,0,0,0,35,17, +70,134,109,179,17,92,81,23,23,32,0,0,0,0,35,17,26,137,153,179,17,204,199,68,68, +66,0,0,0,0,35,17,20,152,132,179,17,85,68,136,72,66,0,0,0,0,35,17,70,134,109,179, +17,84,104,102,214,210,0,0,0,0,35,17,26,150,245,179,17,204,73,255,95,82,0,0,0,0, +35,17,20,152,132,179,17,85,193,153,154,162,0,0,0,0,35,17,70,134,109,179,17,92, +193,20,68,210,0,0,0,0,35,17,26,150,245,179,17,197,193,20,246,130,0,0,0,0,35,17, +72,137,153,179,17,197,81,20,93,66,0,0,0,0,35,17,26,152,132,179,17,92,193,25,246, +130,0,0,0,0,35,17,166,134,109,179,17,92,81,17,150,130,0,0,0,0,2,34,42,166,245, +179,17,204,193,17,152,32,0,0,0,0,0,0,0,2,34,179,17,85,81,17,58,32,0,0,0,0,0,0,0, +0,0,35,17,85,81,17,49,32,0,0,0,0,0,0,0,0,0,34,34,153,146,34,49,32,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,34,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0 +, // 3, ammo: rockets +175,1,117,120,30,3,33,82,5,98,101,102,2,178,174,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,204,16,0,0,0,0,0,0,0,0,0, +0,0,0,17,26,197,81,17,17,17,16,0,0,0,0,0,0,0,17,204,202,85,92,113,119,23,16,0,0, +0,0,0,0,1,85,197,90,85,204,119,17,119,16,0,0,3,51,0,0,1,170,85,90,85,92,119,119, +119,16,0,3,59,47,51,0,1,85,197,90,85,204,124,119,199,193,0,59,187,42,169,51,53, +170,92,90,85,87,246,31,31,193,3,187,238,218,153,157,149,68,37,36,42,39,135,17, +17,17,0,62,238,217,153,51,53,85,82,36,34,167,136,97,17,16,0,3,222,217,211,0,6, +68,34,36,42,247,136,246,17,96,0,3,221,221,211,0,6,68,85,36,34,247,136,246,225, +96,0,59,187,42,169,51,53,68,133,36,42,39,136,246,209,96,3,187,238,218,153,157, +149,68,40,36,34,167,136,246,145,96,0,62,238,217,153,51,53,68,85,36,42,39,136, +246,225,96,0,3,222,217,211,0,6,68,130,36,34,167,136,246,209,96,0,3,221,221,211, +51,54,68,85,36,42,247,136,246,145,96,0,59,187,42,169,51,53,68,85,36,34,247,136, +246,225,96,3,187,238,218,153,157,149,68,34,36,42,39,136,246,209,96,0,62,238,217, +153,51,53,68,85,36,34,167,136,118,145,96,0,3,62,217,51,59,230,68,34,36,42,39, +136,201,153,16,0,0,3,51,0,50,182,68,34,36,34,167,135,106,153,16,0,0,0,0,0,3,54, +85,82,36,42,247,140,250,169,145,0,0,0,0,0,0,6,136,37,36,34,247,134,34,221,209,0, +0,0,0,0,0,0,102,72,68,42,39,134,187,238,236,0,0,0,0,0,0,0,0,102,104,34,166,102, +203,238,192,0,0,0,0,0,0,0,0,0,6,68,105,209,203,190,192,0,0,0,0,0,0,0,0,0,0,102, +1,145,28,188,0,0,0,0,0,0,0,0,0,0,0,0,0,17,16,192,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 4, ammo: plasma +175,6,0,2,4,142,206,5,7,62,205,115,207,116,1,201,0,0,0,0,35,51,51,51,51,50,0,3, +48,0,0,0,0,0,0,3,57,145,145,145,153,147,32,54,99,0,0,0,0,0,0,51,149,34,34,34,34, +52,34,42,162,34,34,32,0,0,2,57,50,143,255,34,243,34,238,39,66,238,62,32,0,0,3, +149,40,252,106,175,84,51,51,55,67,62,67,32,0,0,3,146,2,198,170,219,87,68,67,67, +52,67,116,32,0,0,3,146,2,198,170,221,87,68,67,68,68,67,116,32,0,0,3,146,2,198, +106,219,81,119,116,55,119,116,23,32,0,0,3,146,0,54,102,106,81,119,119,67,51,51, +52,32,0,0,3,146,0,251,187,187,184,17,17,17,17,23,67,32,0,0,3,50,2,106,221,219, +88,17,145,25,27,182,132,32,0,0,2,66,2,198,170,173,88,17,81,21,27,172,132,32,0,0, +3,50,2,198,106,171,88,17,81,89,27,172,132,32,0,0,2,66,0,54,102,106,88,153,85, +145,26,204,132,32,0,0,3,50,0,251,187,187,184,149,17,17,17,23,132,32,0,0,2,66,2, +106,221,219,88,17,25,25,17,23,132,32,0,0,3,50,2,198,170,221,88,21,21,21,17,23, +132,32,0,0,2,66,2,198,106,219,88,21,21,21,17,23,132,32,0,0,3,50,0,54,102,106,88, +25,21,81,17,23,132,32,0,0,2,66,0,251,187,187,184,17,17,25,17,23,132,32,0,0,3,50, +2,106,221,219,88,17,81,21,17,23,132,32,0,0,2,66,2,198,170,221,88,17,81,81,17,23, +132,32,0,0,3,146,2,198,106,219,88,17,85,21,17,23,132,32,0,0,3,146,0,54,102,106, +88,149,17,17,17,23,132,32,0,0,3,146,0,251,187,187,184,81,145,17,20,23,132,32,0, +0,3,146,2,106,221,219,88,17,81,81,23,23,132,32,0,0,3,146,2,198,170,221,88,17,81, +149,20,23,132,32,0,0,3,149,34,198,106,170,88,17,85,17,17,23,67,32,0,0,2,52,62, +54,102,106,88,17,17,51,51,51,52,32,0,0,0,35,69,46,238,238,247,119,115,71,119, +116,116,32,0,0,0,2,52,65,65,65,67,51,34,35,50,34,34,32,0,0,0,0,34,34,34,34,34, +34,0,2,32,0,0,0 +, // 5, tree +175,0,17,115,5,3,2,196,4,114,20,38,22,96,37,21,0,0,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,1,17,0,0,0,3,54,32,0,0,0,3,51,51,0,17,26,72,0,0,0, +59,187,178,0,0,0,0,3,51,49,72,100,72,0,0,3,187,238,113,0,0,0,0,38,98,49,68,100, +72,0,0,6,190,231,57,16,0,0,34,187,238,33,68,100,72,0,0,34,190,119,57,16,0,0,43, +119,119,114,100,101,72,0,2,194,231,115,145,16,2,32,1,23,119,114,100,70,136,2,34, +194,231,57,145,0,44,16,51,49,19,114,68,134,85,2,204,207,147,153,145,2,193,3,51, +27,51,50,72,100,72,0,17,204,169,34,209,26,16,0,1,179,50,33,70,68,72,0,0,17,207, +82,37,173,16,0,0,17,38,98,86,164,72,0,0,0,17,26,85,33,98,0,1,170,85,82,72,106, +72,0,0,0,0,1,90,93,22,17,31,165,85,34,68,134,88,0,51,102,0,29,42,166,221,42,250, +85,34,33,68,72,101,3,187,183,17,204,246,250,82,255,85,82,45,210,100,70,72,3,190, +121,111,245,95,207,255,165,85,45,17,18,100,70,72,59,183,115,146,93,223,204,165, +85,45,17,119,114,68,72,101,59,231,115,146,209,165,44,109,17,29,42,17,50,68,134, +88,110,119,57,157,218,93,198,209,17,1,29,165,18,72,106,72,30,115,57,157,170,34, +198,17,145,0,49,37,82,86,164,72,1,51,153,37,93,28,81,41,16,3,49,210,82,70,68,72, +0,25,34,121,17,28,33,17,0,0,51,29,34,72,100,72,0,1,119,57,16,26,33,0,0,3,54,177, +34,68,134,85,0,1,115,145,16,21,16,0,3,54,107,18,82,100,70,136,0,0,17,17,2,25,18, +0,0,43,231,21,82,100,101,72,0,0,0,0,33,123,113,32,0,2,35,49,82,68,100,72,0,0,0, +0,27,238,121,16,0,0,49,17,18,68,100,72,0,0,0,0,30,231,57,16,0,51,51,51,50,72, +100,72,0,0,0,0,30,115,145,16,0,0,51,48,0,17,26,72,0,0,0,0,1,57,17,0,0,3,48,0,0, +0,1,17,0,0,0,0,0,17,16,0,0,0,0,0,0,0,0,0 +, // 6, finish +175,3,4,0,5,1,2,6,50,7,198,209,48,42,44,49,0,0,0,0,0,0,0,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,3,147,3,51,51,51,51,51, +51,51,51,51,51,51,51,51,54,115,3,153,153,153,34,153,153,146,41,153,153,34,153, +153,153,115,3,119,119,119,34,119,119,114,39,119,119,34,119,119,119,67,3,68,68, +71,119,119,119,119,119,119,119,119,119,119,119,67,3,68,68,71,34,34,34,34,34,34, +34,34,34,34,34,67,53,85,85,71,40,136,136,136,136,136,136,136,136,129,68,115,49, +170,165,36,43,204,204,95,102,102,102,102,102,97,71,115,49,170,165,36,43,204,197, +246,102,102,102,102,102,97,65,67,49,161,165,36,43,187,255,216,136,136,136,136, +136,129,65,67,49,17,21,36,43,187,253,136,136,136,136,136,136,129,65,67,49,161, +165,36,43,187,253,136,136,136,136,136,136,129,65,67,49,26,21,36,43,102,129,17, +17,17,17,17,17,17,65,67,49,161,165,18,43,102,129,17,17,17,17,17,17,17,65,67,49, +17,21,18,43,102,129,17,17,17,17,17,17,17,65,67,49,170,165,18,43,17,34,34,34,34, +34,34,34,33,65,67,49,17,21,18,43,17,34,34,34,34,34,34,34,33,65,67,49,161,21,18, +43,18,68,68,68,68,68,68,68,65,65,67,49,170,165,142,43,18,68,68,68,68,68,68,68, +65,65,67,49,161,21,142,43,18,119,119,119,119,119,119,119,113,85,83,53,85,85,142, +38,18,68,68,68,68,68,68,68,65,245,83,3,102,102,97,34,34,34,34,34,34,34,34,34,33, +255,99,3,102,102,97,85,85,85,85,85,85,85,85,85,85,85,99,3,102,102,102,17,102, +102,97,22,102,102,17,102,102,102,99,3,85,85,85,17,85,85,81,21,85,85,17,85,85,86, +99,3,51,51,51,51,51,51,51,51,51,51,51,51,51,53,83,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3, +83,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 +, // 7, teleport +175,0,151,6,3,143,5,4,134,53,55,2,127,63,45,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,17,16,0,0,1,17,0,0,1,17,17,16,0,0,0,1,183,177,0,0,27,123,16,0,18,33,18, +33,0,0,0,1,86,113,0,0,21,103,16,0,18,123,27,177,0,0,0,1,86,113,0,0,21,103,17,17, +18,55,183,113,0,1,17,17,68,65,176,11,20,68,67,51,123,51,182,97,0,20,51,51,51,51, +17,17,51,51,54,37,17,99,118,97,0,19,100,68,34,86,51,51,101,34,41,204,145,68,71, +113,0,19,68,68,34,34,34,37,82,34,124,136,155,68,68,65,0,19,221,37,82,40,130,34, +130,85,142,232,235,151,116,65,0,19,68,40,130,85,85,88,200,204,206,233,235,244, +75,177,0,19,69,172,205,165,34,34,85,136,204,136,228,254,70,116,0,19,68,172,202, +170,221,34,85,34,233,153,148,249,70,116,0,19,74,172,205,170,210,34,85,34,238, +153,151,249,70,116,0,19,74,170,221,170,210,34,85,37,140,136,151,249,118,116,0, +19,173,221,210,85,34,37,88,136,200,233,151,249,230,116,0,19,77,221,210,88,34,85, +136,136,200,153,158,249,230,116,0,19,68,221,221,218,34,34,85,37,136,136,158,249, +230,116,0,19,69,221,221,218,210,34,130,34,156,201,151,249,118,116,0,19,68,90, +170,170,173,34,130,34,156,201,151,249,118,116,0,19,170,74,221,213,130,37,85,136, +140,204,151,249,70,116,0,19,90,88,34,37,82,89,137,156,204,238,158,244,68,177,0, +19,165,40,34,34,130,37,130,85,94,232,155,246,51,49,0,19,68,68,34,34,34,34,85,34, +200,85,155,147,54,49,0,19,100,68,34,86,51,51,101,34,44,153,155,99,118,97,0,20, +51,51,51,51,17,17,51,51,54,85,113,115,118,97,0,1,17,17,68,65,176,11,20,68,67,51, +228,99,182,97,0,0,0,1,86,113,0,0,21,103,17,17,23,54,182,113,0,0,0,1,86,113,0,0, +21,103,16,0,18,107,23,113,0,0,0,1,183,177,0,0,27,123,16,0,18,33,18,33,0,0,0,0, +17,16,0,0,1,17,0,0,1,17,17,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 8, computer terminal +175,0,1,85,5,4,23,6,9,26,80,65,2,84,161,194,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,17,0,1,17,17,17,17,17,17,0,1,16,0,0,0,1,116,0,22,101,101,102,102,102, +101,16,1,65,0,0,238,225,117,1,99,53,53,51,51,51,53,187,27,75,17,17,238,17,69,22, +60,129,17,17,17,17,139,83,102,74,140,158,233,154,69,22,56,148,68,68,68,73,21,51, +54,74,142,238,51,25,69,22,49,66,34,34,34,36,19,68,54,90,238,141,61,169,69,21, +177,66,242,242,34,36,19,119,54,202,131,51,218,121,69,22,49,66,242,34,34,36,31, +119,54,90,141,216,167,121,69,22,49,66,242,242,34,36,131,119,54,202,17,138,119, +73,69,22,49,66,242,34,34,36,207,119,54,90,87,119,68,89,69,22,49,66,242,34,34,36, +195,119,54,90,148,68,85,89,69,22,49,66,34,34,34,36,195,119,54,90,181,85,85,89, +69,22,49,79,255,255,255,244,195,119,54,202,185,153,149,89,69,22,49,66,34,34,34, +36,195,119,54,90,185,153,153,153,69,22,49,66,34,34,34,36,140,119,54,90,17,138, +187,153,85,22,49,66,34,34,34,36,19,119,54,202,141,216,171,187,69,21,177,66,34, +34,34,36,28,119,54,90,131,51,218,187,85,22,49,66,34,34,34,36,19,68,54,90,133,85, +93,171,149,22,56,148,68,68,68,73,21,51,54,74,141,221,93,27,89,22,60,129,17,17, +17,17,139,83,54,74,136,136,136,138,149,1,51,60,60,51,51,51,53,187,27,75,17,17, +17,17,153,0,24,140,140,136,136,136,136,16,1,65,0,0,0,1,153,0,1,17,17,17,17,17, +17,0,1,16,0,0,0,1,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0 +, // 9, column +175,2,4,3,5,48,6,63,51,7,81,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,65,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,20,65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,73,16,0,0,0,0,0,0,0, +0,0,0,0,0,1,148,38,145,16,0,0,16,0,0,0,1,0,0,0,1,22,146,36,105,145,17,17,33,17, +17,17,23,17,17,17,25,150,98,36,102,67,119,119,41,121,150,102,103,119,118,121,54, +150,98,36,70,67,68,71,36,68,68,68,71,66,119,119,57,70,66,50,68,67,36,68,40,68, +68,67,34,66,36,68,52,36,66,34,34,35,51,51,40,34,50,40,34,35,50,34,52,36,66,50, +34,33,49,129,40,35,131,49,50,35,50,50,20,36,66,35,34,33,17,17,40,129,51,49,18, +51,50,131,18,36,34,51,51,49,17,24,33,19,51,17,50,56,51,131,18,34,66,50,51,49,26, +161,33,51,17,19,50,17,51,19,19,50,51,51,19,49,170,161,35,17,17,17,18,51,19,19, +19,50,35,49,19,17,161,168,34,130,35,56,34,34,33,131,17,34,33,49,50,53,85,85,37, +85,85,85,82,85,85,85,82,67,49,17,42,160,0,0,16,0,0,0,1,0,0,0,10,162,33,19,160,0, +0,0,0,0,0,0,0,0,0,0,0,10,33,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,17,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 10, ruin +175,5,4,3,50,153,2,75,12,6,13,21,240,17,74,83,0,0,0,0,0,0,0,5,0,0,0,9,25,56,18, +19,0,0,0,0,0,0,0,5,0,0,0,145,34,162,56,35,0,0,0,0,0,0,0,117,0,0,0,18,19,49,35, +50,0,0,0,0,119,87,116,69,119,87,82,25,34,51,50,162,0,0,0,5,84,84,84,84,84,85,69, +154,34,34,51,34,0,0,0,0,0,0,0,117,0,0,2,145,33,177,19,50,0,0,0,0,0,0,0,236,0,0, +153,17,17,18,34,51,0,0,0,0,0,0,0,204,0,9,155,17,177,17,17,19,0,0,0,0,0,0,0,236, +0,9,17,17,34,17,17,131,0,0,0,0,0,0,17,17,17,17,17,17,161,17,17,38,0,0,0,0,0,1, +17,35,51,17,177,17,17,17,19,99,0,0,0,0,0,1,19,35,57,33,17,17,18,177,35,102,0,0, +0,0,0,2,24,51,17,17,17,18,17,17,54,102,0,0,0,7,119,124,34,56,33,177,17,27,18,18, +102,214,0,0,0,119,84,92,19,50,33,18,33,17,17,40,99,51,0,0,119,117,0,4,19,51,161, +17,17,17,27,54,70,111,0,0,0,0,0,3,35,67,49,177,33,17,18,99,18,34,0,0,0,0,0,0,34, +51,52,50,34,162,38,49,161,130,0,0,0,0,0,0,65,34,130,68,50,18,131,34,17,33,0,0,0, +0,0,0,49,35,34,52,72,34,99,18,18,42,0,0,0,0,0,0,66,35,35,56,68,214,49,34,33,34, +0,0,7,119,71,71,193,51,50,51,34,70,50,18,162,33,0,0,0,85,84,84,65,35,131,50,132, +70,33,18,34,34,0,0,0,0,0,0,49,35,51,51,52,70,34,35,51,50,0,0,0,0,0,0,51,52,68, +67,68,46,131,51,51,51,0,0,0,0,0,0,244,68,221,77,221,34,102,102,54,109,0,0,0,0,0, +0,0,7,80,0,6,18,35,238,102,102,0,0,0,0,0,0,0,7,80,0,3,18,34,243,51,230,0,0,0,0, +0,84,68,71,84,119,117,146,34,40,51,246,0,0,0,0,0,0,68,85,85,85,67,18,35,35,34, +52,0,0,0,0,0,0,0,5,80,0,0,51,51,51,51,51,0,0,0,0,0,0,0,5,0,0,0,0,51,50,51,35 +, // 11, lamp +175,0,49,31,7,106,27,28,107,3,4,105,1,2,26,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,220,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,220, +16,0,0,0,0,0,0,0,0,0,0,0,0,0,29,220,193,0,0,0,0,0,0,0,0,0,0,0,0,0,22,220,91,0,0, +0,0,0,0,0,0,17,0,1,16,85,103,146,88,85,0,0,0,0,0,0,1,33,0,22,133,51,103,146,232, +51,80,0,0,0,0,0,1,33,17,215,131,51,103,146,248,67,80,0,0,1,16,0,25,33,28,103, +132,68,103,146,248,68,59,187,177,26,33,17,153,33,28,119,132,68,231,98,232,68,55, +119,226,42,34,34,153,33,28,167,132,68,103,111,104,68,59,187,177,26,33,17,169,33, +17,167,131,51,119,98,136,67,80,0,0,1,16,0,26,33,0,23,85,51,119,111,230,51,80,0, +0,0,0,0,1,33,0,1,16,85,119,146,230,85,0,0,0,0,0,0,1,33,0,0,0,0,26,146,97,0,0,0, +0,0,0,0,0,17,0,0,0,0,26,162,241,0,0,0,0,0,0,0,0,0,0,0,0,0,1,175,16,0,0,0,0,0,0, +0,0,0,0,0,0,0,1,162,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,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, access card +175,0,21,45,44,23,46,2,19,34,69,22,68,60,131,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,1, +68,17,24,102,101,86,97,0,0,0,0,0,0,0,0,1,68,17,24,102,85,86,101,16,0,0,0,0,0,0, +0,1,67,17,24,101,85,86,101,183,16,0,0,0,0,0,0,1,51,17,24,85,85,102,59,178,16,0, +0,0,0,0,0,1,51,17,24,85,86,232,219,34,240,0,0,0,0,0,0,1,51,17,24,85,86,131,130, +34,240,0,0,0,0,0,0,1,51,17,24,85,102,52,114,34,16,0,0,0,0,0,0,1,54,17,24,86,99, +56,66,34,16,0,0,0,0,0,0,1,102,17,24,86,51,141,114,34,16,0,0,0,0,0,0,1,101,17,24, +102,51,211,114,34,16,0,0,0,0,0,0,1,101,17,24,99,51,55,114,34,16,0,0,0,0,0,0,1, +85,17,24,51,51,119,226,34,16,0,0,0,0,0,0,1,85,17,24,51,52,71,34,34,16,0,0,0,0,0, +0,1,85,17,24,51,52,119,130,34,16,0,0,0,0,0,0,1,85,17,24,51,68,228,114,34,16,0,0, +0,0,0,0,1,85,17,24,52,68,66,34,34,16,0,0,0,0,0,0,1,86,17,25,52,68,66,34,34,16,0, +0,0,0,0,0,1,86,17,23,68,68,34,34,34,16,0,0,0,0,0,0,1,102,17,23,68,68,34,34,34, +16,0,0,0,0,0,0,1,99,17,23,68,153,153,114,34,16,0,0,0,0,0,0,1,99,17,23,68,154, +170,114,34,16,0,0,0,0,0,0,1,51,17,23,68,154,204,114,34,16,0,0,0,0,0,0,1,51,17, +23,68,154,204,114,34,16,0,0,0,0,0,0,1,51,17,23,68,151,119,114,34,16,0,0,0,0,0,0, +1,51,17,23,66,130,34,130,34,16,0,0,0,0,0,0,1,51,17,23,66,130,34,130,34,16,0,0,0, +0,0,0,0,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,0,0,0 +}; + +SFG_PROGRAM_MEMORY uint8_t SFG_backgroundImages[3 * SFG_TEXTURE_STORE_SIZE] = +{ +// 0, city +64,10,73,168,19,12,14,13,80,1,72,101,0,100,136,57,17,17,17,68,87,119,119,119, +118,8,0,32,0,46,34,154,17,17,20,85,84,85,119,118,102,96,0,130,130,2,34,154,17, +17,20,65,68,69,119,102,99,48,48,0,2,32,34,154,17,17,17,17,68,68,87,118,102,102, +104,0,2,14,34,154,17,17,17,20,69,69,51,51,0,8,0,224,2,32,34,154,17,17,17,20,85, +87,60,204,195,51,0,0,0,2,34,154,17,17,17,68,85,119,252,204,51,224,48,0,0,32,34, +154,17,17,17,68,85,119,51,51,48,3,0,0,130,34,34,154,17,17,68,68,85,119,119,102, +102,104,48,40,32,32,34,154,17,17,20,69,87,119,119,102,102,102,128,128,0,2,34, +154,17,17,17,69,87,51,51,51,0,8,48,40,32,32,34,154,17,17,17,20,87,60,252,252, +243,51,0,0,128,2,34,154,65,17,17,20,85,60,204,204,51,48,48,0,32,32,34,154,17,17, +17,68,85,51,63,51,48,51,8,130,130,2,34,154,17,17,20,69,103,181,85,86,102,0,56,0, +0,46,34,154,17,17,17,69,85,187,85,91,102,3,15,0,0,2,34,154,17,17,17,68,85,187, +51,51,0,8,8,0,0,32,34,154,17,17,17,68,77,187,51,51,48,0,142,0,0,2,34,154,17,17, +17,68,77,219,51,51,0,8,48,0,0,32,34,154,17,17,65,69,51,51,60,204,195,51,224,0,0, +2,34,154,17,17,68,69,63,239,204,204,51,48,224,0,0,32,34,154,17,17,71,69,51,51, +51,51,48,240,136,128,14,2,34,154,68,17,71,68,85,221,187,219,176,8,48,40,32,46, +34,154,17,17,20,68,69,93,219,211,48,0,0,0,0,2,34,154,17,17,68,68,77,219,221,211, +0,8,48,0,224,32,34,154,65,20,69,85,84,219,221,179,48,0,136,128,0,2,34,154,17,68, +69,85,119,123,221,219,182,104,8,32,0,32,34,154,17,17,68,69,87,107,221,187,102, +102,102,128,0,2,34,154,17,17,20,85,87,107,219,190,0,8,8,0,0,32,34,154,17,17,20, +84,86,107,182,102,102,3,224,0,2,2,34,154,17,17,20,68,71,103,118,110,0,8,0,40,34, +32,34,154,17,17,17,68,71,102,103,102,102,102,104,128,0,2,34,154 +, // 1, reddish scifi interior +168,18,17,19,65,153,1,9,152,232,0,45,61,80,96,160,18,114,34,34,34,34,34,80,0,0, +0,0,0,0,0,0,18,114,34,34,34,34,34,80,0,0,0,0,0,0,0,0,0,215,34,34,34,34,34,80,0, +0,0,0,0,0,0,0,0,119,34,34,34,34,34,80,0,0,0,0,0,0,0,0,0,214,34,34,34,34,34,34, +32,0,0,0,0,0,0,0,0,118,34,34,34,34,34,34,36,69,0,0,0,0,0,0,18,118,17,17,17,17, +17,17,20,69,0,0,0,0,0,0,18,118,17,17,17,17,17,17,20,69,0,0,0,0,0,0,18,118,114, +34,34,34,34,34,116,69,0,0,0,0,0,0,18,118,130,34,34,38,0,0,0,0,0,0,0,0,0,0,18, +118,135,34,34,34,0,0,0,0,0,0,0,0,0,0,85,86,138,34,34,34,34,41,133,0,0,0,0,0,0,0, +0,86,138,17,17,17,17,25,133,85,0,0,0,0,0,0,0,86,138,17,17,17,27,25,132,70,0,0,0, +0,0,0,0,85,85,85,17,17,17,25,132,70,0,0,0,0,0,0,0,0,0,5,17,17,17,25,132,70,0,0, +0,0,0,0,0,0,0,5,17,27,17,25,132,70,0,0,0,0,0,0,0,6,128,17,17,17,17,25,132,70,0, +0,0,0,0,0,16,118,128,17,17,27,17,25,246,0,0,0,0,0,0,0,16,118,128,17,17,17,17,25, +132,0,0,0,0,0,0,0,16,118,128,51,51,51,51,57,246,0,0,0,0,0,0,0,16,118,130,51,51, +51,51,50,132,0,0,0,0,0,0,0,16,118,130,51,51,51,51,50,132,0,0,0,0,0,0,0,16,118, +131,51,51,51,51,51,132,70,0,0,0,0,0,0,0,0,5,60,51,51,51,51,36,70,0,0,0,0,0,0,0, +0,5,51,51,51,51,51,36,70,0,0,0,0,0,0,0,14,229,51,51,51,51,51,52,70,0,0,0,0,0,0, +85,85,51,195,51,51,51,51,52,64,0,0,0,0,0,0,18,114,17,17,17,17,17,17,18,64,0,0,0, +0,0,0,18,113,17,17,17,17,17,17,17,64,0,0,0,0,0,0,18,115,51,51,51,51,51,80,0,0,0, +0,0,0,0,0,18,115,51,51,51,51,51,80,0,0,0,0,0,0,0,0 +, // 2, red city at night +171,1,175,90,172,174,173,25,27,30,91,103,0,0,0,0,113,23,113,17,51,68,68,102,102, +85,82,34,34,34,38,49,113,23,113,17,51,68,68,102,102,85,82,34,34,34,35,51,113,0, +0,0,0,0,0,0,68,69,85,19,4,101,166,17,113,0,0,4,68,102,102,85,85,81,17,19,4,101, +38,54,113,0,0,4,68,102,102,85,85,81,17,19,4,101,38,51,113,0,0,4,68,102,102,85, +85,82,33,19,4,101,34,49,113,0,0,0,0,0,0,0,4,69,81,19,4,101,42,17,119,17,17,17, +17,0,4,68,102,85,85,35,4,101,42,51,135,17,17,51,51,51,0,0,0,0,68,83,4,101,34,17, +152,113,17,59,51,48,0,4,68,102,85,19,4,101,34,83,152,113,17,51,51,48,0,4,68,17, +17,19,4,101,42,51,135,113,17,51,51,48,0,4,68,17,17,19,4,101,164,17,119,17,17,59, +51,48,0,4,68,102,82,19,4,101,165,17,119,17,17,51,51,51,0,0,0,0,69,85,85,34,37, +51,119,113,17,17,17,16,4,68,102,101,82,37,85,34,34,102,119,119,17,19,51,0,4,70, +102,85,34,37,85,34,34,34,119,119,17,17,17,0,4,70,101,85,34,37,85,34,34,34,119, +17,17,17,17,16,4,70,101,82,38,17,48,70,51,34,113,16,0,0,0,0,0,0,102,102,33,17, +48,67,50,38,17,16,176,176,0,4,68,102,101,82,33,17,48,17,51,51,113,16,0,0,0,4,68, +102,101,82,33,17,48,17,51,50,113,16,0,0,0,4,68,102,101,82,38,17,48,17,51,51,135, +17,17,17,17,16,0,0,0,82,34,34,34,35,50,34,136,113,17,17,17,19,0,0,70,85,85,34, +34,36,51,36,136,113,17,16,0,3,48,0,0,0,68,102,82,36,17,17,152,135,17,16,0,0,51, +0,4,68,85,85,34,33,17,22,153,135,17,16,0,0,0,0,0,0,68,102,82,37,17,17,153,135, +17,17,17,16,0,68,70,101,1,19,4,101,81,34,152,119,16,0,0,0,4,68,64,17,17,19,4, +101,34,36,152,119,16,0,0,0,0,68,70,101,1,19,4,101,35,51,135,119,16,0,0,0,0,4,70, +101,85,34,34,34,35,54,119,23,16,0,0,0,0,0,0,4,69,82,34,34,35,51 +}; + +SFG_PROGRAM_MEMORY uint8_t SFG_weaponImages[6 * SFG_TEXTURE_STORE_SIZE] = +{ +// 0, knife +175,5,4,2,0,3,6,1,61,83,85,60,63,77,40,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,68,0,0,0,0,0,0,0,0,0,0,0,0,0,4,97,163,64,0,0,0,0,0,0,0,0,0,0,0,0,4,106,169, +64,0,0,0,0,0,0,0,0,0,0,0,0,4,26,217,64,0,0,0,0,0,0,0,0,0,0,0,0,0,74,147,64,0,0, +0,0,0,0,0,0,0,0,5,85,85,57,147,116,0,0,0,0,0,0,0,0,5,85,86,108,136,61,153,116,0, +0,0,0,0,0,0,85,88,102,102,102,136,49,148,68,68,0,0,0,0,0,88,17,102,204,102,102, +136,54,227,83,52,0,0,0,0,85,34,17,102,102,111,246,24,118,114,34,34,0,0,0,85,17, +34,22,111,108,97,17,18,118,114,53,83,0,0,85,17,22,17,17,34,34,37,85,87,113,117, +51,83,0,5,17,22,24,130,34,17,17,24,27,37,114,51,51,83,0,81,22,98,187,184,17,102, +97,17,34,37,114,51,51,51,5,17,104,187,34,134,102,102,102,18,33,37,121,51,51,51, +5,22,139,130,40,24,140,204,129,34,17,37,121,115,115,119,81,17,85,82,82,33,28,97, +17,34,34,37,125,119,115,119,51,51,52,116,68,68,49,33,21,34,82,37,125,55,119,119, +0,0,0,0,0,0,3,65,35,43,226,37,125,151,71,119,0,0,0,0,0,0,0,3,126,35,69,37,58, +147,116,68,0,0,0,0,0,0,0,0,14,52,4,87,61,147,116,0,0,0,0,0,0,0,0,0,0,0,14,68,57, +147,64,0,0,0,0,0,0,0,0,0,0,0,0,0,74,147,64,0,0,0,0,0,0,0,0,0,0,0,0,4,26,217,64, +0,0,0,0,0,0,0,0,0,0,0,0,4,170,167,64,0,0,0,0,0,0,0,0,0,0,0,0,4,157,167,64,0,0,0, +0,0,0,0,0,0,0,0,0,0,68,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,0,0 +, // 1, shotgun +175,3,4,54,5,17,2,1,7,101,100,99,25,98,9,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,119,119, +0,0,0,0,0,0,0,0,0,0,0,0,102,103,91,170,0,0,0,0,0,0,0,0,0,0,1,22,67,45,186,153,0, +0,0,0,0,0,0,0,1,17,20,50,52,218,153,74,0,0,0,0,0,0,0,17,18,35,136,55,20,218,153, +75,0,0,0,0,0,17,17,68,72,131,51,71,20,91,169,170,0,0,0,0,17,52,51,136,51,35,136, +35,52,93,187,180,0,0,0,1,51,19,131,56,130,67,50,36,66,91,186,148,0,0,0,19,51,19, +136,136,50,36,17,71,18,93,186,154,0,0,0,24,134,56,131,52,68,17,194,39,18,85,219, +187,0,0,6,51,54,51,52,68,66,34,34,34,34,21,255,185,0,0,6,51,50,50,34,34,34,33, +17,17,23,28,93,169,0,0,87,114,34,98,17,17,17,17,17,17,23,28,85,169,0,9,188,231, +21,97,81,85,85,85,92,92,197,197,87,218,0,5,85,206,236,229,85,85,117,117,119,119, +119,199,119,221,0,0,7,204,193,17,17,17,17,17,17,17,17,252,87,218,0,5,85,204,202, +170,169,153,153,153,153,153,170,170,87,169,0,9,188,199,34,193,17,17,17,17,17,17, +23,17,85,169,0,0,87,115,50,35,51,136,51,52,68,34,39,17,91,153,0,0,6,136,134,56, +136,136,136,131,51,136,136,65,219,185,0,0,6,51,54,67,51,51,131,56,136,55,24,77, +186,187,0,0,0,98,38,35,68,68,51,34,35,55,20,45,169,148,0,0,0,100,68,100,34,34, +44,18,17,67,52,219,153,68,0,0,0,6,68,34,34,18,38,97,28,98,34,219,171,186,0,0,0, +0,102,17,68,33,17,108,17,103,17,91,219,171,0,0,0,0,0,102,102,20,68,34,33,103,22, +93,186,154,0,0,0,0,0,0,0,102,98,34,68,70,22,91,186,153,0,0,0,0,0,0,0,0,6,102,98, +44,38,93,186,153,0,0,0,0,0,0,0,0,0,0,6,102,34,101,219,153,0,0,0,0,0,0,0,0,0,0,0, +0,102,103,95,170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,119,119,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0 +, // 2, machine gun +175,2,4,3,1,5,6,0,60,59,50,53,61,62,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,20,68,64,0,0,0,0,0,0,0,0,0,0,0,17,34,51,17,20,0, +0,0,0,0,0,0,0,0,0,1,98,17,17,68,71,65,17,16,0,0,0,0,0,0,0,22,33,17,20,68,70,102, +35,167,0,0,0,0,0,0,0,22,33,20,68,97,22,98,50,228,0,0,0,0,0,0,0,118,52,70,17,102, +102,34,34,20,0,0,0,0,0,0,7,51,17,22,102,102,101,37,35,20,0,0,0,0,0,0,22,102,22, +34,82,140,178,34,49,20,0,0,0,0,0,1,82,34,51,50,34,43,178,51,161,68,0,0,0,0,17, +17,34,35,51,152,49,19,51,161,68,68,0,0,1,17,88,83,34,58,19,136,37,37,50,51,133, +85,0,0,22,150,134,99,35,147,50,34,85,85,34,51,34,85,0,0,121,24,56,209,35,51,50, +34,85,82,34,51,34,37,0,0,113,19,18,33,35,51,34,37,85,34,37,51,34,34,0,0,1,119, +49,49,147,38,101,85,85,34,85,51,130,34,0,0,0,0,119,113,147,50,34,86,102,86,98, +161,68,68,0,0,0,0,0,7,25,34,37,85,34,37,195,51,161,68,0,0,0,0,0,0,113,17,17,51, +53,92,131,51,49,20,0,0,0,0,0,0,7,19,20,65,17,17,19,50,51,20,0,0,0,0,0,0,0,118, +20,65,68,17,17,50,35,20,0,0,0,0,0,0,0,22,17,68,68,20,65,19,51,20,0,0,0,0,0,0,0, +22,33,17,68,68,65,17,51,23,0,0,0,0,0,0,0,7,98,49,17,20,119,68,68,64,0,0,0,0,0,0, +0,0,23,34,51,17,20,0,0,0,0,0,0,0,0,0,0,0,0,17,119,119,64,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 3, rocket launcher +175,33,7,39,115,2,0,5,117,116,4,37,114,3,36,108,0,0,0,0,0,0,0,0,0,0,0,0,13,209, +102,0,0,0,0,0,0,0,0,0,0,0,0,221,218,122,85,96,0,0,0,0,0,0,0,0,0,0,13,34,39,165, +51,96,0,0,0,0,0,0,0,0,0,0,5,170,170,165,51,96,0,0,0,0,0,0,0,0,0,0,5,93,221,221, +81,102,0,0,0,0,102,102,16,0,0,0,17,102,102,102,102,204,0,0,0,17,170,173,214,80, +17,17,136,137,198,204,193,206,0,0,93,122,213,81,17,17,136,136,137,68,193,236, +158,238,0,5,170,17,22,20,148,152,148,204,196,153,66,153,136,136,0,90,161,17,100, +68,76,68,76,153,153,137,40,136,136,136,5,163,17,17,73,153,201,153,201,136,139, +190,43,179,51,51,5,58,81,20,136,132,136,132,139,179,55,226,51,51,51,51,13,42,17, +24,187,180,68,68,178,34,34,162,34,34,34,35,215,33,17,72,187,119,114,36,34,34,35, +162,35,51,51,17,211,33,21,131,50,34,34,46,34,34,34,162,34,34,209,51,163,37,85, +131,51,51,34,46,34,34,34,114,34,45,51,119,163,37,85,232,51,51,51,62,51,51,51, +178,51,127,55,187,211,37,85,238,238,238,238,228,136,136,187,226,51,115,123,185, +215,49,81,20,68,68,73,148,153,152,142,146,235,175,251,153,13,58,17,28,68,68,68, +68,68,68,153,67,153,175,123,153,5,122,17,81,204,196,68,68,68,68,68,67,116,175, +123,137,5,119,85,85,97,204,204,204,204,68,68,71,36,223,123,185,0,87,117,85,81, +102,17,17,28,204,204,196,58,211,123,184,0,5,119,165,85,81,102,85,17,17,17,204, +167,211,119,187,0,0,81,122,213,85,85,22,101,85,17,17,74,31,119,187,0,0,0,17,170, +173,214,16,102,102,85,17,17,31,247,119,0,0,0,0,102,102,96,0,0,0,102,102,81,31, +119,119,0,0,0,0,0,0,0,0,0,0,0,0,102,23,123,183,0,0,0,0,0,0,0,0,0,0,0,0,0,109, +123,187,0,0,0,0,0,0,0,0,0,0,0,0,0,97,215,136,0,0,0,0,0,0,0,0,0,0,0,0,0,6,109, +255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,102 +, // 4, plasma gun +175,4,3,6,5,17,50,49,0,187,7,190,37,42,100,209,0,0,0,0,0,0,0,0,0,0,0,0,2,80,1, +17,0,0,0,0,0,0,0,0,0,0,37,0,44,149,26,163,0,0,0,0,0,0,0,2,80,2,198,80,134,106, +163,51,0,0,0,0,0,0,0,44,101,2,194,37,170,170,51,51,0,0,0,0,0,0,2,201,103,88,42, +170,163,51,21,86,0,0,0,0,119,0,2,194,37,170,74,51,52,85,102,17,0,0,0,34,68,112, +40,42,170,172,67,51,70,33,17,17,0,0,34,52,68,130,74,164,51,196,51,51,110,17,18, +85,0,2,51,66,136,170,67,51,68,67,51,52,81,17,37,51,0,42,52,119,170,68,51,51,51, +51,51,66,17,18,68,68,2,163,55,42,163,51,52,66,221,85,93,33,17,68,17,153,2,119, +119,118,102,102,98,33,17,18,17,18,20,73,187,187,42,52,17,17,17,17,17,17,17,17, +33,17,36,155,149,136,36,18,119,117,86,97,20,68,68,68,36,68,33,185,83,67,35,68, +65,39,150,150,22,22,145,105,22,145,27,181,51,20,35,68,17,39,185,185,185,185,187, +155,185,187,187,182,52,20,35,65,18,39,150,150,22,22,145,105,22,145,27,182,68,20, +33,34,119,117,86,97,20,68,68,68,36,68,33,185,97,33,36,17,19,51,51,51,51,51,51, +51,35,51,36,155,150,88,2,119,118,102,102,102,34,36,68,50,51,50,52,73,187,187,2, +17,39,33,17,17,17,18,101,101,85,99,51,68,17,153,0,34,18,117,34,34,17,17,17,17, +17,229,51,50,68,68,0,7,34,34,88,119,114,17,119,209,17,17,83,51,37,51,0,0,119,34, +39,136,247,47,34,45,17,17,110,51,50,85,0,0,0,119,119,128,136,85,119,34,114,33, +22,228,51,51,0,0,0,0,136,0,8,198,87,117,242,34,33,102,85,67,0,0,0,0,0,0,8,201, +101,136,85,82,34,34,34,85,0,0,0,0,0,0,0,140,152,8,201,136,82,34,34,34,0,0,0,0,0, +0,0,8,128,8,198,128,134,101,34,34,0,0,0,0,0,0,0,0,0,0,136,0,140,152,133,85,0,0, +0,0,0,0,0,0,0,0,0,0,8,128,8,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 5, solution +6,76,175,48,26,5,4,7,57,77,75,27,58,2,28,68,34,34,34,34,34,34,34,34,45,221,211, +34,35,51,50,51,34,34,34,51,51,34,34,34,55,7,119,50,48,6,67,21,34,34,51,69,86,51, +56,45,112,87,119,3,8,136,68,161,34,34,53,102,70,102,68,215,0,87,7,102,131,173, +133,170,34,34,48,182,68,70,103,112,0,231,0,100,134,108,218,90,34,34,48,96,181, +68,112,0,0,231,0,84,134,119,74,165,34,34,53,176,96,183,0,0,5,21,80,4,77,7,124, +170,34,51,53,70,102,112,0,5,105,145,21,0,70,0,7,202,51,85,104,136,71,0,0,97,17, +153,17,85,0,0,0,124,48,70,102,104,135,0,6,17,31,25,17,17,85,0,0,7,48,180,68,70, +103,0,81,17,17,17,153,17,25,80,0,0,48,101,182,68,71,0,81,17,26,17,249,145,17,23, +0,5,48,224,96,230,71,0,101,17,17,17,25,145,17,23,0,92,53,176,224,96,71,0,105,81, +250,241,241,153,17,23,0,202,51,54,70,181,64,0,97,150,144,154,15,153,17,23,0,198, +34,35,68,68,64,5,97,31,127,122,122,25,145,16,85,134,34,35,56,136,128,0,97,31,1, +15,10,17,145,23,0,134,51,51,68,68,64,0,97,26,145,144,159,17,25,23,0,138,53,102, +70,69,176,0,97,17,169,170,241,17,25,151,0,138,53,176,176,224,183,5,97,17,25,145, +17,17,17,151,0,88,48,224,96,101,183,5,81,17,26,153,241,17,17,112,0,5,53,101,229, +180,135,0,85,17,17,25,145,17,80,0,0,0,53,228,77,136,135,0,5,81,26,25,97,7,5,0,0, +6,51,68,136,132,71,0,0,85,81,17,151,0,0,80,0,76,34,51,133,70,70,112,0,85,5,16, +112,0,102,5,100,204,34,34,53,176,229,71,0,5,80,231,0,5,68,102,76,204,34,34,48, +224,182,68,112,0,85,231,0,6,72,68,204,197,34,34,48,182,68,68,71,112,5,87,0,100, +104,141,220,90,34,34,53,68,68,136,136,55,5,96,5,100,3,173,133,170,34,34,51,136, +136,51,51,35,112,102,100,136,64,136,132,161,34,34,34,51,51,34,34,34,54,102,68, +50,56,100,67,21,34,34,34,34,34,34,34,34,35,51,51,34,35,51,50,51 +}; + +SFG_PROGRAM_MEMORY uint8_t SFG_effectSprites[4 * SFG_TEXTURE_STORE_SIZE] = +{ +// 0, explostion +175,183,174,15,103,111,191,7,31,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,48,0,0,0, +0,0,0,0,0,0,0,0,3,3,3,3,19,3,0,0,0,0,0,0,0,0,0,48,48,16,51,49,19,48,48,0,0,0,0, +0,0,0,3,3,1,1,19,17,131,51,49,0,0,0,0,1,16,0,0,48,50,34,20,85,120,49,17,64,0,0, +0,0,65,1,0,0,34,17,69,87,117,17,33,16,0,0,0,0,4,16,16,4,18,17,21,87,85,18,33,16, +0,0,0,1,9,34,34,17,34,17,21,85,85,66,17,48,0,0,0,65,18,34,34,17,65,22,85,86,68, +65,19,51,0,0,48,17,34,34,33,18,65,68,70,68,68,102,67,51,0,1,19,49,34,34,33,18, +36,132,100,70,97,20,81,17,51,48,17,18,34,18,18,34,33,119,85,86,97,33,81,51,48,3, +51,18,33,17,34,33,37,119,85,100,97,18,35,51,0,48,49,34,18,34,33,102,87,119,117, +97,17,34,34,16,48,1,17,18,33,17,22,104,119,119,117,81,18,18,33,67,0,1,65,18,33, +20,71,119,119,119,119,132,65,18,34,64,48,0,69,81,17,86,69,88,119,119,133,81,17, +18,34,147,0,0,56,21,69,86,70,103,119,119,116,17,18,34,34,144,0,3,51,56,86,102, +102,120,118,101,120,81,34,34,35,0,0,48,51,17,85,102,102,103,70,102,136,85,34,34, +17,0,0,3,49,19,53,84,102,100,70,102,88,133,84,66,17,19,0,48,51,51,85,68,102,68, +102,102,101,97,33,68,19,17,48,3,3,49,81,36,84,17,70,101,82,33,18,33,67,51,0,0, +51,49,17,33,33,33,70,102,66,34,34,34,17,51,48,0,3,17,18,34,33,34,20,129,18,34, +34,34,34,51,0,0,49,17,34,33,17,17,33,65,34,34,17,18,34,19,48,0,1,18,33,17,17,17, +34,34,33,145,17,18,34,19,48,0,1,17,17,19,49,49,18,17,49,19,49,18,34,35,51,0,0, +17,51,51,17,49,18,19,3,19,51,17,17,36,3,0,3,51,51,48,48,3,17,16,48,17,3,51,17, +16,0,0,3,48,3,3,0,0,16,19,0,0,0,51,51,0,0,0,51,0,0,0,0,0,1,3,48,0,51,51,48,0,0 +, // 1, fireball +175,103,183,7,191,111,254,31,95,180,173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,0,16,0,0,0,0, +0,0,0,0,0,0,1,1,23,17,17,24,1,0,0,0,0,0,0,0,0,0,16,16,23,85,87,81,24,16,0,0,0,0, +0,0,0,1,8,17,119,115,55,119,17,129,16,0,0,0,0,0,0,0,129,23,119,51,51,55,113,24, +23,0,0,0,0,0,0,8,17,17,113,83,51,85,119,23,113,0,0,0,0,0,0,1,21,113,81,19,53,81, +17,119,129,0,0,0,0,0,0,17,19,53,17,19,50,17,17,113,16,16,0,0,0,0,1,33,83,49,17, +19,66,34,17,17,18,0,0,0,0,0,0,33,85,53,21,19,18,34,34,24,18,16,0,0,0,0,1,33,85, +85,84,68,20,34,35,66,98,0,0,0,0,0,0,33,83,53,20,68,51,51,51,70,34,16,0,0,0,0,1, +33,19,49,66,36,67,52,41,40,98,0,0,0,0,0,0,33,19,84,34,36,36,70,38,134,34,0,0,0, +0,0,0,8,21,81,18,36,66,98,102,166,32,0,0,0,0,0,0,2,21,81,18,68,68,38,134,105,33, +0,0,0,0,0,0,0,18,33,18,68,51,73,102,98,16,0,0,0,0,0,0,0,18,18,34,68,51,74,102, +102,16,0,0,0,0,0,0,0,1,17,18,34,36,38,38,129,0,0,0,0,0,0,0,0,0,8,134,38,34,34, +104,0,0,0,0,0,0,0,0,0,0,0,2,34,102,96,16,0,0,0,0,0,0,0,0,0,0,0,0,1,16,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0 +, // 2, plasma +175,199,126,213,198,215,118,46,125,204,124,134,45,117,135,116,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,1,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,68,16,0,0,0,0,0,0,0,0,0,0,16, +1,17,20,17,16,16,16,0,0,0,0,0,0,0,17,18,7,113,20,17,119,1,1,0,0,0,0,0,0,1,17,65, +16,34,67,50,33,17,16,0,0,0,0,0,0,1,36,34,1,19,153,51,33,65,0,0,0,0,0,0,0,14,37, +34,32,51,57,163,35,50,16,0,0,0,0,0,0,114,37,82,2,17,51,170,51,34,17,0,0,0,0,0,0, +18,51,83,34,17,3,152,138,43,178,16,0,0,0,0,1,20,34,52,83,163,32,123,136,199,34, +17,0,0,0,0,1,17,18,35,51,51,34,18,34,194,36,68,0,0,0,0,0,17,17,104,109,250,51, +18,34,34,51,17,0,0,0,0,1,7,113,34,134,136,34,211,70,34,131,17,0,0,0,0,0,16,34, +34,134,34,34,97,17,102,98,16,0,0,0,0,0,1,18,85,84,17,98,97,33,22,98,1,0,0,0,0,1, +17,37,83,242,68,70,18,146,33,23,16,0,0,0,0,1,50,53,35,134,133,65,39,185,37,17,1, +0,0,0,0,0,19,147,34,136,51,81,39,190,36,65,32,0,0,0,0,0,17,18,34,131,34,83,39,0, +35,34,32,0,0,0,0,1,1,17,34,34,34,57,50,114,49,34,0,0,0,0,0,0,16,17,34,34,83,147, +67,33,64,0,0,0,0,0,0,0,1,2,33,35,81,17,68,68,65,0,0,0,0,0,0,0,0,2,33,21,17,17, +17,17,16,0,0,0,0,0,0,0,0,0,0,20,65,0,1,17,0,0,0,0,0,0,0,0,0,0,0,1,65,16,0,16,0, +0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 3, dust +175,5,3,4,53,2,6,52,50,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,2,34,0,0,16, +1,0,0,0,0,0,0,0,0,0,0,34,50,32,3,48,0,0,0,0,0,0,0,0,0,0,2,35,50,16,66,18,0,0,0, +0,0,0,0,1,16,0,2,49,51,4,4,2,82,34,0,0,0,0,0,0,1,16,0,49,49,32,64,18,81,51,32,0, +0,0,0,0,0,0,0,3,22,55,97,18,33,19,48,0,0,0,0,0,0,0,0,0,6,19,50,34,19,17,48,0,0, +0,0,0,0,1,51,17,17,99,35,129,51,50,0,0,0,0,0,0,0,0,1,55,0,7,50,4,34,32,1,0,0,0, +0,0,0,0,3,112,64,2,64,32,98,0,0,0,0,0,0,0,0,0,9,52,4,3,4,4,5,0,0,0,0,0,0,0,0,0, +18,64,34,49,0,32,18,1,16,0,0,0,0,0,0,0,18,34,35,19,32,18,50,0,1,16,0,0,0,0,0,0, +0,37,19,34,136,18,51,16,0,0,0,0,0,0,0,0,0,5,35,49,51,1,0,16,0,0,0,0,0,0,0,0,0,1, +17,19,34,0,0,0,0,0,0,0,0,0,0,0,0,0,34,18,32,0,0,0,0,0,0,0,0,0,0,0,1,0,0,34,0,1, +0,0,0,0,0,0,0,0,0,0,16,0,16,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,16,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +SFG_PROGRAM_MEMORY uint8_t SFG_monsterSprites[19 * SFG_TEXTURE_STORE_SIZE] = +{ +// 0, spider idle +175,0,4,3,5,6,223,1,7,10,2,20,62,95,120,18,0,1,17,16,0,0,0,0,0,0,0,0,1,17,16,0, +0,20,45,65,0,0,0,0,0,0,0,0,21,52,33,0,1,65,170,20,16,0,0,0,0,0,0,17,133,50,51, +16,1,218,211,162,16,0,0,0,0,0,17,133,84,17,17,17,1,42,61,173,16,1,0,0,0,1,133, +84,33,0,0,0,1,65,170,20,17,1,16,0,1,24,85,73,16,0,0,0,0,20,210,71,119,19,81,0,0, +1,19,146,16,0,0,0,1,115,17,115,115,68,65,0,0,0,1,66,49,0,0,0,20,36,119,41,37,69, +85,16,0,0,1,66,49,17,17,0,18,50,115,21,85,68,68,33,0,1,17,51,133,52,66,16,20,45, +113,28,197,66,66,65,1,24,136,85,85,50,35,49,1,17,37,86,198,196,34,33,0,1,85,85, +68,153,153,145,0,21,85,70,140,102,34,34,16,0,147,57,147,51,35,16,0,17,119,60, +104,102,98,34,46,238,191,66,243,17,17,17,1,57,115,115,38,108,198,34,231,243,187, +116,33,0,0,0,18,49,153,151,34,104,198,62,255,59,180,51,112,0,0,0,18,49,51,55,34, +104,198,62,255,59,180,51,112,0,0,0,1,57,121,115,38,108,198,34,231,243,187,116, +33,0,0,0,0,17,119,60,104,102,98,34,46,238,191,66,147,17,17,17,0,21,85,70,140, +102,34,34,16,0,148,41,147,51,35,16,1,17,37,86,198,196,34,33,0,1,136,136,133,153, +153,145,20,45,113,28,197,66,66,65,1,21,85,85,85,52,66,49,18,50,115,21,85,84,68, +33,0,1,17,51,133,50,35,16,20,36,119,41,37,85,85,16,0,0,1,66,55,17,17,0,1,115,17, +115,115,68,65,0,0,0,1,66,49,0,0,0,0,20,45,71,119,19,81,0,0,1,19,50,16,0,0,0,1, +65,170,20,17,1,16,0,1,24,136,137,16,0,0,0,1,218,61,162,16,1,0,0,0,1,133,85,129, +0,0,0,1,42,211,173,16,0,0,0,0,0,17,69,85,17,17,17,1,65,170,20,16,0,0,0,0,0,0,17, +69,50,35,16,0,20,210,65,0,0,0,0,0,0,0,0,20,50,49,0,0,1,17,16,0,0,0,0,0,0,0,0,1, +17,16,0 +, // 1, spider attacking +175,0,183,3,4,1,191,5,31,6,7,22,10,223,20,18,0,34,37,85,43,176,0,0,0,0,0,0,17, +17,16,0,0,34,98,34,38,102,0,0,0,0,0,1,148,71,65,16,0,2,98,34,102,98,0,0,0,0,0, +89,169,52,51,49,0,2,104,40,102,32,0,0,0,0,5,170,145,17,17,16,2,38,104,136,98,32, +80,0,0,0,90,167,65,0,0,0,2,102,102,102,102,34,85,0,0,5,184,124,16,0,0,0,2,102, +34,34,102,102,232,80,0,91,139,76,16,0,0,0,2,34,46,34,38,102,187,113,0,85,84,196, +49,17,17,0,0,91,235,85,34,107,136,145,0,0,5,115,19,71,116,16,0,94,238,94,88,139, +139,116,80,0,85,58,169,52,67,49,0,23,75,85,91,184,231,71,80,5,170,153,119,60, +204,17,0,1,21,232,141,141,116,68,16,88,137,119,204,195,49,0,0,1,153,136,189,169, +212,68,65,1,195,60,51,51,67,16,0,1,17,85,55,218,221,212,68,85,95,116,243,49,17, +17,0,19,197,51,83,77,217,125,69,95,62,87,65,16,0,0,1,67,49,204,197,68,218,157, +95,243,235,51,80,0,0,0,1,67,193,51,53,68,218,157,95,243,235,51,80,0,0,0,0,19, +197,204,83,77,217,125,69,95,62,87,65,16,0,0,0,1,17,85,55,218,221,212,68,85,95, +116,243,49,17,17,0,1,153,153,125,168,221,68,65,5,51,60,51,51,67,16,0,1,17,232, +141,141,190,68,16,90,170,170,204,195,49,0,0,23,75,85,91,184,235,71,85,5,183,153, +170,60,204,17,0,94,238,94,88,184,187,116,80,0,85,55,153,52,67,49,2,43,235,82,34, +136,136,145,0,0,1,115,19,71,116,16,2,34,82,34,98,46,187,113,0,85,83,196,49,17, +17,0,2,98,34,38,102,44,232,16,0,91,170,124,16,0,0,0,2,102,102,102,98,37,85,0,0, +5,185,172,16,0,0,0,2,38,136,134,34,80,80,0,0,0,88,167,65,0,0,0,0,182,136,134,98, +80,0,0,0,0,5,185,145,17,17,16,0,34,102,102,102,32,0,0,0,0,0,87,153,52,51,49,0,2, +98,34,102,107,0,0,0,0,0,1,116,71,65,16,0,2,37,82,43,32,0,0,0,0,0,0,17,17,16,0 +, // 2, spider walking +175,0,4,5,6,3,223,1,10,7,2,18,62,95,120,63,0,0,17,17,0,0,0,0,0,0,0,1,17,17,0,0, +0,1,50,211,16,0,0,0,0,0,0,21,51,50,16,0,0,19,26,161,49,0,0,0,0,0,17,146,35,33,0, +0,0,29,173,90,33,0,0,0,0,1,148,68,81,16,0,0,0,18,165,218,209,0,16,0,0,25,67,49, +16,0,0,0,0,19,26,161,49,16,17,0,1,148,51,16,0,0,0,0,0,1,61,35,119,113,84,16,25, +68,56,0,0,0,0,0,0,23,81,23,87,83,51,16,17,21,129,0,0,0,0,0,1,50,55,114,130,67, +68,65,0,1,50,16,0,0,0,0,1,37,39,81,68,67,51,50,0,1,85,81,17,17,17,0,1,50,215,17, +204,67,35,35,16,25,153,148,68,83,50,16,0,17,18,68,111,108,50,34,16,1,68,68,68, +82,37,81,0,1,68,67,105,246,98,34,33,0,133,88,136,136,136,129,0,1,23,117,198,150, +102,34,34,238,227,37,181,17,0,0,0,21,135,87,82,102,252,98,46,123,91,50,81,0,0,0, +1,37,24,136,114,38,159,101,235,181,35,181,112,0,0,0,1,37,24,136,114,38,159,101, +235,181,35,181,112,0,0,0,0,21,135,87,82,102,252,98,46,123,83,123,33,0,0,0,0,1, +23,117,198,150,102,34,34,238,235,50,133,17,17,0,0,1,68,67,105,246,98,34,33,0, +131,40,85,85,34,16,0,17,18,68,111,108,50,34,16,1,148,33,17,17,17,0,1,50,215,17, +204,67,35,35,16,25,50,16,0,0,0,0,1,37,39,81,68,67,51,50,17,148,72,136,128,0,0,0, +1,50,55,114,130,67,68,65,20,68,73,148,136,128,0,0,0,23,81,23,87,83,51,16,1,17, +84,68,83,56,129,0,0,1,61,35,119,113,84,16,0,5,21,68,82,34,81,0,0,19,26,161,49, +16,17,0,0,20,66,87,18,37,16,0,0,18,165,218,209,0,16,0,0,1,84,52,65,17,81,17,0, +29,173,90,33,0,0,0,0,0,17,19,52,82,37,16,0,19,26,161,49,0,0,0,0,0,0,1,19,82,81, +0,0,1,50,211,16,0,0,0,0,0,0,0,1,17,16,0,0,0,17,17,0,0,0,0,0,0,0,0,0,0,0,0 +, // 3, destroyer idle +0,175,3,4,5,73,1,6,2,77,157,79,7,78,76,75,17,0,0,0,17,17,17,17,17,17,17,17,17, +17,17,17,17,11,221,219,0,17,17,17,16,0,0,0,0,0,1,17,17,11,217,153,219,1,17,16,2, +119,114,39,116,119,1,17,17,11,189,154,155,1,16,12,194,124,204,204,199,204,1,17, +17,16,189,154,169,176,12,199,116,35,51,51,50,51,1,17,17,17,11,217,170,213,196, +68,67,34,34,34,40,34,0,0,17,16,11,217,154,149,52,50,50,0,0,0,0,0,4,64,17,7,118, +102,138,173,83,68,128,17,17,17,17,7,114,32,16,116,12,66,106,169,181,51,71,0,1, +17,0,115,56,128,16,67,0,102,102,42,213,35,52,71,112,0,119,51,40,128,7,48,194,0, +7,114,171,82,51,68,71,114,83,34,40,128,4,12,204,64,0,71,106,181,131,52,68,71,82, +34,40,80,4,12,199,114,192,36,70,157,184,52,119,116,37,40,133,80,0,204,119,119, +96,4,70,169,213,55,51,55,69,80,102,96,0,102,103,116,44,4,50,106,155,83,157,147, +117,34,0,0,2,9,230,68,32,3,50,106,173,83,57,211,53,34,1,17,2,11,150,68,48,3,50, +106,233,83,57,211,53,34,1,17,0,34,36,67,44,3,50,106,238,83,157,147,37,34,128,0, +0,119,68,67,128,3,54,254,229,34,51,50,53,88,50,32,6,7,68,50,192,131,38,174,245, +35,34,35,37,34,40,128,2,4,68,48,0,50,111,229,82,51,51,50,82,34,40,128,3,32,66,0, +3,38,254,86,130,34,34,34,88,34,40,128,16,50,0,0,0,111,229,104,34,40,133,85,104, +136,40,80,16,51,99,38,105,154,245,130,40,96,82,67,6,102,133,80,17,3,54,102,137, +238,88,134,96,17,7,66,6,0,101,80,17,16,13,187,154,229,102,104,36,0,116,72,128, +17,6,96,17,17,11,186,170,245,96,130,51,71,67,34,32,17,16,0,17,16,187,218,174, +240,5,130,51,51,51,50,80,17,17,17,17,11,189,170,175,1,16,5,34,34,34,80,1,17,17, +17,17,11,221,170,255,1,17,16,85,85,0,1,17,17,17,17,17,11,218,255,0,17,17,17,0,0, +17,17,17,17,17,17,17,0,0,0,17,17,17,17,17,17,17,17,17,17,17,17 +, // 4, destroyer attacking +175,0,3,4,73,1,5,2,183,6,77,157,79,78,7,31,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0, +17,17,17,0,0,0,0,0,136,136,128,0,0,0,0,0,28,221,220,17,0,0,0,8,136,136,128,0,0, +0,0,0,28,218,170,220,16,1,88,136,136,255,136,128,0,0,0,0,28,218,187,172,85,94, +238,136,136,255,136,128,0,0,0,0,28,218,187,187,215,105,255,248,136,136,136,0,0, +0,0,0,1,221,171,187,163,102,255,255,136,136,136,0,0,1,17,0,25,17,85,87,189,38, +99,99,56,136,0,0,17,86,97,1,150,37,230,37,186,195,51,35,56,0,0,17,255,146,33,1, +99,37,85,85,82,211,35,54,98,17,17,249,99,55,113,25,51,94,33,17,153,44,50,51,111, +255,243,70,50,39,113,22,53,238,230,17,22,148,195,115,54,153,159,114,34,39,113, +19,49,238,153,46,18,102,125,151,57,51,57,100,34,39,65,19,94,233,153,149,17,102, +90,215,51,173,163,148,68,116,65,18,21,85,153,98,225,99,37,172,67,58,211,52,39, +69,81,19,33,163,86,98,17,51,37,189,67,58,211,52,34,17,17,18,33,202,86,99,17,51, +37,58,67,173,163,36,34,16,0,19,18,34,102,50,225,51,37,58,66,51,50,52,34,113,17, +18,89,150,102,55,17,51,82,52,35,34,35,36,71,50,33,19,33,150,99,46,23,50,82,36, +35,51,50,116,34,39,113,19,37,102,99,17,19,37,36,66,51,50,39,66,34,39,113,19,34, +22,33,17,50,82,69,114,34,36,68,71,34,39,113,1,50,81,17,85,85,36,87,34,39,66,99, +23,119,39,65,1,51,37,50,87,171,68,21,81,119,25,98,21,85,116,65,0,19,51,85,123, +50,65,87,38,17,150,103,113,17,84,65,0,1,92,202,171,52,81,35,51,105,99,34,33,0, +21,81,0,1,204,219,187,36,20,114,51,51,51,50,65,0,1,17,0,28,205,219,178,65,20, +119,34,34,34,65,16,0,0,0,0,28,205,187,36,16,1,20,68,68,65,16,0,0,0,0,0,28,219, +187,33,0,0,1,17,17,16,0,0,0,0,0,0,28,219,177,16,0,0,0,0,0,0,0,0,0,0,0,0,17,17, +16,0,0,0,0,0,0,0,0,0,0,0,0 +, // 5, destroyer walking +175,0,3,4,1,5,2,73,6,77,79,7,78,157,75,76,0,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0, +26,204,202,17,0,0,1,17,17,17,0,0,0,0,0,0,26,201,153,202,16,1,19,136,130,33,17, +17,0,0,0,0,26,172,157,154,16,27,179,40,187,184,133,129,16,0,0,0,1,172,157,217, +161,184,136,50,51,59,184,102,16,0,0,0,0,26,201,221,199,85,85,50,34,35,50,102,16, +0,0,0,1,26,201,157,151,53,35,97,17,18,38,102,16,17,16,0,24,17,68,70,220,115,54, +16,0,1,17,97,17,85,16,1,133,36,181,36,217,167,51,81,17,16,0,17,56,34,16,1,83,36, +68,68,119,199,35,53,88,129,17,136,51,102,16,24,51,75,33,17,136,122,114,51,85,88, +130,115,34,102,16,21,52,187,181,17,21,135,167,99,53,85,88,114,34,102,16,19,49, +187,136,43,18,85,76,214,53,136,133,39,34,103,16,19,75,184,136,132,17,85,73,199, +56,51,56,87,118,119,16,18,20,68,136,82,177,83,36,154,115,156,147,135,33,68,16, +19,33,159,69,82,17,51,36,220,115,57,195,55,34,17,16,18,33,169,69,83,17,51,36, +249,115,57,195,55,34,97,17,19,18,34,85,50,177,51,36,255,115,156,147,39,38,50,33, +18,72,133,85,54,17,51,78,247,34,51,50,55,114,38,97,19,33,133,83,43,22,50,78,231, +35,34,35,39,34,38,97,19,36,85,83,17,19,36,231,114,51,51,50,114,34,38,97,19,34, +21,33,17,50,78,116,98,34,34,38,118,34,38,113,1,50,65,17,68,68,231,70,34,38,97, +17,22,102,103,113,1,51,36,50,70,157,119,20,38,65,16,0,1,20,71,113,0,19,51,68, +109,254,113,70,65,23,97,16,0,1,20,65,0,1,74,169,157,247,65,35,37,136,133,33,0,0, +1,17,0,0,26,173,221,231,65,98,51,85,134,97,0,0,0,0,0,1,170,205,223,225,23,98,34, +51,51,33,0,0,0,0,0,26,172,221,222,16,1,17,118,34,38,97,0,0,0,0,0,26,204,221,238, +16,0,0,17,17,17,16,0,0,0,0,0,26,205,238,17,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,0,0, +0,0,0,0,0,0,0,0,0,0 +, // 6, warrior idle +175,0,3,5,1,4,6,62,2,7,92,170,151,93,95,148,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,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,199,119,119, +119,204,204,187,176,0,0,0,0,0,0,0,185,153,153,153,153,150,103,119,123,0,0,0,0,0, +0,1,255,204,119,119,119,119,119,119,193,0,0,0,0,0,0,1,17,17,17,17,17,17,17,28, +133,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,85,16,0,0,1,17,16,0,0,0,0,0,0,0,0,0,21,81,0, +1,19,53,81,0,0,0,0,0,0,0,0,0,1,33,1,22,99,51,81,0,0,17,0,0,0,0,0,0,1,40,22,102, +51,51,33,0,0,25,16,0,17,16,0,0,18,40,153,102,99,50,68,0,0,22,145,17,234,145,0,1, +173,85,85,54,51,50,68,0,0,19,105,155,234,102,16,24,90,173,51,38,99,50,68,0,0,1, +51,54,178,54,129,130,55,218,211,38,51,50,68,0,0,0,21,51,102,99,136,34,55,122, +211,38,99,51,36,0,1,17,34,85,51,102,56,34,55,218,211,38,51,51,81,0,19,51,51,51, +51,51,88,34,58,173,50,86,99,53,81,0,1,17,34,37,51,53,88,34,170,51,35,102,50,34, +36,0,0,0,18,85,85,85,136,40,163,50,57,98,34,34,36,0,0,1,37,85,178,82,136,136, +162,43,149,34,180,68,68,0,0,21,85,43,234,34,65,132,162,43,82,36,68,34,36,0,0,21, +33,17,234,33,0,20,162,36,43,68,66,83,82,0,0,18,16,0,17,16,0,1,17,17,36,68,68,68, +68,0,0,17,0,0,0,0,0,0,0,1,43,68,68,34,36,0,0,0,0,0,0,0,0,0,0,0,18,43,66,83,82,0, +0,0,0,0,0,0,0,0,0,0,1,18,36,68,68,0,0,0,0,0,0,0,0,0,0,0,0,1,18,34,36,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,17,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 7, warrior attacking +175,0,62,5,7,3,4,1,2,6,170,151,92,95,148,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +17,0,0,1,17,16,0,0,0,0,0,0,0,0,0,1,85,16,1,19,54,97,0,0,1,16,0,0,0,0,0,19,82,17, +25,147,51,97,0,0,1,145,16,1,17,0,1,53,126,74,89,51,51,87,0,0,1,153,17,29,201,16, +1,136,135,72,85,147,53,119,0,0,1,57,68,205,201,49,24,99,34,68,165,51,53,119,0,0, +0,19,51,154,163,152,136,50,36,68,133,83,53,119,0,0,0,1,86,57,153,150,133,50,34, +36,74,83,53,119,0,0,1,17,17,86,51,147,34,34,34,36,72,85,51,87,0,0,19,51,51,51, +51,54,133,34,43,180,68,165,51,97,0,0,1,17,17,83,54,102,133,51,34,34,68,133,83, +97,0,0,0,1,86,102,102,104,133,50,34,34,68,74,86,97,0,0,0,21,102,106,165,88,130, +34,68,68,68,69,133,87,0,0,1,86,101,205,197,135,120,34,34,34,36,66,167,119,0,0,1, +101,17,29,197,16,7,130,34,187,180,68,165,101,0,0,1,81,0,1,17,34,34,34,34,34,34, +68,42,119,0,0,1,16,0,0,0,2,34,36,68,68,68,68,74,85,0,0,0,0,0,0,0,0,0,34,34,68, +68,68,68,23,0,0,0,0,0,0,0,0,0,0,2,43,187,187,187,17,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +17,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 8, plasmabot idle +175,0,72,65,2,3,4,5,61,60,54,62,6,59,49,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,34,34,0,0,0,0,0,0,0,0,0,0,0,0,0,42,170,170,34,0,0,0,0,0,0,1,17,0,0,0,0,42,147, +56,171,32,0,0,0,0,0,1,193,0,0,0,0,42,50,35,153,32,0,0,0,1,17,20,68,17,17,0,2, +171,50,34,57,32,0,0,0,1,119,118,102,85,65,0,2,163,34,34,57,33,0,0,0,1,101,85,68, +68,65,0,2,163,34,35,137,35,16,0,0,1,17,17,17,17,17,0,42,185,50,35,141,50,49,0,0, +0,0,1,65,0,0,0,42,187,131,57,211,66,52,16,0,0,0,21,81,0,0,0,43,51,136,179,68, +136,34,17,17,17,17,68,65,0,0,0,36,101,51,52,216,136,146,86,124,197,204,204,113, +0,0,0,3,122,229,61,136,137,242,17,17,17,17,28,17,0,0,0,2,122,174,83,153,211,35, +65,0,0,0,28,16,0,0,0,2,118,174,101,51,50,51,65,0,17,17,68,65,17,16,0,2,118,102, +238,85,82,52,65,1,119,119,102,102,85,65,0,2,118,102,238,102,98,52,81,1,102,85, +85,68,68,65,0,2,118,174,102,83,50,53,81,0,17,17,17,17,17,16,0,2,122,174,101,171, +179,37,81,0,0,0,20,16,0,0,0,3,122,230,93,184,136,210,17,17,17,17,21,17,0,0,0,35, +118,85,52,216,137,243,86,124,197,204,199,81,0,0,0,43,85,170,179,68,159,34,17,17, +17,17,68,65,0,0,0,42,171,147,57,211,66,52,16,0,0,0,23,113,0,0,0,42,185,50,35, +136,50,65,0,0,0,0,1,193,0,0,0,2,179,34,35,137,36,16,0,0,1,17,20,68,17,17,0,2, +179,34,34,57,33,0,0,0,1,119,118,102,85,65,0,2,152,50,34,61,32,0,0,0,1,101,85,68, +68,65,0,0,40,50,35,223,32,0,0,0,1,17,17,17,17,17,0,0,41,147,61,255,32,0,0,0,0,0, +1,81,0,0,0,0,47,255,223,34,0,0,0,0,0,0,1,17,0,0,0,0,2,34,34,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 9, plasmabot attacking +175,198,0,2,4,3,72,39,193,5,194,6,49,192,65,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,111,193,1,0,0,0,0,0,0,0,0,0,0,0,0,6,177,17,17,0,0,0,0,0,0,2,34,0,0,0,0,15, +113,17,17,240,0,0,0,0,0,2,178,0,0,0,0,107,17,23,17,31,0,0,0,8,136,131,51,34,34, +0,0,97,23,119,113,17,17,0,0,10,153,153,68,85,50,0,0,103,17,119,119,17,16,0,0,10, +68,85,83,51,50,0,6,145,17,119,17,19,61,0,0,10,168,141,34,34,34,0,1,17,17,23,17, +85,172,128,0,0,0,2,50,0,0,0,6,17,113,17,17,85,172,128,0,0,0,2,82,0,0,0,6,156,55, +113,85,84,76,200,170,168,136,211,50,0,0,0,6,52,85,81,84,180,68,245,73,187,91, +187,146,0,0,0,0,233,151,85,91,180,67,98,34,34,34,43,34,0,0,0,0,105,71,115,52,69, +230,227,32,0,0,43,32,0,0,0,0,105,68,124,83,206,110,227,32,168,141,51,50,34,32,0, +0,105,68,68,204,85,110,51,218,153,153,68,68,85,50,0,0,105,68,68,204,68,110,51, +218,68,85,85,51,51,50,0,0,105,68,124,69,238,254,53,208,136,136,221,210,34,32,0, +0,105,71,124,91,153,207,85,32,0,0,35,32,0,0,0,0,233,71,197,25,68,69,253,136,221, +221,37,34,0,0,0,6,233,149,81,20,148,67,197,73,187,91,185,82,0,0,0,6,149,87,17, +17,84,60,200,136,136,136,211,50,0,0,0,6,187,113,17,17,21,172,208,0,0,0,13,146,0, +0,0,6,177,17,119,17,17,163,32,0,0,0,13,178,0,0,0,6,73,145,23,119,19,50,0,0,10, +136,131,51,34,34,0,0,105,17,119,113,28,32,0,0,10,153,68,68,85,50,0,0,105,17,119, +17,17,0,0,0,10,69,85,51,51,50,0,0,97,17,23,17,22,0,0,0,10,168,210,34,34,34,0,0, +1,65,17,21,17,0,0,0,0,0,2,82,0,0,0,0,6,52,69,31,0,0,0,0,0,0,2,34,0,0,0,0,0,102, +102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 10, ender idle +0,3,4,5,2,175,1,6,52,7,93,92,50,74,73,0,85,85,85,85,0,0,0,80,5,0,5,85,85,80,0,0, +85,85,80,0,153,153,52,1,134,17,16,80,0,9,114,32,85,80,3,151,119,119,119,104,97, +135,129,9,119,115,36,16,85,9,114,115,51,51,51,54,97,114,113,99,50,17,22,16,80, +151,113,18,4,18,34,51,97,135,129,102,33,20,70,16,9,119,20,55,114,0,65,34,16,17, +22,24,4,68,70,16,2,20,67,51,51,51,48,34,33,6,96,129,4,65,0,0,9,113,51,58,58,51, +115,3,49,65,51,0,65,96,85,85,9,49,33,34,35,34,35,49,51,18,34,38,102,102,0,0,7, +49,36,34,33,35,18,113,115,43,50,22,23,119,114,32,7,49,33,1,34,51,49,39,23,114, +51,22,18,34,36,16,7,19,34,64,66,34,51,19,35,51,50,6,102,17,22,96,80,115,35,11, +176,34,49,19,45,194,35,51,116,100,70,16,85,3,55,10,164,18,18,61,17,18,18,50,55, +97,22,16,80,1,121,10,170,65,35,18,34,34,33,34,35,96,0,0,3,68,121,64,0,1,18,34, +32,68,18,34,34,6,5,85,1,68,119,64,0,1,17,18,32,68,18,34,34,6,5,85,80,1,55,10, +170,65,34,65,34,34,33,34,33,96,0,0,85,3,51,10,164,35,34,52,17,18,17,34,36,103, +114,32,80,115,35,11,176,51,49,19,20,65,18,34,68,98,36,16,9,19,34,64,67,51,119, +19,35,50,33,70,6,17,22,96,7,49,33,1,51,51,113,35,19,52,34,16,100,68,70,16,3,49, +36,34,50,39,18,49,35,65,17,70,65,17,22,16,3,49,33,51,51,35,35,16,18,75,68,102, +102,102,0,0,3,33,35,51,51,51,49,1,17,68,70,0,98,96,85,85,1,68,18,58,58,49,208, +17,68,6,96,129,2,34,0,0,3,34,65,35,50,0,65,20,96,17,22,24,1,18,36,32,80,50,36, +29,4,18,17,70,97,135,129,0,17,17,20,16,85,2,36,34,34,33,20,230,97,114,113,100, +68,17,22,16,85,80,4,193,17,204,68,104,1,135,129,4,68,68,70,16,85,85,80,0,68,68, +70,1,128,17,16,80,0,4,70,16,85,85,85,85,0,0,0,80,5,0,5,85,85,80,0,0 +, // 11, ender walking +0,3,4,5,175,2,1,6,52,93,7,92,50,74,73,0,68,68,68,68,64,0,0,4,0,64,0,68,68,0,0,4, +68,68,68,0,10,170,114,80,136,97,17,4,0,167,34,4,68,68,0,39,119,119,119,21,86,24, +120,16,119,50,81,4,68,0,167,35,51,51,51,49,102,23,39,22,33,17,97,4,64,42,114,18, +85,1,34,51,22,24,120,22,1,85,97,4,64,167,37,87,114,32,81,34,49,1,17,97,128,85, +97,4,2,21,85,51,51,51,53,18,34,16,102,8,16,81,0,4,10,119,19,51,147,147,115,1,49, +85,18,0,1,96,68,68,10,115,18,34,34,50,35,50,35,33,34,22,102,96,68,68,7,115,18, +81,34,18,49,55,19,50,178,22,23,114,0,0,7,115,18,16,18,35,50,23,23,115,35,22,18, +39,114,32,3,17,50,53,5,34,51,35,35,51,50,6,102,18,37,16,64,115,34,48,187,2,49, +19,45,194,35,51,117,101,22,96,64,50,39,112,153,177,18,49,209,17,33,35,55,97,86, +16,68,0,39,160,153,149,35,17,34,34,34,18,51,96,22,16,64,53,87,165,0,0,17,34,33, +5,82,34,35,6,0,0,64,21,87,165,0,0,17,18,33,5,82,34,34,6,4,68,68,0,39,112,153, +149,34,81,34,34,34,18,33,96,0,4,68,7,51,48,153,178,34,53,17,17,33,18,21,103,34, +4,64,115,35,48,187,3,49,19,21,81,18,17,85,98,81,4,10,17,34,37,5,51,55,19,34,51, +33,86,6,17,102,4,7,50,18,16,19,51,113,35,19,50,81,80,101,85,97,4,7,50,18,82,35, +39,18,49,83,37,21,86,81,17,97,4,3,50,18,35,51,50,35,16,18,37,181,102,102,96,0,4, +2,34,19,51,51,51,49,101,17,85,86,0,2,34,102,96,1,21,81,51,147,145,214,81,85,80, +102,1,128,18,37,32,64,50,37,19,50,37,1,21,86,1,17,104,16,17,21,16,64,51,33,93, +80,82,17,86,96,24,120,22,1,17,22,16,68,0,33,82,34,33,21,230,96,23,39,22,85,85, +86,16,68,68,0,92,17,204,85,96,16,24,120,16,85,85,86,16,68,68,68,0,5,85,86,0,136, +1,17,4,0,0,0,0,68,68,68,68,64,0,0,68,0,64,0,68,68,68,68,68 +, // 12, ender attacking +0,4,5,175,3,26,28,191,6,29,2,1,30,7,105,27,51,51,51,51,48,0,0,3,0,48,112,51,51, +48,0,0,51,51,51,0,13,221,137,80,153,231,119,115,0,13,129,16,51,51,0,24,136,136, +136,101,94,119,221,119,136,130,26,64,51,0,216,18,204,204,204,198,119,125,221, +119,118,244,75,64,48,29,129,73,85,6,153,204,103,119,215,126,6,250,171,64,48,216, +26,168,137,144,86,153,198,7,119,118,144,90,171,64,1,74,170,34,34,34,37,105,153, +96,119,9,96,84,0,0,13,136,66,34,82,82,130,6,198,85,121,0,6,176,51,51,13,130,65, +17,17,33,18,41,156,150,153,110,187,187,0,0,8,130,65,164,17,65,36,40,108,201,89, +110,104,136,129,16,8,130,65,64,65,18,33,72,248,140,156,110,105,145,26,64,2,68, +33,42,170,17,34,18,18,34,41,14,235,255,75,176,48,130,17,42,85,1,36,66,26,81,18, +34,133,181,171,64,48,33,17,40,5,84,65,36,164,68,20,18,40,180,75,64,51,0,17,141, +5,90,18,68,17,17,17,65,34,176,0,0,48,42,161,141,0,0,68,17,20,10,161,17,18,11,3, +51,48,74,161,136,0,0,68,65,20,10,161,17,17,11,3,51,51,0,18,40,5,90,17,95,145,17, +17,65,20,176,0,0,51,8,34,33,5,81,17,37,255,255,31,65,74,184,129,16,48,130,18,42, +85,2,47,242,101,95,249,255,85,177,26,64,13,68,17,26,10,34,40,108,153,34,150,91, +11,244,75,176,8,33,65,64,66,34,134,156,108,201,86,80,181,170,171,64,8,33,65,161, +18,152,105,198,92,149,101,94,95,68,75,64,2,33,65,18,34,41,156,96,105,149,85,238, +235,187,0,0,1,17,66,34,34,44,198,229,102,85,126,0,9,176,51,51,4,74,164,34,82, +166,254,86,85,80,119,6,144,145,0,0,48,33,26,66,41,149,6,101,94,119,119,121,96, +97,26,16,48,34,20,95,80,89,102,94,224,119,215,126,6,111,74,64,51,0,20,89,153, +150,101,238,231,125,221,119,117,111,75,64,51,51,0,95,102,255,85,224,96,119,215, +112,85,90,171,64,51,51,51,0,5,85,94,0,153,7,119,3,0,10,171,64,51,51,51,51,48,0, +0,51,0,48,112,51,51,48,0,0 +, // 13, turret idle +175,0,131,26,41,168,37,6,91,7,48,93,90,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,16,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,25,145,0,0,0,0,0,0,0,0,17,0,0,0,0,17,151,98,16,0,0,0,0,0,0,1,130,16,0,0, +1,35,184,130,81,16,0,0,0,0,0,1,40,16,0,0,1,34,123,178,85,65,0,0,0,0,0,23,49,0,0, +0,25,98,187,98,81,16,0,0,0,0,0,23,65,0,0,0,25,98,118,98,16,0,0,0,0,0,1,115,16,0, +17,17,71,98,118,98,81,16,0,0,0,1,20,116,16,0,0,0,22,35,114,36,85,65,0,0,1,25, +103,53,16,0,0,1,50,52,98,36,81,16,0,0,25,151,39,69,161,0,0,25,51,68,98,36,16,0, +0,0,25,118,100,84,161,0,1,151,54,35,184,36,16,0,0,1,151,98,35,52,85,17,23,102, +70,35,104,132,81,16,0,1,151,98,35,52,85,162,50,34,70,35,104,132,85,65,0,1,118, +34,51,68,85,17,19,51,70,35,104,132,81,16,0,1,118,35,51,68,81,0,1,67,70,35,184, +36,16,0,0,1,102,35,52,69,81,0,0,20,66,53,98,36,16,0,0,1,115,51,68,81,16,0,0,1, +67,165,98,36,81,16,0,1,114,51,69,16,0,0,0,0,20,85,98,36,85,65,0,27,98,35,65,0,0, +1,17,17,18,58,35,58,81,16,0,27,34,35,16,0,0,23,98,51,18,58,35,58,16,0,1,123,130, +52,16,0,0,22,34,68,18,58,140,58,81,16,23,98,184,129,0,0,0,1,35,65,1,90,44,202, +85,65,25,34,35,193,0,0,0,1,20,81,1,85,140,202,81,16,22,34,52,65,0,0,0,17,1,16,0, +17,35,58,16,0,1,35,68,16,0,0,0,16,0,0,0,0,19,49,0,0,0,17,17,0,0,0,0,0,0,0,0,0,1, +16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0 +, // 14 turret walk +175,0,131,26,41,37,168,6,91,7,48,93,90,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,153,16,0,0,0,0,0,0,0,0,0,0,0,0,1,25,117,33,0,0,0,0,0,0,0,0,1,16,0,0, +18,59,136,33,0,0,0,0,0,0,0,0,24,33,0,0,18,39,187,38,16,0,0,0,0,0,0,0,18,129,0,1, +149,43,181,38,65,0,0,0,0,0,0,1,115,16,0,1,149,39,85,38,16,0,0,0,0,0,0,25,33,0,1, +20,117,39,85,33,0,0,0,0,0,1,17,114,49,0,16,1,82,55,34,70,16,0,0,0,1,25,87,51,16, +0,0,19,35,69,34,65,0,0,0,0,25,151,39,70,16,0,1,147,52,69,34,65,0,0,0,0,25,117, +84,100,161,0,25,115,82,59,130,70,16,0,0,1,151,82,35,52,161,17,117,83,82,53,136, +70,65,0,0,1,151,82,35,52,102,35,34,35,82,53,136,70,16,0,0,1,117,34,51,68,102,17, +51,52,82,53,136,65,0,0,0,1,117,34,51,68,102,0,20,52,82,59,130,65,0,0,0,23,85,35, +52,70,97,0,1,68,35,101,34,65,0,0,0,23,82,51,68,102,96,0,0,20,58,101,34,70,16,0, +1,181,34,52,65,16,0,17,16,1,70,101,34,65,0,0,23,178,34,52,16,0,1,119,81,17,35, +162,51,161,0,1,117,40,35,65,0,0,1,82,35,49,35,162,51,166,16,1,146,43,136,65,0,0, +17,34,52,17,35,168,195,166,65,1,82,34,60,16,0,0,1,51,65,0,22,162,204,166,16,1, +34,51,68,16,0,0,0,17,16,0,22,104,204,161,0,0,17,52,65,0,0,0,0,0,0,0,1,18,51,161, +0,0,0,17,16,0,0,0,0,0,0,0,0,1,51,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0 +, // 15 turret attack +175,0,131,41,26,1,168,191,7,48,81,6,37,21,35,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1,136,16,0,0,0,0,0,0,0,0,0,0,0,0,1,24,188,33,0,0,0,0,0,0,0,0,0,0,0,0, +18,77,170,38,16,0,0,0,0,0,0,0,0,0,0,0,18,43,212,38,49,0,0,0,0,0,0,0,0,0,0,1,140, +45,220,38,16,0,0,0,0,0,0,0,0,0,0,1,140,43,220,33,0,0,0,0,0,0,0,0,0,1,17,19,188, +43,220,38,16,0,0,0,0,80,85,0,0,0,0,1,194,75,226,54,49,0,0,0,85,135,188,165,0,0, +0,148,36,61,226,54,16,0,0,90,136,183,15,254,80,0,9,132,67,61,226,49,0,0,0,168, +139,119,112,238,80,0,24,180,194,77,162,49,0,0,1,187,183,120,135,116,161,21,189, +211,194,77,170,54,16,0,1,192,119,120,135,119,9,173,204,195,194,77,170,54,49,0,1, +204,192,119,119,106,169,21,221,211,194,77,170,54,16,0,0,175,255,247,122,170,80, +0,94,211,194,77,162,49,0,0,0,90,255,231,68,170,80,0,5,227,36,109,226,49,0,0,0,0, +85,224,74,85,0,0,0,83,73,109,226,54,16,0,0,0,0,85,85,0,0,0,0,1,54,109,226,54,49, +0,0,0,0,0,0,0,0,68,68,65,36,158,68,150,16,0,0,0,0,0,0,0,4,141,221,225,36,158,68, +145,0,0,0,0,0,0,0,0,4,221,35,49,36,154,164,150,16,0,0,0,0,0,0,0,0,18,67,16,22, +158,170,150,49,0,0,0,0,0,0,0,0,17,54,16,22,106,170,150,16,0,0,0,0,0,0,0,1,16,17, +0,1,30,68,145,0,0,0,0,0,0,0,0,1,0,0,0,0,1,68,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0 +, // 16 exploder walk +175,168,1,2,3,102,4,5,23,174,99,191,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,1,16,0,0, +0,0,89,0,0,0,0,0,0,0,0,68,65,177,0,0,5,85,89,0,0,0,0,0,0,0,4,34,33,177,0,0,19, +187,144,0,0,0,0,0,0,0,1,32,1,131,16,1,198,57,0,0,0,0,0,0,0,0,23,97,1,138,16,28, +116,16,0,0,0,0,0,0,17,17,34,34,17,138,17,17,65,0,0,0,0,0,0,0,22,50,51,51,50,134, +19,49,16,1,17,0,0,0,0,0,23,66,51,34,184,134,33,49,1,23,199,21,153,0,0,0,23,66, +34,184,133,85,50,17,28,199,103,99,85,80,0,0,23,66,136,138,18,85,106,50,199,119, +100,99,85,153,0,0,23,66,136,85,171,166,102,34,39,102,51,36,181,89,144,0,23,34, +34,165,90,21,130,33,36,35,55,103,75,89,0,1,18,187,136,136,81,168,36,116,18,119, +118,70,59,185,144,24,139,85,85,102,98,88,39,71,18,102,102,68,59,187,153,1,18,51, +170,170,97,168,36,116,18,68,68,68,59,185,144,0,19,34,34,58,106,21,130,33,39,34, +51,68,75,89,0,0,23,50,35,35,171,166,163,34,54,103,51,36,85,153,0,0,23,66,42,51, +18,102,163,34,52,70,102,115,89,144,0,0,23,66,34,163,51,86,50,17,19,52,68,97,89, +0,0,0,23,66,50,34,58,90,33,49,1,19,51,16,0,0,0,0,22,50,51,51,34,90,19,49,16,1, +17,0,0,0,0,0,17,17,34,34,17,138,17,17,193,0,0,0,0,0,0,0,0,0,20,65,1,131,16,20, +124,16,0,0,0,0,0,0,0,0,1,32,1,131,16,1,70,57,0,0,0,0,0,0,0,0,1,18,33,129,0,0,19, +187,144,0,0,0,0,0,0,0,0,17,17,129,0,0,5,155,153,0,0,0,0,0,0,0,0,0,1,16,0,0,0,5, +80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +, // 17 universal dying sprite +175,0,223,1,3,4,5,2,6,73,135,79,26,159,131,37,0,0,0,0,0,0,0,0,0,0,0,51,0,0,0,0, +0,0,0,0,0,2,0,0,0,34,32,51,0,0,0,0,0,0,0,0,0,2,32,0,2,163,34,0,0,0,0,0,0,0,0,0, +0,0,0,0,42,3,50,33,16,0,0,0,0,0,0,0,0,0,1,16,32,0,2,22,97,16,0,0,0,0,0,0,0,1,24, +129,16,0,1,119,85,81,0,0,0,0,0,0,0,24,134,134,1,16,1,68,119,84,16,0,0,0,0,0,0, +24,102,136,102,81,0,20,68,116,16,0,0,0,0,0,1,102,102,104,134,65,2,20,68,151,113, +0,0,0,0,0,1,101,86,102,101,48,2,1,68,73,113,0,0,0,0,0,1,101,85,102,100,48,35,52, +17,73,16,0,0,0,0,0,1,85,85,85,71,51,37,84,48,17,0,0,0,0,0,0,1,84,80,80,71,50,34, +36,48,0,0,0,0,0,0,0,0,20,68,68,115,34,85,34,35,0,51,0,0,0,0,0,0,1,68,19,50,42, +51,85,34,3,48,0,0,0,0,0,0,0,17,34,34,163,101,51,67,32,0,0,0,0,0,0,0,0,2,42,68, +83,67,85,49,0,0,0,0,0,0,0,0,2,34,0,53,51,53,51,84,16,0,0,0,0,0,0,0,0,32,0,1,187, +211,115,21,16,0,0,0,0,0,0,0,2,32,0,27,189,211,48,23,16,0,0,0,0,0,0,0,2,0,0,27, +221,209,1,97,0,0,0,0,0,0,0,0,0,0,1,155,221,65,1,112,1,17,16,0,0,0,0,0,0,0,22, +153,145,17,22,49,22,117,16,0,0,0,0,0,0,1,101,84,113,0,23,54,102,53,16,0,0,0,0,0, +0,33,85,84,121,16,1,85,68,55,81,0,0,0,0,0,2,33,68,73,17,193,1,68,71,115,65,0,0, +0,0,0,34,42,153,145,1,195,16,23,119,115,65,0,0,0,0,0,32,2,170,34,31,236,49,23, +116,17,17,0,0,0,0,0,0,0,34,2,24,238,193,1,17,0,0,0,0,0,0,0,0,0,32,0,24,254,193, +0,35,48,0,0,0,0,0,0,0,0,0,0,1,17,16,2,32,48,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,0,0 +, // 18 universal dead/corpse sprite +175,0,3,4,1,5,6,2,157,18,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,4,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,34,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,50,34,0,0,0,0,0,0,0,0,0,0,0,0,0,4,36,17,0,0,0,0,0,0,0,0,0,0,0,0,1,18,65, +49,0,0,0,0,0,0,0,0,0,0,1,17,34,34,19,51,0,0,0,0,0,0,0,0,0,1,22,98,34,34,33,20,0, +0,0,0,0,0,0,0,0,22,101,101,40,130,36,68,0,0,0,0,0,0,0,0,0,22,85,102,85,136,129, +17,0,0,0,0,0,0,0,0,1,85,85,82,37,136,22,68,0,0,0,0,0,0,0,0,1,18,53,85,34,132,19, +36,0,0,0,0,0,0,0,0,0,2,34,85,84,33,100,66,0,0,0,0,0,0,0,0,1,35,51,51,39,22,102, +49,0,0,0,0,0,0,0,0,1,50,58,58,39,65,101,33,0,0,0,0,0,0,0,0,0,18,34,34,116,22,83, +17,0,0,0,0,0,0,0,0,0,1,34,20,68,17,50,20,0,0,0,0,0,0,0,0,0,0,17,4,68,34,20,52,0, +0,0,0,0,0,0,0,0,0,0,0,34,39,83,49,0,0,0,0,0,0,0,0,0,0,0,34,35,117,51,65,0,0,0,0, +0,0,0,0,0,0,0,0,19,115,51,52,0,0,0,0,0,0,0,0,0,0,0,0,19,55,163,153,0,0,0,0,0,0, +0,0,0,0,0,0,1,55,51,153,0,0,0,0,0,0,0,0,0,0,0,0,0,17,115,41,0,0,0,0,0,0,0,0,0,0, +0,0,17,53,36,65,0,0,0,0,0,0,0,0,0,0,0,0,21,33,17,18,0,0,0,0,0,0,0,0,0,0,0,0,1, +16,1,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,34,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,2,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0 +}; + +SFG_PROGRAM_MEMORY uint8_t SFG_logoImage[SFG_TEXTURE_STORE_SIZE] = +{ +175,224,0,7,4,5,162,77,2,74,70,69,6,11,68,75,0,0,0,0,0,0,17,17,17,17,17,0,0,0,0, +0,0,0,0,0,0,1,132,69,51,84,65,0,0,0,0,0,0,0,0,0,0,24,65,17,19,17,17,0,0,0,0,0,0, +0,0,0,0,24,65,0,19,16,0,0,0,0,0,0,0,0,0,0,0,24,65,17,19,17,17,0,0,0,0,0,0,0,0,0, +0,1,132,69,51,84,65,32,0,0,0,0,0,0,0,0,0,1,17,17,17,17,17,242,0,0,0,0,0,0,0,6, +97,243,94,40,51,84,66,159,32,0,0,0,0,0,17,17,24,60,190,40,50,34,34,155,146,0,0, +0,0,0,33,17,20,203,238,109,51,84,66,251,178,0,0,0,0,0,17,17,131,171,123,145,18, +34,38,122,187,32,0,0,0,0,6,97,92,170,167,113,115,35,81,122,171,32,0,0,0,0,2,22, +202,170,170,212,51,37,210,26,121,130,0,0,0,0,34,17,22,234,164,28,60,34,92,23, +218,56,32,0,0,2,33,17,102,110,113,69,210,35,51,93,51,66,50,0,0,34,34,40,126,246, +210,34,195,35,51,49,210,34,34,0,0,0,2,40,119,238,105,197,210,35,51,93,51,65,50, +0,0,0,2,38,87,119,166,156,60,34,92,223,218,161,32,0,0,2,34,38,87,119,170,20,51, +37,223,23,114,18,0,0,0,2,34,34,69,122,119,241,211,35,86,102,187,32,0,0,0,0,0,97, +213,119,187,97,134,45,17,246,105,32,0,0,0,0,34,33,22,247,238,29,51,53,65,155,98, +0,0,0,0,0,2,34,33,110,233,29,54,17,17,155,146,0,0,0,0,0,0,0,97,111,153,34,34,34, +29,159,32,0,0,0,0,0,0,0,0,41,150,40,51,84,65,146,0,0,0,0,0,0,0,0,0,2,38,40,56, +24,65,32,0,0,0,0,0,0,0,0,0,0,2,40,49,145,65,0,0,0,0,0,0,0,0,0,0,1,17,34,17,17, +17,0,0,0,0,0,0,0,0,0,0,1,132,69,51,84,65,0,0,0,0,0,0,0,0,0,0,1,17,24,56,17,17,0, +0,0,0,0,0,0,0,0,0,0,0,24,51,84,65,0,0,0,0,0,0,0,0,0,0,0,0,1,17,17,17,0,0,0,0,0 +}; + +uint8_t SFG_charToFontIndex(char c) +{ + if (c >= 'a' && c <= 'z') + return c - 'a'; + + if (c >= 'A' && c <= 'Z') + return c - 'A'; + + if (c >= '0' && c <= '9') + return c - '0' + 31; + + switch (c) + { + case ' ': return 26; break; + case '.': return 27; break; + case ',': return 28; break; + case '!': return 29; break; + case '/': return 41; break; + case '-': return 42; break; + case '+': return 43; break; + case '(': return 44; break; + case ')': return 45; break; + case '%': return 46; break; + default: return 30; break; // "?" + } +} + +#define SFG_FONT_CHARACTER_SIZE 4 + +/** + 4x4 font, each character stored as 16 bits. +*/ +SFG_PROGRAM_MEMORY uint16_t SFG_font[47] = +{ + 0xfaf0, // 0 "A" + 0xfd70, // 1 "B" + 0x6990, // 2 "C" + 0xf960, // 3 "D" + 0xfd90, // 4 "E" + 0xfa80, // 5 "F" + 0x69b0, // 6 "G" + 0xf4f0, // 7 "H" + 0x9f90, // 8 "I" + 0x31f0, // 9 "J" + 0xf4b0, // 10 "K" + 0xf110, // 11 "L" + 0xfc4f, // 12 "M" + 0xf42f, // 13 "N" + 0x6996, // 14 "O" + 0xfae0, // 15 "P" + 0x69b7, // 16 "Q" + 0xfad0, // 17 "R" + 0x5da0, // 18 "S" + 0x8f80, // 19 "T" + 0xf1f0, // 20 "U" + 0xe1e0, // 21 "V" + 0xf32f, // 22 "W" + 0x9690, // 23 "X" + 0xc7c0, // 24 "Y" + 0xbd90, // 25 "Z" + 0x0000, // 26 " " + 0x0100, // 27 "." + 0x0300, // 28 "," + 0x0d00, // 29 "!" + 0x48b4, // 30 "?" + 0xf9f0, // 31 "0" + 0x9f10, // 32 "1" + 0xbdd0, // 33 "2" + 0x9da0, // 34 "3" + 0xe2f0, // 35 "4" + 0xdbb0, // 36 "5" + 0xfbb0, // 37 "6" + 0x8bc0, // 38 "7" + 0xfdf0, // 39 "8" + 0xddf0, // 40 "9" + 0x1680, // 41 "/" + 0x2220, // 42 "-" + 0x2720, // 43 "+" + 0x0690, // 44 "(" + 0x0960, // 45 ")" + 0x9249 // 46 "%" +}; + +#endif // guard diff --git a/main_gbmeta/levels.h b/main_gbmeta/levels.h new file mode 100644 index 0000000..d2868f1 --- /dev/null +++ b/main_gbmeta/levels.h @@ -0,0 +1,1809 @@ +/** + @file levels.h + + This file contains game levels and related code. + + by Miloslav Ciz (drummyfish), 2019 + + Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) + plus a waiver of all other intellectual property. The goal of this work is + be and remain completely in the public domain forever, available for any use + whatsoever. +*/ + +#ifndef _SFG_LEVELS_H +#define _SFG_LEVELS_H + +#define SFG_MAP_SIZE 64 +#define SFG_TILE_DICTIONARY_SIZE 64 + +typedef uint16_t SFG_TileDefinition; +/**< + Defines a single game map tile. The format is following: + + MSB aaabbbbb cccddddd LSB + + aaa: ceiling texture index (from texture available on the map), 111 + means completely transparent texture + bbbbb: ceiling height (1111 meaning no ceiling) ABOVE the floor + ccc: floor texture index, 111 means completely transparent texture + ddddd: floor height +*/ + +#define SFG_TILE_CEILING_MAX_HEIGHT 31 +#define SFG_TILE_TEXTURE_TRANSPARENT 7 + +typedef SFG_TileDefinition SFG_TileDictionary[SFG_TILE_DICTIONARY_SIZE]; + +/// helper macros for SFG_TileDefinition +#define SFG_TD(floorH, ceilH, floorT, ceilT)\ + ((floorH & 0x001f) |\ + ((floorT & 0x0007) << 5) |\ + ((ceilH & 0x001f) << 8) |\ + ((ceilT & 0x0007) << 13)) + +#define SFG_TILE_FLOOR_HEIGHT(tile) (tile & 0x1f) +#define SFG_TILE_FLOOR_TEXTURE(tile) ((tile & 0xe0) >> 5) +#define SFG_TILE_CEILING_HEIGHT(tile) ((tile & 0x1f00) >> 8) +#define SFG_TILE_CEILING_TEXTURE(tile) ((tile & 0xe000) >> 13) + +#define SFG_OUTSIDE_TILE SFG_TD(63,0,7,7) + +/** + Game map represented as a 2D array. Array item has this format: + + MSB aabbbbbb LSB + + aa: type of square, possible values: + 00: normal + 01: moving floor (elevator), moves from floor height to ceililing height + (there is no ceiling above) + 10: moving ceiling, moves from ceiling height to floor height + 11: door + bbbbbb: index into tile dictionary +*/ +typedef uint8_t SFG_MapArray[SFG_MAP_SIZE * SFG_MAP_SIZE]; + +#define SFG_TILE_PROPERTY_MASK 0xc0 +#define SFG_TILE_PROPERTY_NORMAL 0x00 +#define SFG_TILE_PROPERTY_ELEVATOR 0x40 +#define SFG_TILE_PROPERTY_SQUEEZER 0x80 +#define SFG_TILE_PROPERTY_DOOR 0xc0 + +/** + Serves to place elements (items, enemies etc.) into the game level. +*/ +typedef struct +{ + uint8_t type; + uint8_t coords[2]; +} SFG_LevelElement; + +#define SFG_MAX_LEVEL_ELEMENTS 128 + +/* + Definitions of level element type. These values must leave the highest bit + unused because that will be used by the game engine, so the values must be + lower than 128. +*/ +#define SFG_LEVEL_ELEMENT_NONE 0 +#define SFG_LEVEL_ELEMENT_BARREL 0x01 +#define SFG_LEVEL_ELEMENT_HEALTH 0x02 +#define SFG_LEVEL_ELEMENT_BULLETS 0x03 +#define SFG_LEVEL_ELEMENT_ROCKETS 0x04 +#define SFG_LEVEL_ELEMENT_PLASMA 0x05 +#define SFG_LEVEL_ELEMENT_TREE 0x06 +#define SFG_LEVEL_ELEMENT_FINISH 0x07 +#define SFG_LEVEL_ELEMENT_TELEPORTER 0x08 +#define SFG_LEVEL_ELEMENT_TERMINAL 0x09 +#define SFG_LEVEL_ELEMENT_COLUMN 0x0a +#define SFG_LEVEL_ELEMENT_RUIN 0x0b +#define SFG_LEVEL_ELEMENT_LAMP 0x0c +#define SFG_LEVEL_ELEMENT_CARD0 0x0d ///< Access card, unlocks doors with lock. +#define SFG_LEVEL_ELEMENT_CARD1 0x0e +#define SFG_LEVEL_ELEMENT_CARD2 0x0f +#define SFG_LEVEL_ELEMENT_LOCK0 0x10 /**< Special level element that must be + placed on a tile with door. This door is + then unlocked by taking the corresponding + access card. */ +#define SFG_LEVEL_ELEMENT_LOCK1 0x11 +#define SFG_LEVEL_ELEMENT_LOCK2 0x12 +#define SFG_LEVEL_ELEMENT_BLOCKER 0x13 ///< Invisible wall. + +#define SFG_LEVEL_ELEMENT_MONSTER_SPIDER 0x20 +#define SFG_LEVEL_ELEMENT_MONSTER_DESTROYER 0x21 +#define SFG_LEVEL_ELEMENT_MONSTER_WARRIOR 0x22 +#define SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT 0x23 +#define SFG_LEVEL_ELEMENT_MONSTER_ENDER 0x24 +#define SFG_LEVEL_ELEMENT_MONSTER_TURRET 0x25 +#define SFG_LEVEL_ELEMENT_MONSTER_EXPLODER 0x26 + +#define SFG_MONSTERS_TOTAL 7 + +#define SFG_MONSTER_TYPE_TO_INDEX(monsterType) \ + ((monsterType) - SFG_LEVEL_ELEMENT_MONSTER_SPIDER) + +#define SFG_MONSTER_INDEX_TO_TYPE(monsterIndex) \ + ((monsterIndex) + SFG_LEVEL_ELEMENT_MONSTER_SPIDER) + +#define SFG_LEVEL_ELEMENT_TYPE_IS_MOSTER(t) \ + ((t) >= SFG_LEVEL_ELEMENT_MONSTER_SPIDER) + +typedef struct +{ + SFG_MapArray mapArray; + SFG_TileDictionary tileDictionary; + uint8_t textureIndices[7]; /**< Says which textures are used on the map. There + can be at most 7 because of 3bit indexing (one + value is reserved for special transparent + texture). */ + uint8_t doorTextureIndex; /**< Index (global, NOT from textureIndices) of a + texture used for door. */ + uint8_t floorColor; + uint8_t ceilingColor; + uint8_t playerStart[3]; /**< Player starting location: square X, square Y, + direction (fourths of RCL_Unit). */ + uint8_t backgroundImage; /** Index of level background image. */ + SFG_LevelElement elements[SFG_MAX_LEVEL_ELEMENTS]; +} SFG_Level; + +static inline SFG_TileDefinition SFG_getMapTile +( + const SFG_Level *level, + int16_t x, + int16_t y, + uint8_t *properties +) +{ + if (x >= 0 && x < SFG_MAP_SIZE && y >= 0 && y < SFG_MAP_SIZE) + { + uint8_t tile = level->mapArray[y * SFG_MAP_SIZE + x]; + + *properties = tile & 0xc0; + return level->tileDictionary[tile & 0x3f]; + } + + *properties = SFG_TILE_PROPERTY_NORMAL; + return SFG_OUTSIDE_TILE; +} + +#define SFG_NUMBER_OF_LEVELS 10 + +/* + NOTE: Initially the levels were stored sequentially in one big array, but that + caused some issues with Arduino's PROGMEM, so now we store each level in a + separate variable and eventually create an array of pointers to these. +*/ + +SFG_PROGRAM_MEMORY SFG_Level SFG_level0 = + #include "/home/tastyfish/git/anarch/assets/tmp.txt" + ; + +SFG_PROGRAM_MEMORY SFG_Level SFG_level1 = + { // level + { // mapArray + #define o 0 + #define AA (21 | SFG_TILE_PROPERTY_DOOR) + #define BB (23 | SFG_TILE_PROPERTY_ELEVATOR) + #define CC (3 | SFG_TILE_PROPERTY_SQUEEZER) + #define DD (31 | SFG_TILE_PROPERTY_ELEVATOR) + #define EE (1 | SFG_TILE_PROPERTY_DOOR) + #define FF (22 | SFG_TILE_PROPERTY_DOOR) + #define GG (50 | SFG_TILE_PROPERTY_ELEVATOR) + #define HH (49 | SFG_TILE_PROPERTY_ELEVATOR) + #define II (48 | SFG_TILE_PROPERTY_ELEVATOR) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +/*0 */ 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,6 ,7 ,7 ,7 ,7 ,6 ,7 ,7 ,7 ,7 ,6 ,6 ,6 ,6 ,6 ,7 ,7 ,6 ,6 ,6 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,12,6 ,6 ,6 ,12,6 ,6 ,6 ,12,6 ,6 ,6 ,12,6 ,6 ,6 ,12,6 ,6 , /*0 */ +/*1 */ 4 ,4 ,4 ,4 ,5 ,5 ,5 ,4 ,4 ,4 ,4 ,4 ,6 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,21,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,7 ,9 ,9 ,9 ,9 ,6 ,5 ,5 ,5 ,5 ,5 ,21,6 ,5 ,5 ,5 ,57,57,5 ,5 ,5 ,13,16,16,16,16,16,16,16,16,16,16,6 , /*1 */ +/*2 */ 4 ,4 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,4 ,4 ,4 ,6 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,21,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,7 ,9 ,9 ,9 ,9 ,6 ,28,28,28,5 ,5 ,21,4 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,16,16,16,16,16,16,16,16,16,16,16,15, /*2 */ +/*3 */ 4 ,4 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,4 ,4 ,4 ,6 ,54,54,54,54,4 ,8 ,8 ,8 ,8 ,21,8 ,8 ,4 ,54,54,54,54,54,6 ,9 ,9 ,9 ,9 ,6 ,21,21,28,5 ,5 ,21,21,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,16,16,16,16,16,16,16,16,16,16,16,6 , /*3 */ +/*4 */ 4 ,5 ,5 ,5 ,9 ,9 ,9 ,5 ,5 ,5 ,4 ,4 ,4 ,8 ,8 ,8 ,8 ,54,8 ,8 ,8 ,8 ,21,8 ,8 ,54,8 ,8 ,8 ,8 ,8 ,6 ,6 ,6 ,6 ,6 ,6 ,21,21,28,5 ,5 ,21,39,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,13,16,16,16,16,16,16,16,16,16,16,6 , /*4 */ +/*5 */ 4 ,5 ,5 ,5 ,9 ,9 ,9 ,5 ,5 ,5 ,8 ,8 ,AA,8 ,8 ,8 ,8 ,54,8 ,8 ,8 ,8 ,21,8 ,8 ,54,8 ,8 ,8 ,8 ,8 ,6 ,16,16,16,16,16,21,21,28,5 ,5 ,21,13,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,6 , /*5 */ +/*6 */ 4 ,5 ,5 ,5 ,9 ,9 ,9 ,5 ,5 ,5 ,4 ,4 ,4 ,8 ,8 ,8 ,8 ,54,8 ,8 ,8 ,8 ,21,8 ,8 ,54,8 ,8 ,8 ,8 ,8 ,6 ,16,16,16,16,16,63,21,28,5 ,5 ,21,39,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,57,6 , /*6 */ +/*7 */ 9 ,4 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,4 ,4 ,4 ,6 ,8 ,8 ,8 ,8 ,4 ,21,21,21,21,21,AA,21,4 ,8 ,8 ,8 ,8 ,8 ,6 ,16,16,16,16,16,63,21,28,5 ,5 ,21,21,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,57,6 , /*7 */ +/*8 */ 9 ,4 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,4 ,4 ,4 ,6 ,8 ,8 ,21,21,4 ,54,54,54,54,54,54,54,4 ,21,21,21,BB,BB,27,16,16,16,16,16,21,21,28,5 ,5 ,21,39,5 ,5 ,5 ,5 ,5 ,5 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 , /*8 */ +/*9 */ 10,10,4 ,4 ,5 ,5 ,5 ,4 ,4 ,4 ,4 ,4 ,6 ,8 ,8 ,8 ,8 ,54,8 ,8 ,8 ,8 ,8 ,8 ,8 ,54,8 ,8 ,21,BB,BB,27,16,16,17,17,17,21,21,28,5 ,5 ,21,13,5 ,5 ,5 ,5 ,5 ,5 ,4 ,5 ,5 ,5 ,5 ,53,53,53,53,5 ,5 ,5 ,56,6 , /*9 */ +/*10*/ 10,10,10,9 ,4 ,3 ,4 ,4 ,4 ,4 ,4 ,4 ,6 ,8 ,8 ,8 ,8 ,54,8 ,8 ,8 ,8 ,8 ,8 ,8 ,54,8 ,8 ,21,BB,BB,27,16,16,18,18,18,21,21,28,5 ,5 ,21,21,5 ,5 ,5 ,5 ,5 ,5 ,20,5 ,5 ,5 ,5 ,53,53,53,53,5 ,5 ,5 ,57,6 , /*10*/ +/*11*/ 10,10,10,9 ,9 ,9 ,9 ,1 ,6 ,6 ,15,6 ,6 ,6 ,6 ,6 ,6 ,6 ,7 ,7 ,7 ,7 ,7 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,19,19,19,21,21,28,5 ,5 ,21,21,59,5 ,5 ,5 ,5 ,5 ,21,5 ,5 ,5 ,5 ,53,53,53,53,1 ,13,13,13,1 , /*11*/ +/*12*/ 10,10,10,9 ,9 ,9 ,9 ,1 ,12,16,16,16,16,16,16,12,5 ,56,28,28,28,28,28,60,58,58,5 ,5 ,5 ,5 ,5 ,5 ,21,21,20,20,20,21,21,28,5 ,5 ,21,21,5 ,5 ,59,5 ,5 ,5 ,21,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,1 ,o ,o ,o ,1 , /*12*/ +/*13*/ 9 ,11,9 ,9 ,9 ,9 ,11,1 ,6 ,16,16,16,16,16,16,16,5 ,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,21,28,28,28,28,28,28,28,28,28,4 ,21,21,21,21,20,20,20,21,1 ,1 ,1 ,1 ,2 ,4 ,1 ,1 ,4 ,3 ,3 ,4 ,1 , /*13*/ +/*14*/ 9 ,11,9 ,9 ,9 ,9 ,11,1 ,6 ,16,16,16,16,16,16,16,5 ,25,5 ,5 ,5 ,5 ,5 ,5 ,56,5 ,5 ,5 ,5 ,5 ,5 ,5 ,20,28,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,21,21,21,21,o ,CC,CC,CC,o ,21,1 ,4 ,o ,o ,o ,o ,o ,o ,14,14,o ,1 , /*14*/ +/*15*/ 9 ,11,11,11,9 ,9 ,9 ,1 ,12,16,16,16,16,16,16,12,5 ,25,5 ,5 ,5 ,5 ,5 ,59,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,20,28,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,21,21,21,21,21,28,28,28,21,21,1 ,3 ,o ,o ,o ,o ,o ,o ,14,14,o ,1 , /*15*/ +/*16*/ 10,10,11,11,9 ,9 ,9 ,1 ,6 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,25,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,20,28,5 ,5 ,5 ,5 ,5 ,5 ,5 ,60,29,5 ,5 ,21,21,53,53,53,21,21,1 ,3 ,o ,o ,o ,o ,o ,o ,14,14,o ,1 , /*16*/ +/*17*/ 10,10,9 ,9 ,9 ,9 ,9 ,1 ,6 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,21,28,5 ,5 ,5 ,5 ,5 ,5 ,5 ,60,29,5 ,5 ,53,53,53,53,53,53,53,1 ,3 ,o ,o ,o ,o ,o ,o ,14,14,o ,1 , /*17*/ +/*18*/ 10,10,9 ,9 ,9 ,9 ,9 ,1 ,6 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,58,58,5 ,5 ,5 ,5 ,21,4 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,29,5 ,5 ,53,53,53,53,53,53,53,1 ,3 ,o ,o ,o ,o ,o ,o ,14,14,o ,1 , /*18*/ +/*19*/ 10,9 ,9 ,9 ,9 ,9 ,9 ,4 ,21,21,20,20,21,6 ,6 ,58,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,59,5 ,6 ,6 ,21,21,21,21,21,24,24,24,24,24,24,24,24,5 ,21,5 ,5 ,53,53,53,53,53,53,53,1 ,3 ,o ,o ,o ,o ,13,o ,14,14,o ,1 , /*19*/ +/*20*/ 10,10,10,9 ,9 ,9 ,9 ,8 ,8 ,8 ,20,20,8 ,6 ,6 ,58,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,6 ,6 ,31,30,30,31,31,31,31,31,31,31,30,31,31,6 ,6 ,5 ,5 ,53,53,53,53,53,53,53,1 ,3 ,o ,o ,o ,o ,1 ,o ,14,14,o ,1 , /*20*/ +/*21*/ 9 ,10,10,9 ,9 ,9 ,9 ,8 ,8 ,8 ,20,20,8 ,6 ,6 ,5 ,5 ,59,5 ,5 ,5 ,5 ,5 ,5 ,5 ,56,6 ,6 ,31,31,31,31,31,31,31,31,31,31,30,31,31,6 ,DD,8 ,8 ,53,53,53,53,53,53,53,1 ,3 ,3 ,3 ,3 ,3 ,1 ,3 ,3 ,3 ,3 ,1 , /*21*/ +/*22*/ 11,11,9 ,9 ,9 ,9 ,9 ,4 ,8 ,8 ,20,20,8 ,6 ,6 ,58,58,5 ,5 ,5 ,5 ,5 ,5 ,56,5 ,59,6 ,6 ,31,30,30,30,31,31,31,31,31,31,30,31,31,6 ,31,8 ,8 ,53,53,53,53,53,53,53,1 ,o ,o ,o ,o ,3 ,1 ,o ,14,14,o ,1 , /*22*/ +/*23*/ 11,11,9 ,9 ,9 ,9 ,9 ,21,8 ,8 ,20,20,8 ,8 ,8 ,58,58,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,57,6 ,6 ,31,30,31,30,30,31,31,31,31,31,30,31,31,31,31,8 ,8 ,53,53,53,53,53,53,53,1 ,o ,o ,o ,o ,3 ,1 ,o ,14,14,o ,1 , /*23*/ +/*24*/ 9 ,10,10,10,9 ,9 ,9 ,21,8 ,8 ,20,20,8 ,8 ,8 ,62,58,5 ,5 ,5 ,5 ,57,61,5 ,61,57,6 ,6 ,31,30,31,31,30,30,30,30,30,30,30,31,31,6 ,6 ,6 ,6 ,1 ,1 ,1 ,1 ,EE,1 ,1 ,1 ,o ,o ,o ,o ,3 ,1 ,o ,14,14,o ,1 , /*24*/ +/*25*/ 9 ,10,10,10,9 ,9 ,9 ,21,8 ,5 ,5 ,5 ,8 ,6 ,6 ,57,61,56,5 ,5 ,5 ,57,5 ,5 ,56,58,6 ,6 ,31,30,31,31,31,31,31,31,31,31,31,31,31,6 ,58,o ,o ,o ,1 ,o ,o ,o ,o ,o ,61,o ,o ,o ,o ,3 ,1 ,1 ,19,19,1 ,1 , /*25*/ +/*26*/ 9 ,10,10,10,9 ,9 ,9 ,21,8 ,5 ,5 ,5 ,8 ,6 ,12,57,5 ,5 ,5 ,5 ,5 ,5 ,56,5 ,5 ,5 ,12,6 ,31,30,31,31,31,31,31,31,31,31,31,31,31,6 ,58,o ,o ,o ,2 ,o ,o ,o ,o ,o ,EE,o ,o ,o ,o ,3 ,1 ,1 ,18,18,1 ,1 , /*26*/ +/*27*/ 9 ,11,11,9 ,9 ,9 ,9 ,20,5 ,5 ,5 ,5 ,8 ,6 ,6 ,61,5 ,5 ,5 ,5 ,5 ,5 ,5 ,59,58,5 ,6 ,6 ,31,31,31,31,31,31,31,31,31,31,31,31,31,6 ,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,3 ,61,3 ,3 ,3 ,3 ,4 ,1 ,1 ,17,17,1 ,1 , /*27*/ +/*28*/ 9 ,11,11,9 ,9 ,9 ,9 ,21,8 ,8 ,8 ,8 ,8 ,21,6 ,58,5 ,5 ,5 ,5 ,5 ,5 ,5 ,56,5 ,5 ,6 ,6 ,31,30,31,31,31,31,31,31,31,31,31,31,31,6 ,58,o ,o ,o ,1 ,o ,o ,o ,o ,3 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,16,16,16,16,1 , /*28*/ +/*29*/ 1 ,1 ,1 ,1 ,1 ,1 ,20,20,20,20,20,20,20,21,6 ,58,5 ,5 ,5 ,5 ,5 ,5 ,5 ,58,5 ,56,6 ,6 ,31,30,31,30,30,30,30,30,30,30,31,31,31,6 ,58,o ,o ,o ,2 ,o ,o ,o ,o ,3 ,EE,5 ,5 ,5 ,5 ,5 ,1 ,16,16,16,16,1 , /*29*/ +/*30*/ 1 ,58,58,57,57,57,21,21,21,21,20,20,20,21,6 ,56,5 ,5 ,5 ,5 ,5 ,5 ,5 ,57,5 ,60,6 ,6 ,31,30,30,30,31,31,31,31,31,30,30,31,31,6 ,58,o ,o ,o ,1 ,o ,o ,o ,o ,3 ,1 ,o ,o ,o ,5 ,5 ,1 ,16,16,16,16,1 , /*30*/ +/*31*/ 1 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,1 ,21,20,20,20,21,6 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,59,5 ,6 ,6 ,31,31,31,31,31,31,31,31,31,31,30,31,31,6 ,58,o ,o ,1 ,1 ,o ,o ,o ,o ,3 ,1 ,o ,o ,o ,5 ,5 ,1 ,16,16,16,16,1 , /*31*/ +/*32*/ 1 ,5 ,58,58,5 ,1 ,5 ,57,57,21,20,20,20,21,21,21,21,21,20,20,20,20,21,4 ,7 ,7 ,6 ,6 ,31,31,31,31,31,31,31,31,31,31,30,31,31,6 ,58,o ,o ,o ,EE,o ,o ,o ,o ,3 ,EE,o ,o ,o ,5 ,5 ,1 ,16,16,16,16,1 , /*32*/ +/*33*/ 1 ,5 ,1 ,5 ,5 ,5 ,5 ,5 ,1 ,57,5 ,5 ,5 ,5 ,5 ,12,13,13,53,53,53,53,21,21,13,13,6 ,6 ,6 ,6 ,6 ,6 ,31,31,30,30,30,30,30,31,31,6 ,58,o ,o ,o ,1 ,o ,o ,o ,o ,3 ,1 ,5 ,5 ,5 ,5 ,5 ,1 ,16,16,16,16,1 , /*33*/ +/*34*/ 1 ,58,5 ,5 ,1 ,1 ,5 ,5 ,5 ,57,5 ,5 ,5 ,5 ,5 ,13,13,13,53,53,53,53,53,53,13,13,13,13,53,53,53,53,24,24,24,24,6 ,6 ,6 ,6 ,6 ,6 ,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,3 ,1 ,1 ,1 ,1 ,16,16,1 ,16,16,16,16,15, /*34*/ +/*35*/ 1 ,5 ,5 ,1 ,5 ,5 ,5 ,57,5 ,57,5 ,5 ,5 ,5 ,5 ,13,13,13,53,53,53,53,53,53,13,5 ,5 ,13,53,53,53,53,53,53,53,53,6 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,o ,o ,o ,o ,3 ,2 ,o ,o ,1 ,16,16,1 ,16,16,16,16,21, /*35*/ +/*36*/ 1 ,5 ,1 ,1 ,5 ,57,1 ,5 ,1 ,1 ,1 ,5 ,5 ,5 ,5 ,12,13,13,53,53,53,53,53,5 ,5 ,5 ,5 ,5 ,5 ,53,53,53,13,13,13,13,13,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,3 ,1 ,o ,o ,21,16,16,16,16,21,27,27,21, /*36*/ +/*37*/ 1 ,19,18,1 ,5 ,1 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,53,13,13,53,53,53,53,13,5 ,5 ,5 ,5 ,5 ,5 ,13,13,13,13,13,4 ,61,1 ,2 ,1 ,1 ,2 ,1 ,1 ,2 ,1 ,61,4 ,o ,o ,o ,o ,3 ,1 ,o ,o ,21,16,16,16,16,21,BB,BB,21, /*37*/ +/*38*/ 1 ,57,17,1 ,5 ,1 ,5 ,57,57,5 ,58,5 ,5 ,5 ,5 ,53,53,13,13,13,13,13,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,13,13,13,1 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,o ,3 ,4 ,o ,o ,21,21,21,21,21,21,8 ,8 ,21, /*38*/ +/*39*/ 1 ,16,16,1 ,5 ,5 ,5 ,58,5 ,5 ,58,5 ,5 ,5 ,5 ,12,53,53,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,59,57,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,1 ,o ,o ,1 ,o ,o ,21,7 ,7 ,54,54,4 , /*39*/ +/*40*/ 1 ,16,1 ,1 ,1 ,1 ,1 ,5 ,5 ,58,62,5 ,5 ,5 ,5 ,53,53,53,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,EE,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,1 ,1 ,1 ,1 ,o ,o ,21,7 ,8 ,8 ,54,21, /*40*/ +/*41*/ 1 ,16,1 ,16,16,16,16,1 ,5 ,5 ,62,5 ,5 ,5 ,5 ,53,53,53,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,EE,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,2 ,o ,o ,o ,o ,o ,21,7 ,8 ,8 ,54,21, /*41*/ +/*42*/ 1 ,16,16,16,16,16,1 ,1 ,58,5 ,62,59,5 ,5 ,5 ,12,53,53,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,59,57,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,1 ,o ,o ,o ,o ,o ,21,7 ,8 ,8 ,54,21, /*42*/ +/*43*/ 1 ,58,5 ,1 ,5 ,57,5 ,5 ,5 ,5 ,1 ,5 ,5 ,5 ,5 ,53,53,13,13,13,13,13,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,13,13,13,1 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,1 ,o ,o ,21,21,21,21,7 ,8 ,8 ,54,21, /*43*/ +/*44*/ 1 ,5 ,5 ,1 ,5 ,5 ,5 ,1 ,1 ,5 ,1 ,5 ,5 ,5 ,5 ,53,13,13,13,13,13,13,13,5 ,5 ,5 ,5 ,5 ,5 ,13,13,1 ,1 ,1 ,4 ,1 ,1 ,2 ,1 ,1 ,2 ,1 ,1 ,57,EE,57,1 ,1 ,1 ,EE,1 ,4 ,1 ,o ,o ,1 ,7 ,7 ,7 ,7 ,54,54,54,4 , /*44*/ +/*45*/ 1 ,5 ,5 ,5 ,57,1 ,1 ,5 ,58,5 ,1 ,5 ,56,5 ,5 ,12,13,13,13,13,13,13,13,13,5 ,5 ,5 ,5 ,13,13,13,1 ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,22,22,22,FF,22,22,22,1 ,o ,1 ,1 ,1 ,o ,o ,1 ,8 ,8 ,8 ,8 ,8 ,8 ,54,1 , /*45*/ +/*46*/ 1 ,5 ,57,5 ,5 ,5 ,1 ,5 ,5 ,5 ,58,21,21,21,21,21,21,21,21,21,13,13,13,13,13,5 ,5 ,13,13,53,53,1 ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,22,o ,o ,o ,o ,o ,22,1 ,o ,o ,o ,1 ,o ,o ,1 ,8 ,8 ,8 ,8 ,8 ,8 ,54,1 , /*46*/ +/*47*/ 1 ,58,57,1 ,1 ,5 ,58,58,1 ,1 ,58,21,5 ,5 ,5 ,5 ,56,5 ,5 ,21,13,13,13,13,13,5 ,5 ,13,13,53,53,EE,o ,o ,55,1 ,1 ,1 ,1 ,o ,o ,22,o ,o ,o ,o ,o ,22,1 ,o ,o ,o ,1 ,o ,o ,1 ,8 ,8 ,8 ,8 ,8 ,8 ,54,1 , /*47*/ +/*48*/ 6 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,20,5 ,5 ,5 ,5 ,5 ,5 ,5 ,20,53,53,53,EE,53,53,53,53,53,53,53,1 ,o ,o ,55,1 ,o ,o ,o ,o ,o ,22,o ,o ,o ,o ,o ,22,4 ,5 ,5 ,5 ,4 ,1 ,1 ,1 ,1 ,1 ,1 ,8 ,8 ,8 ,54,1 , /*48*/ +/*49*/ 7 ,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,20,5 ,5 ,5 ,5 ,5 ,5 ,5 ,20,53,53,53,1 ,53,53,53,53,53,53,53,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,22,o ,o ,o ,o ,o ,22,1 ,8 ,8 ,8 ,54,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,54,1 , /*49*/ +/*50*/ 7 ,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,20,5 ,5 ,5 ,5 ,5 ,5 ,5 ,21,13,13,13,13,13,13,13,13,53,53,53,1 ,1 ,22,22,22,22,22,22,22,22,4 ,o ,o ,o ,o ,o ,22,1 ,8 ,8 ,8 ,54,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,54,1 , /*50*/ +/*51*/ 6 ,5 ,5 ,57,58,5 ,1 ,1 ,58,58,58,21,59,5 ,5 ,5 ,5 ,5 ,5 ,21,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,28,28,28,1 ,4 ,GG,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,o ,o ,22,1 ,8 ,8 ,8 ,54,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,54,1 , /*51*/ +/*52*/ 6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,6 ,28,28,28,28,28,28,28,1 ,28,28,28,1 ,1 ,22,3 ,o ,o ,o ,o ,3 ,3 ,3 ,o ,o ,o ,o ,o ,22,1 ,8 ,8 ,8 ,54,54,54,54,54,54,54,54,54,54,54,4 , /*52*/ +/*53*/ 11,11,11,11,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,6 ,28,28,28,28,28,28,28,1 ,28,28,28,1 ,1 ,22,3 ,o ,o ,o ,o ,3 ,3 ,3 ,o ,o ,o ,o ,o ,22,1 ,8 ,8 ,1 ,4 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*53*/ +/*54*/ 11,11,11,11,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,6 ,28,28,28,28,28,28,28,1 ,28,28,28,1 ,4 ,HH,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,o ,o ,22,1 ,8 ,8 ,1 ,22,22,22,22,22,22,22,22,22,22,22,22, /*54*/ +/*55*/ 11,11,10,10,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,6 ,28,28,28,28,28,28,28,1 ,28,28,28,1 ,1 ,22,22,22,22,22,22,22,22,4 ,22,GG,HH,II,22,22,1 ,8 ,8 ,1 ,22,22,22,22,22,63,6 ,6 ,6 ,6 ,6 ,6 , /*55*/ +/*56*/ 6 ,10,10,10,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,6 ,o ,o ,o ,o ,1 ,26,26,1 ,28,28,28,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,63,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,1 ,22,5 ,5 ,56,5 ,5 ,5 ,56,6 ,6 ,6 ,6 , /*56*/ +/*57*/ 6 ,10,10,10,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,6 ,o ,o ,o ,o ,26,28,28,28,28,28,28,5 ,5 ,5 ,5 ,5 ,5 ,5 ,63,54,54,8 ,54,54,54,54,54,54,54,54,54,1 ,22,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,6 ,6 ,6 , /*57*/ +/*58*/ 6 ,6 ,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,6 ,o ,o ,o ,o ,26,28,28,28,28,28,28,5 ,5 ,5 ,5 ,5 ,5 ,5 ,1 ,28,28,28,28,28,28,28,28,28,28,12,12,12,22,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,4 ,6 ,6 , /*58*/ +/*59*/ 6 ,6 ,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,6 ,o ,o ,o ,o ,26,28,28,28,28,28,28,5 ,5 ,5 ,5 ,5 ,5 ,5 ,EE,28,28,28,28,28,28,28,28,28,28,28,FF,FF,FF,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,3 ,31,13, /*59*/ +/*60*/ 6 ,6 ,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,6 ,o ,o ,o ,o ,EE,28,28,28,28,28,28,5 ,5 ,5 ,5 ,5 ,5 ,5 ,1 ,28,28,28,28,28,28,28,28,28,28,12,12,12,22,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,4 ,6 ,6 , /*60*/ +/*61*/ 6 ,6 ,6 ,6 ,6 ,11,11,11,11,9 ,9 ,9 ,9 ,9 ,9 ,9 ,11,11,11,6 ,o ,o ,o ,o ,26,28,28,28,28,28,28,5 ,5 ,5 ,5 ,5 ,5 ,5 ,63,54,54,8 ,54,54,54,54,54,54,54,54,54,1 ,22,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,6 ,6 ,6 , /*61*/ +/*62*/ 9 ,9 ,9 ,9 ,9 ,11,11,11,11,10,10,10,10,10,10,10,11,11,11,6 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,1 ,1 ,2 ,1 ,1 ,1 ,1 ,1 ,26,26,26,1 ,63,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,1 ,22,5 ,5 ,5 ,5 ,5 ,5 ,59,6 ,6 ,6 ,6 , /*62*/ +/*63*/ 9 ,9 ,9 ,9 ,9 ,11,11,11,11,10,10,10,10,10,10,10,11,11,11,6 ,28,28,28,28,22,22,22,22,22,22,22,22,22,22,6 ,9 ,9 ,9 ,6 ,22,22,4 ,22,II,GG,HH,22,22,22,22,22,22,22,22,22,22,22,63,6 ,6 ,6 ,6 ,6 ,6 /*63*/ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + #undef AA + #undef BB + #undef CC + #undef DD + #undef EE + #undef FF + #undef GG + #undef HH + #undef II + #undef o + }, + { // tileDictionary + SFG_TD(14, 7,0,0),SFG_TD(18, 0,0,1),SFG_TD(18, 0,2,1),SFG_TD(14, 6,0,4), // 0 + SFG_TD(14, 0,4,4),SFG_TD(14,20,4,4),SFG_TD(29, 0,3,4),SFG_TD(27, 2,3,4), // 4 + SFG_TD(25, 6,4,4),SFG_TD(14,31,0,0),SFG_TD(26,31,1,0),SFG_TD(30,31,0,0), // 8 + SFG_TD(31, 0,2,2),SFG_TD(14, 0,6,6),SFG_TD(14, 8,0,0),SFG_TD(22, 0,2,3), // 12 + SFG_TD(18, 8,6,0),SFG_TD(17, 9,6,0),SFG_TD(16,10,6,0),SFG_TD(15,11,6,0), // 16 + SFG_TD(14, 7,3,3),SFG_TD(29, 0,3,3),SFG_TD(18, 0,5,2),SFG_TD(18, 7,4,0), // 20 + SFG_TD(14,20,3,4),SFG_TD(13,21,0,4),SFG_TD(16, 2,0,1),SFG_TD(18, 4,6,3), // 24 + SFG_TD(14,17,0,4),SFG_TD(18, 8,3,3),SFG_TD(13,21,0,0),SFG_TD( 4,30,0,0), // 28 + SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0), // 32 + SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0),SFG_TD(30, 0,3,6), // 36 + SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0), // 40 + SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0),SFG_TD(14, 8,0,0), // 44 + SFG_TD(29,17,5,5),SFG_TD(29,18,5,5),SFG_TD(29,19,5,5),SFG_TD(14, 8,0,0), // 48 + SFG_TD(14, 8,0,0),SFG_TD(14, 7,0,6),SFG_TD(25, 5,4,4),SFG_TD(16, 5,1,0), // 52 + SFG_TD(18,16,1,0),SFG_TD(22,12,1,0),SFG_TD(26, 8,0,0),SFG_TD(18,16,0,0), // 56 + SFG_TD(17,17,1,0),SFG_TD(21,13,0,0),SFG_TD(25, 9,1,0),SFG_TD(14, 0,5,5) // 60 + }, // tileDictionary + {0 ,4 ,7 ,5 ,11,15,3 }, // textureIndices + 7, // doorTextureIndex + 3, // floorColor + 18, // ceilingColor + {62, 2 , 144}, // player start: x, y, direction + 1, // backgroundImage + { // elements + {SFG_LEVEL_ELEMENT_BULLETS, {28,1}},{SFG_LEVEL_ELEMENT_BULLETS, {27,1}}, + {SFG_LEVEL_ELEMENT_BULLETS, {56,2}},{SFG_LEVEL_ELEMENT_HEALTH, {21,4}}, + {SFG_LEVEL_ELEMENT_LOCK1, {12,5}},{SFG_LEVEL_ELEMENT_CARD2, {10,5}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {5,7}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {45,8}}, + {SFG_LEVEL_ELEMENT_BARREL, {45,9}},{SFG_LEVEL_ELEMENT_RUIN, {40,9}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {20,9}},{SFG_LEVEL_ELEMENT_RUIN, {41,10}}, + {SFG_LEVEL_ELEMENT_RUIN, {39,10}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {20,10}}, + {SFG_LEVEL_ELEMENT_HEALTH, {3,10}},{SFG_LEVEL_ELEMENT_RUIN, {39,11}}, + {SFG_LEVEL_ELEMENT_HEALTH, {61,12}},{SFG_LEVEL_ELEMENT_BULLETS, {58,12}}, + {SFG_LEVEL_ELEMENT_BULLETS, {57,12}},{SFG_LEVEL_ELEMENT_HEALTH, {11,12}}, + {SFG_LEVEL_ELEMENT_BULLETS, {41,15}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {23,15}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {36,16}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {18,16}}, + {SFG_LEVEL_ELEMENT_BULLETS, {53,17}},{SFG_LEVEL_ELEMENT_BULLETS, {53,18}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {14,18}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {24,19}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {7,20}},{SFG_LEVEL_ELEMENT_BULLETS, {7,21}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {61,23}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {42,23}}, + {SFG_LEVEL_ELEMENT_BARREL, {23,23}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {61,26}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {37,26}},{SFG_LEVEL_ELEMENT_HEALTH, {43,28}}, + {SFG_LEVEL_ELEMENT_BULLETS, {16,28}},{SFG_LEVEL_ELEMENT_RUIN, {53,29}}, + {SFG_LEVEL_ELEMENT_BULLETS, {16,29}},{SFG_LEVEL_ELEMENT_HEALTH, {57,31}}, + {SFG_LEVEL_ELEMENT_RUIN, {44,31}},{SFG_LEVEL_ELEMENT_BULLETS, {43,32}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {43,39}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {41,39}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {26,40}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {41,41}}, + {SFG_LEVEL_ELEMENT_HEALTH, {36,45}},{SFG_LEVEL_ELEMENT_BULLETS, {35,45}}, + {SFG_LEVEL_ELEMENT_TREE, {32,45}},{SFG_LEVEL_ELEMENT_BULLETS, {7,45}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {37,46}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {43,47}}, + {SFG_LEVEL_ELEMENT_LOCK1, {23,48}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {44,50}}, + {SFG_LEVEL_ELEMENT_COLUMN, {29,50}},{SFG_LEVEL_ELEMENT_HEALTH, {39,52}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {34,52}},{SFG_LEVEL_ELEMENT_BULLETS, {39,53}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {34,53}},{SFG_LEVEL_ELEMENT_TELEPORTER, {46,54}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {35,54}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {9,54}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {25,55}},{SFG_LEVEL_ELEMENT_BARREL, {18,55}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {11,55}},{SFG_LEVEL_ELEMENT_TERMINAL, {57,56}}, + {SFG_LEVEL_ELEMENT_COLUMN, {23,56}},{SFG_LEVEL_ELEMENT_COLUMN, {20,56}}, + {SFG_LEVEL_ELEMENT_HEALTH, {4,56}},{SFG_LEVEL_ELEMENT_TREE, {37,57}}, + {SFG_LEVEL_ELEMENT_TREE, {32,57}},{SFG_LEVEL_ELEMENT_BULLETS, {20,58}}, + {SFG_LEVEL_ELEMENT_CARD1, {8,58}},{SFG_LEVEL_ELEMENT_FINISH, {62,59}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {58,59}},{SFG_LEVEL_ELEMENT_LOCK2, {52,59}}, + {SFG_LEVEL_ELEMENT_CARD0, {41,59}},{SFG_LEVEL_ELEMENT_LOCK0, {38,59}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {28,59}},{SFG_LEVEL_ELEMENT_BULLETS, {20,60}}, + {SFG_LEVEL_ELEMENT_TREE, {37,61}},{SFG_LEVEL_ELEMENT_TREE, {32,61}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {57,62}},{SFG_LEVEL_ELEMENT_ROCKETS, {49,62}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}} + }, // elements + } // level + ; + +SFG_PROGRAM_MEMORY SFG_Level SFG_level2 = + { // level + { // mapArray + #define o 0 + #define AA (20 | SFG_TILE_PROPERTY_DOOR) + #define BB (32 | SFG_TILE_PROPERTY_DOOR) + #define CC (22 | SFG_TILE_PROPERTY_ELEVATOR) + #define DD (40 | SFG_TILE_PROPERTY_SQUEEZER) + #define EE (44 | SFG_TILE_PROPERTY_DOOR) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +/*0 */ 23,23,23,23,23,23,23,23,23,20,4 ,4 ,4 ,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 , /*0 */ +/*1 */ 23,22,22,22,22,22,22,22,22,16,16,4 ,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,20,16,16,16,16,16,20,4 ,2 ,2 ,2 ,48,3 ,3 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,2 ,o ,o ,48,4 ,4 ,4 ,4 ,4 ,4 ,4 , /*1 */ +/*2 */ 23,22,22,22,22,22,22,22,22,o ,o ,3 ,o ,o ,18,18,18,18,18,18,18,o ,o ,46,o ,o ,o ,o ,o ,16,20,21,19,19,19,19,4 ,2 ,2 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,2 ,48,4 ,3 ,o ,5 ,5 ,3 ,4 ,4 ,4 ,4 ,4 ,4 ,4 , /*2 */ +/*3 */ 23,22,22,22,22,22,22,22,22,17,17,3 ,17,17,18,18,18,18,18,18,18,17,17,47,17,17,17,17,o ,16,AA,19,19,19,19,19,2 ,o ,o ,5 ,5 ,o ,o ,3 ,48,4 ,5 ,5 ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,6 ,7 ,6 ,4 ,4 ,4 , /*3 */ +/*4 */ 23,22,22,22,22,22,22,22,22,o ,3 ,o ,o ,o ,18,18,18,18,18,18,18,o ,o ,46,o ,o ,o ,17,o ,16,20,19,19,19,19,19,3 ,o ,o ,o ,o ,2 ,4 ,4 ,4 ,4 ,2 ,o ,3 ,3 ,4 ,o ,2 ,4 ,4 ,4 ,4 ,4 ,10,11,11,4 ,4 ,4 , /*4 */ +/*5 */ 23,22,22,22,22,22,22,22,22,16,4 ,4 ,16,16,16,16,16,16,16,16,16,16,16,16,16,16,o ,17,o ,16,20,16,16,16,16,16,20,20,20,20,20,20,20,20,20,4 ,4 ,4 ,4 ,4 ,4 ,8 ,4 ,4 ,4 ,4 ,9 ,9 ,10,4 ,11,12,4 ,4 , /*5 */ +/*6 */ 23,22,22,22,22,22,23,23,23,20,4 ,4 ,4 ,20,20,20,20,20,20,20,20,20,20,20,20,16,o ,17,o ,16,20,20,20,AA,20,20,20,19,19,19,19,19,19,19,20,4 ,4 ,4 ,4 ,4 ,9 ,9 ,4 ,4 ,4 ,4 ,9 ,4 ,4 ,4 ,4 ,12,4 ,4 , /*6 */ +/*7 */ 23,22,22,22,22,22,23,23,23,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,16,o ,17,o ,16,20,20,20,19,19,19,19,19,19,19,19,19,19,19,20,4 ,4 ,4 ,4 ,10,10,9 ,10,11,4 ,8 ,8 ,4 ,4 ,13,13,12,4 ,4 , /*7 */ +/*8 */ 23,22,22,22,22,22,23,23,23,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,4 ,3 ,18,18,18,16,20,20,20,20,20,20,20,20,20,24,24,29,29,29,20,4 ,4 ,4 ,11,11,4 ,4 ,4 ,12,12,8 ,4 ,4 ,13,13,4 ,4 ,4 ,4 , /*8 */ +/*9 */ 23,22,22,22,22,22,23,23,23,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,4 ,4 ,18,18,18,16,20,29,29,29,29,29,29,29,20,25,25,29,29,29,20,4 ,4 ,12,12,4 ,4 ,4 ,4 ,4 ,4 ,8 ,4 ,4 ,13,4 ,4 ,4 ,4 ,4 , /*9 */ +/*10*/ 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,20,20,20,4 ,3 ,18,18,18,3 ,20,29,29,29,29,29,29,29,20,26,26,29,20,29,20,4 ,4 ,12,12,4 ,4 ,15,9 ,9 ,8 ,8 ,13,13,13,13,15,4 ,4 ,4 , /*10*/ +/*11*/ 30,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,41,o ,o ,20,16,18,18,18,16,20,29,29,34,34,34,29,29,20,27,27,29,20,29,20,4 ,4 ,13,13,4 ,4 ,15,8 ,8 ,8 ,8 ,13,13,13,13,13,15,4 ,4 , /*11*/ +/*12*/ 30,40,41,41,41,41,41,40,40,40,40,40,41,41,41,41,41,41,40,40,40,41,o ,o ,20,16,18,18,18,16,20,29,29,34,34,34,29,29,20,28,28,29,20,29,20,4 ,4 ,13,13,13,4 ,13,8 ,8 ,8 ,8 ,13,13,4 ,13,13,13,4 ,4 , /*12*/ +/*13*/ 30,40,41,40,40,40,41,41,41,41,40,40,41,40,40,40,40,41,40,40,40,41,o ,o ,31,16,18,18,18,16,20,29,29,29,29,29,29,29,20,29,29,29,20,29,20,4 ,4 ,4 ,4 ,13,4 ,8 ,8 ,8 ,8 ,8 ,13,13,4 ,4 ,13,13,6 ,4 , /*13*/ +/*14*/ 30,40,41,40,40,40,40,40,40,41,40,40,41,40,40,41,41,41,40,40,40,41,o ,o ,32,16,18,18,18,16,20,29,29,29,29,29,29,29,20,29,29,29,20,29,20,4 ,4 ,4 ,4 ,13,13,8 ,8 ,8 ,8 ,8 ,12,13,4 ,6 ,13,13,7 ,4 , /*14*/ +/*15*/ 30,40,41,40,40,40,40,40,40,41,41,41,41,40,40,41,40,40,40,40,42,41,o ,36,31,16,o ,17,o ,16,20,20,20,29,29,29,20,20,20,32,32,32,32,29,20,20,4 ,4 ,4 ,13,13,8 ,8 ,8 ,8 ,8 ,8 ,13,4 ,7 ,12,12,6 ,4 , /*15*/ +/*16*/ 30,40,41,40,40,40,40,40,40,40,40,40,40,40,40,41,40,40,40,40,43,41,o ,35,20,16,o ,17,o ,16,20,19,19,28,28,28,19,19,20,29,29,29,29,29,29,20,4 ,4 ,4 ,13,13,8 ,8 ,8 ,8 ,8 ,8 ,13,13,6 ,11,11,4 ,4 , /*16*/ +/*17*/ 30,40,41,41,41,41,41,41,40,40,40,40,40,40,40,41,40,40,41,41,41,41,o ,16,AA,16,o ,17,o ,16,20,19,19,27,27,27,19,19,20,29,30,31,31,30,29,31,4 ,4 ,4 ,13,13,12,8 ,8 ,8 ,8 ,12,13,13,4 ,11,10,10,4 , /*17*/ +/*18*/ 30,40,40,40,40,40,40,41,40,40,40,40,40,41,40,41,40,40,41,40,43,41,o ,35,20,16,o ,17,o ,16,20,19,19,26,26,26,19,19,20,29,31,31,31,31,29,30,4 ,4 ,4 ,4 ,13,13,13,13,10,13,13,13,4 ,4 ,4 ,10,9 ,4 , /*18*/ +/*19*/ 30,40,40,40,40,40,40,41,40,40,41,40,40,41,40,41,40,40,41,40,42,41,o ,36,31,16,o ,17,o ,16,20,19,19,25,25,25,19,19,20,29,31,31,31,31,29,30,4 ,4 ,15,15,15,13,13,13,13,13,13,4 ,4 ,4 ,4 ,9 ,9 ,4 , /*19*/ +/*20*/ 30,41,41,41,41,40,40,41,41,41,41,40,40,41,40,41,41,41,41,40,40,41,o ,o ,32,16,o ,17,o ,16,20,19,19,24,24,24,19,19,20,29,30,31,31,30,29,31,4 ,4 ,15,4 ,15,4 ,4 ,14,4 ,4 ,4 ,4 ,4 ,4 ,8 ,8 ,8 ,4 , /*20*/ +/*21*/ 30,40,40,40,40,40,40,40,40,40,41,40,40,41,40,40,40,40,40,40,40,41,o ,o ,31,16,o ,17,o ,16,20,19,19,19,19,19,19,19,20,29,29,29,29,29,29,20,4 ,4 ,15,4 ,11,11,11,12,4 ,4 ,o ,o ,3 ,4 ,8 ,8 ,4 ,4 , /*21*/ +/*22*/ 30,40,40,40,40,40,40,40,40,40,41,40,40,41,40,40,40,40,40,40,40,41,o ,o ,20,16,o ,17,o ,16,16,19,19,19,19,25,21,19,20,24,25,26,27,28,28,20,4 ,4 ,15,15,4 ,11,4 ,4 ,4 ,o ,5 ,5 ,o ,1 ,o ,4 ,4 ,4 , /*22*/ +/*23*/ 30,40,41,41,41,41,41,41,40,40,41,40,30,30,30,30,30,30,30,30,30,20,20,20,20,16,o ,17,o ,16,16,19,19,19,19,25,34,19,20,19,19,19,19,19,19,20,4 ,4 ,4 ,15,15,8 ,33,4 ,4 ,48,o ,o ,3 ,4 ,4 ,4 ,4 ,4 , /*23*/ +/*24*/ 30,40,41,40,40,40,40,41,41,40,41,40,30,31,31,31,31,31,31,31,31,31,31,31,20,16,o ,17,o ,16,16,19,19,19,19,19,19,19,20,19,19,19,19,19,19,20,4 ,4 ,4 ,4 ,4 ,14,14,4 ,4 ,2 ,3 ,6 ,4 ,4 ,4 ,4 ,4 ,4 , /*24*/ +/*25*/ 30,40,41,40,40,40,40,40,41,41,41,40,30,31,o ,o ,o ,o ,o ,o ,o ,o ,o ,31,31,16,o ,17,o ,16,16,19,19,19,19,19,19,21,20,19,19,19,19,19,19,20,4 ,4 ,4 ,14,14,14,14,3 ,3 ,3 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 , /*25*/ +/*26*/ 30,40,41,41,41,41,40,40,40,40,40,40,30,31,o ,o ,o ,o ,o ,o ,o ,o ,o ,31,32,16,o ,17,o ,16,16,19,19,19,19,19,19,19,20,19,19,19,19,19,19,20,20,4 ,14,14,14,14,4 ,4 ,2 ,3 ,4 ,2 ,3 ,3 ,2 ,4 ,4 ,4 , /*26*/ +/*27*/ 30,40,40,40,40,41,41,40,40,40,40,40,30,31,o ,o ,o ,o ,o ,o ,o ,o ,o ,31,31,16,o ,17,o ,16,16,19,19,19,19,19,19,19,20,21,19,19,19,19,19,19,20,4 ,14,14,14,4 ,4 ,3 ,o ,o ,3 ,o ,o ,o ,o ,3 ,4 ,4 , /*27*/ +/*28*/ 30,40,40,40,40,40,41,40,40,40,40,40,30,31,o ,o ,o ,o ,o ,o ,o ,o ,o ,31,20,16,o ,17,o ,16,16,19,19,19,19,25,34,19,20,19,19,21,19,19,19,19,20,4 ,14,14,14,4 ,3 ,o ,o ,o ,o ,o ,5 ,5 ,5 ,1 ,4 ,4 , /*28*/ +/*29*/ 30,40,40,40,40,40,41,40,40,40,40,40,30,31,o ,o ,o ,o ,o ,o ,o ,o ,o ,31,20,16,o ,17,o ,16,16,19,19,19,19,25,21,19,20,20,20,20,20,20,16,16,20,4 ,14,14,14,8 ,o ,o ,2 ,o ,o ,o ,o ,o ,5 ,o ,3 ,4 , /*29*/ +/*30*/ 30,40,30,40,40,41,41,41,40,40,30,40,30,31,o ,o ,o ,47,31,6 ,36,36,36,31,20,16,o ,17,o ,16,20,19,19,19,19,19,19,19,20,29,29,29,20,20,16,16,32,4 ,14,14,8 ,8 ,o ,3 ,3 ,3 ,o ,o ,4 ,3 ,o ,5 ,o ,4 , /*30*/ +/*31*/ 30,43,30,41,41,41,41,41,41,41,30,43,30,31,o ,o ,o ,o ,46,o ,35,35,35,31,31,16,o ,17,o ,16,20,19,19,24,24,24,19,19,20,29,29,29,20,20,16,16,32,4 ,4 ,4 ,8 ,o ,4 ,4 ,4 ,4 ,o ,4 ,4 ,4 ,o ,5 ,o ,4 , /*31*/ +/*32*/ 30,42,30,40,40,30,30,30,40,40,30,42,30,31,o ,o ,o ,47,46,o ,16,16,16,31,32,16,o ,17,o ,16,20,19,19,25,25,25,19,19,20,29,29,29,20,20,16,16,20,20,20,20,3 ,o ,4 ,4 ,4 ,4 ,2 ,4 ,4 ,4 ,o ,5 ,o ,4 , /*32*/ +/*33*/ 30,40,40,40,40,30,30,30,40,40,40,40,30,31,4 ,3 ,3 ,31,31,31,32,BB,32,32,31,16,o ,17,o ,16,20,19,19,26,26,26,19,19,20,29,29,29,20,20,19,19,19,19,19,20,3 ,o ,o ,4 ,4 ,3 ,3 ,4 ,4 ,4 ,3 ,o ,1 ,4 , /*33*/ +/*34*/ 30,30,30,30,30,30,30,30,30,30,30,30,30,4 ,4 ,o ,o ,4 ,4 ,32,16,16,16,16,20,16,o ,17,o ,16,20,19,19,27,27,27,19,19,20,29,29,29,20,20,19,19,19,19,19,20,6 ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,3 ,2 ,48,4 ,4 , /*34*/ +/*35*/ 30,30,30,30,30,30,30,30,30,30,30,30,30,4 ,2 ,o ,o ,2 ,4 ,32,16,16,16,16,20,16,o ,17,o ,16,20,19,19,28,28,28,19,19,20,29,29,29,20,20,19,19,19,19,19,20,4 ,o ,5 ,o ,1 ,4 ,4 ,4 ,1 ,3 ,4 ,4 ,4 ,4 , /*35*/ +/*36*/ 30,30,30,30,30,30,30,30,30,30,30,30,30,4 ,4 ,o ,o ,o ,4 ,32,16,16,16,16,20,16,o ,17,o ,16,16,20,20,29,29,29,20,20,20,29,29,29,20,34,19,25,25,25,19,34,4 ,3 ,o ,5 ,o ,3 ,3 ,1 ,2 ,2 ,4 ,4 ,4 ,4 , /*36*/ +/*37*/ 30,30,30,30,30,30,30,30,30,30,30,30,30,32,32,4 ,3 ,3 ,4 ,32,16,16,16,16,31,16,o ,17,o ,16,20,29,29,29,29,29,29,29,29,29,29,29,20,34,19,25,25,25,19,34,4 ,4 ,3 ,o ,2 ,3 ,3 ,1 ,o ,o ,3 ,4 ,4 ,4 , /*37*/ +/*38*/ 30,40,40,40,40,40,40,40,40,40,42,43,41,o ,o ,o ,o ,36,35,32,16,16,16,16,32,16,o ,17,o ,16,20,29,29,29,29,29,29,29,29,29,29,29,20,34,19,25,25,25,19,34,4 ,4 ,4 ,4 ,3 ,3 ,4 ,4 ,o ,5 ,o ,3 ,6 ,6 , /*38*/ +/*39*/ 30,40,41,40,40,40,40,40,40,40,42,43,41,o ,o ,o ,o ,o ,16,BB,16,16,16,16,31,16,o ,17,o ,16,20,20,20,34,34,34,20,20,20,20,20,20,20,20,19,19,19,19,19,20,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,o ,5 ,5 ,o ,o ,7 , /*39*/ +/*40*/ 30,40,40,40,40,40,40,40,40,40,40,40,41,o ,o ,o ,o ,36,35,32,16,16,16,16,20,16,o ,17,o ,16,34,20,20,20,20,20,20,34,34,34,20,20,20,20,20,20,20,20,20,20,4 ,4 ,4 ,4 ,4 ,4 ,4 ,2 ,o ,5 ,o ,3 ,6 ,6 , /*40*/ +/*41*/ 30,40,40,40,40,40,40,40,40,40,40,40,30,32,32,38,38,38,32,32,16,16,16,16,20,16,o ,17,o ,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,20,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,2 ,o ,o ,o ,o ,4 ,4 ,4 , /*41*/ +/*42*/ 30,40,40,40,40,40,40,40,40,40,40,40,30,o ,o ,o ,o ,o ,o ,32,16,16,34,AA,20,16,o ,17,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,16,34,20,7 ,7 ,7 ,7 ,7 ,4 ,4 ,1 ,5 ,o ,o ,3 ,4 ,4 ,4 , /*42*/ +/*43*/ 30,40,40,40,40,40,40,40,40,40,40,40,30,o ,o ,o ,o ,o ,o ,32,16,16,34,16,16,16,o ,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,o ,16,16,31,7 ,7 ,o ,o ,7 ,7 ,4 ,1 ,5 ,o ,2 ,3 ,4 ,4 ,4 , /*43*/ +/*44*/ 30,40,40,40,42,43,41,43,42,40,40,40,41,o ,o ,o ,o ,o ,o ,32,32,32,34,34,20,16,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,17,o ,16,34,20,7 ,o ,o ,o ,o ,7 ,4 ,3 ,5 ,5 ,o ,2 ,4 ,4 ,4 , /*44*/ +/*45*/ 30,30,30,30,30,30,41,30,30,30,30,30,30,o ,30,o ,30,o ,30,32,32,32,20,20,20,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,o ,17,o ,16,20,7 ,7 ,o ,o ,o ,o ,7 ,4 ,4 ,o ,5 ,5 ,o ,4 ,4 ,4 , /*45*/ +/*46*/ 44,44,44,44,44,34,46,34,44,44,44,44,44,32,32,32,32,32,32,32,32,32,20,20,20,20,20,31,32,31,20,20,31,32,31,20,20,31,16,31,20,20,16,o ,17,o ,16,20,7 ,o ,o ,o ,o ,7 ,7 ,4 ,4 ,3 ,o ,o ,o ,o ,4 ,4 , /*46*/ +/*47*/ 44,46,46,46,39,o ,o ,o ,39,46,46,46,44,44,44,44,44,44,44,20,20,20,20,30,32,32,16,32,32,30,20,20,20,20,20,20,20,32,32,32,20,20,16,o ,17,o ,16,20,7 ,o ,o ,o ,o ,7 ,4 ,4 ,1 ,3 ,3 ,o ,o ,o ,3 ,4 , /*47*/ +/*48*/ 44,46,46,46,39,o ,o ,o ,39,46,46,46,44,CC,CC,CC,CC,CC,44,20,20,16,16,16,16,16,16,16,16,16,16,16,20,20,20,20,20,20,20,20,20,20,16,o ,17,o ,16,20,7 ,7 ,o ,o ,7 ,7 ,4 ,1 ,1 ,3 ,3 ,4 ,o ,5 ,o ,4 , /*48*/ +/*49*/ 44,46,46,46,39,o ,o ,o ,39,46,46,46,44,CC,DD,DD,DD,CC,44,20,31,16,16,16,16,16,16,16,16,16,16,16,31,16,16,16,16,16,16,16,16,20,16,o ,17,o ,16,20,7 ,7 ,7 ,o ,7 ,6 ,4 ,1 ,3 ,3 ,3 ,4 ,o ,5 ,o ,4 , /*49*/ +/*50*/ 44,46,46,46,39,o ,o ,o ,39,46,46,46,44,CC,DD,DD,DD,CC,44,20,31,16,16,16,16,16,16,16,16,16,16,16,31,16,16,16,16,16,16,16,16,AA,16,o ,17,o ,16,20,4 ,4 ,6 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,4 ,4 ,4 ,o ,3 ,4 , /*50*/ +/*51*/ 44,44,EE,44,44,o ,o ,o ,44,44,EE,44,44,CC,DD,DD,DD,CC,44,20,20,16,16,16,16,16,16,16,16,16,16,16,20,20,20,20,16,16,20,20,20,20,3 ,3 ,3 ,3 ,4 ,4 ,4 ,4 ,6 ,6 ,6 ,4 ,3 ,3 ,3 ,3 ,4 ,4 ,4 ,4 ,4 ,4 , /*51*/ +/*52*/ 44,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,44,CC,CC,CC,CC,CC,44,20,20,16,16,16,20,20,20,20,20,16,16,16,20,20,20,20,16,16,20,16,16,AA,16,o ,17,3 ,3 ,4 ,4 ,4 ,4 ,4 ,4 ,3 ,3 ,o ,o ,3 ,1 ,3 ,4 ,4 ,4 ,4 , /*52*/ +/*53*/ 44,44,44,44,34,o ,o ,o ,34,44,44,44,44,36,36,36,36,36,44,35,35,16,16,16,35,35,37,35,35,16,16,16,35,35,37,20,16,16,20,16,16,20,16,o ,17,o ,16,20,4 ,4 ,4 ,4 ,3 ,2 ,o ,o ,o ,o ,o ,1 ,3 ,4 ,4 ,4 , /*53*/ +/*54*/ 4 ,4 ,4 ,4 ,44,o ,o ,o ,44,36,46,46,46,46,46,46,46,46,44,36,36,o ,o ,o ,36,36,37,36,36,o ,o ,o ,36,36,37,20,16,16,20,16,16,20,16,o ,17,o ,16,20,4 ,4 ,3 ,48,2 ,o ,o ,o ,5 ,5 ,o ,o ,1 ,4 ,4 ,4 , /*54*/ +/*55*/ 4 ,4 ,4 ,4 ,44,o ,o ,o ,44,36,46,o ,o ,o ,o ,o ,o ,o ,44,o ,o ,o ,o ,o ,o ,o ,37,46,o ,o ,o ,o ,o ,46,37,20,16,16,34,16,16,20,16,o ,17,o ,16,20,5 ,5 ,o ,o ,o ,o ,5 ,5 ,5 ,5 ,5 ,o ,1 ,1 ,4 ,4 , /*55*/ +/*56*/ 4 ,4 ,4 ,44,44,o ,o ,o ,44,36,46,45,45,o ,45,45,o ,o ,44,o ,o ,o ,o ,o ,o ,o ,37,46,o ,o ,o ,o ,o ,46,37,20,16,16,16,16,16,20,16,o ,17,o ,3 ,4 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,o ,o ,o ,o ,o ,o ,1 ,4 ,4 , /*56*/ +/*57*/ 4 ,4 ,4 ,o ,o ,o ,o ,o ,o ,o ,46,45,45,o ,45,45,o ,o ,o ,o ,o ,o ,o ,o ,o ,30,37,46,o ,36,36,36,o ,46,37,20,16,16,16,16,16,20,16,o ,17,o ,o ,3 ,o ,5 ,5 ,5 ,o ,o ,o ,2 ,3 ,48,1 ,o ,5 ,5 ,5 ,6 , /*57*/ +/*58*/ 4 ,4 ,4 ,o ,o ,o ,o ,o ,o ,o ,46,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,46,37,46,o ,36,36,36,o ,46,37,20,16,16,16,16,16,20,16,o ,17,o ,o ,3 ,2 ,o ,o ,o ,o ,2 ,2 ,4 ,4 ,4 ,4 ,1 ,o ,5 ,5 ,6 , /*58*/ +/*59*/ 4 ,4 ,4 ,4 ,2 ,o ,o ,o ,o ,o ,46,45,45,o ,45,45,o ,o ,o ,o ,o ,o ,o ,o ,o ,46,37,46,o ,36,36,36,o ,46,37,20,31,31,31,31,31,20,16,o ,17,o ,3 ,4 ,2 ,2 ,o ,o ,2 ,2 ,4 ,4 ,4 ,4 ,4 ,3 ,1 ,o ,o ,4 , /*59*/ +/*60*/ 4 ,4 ,4 ,4 ,4 ,4 ,4 ,3 ,o ,o ,46,45,45,o ,45,45,o ,o ,o ,o ,30,46,46,46,46,46,37,46,o ,o ,o ,o ,o ,46,37,20,20,20,20,20,20,20,16,o ,17,o ,16,20,2 ,2 ,2 ,2 ,2 ,3 ,4 ,4 ,4 ,4 ,4 ,4 ,3 ,3 ,4 ,4 , /*60*/ +/*61*/ 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,3 ,46,o ,o ,o ,o ,o ,o ,o ,37,37,37,37,37,37,37,37,37,30,o ,o ,o ,o ,o ,30,37,20,20,20,20,20,20,20,16,o ,17,22,16,20,2 ,2 ,2 ,3 ,4 ,3 ,3 ,4 ,3 ,3 ,3 ,4 ,4 ,4 ,4 ,4 , /*61*/ +/*62*/ 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,2 ,2 ,o ,o ,3 ,3 ,37,4 ,4 ,4 ,4 ,4 ,4 ,4 ,32,32,32,32,CC,32,32,32,32,20,20,20,20,20,20,20,4 ,3 ,17,2 ,3 ,20,3 ,3 ,4 ,4 ,4 ,4 ,3 ,3 ,3 ,4 ,4 ,4 ,4 ,4 ,4 ,4 , /*62*/ +/*63*/ 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,32,32,32,32,32,32,32,32,32,20,20,20,20,20,20,20,20,4 ,4 ,4 ,4 ,20,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 /*63*/ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + #undef AA + #undef BB + #undef CC + #undef DD + #undef EE + #undef o + }, + { // tileDictionary + SFG_TD(14,10,0,0),SFG_TD(16, 8,0,0),SFG_TD(14, 8,0,0),SFG_TD(16, 6,0,0), // 0 + SFG_TD(14, 0,0,0),SFG_TD(13,12,0,0),SFG_TD(21, 0,1,1),SFG_TD(14, 0,2,2), // 4 + SFG_TD(14,24,0,0),SFG_TD(16,22,0,0),SFG_TD(18,20,0,0),SFG_TD(20,18,0,0), // 8 + SFG_TD(22,16,0,0),SFG_TD(24,14,0,0),SFG_TD(24, 4,0,0),SFG_TD(31, 7,0,0), // 12 + SFG_TD(17, 5,1,1),SFG_TD(15, 9,3,0),SFG_TD(23, 1,3,0),SFG_TD(17,10,1,1), // 16 + SFG_TD(21, 0,1,4),SFG_TD(22, 5,5,1),SFG_TD(14,31,3,0),SFG_TD(26, 0,1,7), // 20 + SFG_TD(18, 9,1,1),SFG_TD(19, 8,1,1),SFG_TD(20, 7,1,1),SFG_TD(21, 6,1,1), // 24 + SFG_TD(22, 5,1,1),SFG_TD(23, 4,1,1),SFG_TD(21, 0,3,3),SFG_TD(21, 0,5,5), // 28 + SFG_TD(21, 0,6,6),SFG_TD(14, 4,0,0),SFG_TD(21, 0,4,4),SFG_TD(16, 6,1,1), // 32 + SFG_TD(15, 7,1,1),SFG_TD(21, 0,5,1),SFG_TD(17, 2,6,6),SFG_TD(16, 3,1,1), // 36 + SFG_TD( 9,15,1,3),SFG_TD(14, 4,3,3),SFG_TD(11,13,3,3),SFG_TD(13,11,3,3), // 40 + SFG_TD(18, 0,1,1),SFG_TD(15, 9,5,1),SFG_TD(14, 9,0,3),SFG_TD(15, 8,3,3), // 44 + SFG_TD(16, 6,1,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0), // 48 + SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0), // 52 + SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0), // 56 + SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0) // 60 + }, // tileDictionary + {9 ,3 ,6 ,11,12,2 ,5 }, // textureIndices + 13, // doorTextureIndex + 18, // floorColor + 26, // ceilingColor + {44, 61, 64 }, // player start: x, y, direction + 0, // backgroundImage + { // elements + {SFG_LEVEL_ELEMENT_BULLETS, {55,2}},{SFG_LEVEL_ELEMENT_ROCKETS, {12,2}}, + {SFG_LEVEL_ELEMENT_RUIN, {11,2}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {25,3}}, + {SFG_LEVEL_ELEMENT_RUIN, {11,3}},{SFG_LEVEL_ELEMENT_RUIN, {10,4}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {51,5}},{SFG_LEVEL_ELEMENT_BARREL, {32,5}}, + {SFG_LEVEL_ELEMENT_LAMP, {31,5}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {61,6}}, + {SFG_LEVEL_ELEMENT_HEALTH, {26,7}},{SFG_LEVEL_ELEMENT_BARREL, {55,10}}, + {SFG_LEVEL_ELEMENT_RUIN, {29,10}},{SFG_LEVEL_ELEMENT_BULLETS, {23,11}}, + {SFG_LEVEL_ELEMENT_BULLETS, {22,11}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {13,11}}, + {SFG_LEVEL_ELEMENT_BULLETS, {54,12}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {43,13}}, + {SFG_LEVEL_ELEMENT_LAMP, {50,14}},{SFG_LEVEL_ELEMENT_RUIN, {34,14}}, + {SFG_LEVEL_ELEMENT_RUIN, {33,14}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {50,15}}, + {SFG_LEVEL_ELEMENT_RUIN, {35,15}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {10,15}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {11,16}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {55,18}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {50,20}},{SFG_LEVEL_ELEMENT_LAMP, {31,20}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {5,21}},{SFG_LEVEL_ELEMENT_TELEPORTER, {51,23}}, + {SFG_LEVEL_ELEMENT_LAMP, {25,23}},{SFG_LEVEL_ELEMENT_TREE, {36,24}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {32,24}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {34,25}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {25,25}},{SFG_LEVEL_ELEMENT_BULLETS, {18,25}}, + {SFG_LEVEL_ELEMENT_BARREL, {55,26}},{SFG_LEVEL_ELEMENT_BARREL, {54,26}}, + {SFG_LEVEL_ELEMENT_PLASMA, {48,26}},{SFG_LEVEL_ELEMENT_LAMP, {39,26}}, + {SFG_LEVEL_ELEMENT_HEALTH, {37,26}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {32,26}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {17,26}},{SFG_LEVEL_ELEMENT_PLASMA, {48,27}}, + {SFG_LEVEL_ELEMENT_TREE, {36,27}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {20,27}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {19,27}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {9,27}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {48,28}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {17,28}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {18,29}},{SFG_LEVEL_ELEMENT_LAMP, {31,31}}, + {SFG_LEVEL_ELEMENT_HEALTH, {50,32}},{SFG_LEVEL_ELEMENT_BARREL, {16,32}}, + {SFG_LEVEL_ELEMENT_BARREL, {15,32}},{SFG_LEVEL_ELEMENT_HEALTH, {55,33}}, + {SFG_LEVEL_ELEMENT_BARREL, {25,33}},{SFG_LEVEL_ELEMENT_BULLETS, {10,33}}, + {SFG_LEVEL_ELEMENT_HEALTH, {9,33}},{SFG_LEVEL_ELEMENT_CARD1, {3,33}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {56,36}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {44,36}}, + {SFG_LEVEL_ELEMENT_LAMP, {30,36}},{SFG_LEVEL_ELEMENT_CARD0, {46,37}}, + {SFG_LEVEL_ELEMENT_RUIN, {36,37}},{SFG_LEVEL_ELEMENT_RUIN, {35,38}}, + {SFG_LEVEL_ELEMENT_HEALTH, {31,38}},{SFG_LEVEL_ELEMENT_RUIN, {18,39}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {2,39}},{SFG_LEVEL_ELEMENT_RUIN, {18,40}}, + {SFG_LEVEL_ELEMENT_BARREL, {33,41}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {23,41}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {37,42}},{SFG_LEVEL_ELEMENT_LOCK1, {23,42}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {9,42}},{SFG_LEVEL_ELEMENT_BLOCKER, {8,42}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {7,42}},{SFG_LEVEL_ELEMENT_BLOCKER, {6,42}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {5,42}},{SFG_LEVEL_ELEMENT_BLOCKER, {4,42}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {3,42}},{SFG_LEVEL_ELEMENT_TERMINAL, {47,43}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {35,43}},{SFG_LEVEL_ELEMENT_BULLETS, {21,43}}, + {SFG_LEVEL_ELEMENT_HEALTH, {20,43}},{SFG_LEVEL_ELEMENT_ROCKETS, {16,43}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {52,44}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {51,44}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {37,44}},{SFG_LEVEL_ELEMENT_LAMP, {38,46}}, + {SFG_LEVEL_ELEMENT_LAMP, {26,47}},{SFG_LEVEL_ELEMENT_HEALTH, {61,49}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {57,49}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {10,49}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {2,49}},{SFG_LEVEL_ELEMENT_BARREL, {1,49}}, + {SFG_LEVEL_ELEMENT_RUIN, {44,50}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {35,50}}, + {SFG_LEVEL_ELEMENT_HEALTH, {33,50}},{SFG_LEVEL_ELEMENT_PLASMA, {15,50}}, + {SFG_LEVEL_ELEMENT_RUIN, {45,51}},{SFG_LEVEL_ELEMENT_RUIN, {43,51}}, + {SFG_LEVEL_ELEMENT_RUIN, {42,51}},{SFG_LEVEL_ELEMENT_LOCK0, {41,52}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {39,52}},{SFG_LEVEL_ELEMENT_RUIN, {9,52}}, + {SFG_LEVEL_ELEMENT_LAMP, {58,55}},{SFG_LEVEL_ELEMENT_BULLETS, {53,56}}, + {SFG_LEVEL_ELEMENT_BULLETS, {52,56}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {39,56}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {30,56}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {40,57}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {22,57}},{SFG_LEVEL_ELEMENT_RUIN, {46,60}}, + {SFG_LEVEL_ELEMENT_FINISH, {30,62}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}} + }, // elements + } // level + ; + +SFG_PROGRAM_MEMORY SFG_Level SFG_level3 = + { // level + { // mapArray + #define o 0 + #define AA (5 | SFG_TILE_PROPERTY_SQUEEZER) + #define BB (19 | SFG_TILE_PROPERTY_DOOR) + #define CC (24 | SFG_TILE_PROPERTY_DOOR) + #define DD (56 | SFG_TILE_PROPERTY_ELEVATOR) + #define EE (7 | SFG_TILE_PROPERTY_ELEVATOR) + #define FF (8 | SFG_TILE_PROPERTY_DOOR) + #define GG (63 | SFG_TILE_PROPERTY_DOOR) + #define HH (47 | SFG_TILE_PROPERTY_SQUEEZER) + #define II (4 | SFG_TILE_PROPERTY_SQUEEZER) + #define JJ (51 | SFG_TILE_PROPERTY_ELEVATOR) + #define KK (17 | SFG_TILE_PROPERTY_ELEVATOR) + #define LL (50 | SFG_TILE_PROPERTY_ELEVATOR) + #define MM (1 | SFG_TILE_PROPERTY_DOOR) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +/*0 */ 8 ,8 ,8 ,8 ,8 ,24,24,24,8 ,8 ,24,24,24,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,21,8 ,8 ,8 ,8 ,8 ,8 ,8 ,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,8 , /*0 */ +/*1 */ 8 ,5 ,5 ,5 ,5 ,24,5 ,24,9 ,9 ,24,5 ,24,5 ,5 ,5 ,5 ,5 ,5 ,27,27,27,59,59,21,59,59,27,27,27,27,27,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*1 */ +/*2 */ 8 ,5 ,24,24,24,9 ,5 ,9 ,9 ,9 ,9 ,5 ,9 ,9 ,5 ,5 ,5 ,5 ,5 ,27,27,27,59,59,21,59,59,27,27,27,27,27,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*2 */ +/*3 */ 8 ,5 ,24,5 ,5 ,AA,AA,AA,AA,9 ,AA,AA,AA,9 ,5 ,5 ,5 ,5 ,5 ,27,27,27,59,5 ,5 ,5 ,59,27,27,27,27,27,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,32,32,32,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,8 , /*3 */ +/*4 */ 8 ,5 ,24,5 ,9 ,AA,AA,9 ,AA,AA,AA,AA,AA,9 ,5 ,5 ,5 ,5 ,57,9 ,59,59,59,5 ,5 ,5 ,59,59,59,9 ,9 ,27,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,32,32,32,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*4 */ +/*5 */ 63,57,24,5 ,9 ,AA,AA,9 ,AA,AA,AA,AA,9 ,9 ,5 ,5 ,5 ,5 ,57,59,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,59,57,5 ,6 ,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,32,32,32,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*5 */ +/*6 */ 8 ,57,9 ,AA,AA,AA,AA,9 ,9 ,9 ,9 ,9 ,5 ,5 ,5 ,5 ,5 ,5 ,57,59,5 ,59,59,59,59,59,59,59,5 ,59,57,5 ,6 ,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,32,32,32,32,32,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,8 , /*6 */ +/*7 */ 8 ,57,9 ,AA,AA,AA,9 ,24,5 ,AA,AA,9 ,5 ,5 ,5 ,5 ,5 ,5 ,57,59,5 ,59,9 ,27,27,27,9 ,59,5 ,59,57,5 ,23,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,32,32,32,32,32,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*7 */ +/*8 */ 53,57,9 ,AA,AA,AA,9 ,24,5 ,AA,AA,21,5 ,5 ,5 ,5 ,5 ,5 ,57,59,5 ,59,27,5 ,5 ,5 ,27,59,5 ,59,57,5 ,23,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,32,32,32,32,32,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*8 */ +/*9 */ 8 ,57,24,5 ,9 ,AA,9 ,24,5 ,AA,AA,21,5 ,5 ,5 ,5 ,5 ,5 ,57,59,5 ,59,27,5 ,5 ,5 ,27,59,5 ,59,57,5 ,23,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,32,32,32,32,32,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,8 , /*9 */ +/*10*/ 8 ,57,24,5 ,9 ,AA,9 ,24,5 ,AA,AA,9 ,5 ,5 ,5 ,5 ,5 ,5 ,57,59,5 ,19,27,5 ,5 ,5 ,27,19,5 ,59,57,5 ,6 ,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,32,32,32,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*10*/ +/*11*/ 63,57,9 ,9 ,9 ,AA,9 ,9 ,9 ,AA,AA,9 ,5 ,5 ,5 ,5 ,5 ,5 ,57,59,5 ,BB,27,5 ,5 ,5 ,27,BB,5 ,59,57,5 ,6 ,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,32,32,32,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*11*/ +/*12*/ 8 ,57,9 ,AA,AA,AA,AA,AA,9 ,AA,AA,9 ,9 ,9 ,9 ,27,27,27,9 ,58,59,58,9 ,27,27,27,9 ,58,59,58,9 ,27,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,32,32,32,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,8 , /*12*/ +/*13*/ 8 ,57,9 ,9 ,AA,AA,AA,AA,9 ,AA,AA,AA,AA,9 ,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*13*/ +/*14*/ 53,57,24,5 ,AA,AA,9 ,9 ,9 ,9 ,9 ,AA,AA,9 ,27,27,27,27,27,27,27,27,9 ,27,27,27,9 ,27,27,27,27,27,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*14*/ +/*15*/ 8 ,57,24,5 ,AA,AA,5 ,24,5 ,AA,AA,AA,AA,9 ,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,8 , /*15*/ +/*16*/ 8 ,57,24,5 ,AA,AA,5 ,24,5 ,AA,AA,AA,9 ,9 ,27,27,27,27,27,27,27,27,9 ,27,9 ,27,9 ,27,27,27,27,27,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*16*/ +/*17*/ 63,57,24,5 ,AA,AA,9 ,9 ,9 ,AA,AA,AA,9 ,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,23,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*17*/ +/*18*/ 8 ,5 ,9 ,9 ,AA,AA,AA,AA,AA,AA,AA,AA,9 ,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,23,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,6 ,6 ,24,8 , /*18*/ +/*19*/ 8 ,5 ,9 ,9 ,AA,9 ,AA,AA,AA,AA,AA,AA,9 ,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,23,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,8 , /*19*/ +/*20*/ 53,5 ,9 ,9 ,AA,9 ,AA,AA,AA,AA,AA,AA,9 ,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,24,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,25,24,8 , /*20*/ +/*21*/ 53,5 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,6 ,6 ,6 ,6 ,6 ,6 ,24,24,24,24,24,24,24,24,24,24,24,24,CC,24,24,24,24,24,24,24,24,24,24,42,24,8 , /*21*/ +/*22*/ 8 ,5 ,19,59,59,59,63,63,63,59,59,59,19,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,26,6 ,6 ,6 ,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,6 ,24,24,42,24,8 , /*22*/ +/*23*/ 8 ,5 ,BB,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,59,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,24,48,48,48,48,48,24,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,26,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,42,42,24,8 , /*23*/ +/*24*/ 8 ,59,19,59,59,59,19,21,19,59,59,59,19,57,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,27,5 ,5 ,5 ,5 ,5 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,26,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,24,24,24,8 , /*24*/ +/*25*/ 53,27,27,27,27,27,27,27,27,27,27,27,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,24,48,48,48,48,5 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,26,6 ,24,24,24,6 ,6 ,6 ,24,24,24,6 ,6 ,6 ,24,24,24,6 ,26,6 ,6 ,8 ,8 , /*25*/ +/*26*/ 8 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,27,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,23,5 ,5 ,5 ,48,5 ,6 ,6 ,6 ,6 ,6 ,6 ,24,26,26,24,6 ,24,24,24,6 ,6 ,6 ,24,6 ,24,6 ,6 ,6 ,24,24,24,6 ,26,6 ,6 ,DD,8 , /*26*/ +/*27*/ 8 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,27,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,23,5 ,48,5 ,5 ,5 ,23,6 ,6 ,6 ,6 ,6 ,26,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,26,6 ,6 ,8 ,8 , /*27*/ +/*28*/ 8 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,27,19,57,57,57,57,57,57,57,57,57,5 ,5 ,5 ,5 ,23,5 ,48,48,48,48,23,6 ,6 ,6 ,6 ,6 ,26,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,24,6 ,6 ,DD,8 , /*28*/ +/*29*/ 8 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,27,19,59,59,59,58,58,59,59,59,19,5 ,5 ,5 ,5 ,23,5 ,5 ,5 ,5 ,5 ,23,6 ,6 ,6 ,6 ,6 ,26,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,8 ,8 , /*29*/ +/*30*/ 8 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,27,BB,27,27,27,27,27,27,27,27,BB,5 ,5 ,5 ,5 ,24,48,48,48,63,11,22,63,20,CC,20,20,20,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,8 ,8 , /*30*/ +/*31*/ 53,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,27,19,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,19,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,22,EE,EE,12,6 ,6 ,20,20,20,6 ,6 ,6 ,23,6 ,6 ,6 ,26,6 ,6 ,6 ,23,6 ,6 ,6 ,23,6 ,6 ,6 ,23,6 ,6 ,6 ,8 ,8 , /*31*/ +/*32*/ 8 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,15,14,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,10,EE,EE,22,47,47,18,4 ,4 ,18,47,47,47,47,47,47,63,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,33,8 , /*32*/ +/*33*/ 8 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,15,14,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,22,FF,63,47,47,18,4 ,4 ,18,47,47,47,47,47,47,63,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,33,8 , /*33*/ +/*34*/ 63,o ,o ,o ,o ,63,63,o ,o ,o ,o ,o ,o ,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,55,8 , /*34*/ +/*35*/ 8 ,o ,o ,o ,63,63,63,63,o ,o ,o ,o ,o ,3 ,3 ,3 ,61,61,63,24,63,61,61,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,18,13,18,4 ,55,DD, /*35*/ +/*36*/ 8 ,o ,o ,o ,63,63,63,63,o ,o ,o ,o ,o ,3 ,3 ,3 ,61,63,62,62,62,63,61,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,13,13,13,4 ,55,DD, /*36*/ +/*37*/ 63,o ,o ,o ,o ,63,63,o ,o ,o ,o ,o ,o ,62,62,62,63,62,62,62,62,62,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,46,46,46,46,46,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,13,13,13,4 ,55,8 , /*37*/ +/*38*/ 8 ,o ,54,54,54,o ,o ,54,54,54,o ,o ,o ,62,62,62,GG,62,62,62,62,62,24,o ,o ,o ,o ,o ,o ,o ,8 ,53,4 ,4 ,4 ,4 ,4 ,4 ,4 ,46,46,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,18,13,13,13,18,18,4 ,53,8 , /*38*/ +/*39*/ 8 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,15,15,62,62,62,63,62,62,62,62,62,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,46,46,16,16,16,16,16,16,16,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,13,13,13,13,18,4 ,4 ,55,8 , /*39*/ +/*40*/ 8 ,3 ,JJ,JJ,JJ,3 ,3 ,JJ,JJ,JJ,3 ,14,14,3 ,3 ,3 ,61,63,62,62,62,63,61,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,46,4 ,16,HH,16,II,16,HH,16,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,13,13,13,4 ,4 ,4 ,4 ,55,8 , /*40*/ +/*41*/ 63,3 ,JJ,JJ,JJ,3 ,3 ,JJ,JJ,JJ,3 ,3 ,3 ,3 ,3 ,3 ,61,61,63,24,63,61,61,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,46,46,4 ,4 ,47,4 ,47,4 ,47,4 ,4 ,8 ,18,4 ,4 ,4 ,4 ,4 ,13,13,13,4 ,4 ,4 ,4 ,55,8 , /*41*/ +/*42*/ 8 ,3 ,JJ,JJ,JJ,3 ,3 ,JJ,JJ,JJ,3 ,14,14,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,61,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,46,4 ,4 ,4 ,47,4 ,47,4 ,47,4 ,4 ,13,45,4 ,4 ,4 ,4 ,4 ,18,13,18,4 ,4 ,4 ,4 ,55,8 , /*42*/ +/*43*/ 8 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,15,15,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,61,o ,o ,8 ,53,4 ,4 ,4 ,4 ,4 ,46,4 ,4 ,4 ,45,4 ,45,4 ,45,4 ,4 ,13,45,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,53,8 , /*43*/ +/*44*/ 8 ,o ,54,54,54,o ,o ,54,54,54,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,61,61,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,46,4 ,4 ,4 ,47,47,47,47,47,4 ,4 ,18,45,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,8 ,8 , /*44*/ +/*45*/ 8 ,o ,49,49,49,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,61,61,61,61,61,61,24,24,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,19,4 ,4 ,4 ,46,46,46,46,47,4 ,4 ,18,45,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,8 ,8 , /*45*/ +/*46*/ 63,o ,49,49,49,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,61,61,61,61,61,61,24,24,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,46,46,46,46,47,4 ,4 ,13,45,4 ,4 ,46,46,4 ,4 ,4 ,4 ,4 ,46,46,4 ,8 ,8 , /*46*/ +/*47*/ 8 ,o ,49,49,49,o ,o ,o ,15,15,15,o ,o ,15,15,15,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,46,46,46,46,47,4 ,4 ,13,45,4 ,4 ,46,46,4 ,4 ,4 ,4 ,4 ,46,46,4 ,8 ,8 , /*47*/ +/*48*/ 8 ,o ,49,49,49,o ,o ,o ,14,14,14,o ,o ,14,14,14,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,53,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,47,47,47,47,47,4 ,4 ,18,18,4 ,4 ,4 ,4 ,4 ,18,13,18,4 ,4 ,4 ,4 ,8 ,8 , /*48*/ +/*49*/ 8 ,o ,49,49,49,o ,o ,o ,3 ,3 ,3 ,o ,o ,3 ,3 ,3 ,o ,o ,54,o ,o ,o ,54,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,18,18,4 ,4 ,4 ,45,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,16,13,16,4 ,4 ,4 ,4 ,8 ,8 , /*49*/ +/*50*/ 8 ,o ,49,49,49,o ,o ,o ,3 ,o ,o ,o ,o ,o ,o ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,18,18,4 ,4 ,4 ,45,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,16,KK,16,4 ,4 ,4 ,4 ,8 ,8 , /*50*/ +/*51*/ 8 ,o ,24,LL,24,o ,o ,54,3 ,54,o ,o ,o ,o ,54,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,18,18,4 ,4 ,4 ,47,47,47,47,47,4 ,4 ,18,18,4 ,4 ,4 ,4 ,4 ,16,16,16,4 ,4 ,4 ,4 ,DD,8 , /*51*/ +/*52*/ 63,o ,2 ,2 ,2 ,o ,o ,o ,3 ,o ,o ,o ,o ,o ,o ,3 ,3 ,49,61,61,49,3 ,3 ,3 ,3 ,54,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,18,4 ,4 ,4 ,4 ,4 ,4 ,4 ,47,4 ,4 ,13,45,4 ,4 ,4 ,4 ,4 ,18,13,18,4 ,4 ,4 ,4 ,8 ,8 , /*52*/ +/*53*/ 8 ,o ,2 ,2 ,2 ,o ,o ,o ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,60,61,61,61,3 ,3 ,3 ,3 ,o ,o ,o ,o ,o ,8 ,53,4 ,4 ,4 ,4 ,4 ,18,4 ,4 ,4 ,4 ,4 ,4 ,4 ,47,4 ,4 ,13,45,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,8 ,8 , /*53*/ +/*54*/ 8 ,15,2 ,2 ,2 ,o ,o ,54,3 ,54,o ,o ,o ,o ,o ,o ,o ,60,61,61,61,3 ,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,18,18,4 ,4 ,4 ,47,47,47,4 ,47,4 ,4 ,18,45,4 ,19,46,46,46,46,46,46,46,46,46,46,19,8 , /*54*/ +/*55*/ 8 ,14,2 ,2 ,2 ,o ,o ,o ,3 ,o ,o ,o ,o ,o ,o ,3 ,3 ,49,61,61,49,3 ,3 ,3 ,3 ,54,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,18,18,4 ,4 ,4 ,45,4 ,45,4 ,47,4 ,4 ,18,45,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,8 ,8 , /*55*/ +/*56*/ 8 ,3 ,2 ,2 ,2 ,2 ,8 ,24,3 ,61,61,o ,o ,o ,54,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,18,18,4 ,4 ,4 ,47,4 ,47,47,47,4 ,4 ,13,45,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,8 ,8 , /*56*/ +/*57*/ 8 ,3 ,2 ,2 ,2 ,2 ,2 ,8 ,3 ,61,61,o ,o ,o ,54,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,47,4 ,4 ,4 ,4 ,4 ,4 ,13,45,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,8 ,8 , /*57*/ +/*58*/ 63,14,2 ,2 ,2 ,2 ,2 ,2 ,MM,61,61,o ,o ,o ,o ,3 ,o ,o ,54,o ,o ,o ,54,o ,o ,o ,63,63,o ,o ,8 ,53,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,18,HH,18,4 ,4 ,4 ,4 ,4 ,8 ,18,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,8 ,8 , /*58*/ +/*59*/ 8 ,15,2 ,2 ,2 ,2 ,2 ,8 ,3 ,61,61,o ,o ,o ,o ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,63,63,63,o ,o ,o ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,16,16,16,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,8 ,8 , /*59*/ +/*60*/ 8 ,o ,2 ,2 ,2 ,2 ,8 ,24,3 ,61,61,54,o ,54,o ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,63,63,63,o ,o ,o ,4 ,4 ,4 ,4 ,19,46,46,46,19,46,19,46,46,46,46,46,46,46,46,19,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,53,8 , /*60*/ +/*61*/ 8 ,o ,o ,o ,o ,o ,o ,o ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,63,o ,o ,o ,o ,4 ,4 ,4 ,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,34,8 , /*61*/ +/*62*/ 8 ,o ,o ,o ,o ,o ,o ,o ,o ,54,o ,54,o ,54,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,4 ,46,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,34,8 , /*62*/ +/*63*/ 8 ,8 ,8 ,DD,8 ,DD,8 ,8 ,8 ,8 ,53,53,53,8 ,8 ,8 ,53,8 ,34,34,34,8 ,53,8 ,34,34,34,8 ,53,8 ,19,19,33,33,33,53,19,8 ,8 ,8 ,8 ,8 ,53,34,34,53,8 ,8 ,8 ,8 ,53,34,34,53,8 ,8 ,8 ,8 ,8 ,53,34,34,34,8 /*63*/ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + #undef AA + #undef BB + #undef CC + #undef DD + #undef EE + #undef FF + #undef GG + #undef HH + #undef II + #undef JJ + #undef KK + #undef LL + #undef MM + #undef o + }, + { // tileDictionary + SFG_TD(10,20,0,0),SFG_TD( 4,26,0,0),SFG_TD( 0, 4,0,0),SFG_TD( 4,26,0,0), // 0 + SFG_TD( 0,30,2,2),SFG_TD(17,13,0,2),SFG_TD(24, 6,0,1),SFG_TD( 0,24,1,0), // 4 + SFG_TD( 4, 0,1,0),SFG_TD(19, 0,4,1),SFG_TD(10, 5,0,0),SFG_TD(17, 5,0,0), // 8 + SFG_TD(24, 5,0,0),SFG_TD( 8,22,3,0),SFG_TD( 6,24,0,0),SFG_TD( 8,22,0,0), // 12 + SFG_TD(11,19,1,0),SFG_TD( 0,10,0,0),SFG_TD( 8,22,0,0),SFG_TD(21, 0,4,4), // 16 + SFG_TD(24, 0,0,5),SFG_TD(17, 5,0,1),SFG_TD( 0, 0,0,0),SFG_TD(24, 6,5,5), // 20 + SFG_TD(28, 0,5,1),SFG_TD(24, 8,0,1),SFG_TD(26, 3,5,1),SFG_TD(17,10,0,5), // 24 + SFG_TD(13,15,0,0),SFG_TD(13,15,0,0),SFG_TD(13,15,0,0),SFG_TD(13,15,0,0), // 28 + SFG_TD(24, 8,0,1),SFG_TD( 8, 0,6,0),SFG_TD(18, 0,0,6),SFG_TD(13,15,0,0), // 32 + SFG_TD(13,15,0,0),SFG_TD(13,15,0,0),SFG_TD(13,15,0,0),SFG_TD(13,15,0,0), // 36 + SFG_TD(13,15,0,0),SFG_TD(13,15,0,0),SFG_TD(28, 4,5,1),SFG_TD(13,15,0,0), // 40 + SFG_TD(13,15,0,0),SFG_TD( 2,28,4,2),SFG_TD( 0,13,0,4),SFG_TD( 2,28,2,2), // 44 + SFG_TD(22, 8,5,2),SFG_TD(15,15,0,0),SFG_TD( 0,15,0,0),SFG_TD(15,11,5,0), // 48 + SFG_TD(13,15,0,0),SFG_TD( 0, 0,1,1),SFG_TD(10,20,1,0),SFG_TD(22, 8,0,0), // 52 + SFG_TD(31,24,4,4),SFG_TD(19,11,6,2),SFG_TD( 0, 0,3,3),SFG_TD(19, 3,4,3), // 56 + SFG_TD(12,18,5,0),SFG_TD(14,16,5,0),SFG_TD(17,13,1,1),SFG_TD(21, 0,2,2) // 60 + }, // tileDictionary + {14,3 ,11,15,2 ,12,10}, // textureIndices + 13, // doorTextureIndex + 50, // floorColor + 186, // ceilingColor + {56, 50, 64 }, // player start: x, y, direction + 1, // backgroundImage + { // elements + {SFG_LEVEL_ELEMENT_FINISH, {24,0}},{SFG_LEVEL_ELEMENT_BULLETS, {29,1}}, + {SFG_LEVEL_ELEMENT_BULLETS, {28,1}},{SFG_LEVEL_ELEMENT_CARD0, {11,1}}, + {SFG_LEVEL_ELEMENT_PLASMA, {4,1}},{SFG_LEVEL_ELEMENT_ROCKETS, {3,1}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {35,2}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {60,3}}, + {SFG_LEVEL_ELEMENT_CARD2, {40,6}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {51,7}}, + {SFG_LEVEL_ELEMENT_LAMP, {12,7}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {36,9}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {47,10}},{SFG_LEVEL_ELEMENT_LOCK2, {27,10}}, + {SFG_LEVEL_ELEMENT_LOCK2, {21,10}},{SFG_LEVEL_ELEMENT_LAMP, {12,10}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {1,10}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {42,11}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {34,11}},{SFG_LEVEL_ELEMENT_BARREL, {5,11}}, + {SFG_LEVEL_ELEMENT_COLUMN, {37,12}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {35,12}}, + {SFG_LEVEL_ELEMENT_COLUMN, {33,12}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {55,13}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {1,13}},{SFG_LEVEL_ELEMENT_HEALTH, {3,15}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {50,17}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {53,20}}, + {SFG_LEVEL_ELEMENT_BARREL, {18,20}},{SFG_LEVEL_ELEMENT_LOCK2, {50,21}}, + {SFG_LEVEL_ELEMENT_BARREL, {19,21}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {18,21}}, + {SFG_LEVEL_ELEMENT_BARREL, {17,21}},{SFG_LEVEL_ELEMENT_BARREL, {18,22}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {60,23}},{SFG_LEVEL_ELEMENT_HEALTH, {39,23}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {39,24}},{SFG_LEVEL_ELEMENT_ROCKETS, {61,25}}, + {SFG_LEVEL_ELEMENT_HEALTH, {60,25}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {50,26}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {29,27}},{SFG_LEVEL_ELEMENT_HEALTH, {5,28}}, + {SFG_LEVEL_ELEMENT_LAMP, {22,29}},{SFG_LEVEL_ELEMENT_LOCK1, {35,30}}, + {SFG_LEVEL_ELEMENT_COLUMN, {56,31}},{SFG_LEVEL_ELEMENT_COLUMN, {50,31}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {54,32}},{SFG_LEVEL_ELEMENT_BULLETS, {53,32}}, + {SFG_LEVEL_ELEMENT_BULLETS, {38,32}},{SFG_LEVEL_ELEMENT_PLASMA, {37,32}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {32,32}},{SFG_LEVEL_ELEMENT_LAMP, {33,34}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {33,35}},{SFG_LEVEL_ELEMENT_PLASMA, {9,35}}, + {SFG_LEVEL_ELEMENT_HEALTH, {23,36}},{SFG_LEVEL_ELEMENT_TERMINAL, {19,36}}, + {SFG_LEVEL_ELEMENT_PLASMA, {9,36}},{SFG_LEVEL_ELEMENT_CARD1, {21,38}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {19,38}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {57,39}}, + {SFG_LEVEL_ELEMENT_PLASMA, {56,40}},{SFG_LEVEL_ELEMENT_ROCKETS, {56,41}}, + {SFG_LEVEL_ELEMENT_BARREL, {37,48}},{SFG_LEVEL_ELEMENT_BARREL, {36,48}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {44,49}},{SFG_LEVEL_ELEMENT_HEALTH, {36,52}}, + {SFG_LEVEL_ELEMENT_BULLETS, {36,53}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {18,53}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {11,53}},{SFG_LEVEL_ELEMENT_BARREL, {3,53}}, + {SFG_LEVEL_ELEMENT_BULLETS, {58,57}},{SFG_LEVEL_ELEMENT_BULLETS, {56,57}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {44,57}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {3,57}}, + {SFG_LEVEL_ELEMENT_BARREL, {51,58}},{SFG_LEVEL_ELEMENT_BARREL, {50,58}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {39,58}},{SFG_LEVEL_ELEMENT_LOCK0, {8,58}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {5,58}},{SFG_LEVEL_ELEMENT_BARREL, {51,59}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {3,59}},{SFG_LEVEL_ELEMENT_BULLETS, {20,61}}, + {SFG_LEVEL_ELEMENT_HEALTH, {3,61}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}} + }, // elements + } // level + ; + +SFG_PROGRAM_MEMORY SFG_Level SFG_level4 = + { // level + { // mapArray + #define o 0 + #define AA (5 | SFG_TILE_PROPERTY_DOOR) + #define BB (10 | SFG_TILE_PROPERTY_DOOR) + #define CC (6 | SFG_TILE_PROPERTY_DOOR) + #define DD (8 | SFG_TILE_PROPERTY_DOOR) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +/*0 */ 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,60,60,62,62,62,62,62,62,62,62,62,o ,o ,o ,o ,o ,62,62,62,18,2 ,2 ,2 ,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, /*0 */ +/*1 */ 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,o ,o ,62,62,62,62,62,62,62,62,62,o ,o ,o ,o ,o ,62,62,62,18,2 ,2 ,2 ,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, /*1 */ +/*2 */ 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,o ,o ,62,62,62,62,62,62,62,62,62,o ,o ,o ,o ,o ,62,62,62,18,2 ,2 ,2 ,18,18,18,18,18,18,18,18,18,17,18,18,18,17,18,18,18,18,18,18, /*2 */ +/*3 */ 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,o ,o ,62,62,62,62,62,62,62,62,62,o ,o ,o ,o ,o ,62,62,62,18,2 ,2 ,2 ,17,18,18,18,17,18,18,18,7 ,7 ,7 ,7 ,7 ,7 ,7 ,17,18,18,18,18, /*3 */ +/*4 */ 62,62,62,62,62,62,62,62,62,62,62,62,62,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,62,62,62,62,62,62,62,62,o ,o ,o ,o ,o ,62,62,62,18,2 ,2 ,2 ,17,2 ,2 ,2 ,2 ,2 ,2 ,2 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,2 ,2 ,2 ,2 ,18, /*4 */ +/*5 */ o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,62,62,18,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,AA,7 ,7 ,7 ,7 ,7 ,7 ,7 ,2 ,2 ,2 ,2 ,18, /*5 */ +/*6 */ o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,62,62,18,2 ,2 ,2 ,17,2 ,2 ,2 ,2 ,2 ,2 ,2 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,2 ,2 ,2 ,2 ,18, /*6 */ +/*7 */ o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,62,62,18,18,18,18,17,18,18,18,17,18,18,18,7 ,7 ,7 ,7 ,7 ,7 ,7 ,17,2 ,2 ,2 ,17, /*7 */ +/*8 */ o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,62,62,18,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,18,2 ,2 ,2 ,18, /*8 */ +/*9 */ o ,o ,o ,o ,63,63,63,61,61,61,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,62,62,18,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,18,2 ,2 ,2 ,18, /*9 */ +/*10*/ o ,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,o ,o ,62,62,62,62,62,62,62,18,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,17,2 ,2 ,2 ,17, /*10*/ +/*11*/ 62,62,o ,o ,63,o ,o ,o ,o ,o ,60,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,o ,o ,62,62,62,62,62,62,62,18,7 ,7 ,11,11,11,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,18,2 ,2 ,2 ,18, /*11*/ +/*12*/ 62,62,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,59,59,59,o ,o ,63,o ,o ,o ,o ,o ,62,62,62,62,62,62,62,18,7 ,7 ,11,11,11,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,18,2 ,2 ,2 ,18, /*12*/ +/*13*/ 62,62,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,59,59,59,o ,o ,63,o ,o ,o ,o ,o ,62,62,62,62,62,62,62,18,7 ,7 ,11,11,11,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,17,2 ,2 ,2 ,17, /*13*/ +/*14*/ 62,62,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,59,59,59,o ,o ,63,o ,o ,o ,o ,o ,62,62,62,62,62,62,62,18,18,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,18,2 ,2 ,2 ,18, /*14*/ +/*15*/ 62,62,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,o ,o ,62,62,62,62,62,62,62,1 ,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,2 ,2 ,2 ,18, /*15*/ +/*16*/ 62,62,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,o ,o ,62,62,62,62,62,62,1 ,17,17,17,17,17,17,17,17,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,18,2 ,2 ,2 ,18, /*16*/ +/*17*/ 62,62,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,62,62,62,62,62,62,62,62,1 ,17,17,17,17,17,2 ,2 ,17,1 ,1 ,55,1 ,1 ,1 ,1 ,1 ,55,1 ,1 ,17,2 ,2 ,2 ,17, /*17*/ +/*18*/ 62,62,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,62,62,62,62,62,62,62,62,1 ,17,17,17,17,17,2 ,2 ,2 ,2 ,2 ,2 ,25,1 ,1 ,1 ,25,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 , /*18*/ +/*19*/ 60,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,62,62,62,62,62,62,62,62,1 ,17,17,17,17,17,2 ,2 ,2 ,2 ,2 ,2 ,25,25,25,25,25,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 , /*19*/ +/*20*/ 60,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,62,62,o ,o ,o ,o ,o ,62,1 ,17,17,17,17,17,2 ,2 ,17,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 , /*20*/ +/*21*/ 60,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,60,60,60,62,62,o ,o ,o ,o ,o ,62,1 ,17,17,17,17,17,17,17,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 , /*21*/ +/*22*/ 60,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,62,62,60,60,60,60,60,o ,62,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 , /*22*/ +/*23*/ 60,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,55,10,BB,BB,BB,10,55,o ,o ,o ,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,60,o ,62,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 , /*23*/ +/*24*/ 60,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,10,10,36,36,36,36,36,10,10,o ,o ,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,60,o ,62,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,1 ,1 , /*24*/ +/*25*/ 60,o ,o ,o ,63,o ,o ,o ,o ,o ,o ,o ,10,36,36,36,36,36,36,36,36,36,10,o ,o ,o ,o ,59,o ,o ,o ,o ,o ,o ,o ,o ,o ,60,o ,62,1 ,1 ,1 ,1 ,1 ,51,51,1 ,1 ,1 ,1 ,2 ,3 ,2 ,3 ,2 ,1 ,1 ,1 ,1 ,51,51,1 ,1 , /*25*/ +/*26*/ 10,49,49,10,10,10,10,10,10,10,10,10,10,36,36,36,36,36,36,36,36,36,10,10,10,10,10,10,10,10,10,10,49,49,10,o ,o ,60,o ,62,62,1 ,1 ,1 ,1 ,51,51,1 ,1 ,1 ,1 ,2 ,CC,2 ,CC,2 ,1 ,1 ,1 ,1 ,51,51,1 ,1 , /*26*/ +/*27*/ 10,33,33,33,45,46,46,46,46,46,46,46,46,36,36,36,36,36,36,36,36,36,46,46,46,46,46,46,46,46,45,33,33,33,10,o ,o ,60,o ,62,62,62,1 ,1 ,1 ,51,51,51,51,51,51,2 ,2 ,2 ,2 ,2 ,51,51,51,51,51,51,1 ,1 , /*27*/ +/*28*/ 10,33,33,33,45,46,46,46,46,46,46,46,46,36,36,36,36,36,36,36,36,36,46,46,46,46,46,46,46,46,45,33,33,33,10,o ,o ,60,o ,62,62,62,62,1 ,1 ,51,51,51,51,51,51,2 ,2 ,2 ,2 ,2 ,51,51,51,51,51,51,1 ,1 , /*28*/ +/*29*/ 10,33,33,33,45,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,45,33,33,33,10,60,60,60,60,8 ,62,62,62,62,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*29*/ +/*30*/ 10,33,33,33,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,33,33,33,10,o ,o ,o ,o ,o ,o ,21,21,62,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*30*/ +/*31*/ 10,34,34,34,10,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,10,34,34,34,10,o ,o ,o ,o ,o ,o ,o ,o ,62,62,62,62,62,62,1 ,1 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*31*/ +/*32*/ 49,35,35,35,10,35,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,35,10,35,35,35,49,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,1 ,1 ,4 ,2 ,2 ,2 ,4 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*32*/ +/*33*/ 49,35,35,35,10,35,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,35,10,35,35,35,49,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,1 ,1 ,1 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*33*/ +/*34*/ 49,35,35,35,10,43,42,41,33,41,33,41,33,41,33,41,33,41,33,41,33,41,33,41,33,41,33,41,42,43,10,35,35,35,49,o ,o ,o ,o ,o ,o ,o ,o ,62,62,62,62,62,62,1 ,1 ,1 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*34*/ +/*35*/ 10,35,35,35,DD,35,34,33,32,40,32,40,32,40,32,40,32,40,32,40,32,40,32,40,32,40,32,33,34,35,DD,35,35,35,10,o ,o ,o ,o ,o ,o ,o ,o ,62,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*35*/ +/*36*/ 10,10,10,10,10,43,42,41,40,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,40,41,42,43,10,10,10,10,10,o ,o ,o ,o ,o ,o ,o ,o ,62,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,1 ,1 ,1 ,17,17,17,17,17,17, /*36*/ +/*37*/ 10,9 ,9 ,9 ,9 ,9 ,34,33,32,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,32,33,34,9 ,9 ,9 ,9 ,9 ,10,o ,o ,60,60,60,60,60,60,62,1 ,1 ,1 ,25,25,25,25,25,1 ,2 ,1 ,1 ,1 ,1 ,17,30,30,30,17,17, /*37*/ +/*38*/ 10,9 ,9 ,9 ,9 ,9 ,42,41,40,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,40,41,42,9 ,9 ,9 ,9 ,9 ,10,o ,o ,60,o ,o ,o ,o ,o ,62,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,29,30,30,30,17,17, /*38*/ +/*39*/ 10,9 ,9 ,9 ,9 ,9 ,34,33,32,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,32,33,34,9 ,9 ,9 ,9 ,9 ,10,o ,o ,60,o ,o ,o ,o ,o ,62,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,29,30,30,30,17,17, /*39*/ +/*40*/ 10,BB,10,10,8 ,43,42,41,40,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,40,41,42,43,8 ,10,10,BB,10,o ,o ,60,62,62,8 ,8 ,62,62,1 ,1 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,2 ,1 ,1 ,1 ,1 ,17,30,30,30,17,17, /*40*/ +/*41*/ 10,9 ,9 ,9 ,8 ,35,34,33,32,36,22,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,36,32,33,34,35,8 ,9 ,9 ,9 ,10,o ,o ,60,62,1 ,1 ,1 ,1 ,1 ,17,1 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,2 ,1 ,1 ,1 ,1 ,17,17,30,17,17,17, /*41*/ +/*42*/ 10,9 ,9 ,9 ,8 ,43,42,41,40,36,22,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,36,40,41,42,43,8 ,9 ,9 ,9 ,10,o ,o ,60,62,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,2 ,1 ,1 ,1 ,1 ,17,30,30,30,17,17, /*42*/ +/*43*/ 10,9 ,9 ,9 ,8 ,35,34,33,32,36,22,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,36,32,33,34,35,8 ,9 ,9 ,9 ,10,o ,o ,60,62,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,2 ,1 ,1 ,1 ,1 ,17,30,30,30,17,17, /*43*/ +/*44*/ 10,9 ,9 ,9 ,8 ,43,42,41,40,36,22,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,36,40,41,42,43,8 ,9 ,9 ,9 ,10,62,62,62,62,1 ,2 ,2 ,2 ,1 ,17,1 ,1 ,1 ,1 ,1 ,1 ,1 ,4 ,2 ,4 ,1 ,1 ,1 ,17,30,30,30,17,17, /*44*/ +/*45*/ 10,9 ,9 ,9 ,8 ,35,34,33,32,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,32,33,34,35,8 ,9 ,9 ,9 ,10,62,62,1 ,1 ,1 ,29,29,29,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,1 ,1 ,1 ,17,17,17,17,17,17, /*45*/ +/*46*/ 10,9 ,9 ,9 ,9 ,9 ,36,36,36,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,36,36,36,9 ,9 ,9 ,9 ,9 ,10,62,62,1 ,1 ,30,30,30,30,30,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*46*/ +/*47*/ BB,9 ,9 ,9 ,9 ,9 ,36,36,36,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,36,36,36,9 ,9 ,9 ,9 ,9 ,BB,62,62,1 ,31,31,31,31,31,31,31,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*47*/ +/*48*/ 10,9 ,9 ,9 ,9 ,9 ,36,36,36,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,36,36,36,9 ,9 ,9 ,9 ,9 ,10,62,62,1 ,31,31,31,31,31,31,31,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*48*/ +/*49*/ 10,9 ,9 ,9 ,8 ,35,34,33,32,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,32,33,34,35,8 ,9 ,9 ,9 ,10,62,62,1 ,31,31,31,31,31,31,31,1 ,1 ,1 ,1 ,4 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,4 ,1 ,1 ,1 ,1 ,1 ,1 , /*49*/ +/*50*/ 10,9 ,9 ,9 ,8 ,43,42,41,40,36,22,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,36,40,41,42,43,8 ,9 ,9 ,9 ,10,62,62,1 ,1 ,31,31,31,31,31,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 , /*50*/ +/*51*/ 10,9 ,9 ,9 ,8 ,35,34,33,32,36,22,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,36,32,33,34,35,8 ,9 ,9 ,9 ,10,62,62,1 ,1 ,31,31,31,31,31,1 ,1 ,17,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,17,1 ,1 ,1 , /*51*/ +/*52*/ 10,9 ,9 ,9 ,8 ,43,42,41,40,36,22,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,36,40,41,42,43,8 ,9 ,9 ,9 ,10,62,62,1 ,1 ,1 ,31,31,31,1 ,1 ,1 ,3 ,1 ,1 ,4 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,4 ,1 ,1 ,3 ,1 ,1 ,1 , /*52*/ +/*53*/ 10,9 ,9 ,9 ,8 ,35,34,33,32,36,22,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,36,32,33,34,35,8 ,9 ,9 ,9 ,12,o ,62,62,62,1 ,31,31,31,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 , /*53*/ +/*54*/ 10,BB,10,10,8 ,43,42,41,40,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,40,41,42,43,8 ,10,10,BB,10,o ,o ,21,8 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 , /*54*/ +/*55*/ 10,9 ,9 ,9 ,9 ,9 ,34,33,32,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,32,33,34,9 ,9 ,9 ,9 ,9 ,10,o ,o ,21,8 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,29,29,2 ,2 ,2 ,29,29,2 ,2 ,2 ,2 ,1 ,1 ,1 , /*55*/ +/*56*/ 10,9 ,9 ,9 ,9 ,9 ,42,41,40,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,40,41,42,9 ,9 ,9 ,9 ,9 ,10,o ,o ,o ,8 ,62,62,62,62,1 ,1 ,1 ,4 ,2 ,2 ,30,30,30,2 ,2 ,2 ,30,30,30,2 ,2 ,4 ,1 ,1 ,1 , /*56*/ +/*57*/ 10,9 ,9 ,9 ,9 ,9 ,34,33,32,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,32,33,34,9 ,9 ,9 ,9 ,9 ,10,o ,o ,o ,o ,o ,o ,o ,62,1 ,1 ,1 ,1 ,1 ,2 ,30,30,30,2 ,2 ,2 ,30,30,30,2 ,1 ,1 ,1 ,1 ,1 , /*57*/ +/*58*/ 10,10,10,10,10,43,42,41,40,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,36,40,41,42,43,10,10,10,10,10,o ,o ,o ,o ,o ,o ,o ,62,1 ,1 ,1 ,1 ,1 ,2 ,30,30,30,2 ,2 ,2 ,30,30,30,2 ,1 ,1 ,1 ,1 ,1 , /*58*/ +/*59*/ 10,35,35,35,DD,35,34,33,32,40,32,40,40,40,32,40,32,40,32,40,32,40,40,40,32,40,32,33,34,35,DD,35,35,35,10,60,60,60,60,60,60,60,62,1 ,1 ,1 ,1 ,1 ,1 ,30,30,30,2 ,2 ,2 ,30,30,30,1 ,1 ,1 ,1 ,1 ,1 , /*59*/ +/*60*/ 49,35,35,35,8 ,43,42,41,33,41,33,41,33,41,33,41,33,41,33,41,33,41,33,41,33,41,33,41,42,43,8 ,35,35,35,49,o ,o ,o ,o ,o ,o ,o ,62,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*60*/ +/*61*/ 49,35,35,35,8 ,35,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,42,34,35,8 ,35,35,35,49,o ,o ,o ,o ,o ,o ,o ,62,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*61*/ +/*62*/ 49,35,35,35,8 ,35,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,43,35,35,8 ,35,35,35,49,o ,o ,o ,o ,o ,o ,o ,62,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*62*/ +/*63*/ 10,35,35,35,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,35,35,35,10,o ,o ,o ,o ,o ,o ,o ,62,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,17,BB,17,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 /*63*/ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + #undef AA + #undef BB + #undef CC + #undef DD + #undef o + }, + { // tileDictionary + SFG_TD(19,31,1,0),SFG_TD(23, 0,4,4),SFG_TD(19, 7,4,4),SFG_TD(22, 4,6,0), // 0 + SFG_TD(19, 3,0,3),SFG_TD(23, 3,3,4),SFG_TD(24, 5,4,4),SFG_TD(19,12,4,4), // 4 + SFG_TD(31, 0,0,1),SFG_TD(19, 6,1,1),SFG_TD(23, 0,1,1),SFG_TD(20,11,1,4), // 8 + SFG_TD(19, 4,1,1),SFG_TD(19,15,0,0),SFG_TD(19,15,0,0),SFG_TD(19,15,0,0), // 12 + SFG_TD(19,15,0,0),SFG_TD(23, 0,1,1),SFG_TD(23, 0,2,4),SFG_TD(19,15,0,0), // 16 + SFG_TD(19,15,0,0),SFG_TD(23,31,2,0),SFG_TD(21,31,2,0),SFG_TD(27,31,1,0), // 20 + SFG_TD(19,15,0,0),SFG_TD(22, 3,4,4),SFG_TD(19,15,0,0),SFG_TD(19,15,0,0), // 24 + SFG_TD(19,15,0,0),SFG_TD(18, 8,4,4),SFG_TD(17, 9,4,4),SFG_TD(16,10,4,4), // 28 + SFG_TD(21,20,0,0),SFG_TD(23,18,0,0),SFG_TD(25,16,0,0),SFG_TD(27,14,0,0), // 32 + SFG_TD(19,22,0,0),SFG_TD(19,15,0,0),SFG_TD(19,15,0,0),SFG_TD(19,15,0,0), // 36 + SFG_TD(21,20,2,0),SFG_TD(23,18,2,0),SFG_TD(25,16,2,0),SFG_TD(27,14,2,0), // 40 + SFG_TD(19,15,0,0),SFG_TD(21,10,0,1),SFG_TD(19,12,1,1),SFG_TD(19,15,0,0), // 44 + SFG_TD(19,15,0,0),SFG_TD(29, 3,1,1),SFG_TD(19,15,0,0),SFG_TD(19, 6,4,4), // 48 + SFG_TD(19,15,0,0),SFG_TD(19,15,0,0),SFG_TD(19,15,0,0),SFG_TD(31,31,3,0), // 52 + SFG_TD(19,15,0,0),SFG_TD(19,15,0,0),SFG_TD(19,15,0,0),SFG_TD(21,31,1,0), // 56 + SFG_TD(25,31,4,0),SFG_TD(22,31,2,0),SFG_TD(19, 0,5,5),SFG_TD(27,31,1,0) // 60 + }, // tileDictionary + {3 ,12,0 ,8 ,5 ,1 ,15}, // textureIndices + 7, // doorTextureIndex + 202, // floorColor + 66, // ceilingColor + {53, 61, 64 }, // player start: x, y, direction + 2, // backgroundImage + { // elements + {SFG_LEVEL_ELEMENT_LAMP, {58,3}},{SFG_LEVEL_ELEMENT_COLUMN, {51,4}}, + {SFG_LEVEL_ELEMENT_LOCK2, {51,5}},{SFG_LEVEL_ELEMENT_FINISH, {44,5}}, + {SFG_LEVEL_ELEMENT_COLUMN, {51,6}},{SFG_LEVEL_ELEMENT_LAMP, {58,7}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {9,9}},{SFG_LEVEL_ELEMENT_BLOCKER, {8,9}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {7,9}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {51,10}}, + {SFG_LEVEL_ELEMENT_LAMP, {6,11}},{SFG_LEVEL_ELEMENT_TELEPORTER, {44,12}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {58,13}},{SFG_LEVEL_ELEMENT_TELEPORTER, {23,13}}, + {SFG_LEVEL_ELEMENT_HEALTH, {17,17}},{SFG_LEVEL_ELEMENT_BULLETS, {15,17}}, + {SFG_LEVEL_ELEMENT_BULLETS, {45,18}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {17,18}}, + {SFG_LEVEL_ELEMENT_HEALTH, {55,19}},{SFG_LEVEL_ELEMENT_BULLETS, {53,19}}, + {SFG_LEVEL_ELEMENT_HEALTH, {51,19}},{SFG_LEVEL_ELEMENT_BULLETS, {45,19}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {56,21}},{SFG_LEVEL_ELEMENT_LAMP, {20,22}}, + {SFG_LEVEL_ELEMENT_LAMP, {14,22}},{SFG_LEVEL_ELEMENT_RUIN, {26,24}}, + {SFG_LEVEL_ELEMENT_HEALTH, {8,24}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {18,25}}, + {SFG_LEVEL_ELEMENT_BULLETS, {5,25}},{SFG_LEVEL_ELEMENT_ROCKETS, {54,26}}, + {SFG_LEVEL_ELEMENT_PLASMA, {52,26}},{SFG_LEVEL_ELEMENT_HEALTH, {36,26}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {16,26}},{SFG_LEVEL_ELEMENT_TREE, {18,29}}, + {SFG_LEVEL_ELEMENT_TREE, {16,29}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {53,30}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {29,35}},{SFG_LEVEL_ELEMENT_ROCKETS, {51,37}}, + {SFG_LEVEL_ELEMENT_HEALTH, {49,37}},{SFG_LEVEL_ELEMENT_COLUMN, {19,37}}, + {SFG_LEVEL_ELEMENT_COLUMN, {15,37}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {60,38}}, + {SFG_LEVEL_ELEMENT_BULLETS, {30,38}},{SFG_LEVEL_ELEMENT_BARREL, {21,38}}, + {SFG_LEVEL_ELEMENT_BARREL, {13,38}},{SFG_LEVEL_ELEMENT_HEALTH, {4,38}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {20,40}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {13,40}}, + {SFG_LEVEL_ELEMENT_HEALTH, {21,41}},{SFG_LEVEL_ELEMENT_PLASMA, {13,41}}, + {SFG_LEVEL_ELEMENT_PLASMA, {60,43}},{SFG_LEVEL_ELEMENT_BARREL, {17,46}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {12,46}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {42,47}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {40,47}},{SFG_LEVEL_ELEMENT_LOCK0, {34,47}}, + {SFG_LEVEL_ELEMENT_BULLETS, {23,47}},{SFG_LEVEL_ELEMENT_BARREL, {18,47}}, + {SFG_LEVEL_ELEMENT_BARREL, {16,47}},{SFG_LEVEL_ELEMENT_ROCKETS, {11,47}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {3,47}},{SFG_LEVEL_ELEMENT_LOCK0, {0,47}}, + {SFG_LEVEL_ELEMENT_BARREL, {41,48}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {32,48}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {21,48}},{SFG_LEVEL_ELEMENT_BARREL, {17,48}}, + {SFG_LEVEL_ELEMENT_BARREL, {42,49}},{SFG_LEVEL_ELEMENT_BARREL, {40,49}}, + {SFG_LEVEL_ELEMENT_PLASMA, {42,50}},{SFG_LEVEL_ELEMENT_PLASMA, {40,50}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {43,51}},{SFG_LEVEL_ELEMENT_PLASMA, {41,51}}, + {SFG_LEVEL_ELEMENT_PLASMA, {39,51}},{SFG_LEVEL_ELEMENT_PLASMA, {60,52}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {46,52}},{SFG_LEVEL_ELEMENT_RUIN, {33,52}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {41,53}},{SFG_LEVEL_ELEMENT_HEALTH, {40,53}}, + {SFG_LEVEL_ELEMENT_PLASMA, {21,53}},{SFG_LEVEL_ELEMENT_HEALTH, {13,53}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {21,54}},{SFG_LEVEL_ELEMENT_MONSTER_ENDER, {17,55}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {13,55}},{SFG_LEVEL_ELEMENT_HEALTH, {30,56}}, + {SFG_LEVEL_ELEMENT_BARREL, {21,56}},{SFG_LEVEL_ELEMENT_BARREL, {13,56}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {4,56}},{SFG_LEVEL_ELEMENT_HEALTH, {41,57}}, + {SFG_LEVEL_ELEMENT_COLUMN, {19,57}},{SFG_LEVEL_ELEMENT_COLUMN, {15,57}}, + {SFG_LEVEL_ELEMENT_RUIN, {29,59}},{SFG_LEVEL_ELEMENT_LOCK0, {4,59}}, + {SFG_LEVEL_ELEMENT_LOCK1, {53,63}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}} + }, // elements + } // level + ; + +SFG_PROGRAM_MEMORY SFG_Level SFG_level5 = + { // level + { // mapArray + #define o 0 + #define AA (63 | SFG_TILE_PROPERTY_ELEVATOR) + #define BB (32 | SFG_TILE_PROPERTY_DOOR) + #define CC (30 | SFG_TILE_PROPERTY_DOOR) + #define DD (59 | SFG_TILE_PROPERTY_ELEVATOR) + #define EE (53 | SFG_TILE_PROPERTY_DOOR) + #define FF (44 | SFG_TILE_PROPERTY_DOOR) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +/*0 */ 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,1 ,1 ,1 ,1 ,1 ,1 ,1 ,5 ,1 ,1 ,1 ,1 ,5 ,7 ,5 ,1 ,1 ,1 ,1 ,5 ,1 ,1 ,1 ,1 ,5 ,1 ,1 ,1 ,1 ,5 ,1 ,1 ,1 ,1 ,5 ,2 ,2 ,2 ,2 , /*0 */ +/*1 */ 22,22,22,22,22,22,22,22,o ,o ,o ,22,22,22,22,22,22,22,22,22,22,22,22,22,22,1 ,1 ,1 ,1 ,1 ,1 ,1 ,35,31,o ,o ,31,35,7 ,40,40,40,40,40,40,40,40,40,26,35,31,o ,o ,31,35,31,o ,o ,31,35,2 ,2 ,2 ,2 , /*1 */ +/*2 */ 23,23,23,23,23,23,22,22,o ,o ,o ,22,22,22,22,22,22,22,22,22,22,22,22,22,22,1 ,1 ,1 ,1 ,1 ,1 ,1 ,35,31,o ,o ,31,35,7 ,11,10,40,40,40,40,40,40,40,26,35,31,o ,o ,31,35,31,o ,o ,31,35,2 ,2 ,2 ,2 , /*2 */ +/*3 */ 23,23,23,23,23,23,22,22,o ,o ,o ,o ,o ,o ,o ,o ,3 ,o ,o ,o ,o ,55,55,55,60,60,60,1 ,1 ,1 ,1 ,1 ,35,o ,o ,o ,o ,35,7 ,11,10,40,40,40,40,40,40,40,26,35,o ,o ,o ,o ,35,o ,o ,o ,o ,35,2 ,2 ,2 ,2 , /*3 */ +/*4 */ 23,23,23,23,23,23,22,22,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,o ,56,56,55,55,60,60,1 ,1 ,1 ,1 ,1 ,35,o ,o ,o ,o ,35,7 ,11,10,40,40,40,40,40,40,40,40,35,o ,o ,o ,o ,35,o ,o ,o ,o ,35,2 ,2 ,2 ,2 , /*4 */ +/*5 */ 23,23,23,23,23,23,55,55,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,61,56,56,5 ,1 ,1 ,5 ,35,35,35,35,35,35,o ,o ,35,35,7 ,40,40,40,40,40,40,40,40,40,40,35,35,o ,o ,35,35,35,o ,o ,35,35,31,31,31,31, /*5 */ +/*6 */ 23,23,23,23,23,23,61,61,55,55,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,2 ,2 ,2 ,61,1 ,1 ,1 ,1 ,31,31,o ,o ,35,o ,o ,o ,o ,o ,7 ,7 ,7 ,7 ,10,34,10,34,40,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o , /*6 */ +/*7 */ 23,23,23,23,23,23,2 ,2 ,56,55,55,55,55,o ,o ,o ,o ,55,55,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,7 ,10,34,10,34,40,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o , /*7 */ +/*8 */ 23,o ,o ,2 ,2 ,2 ,2 ,2 ,2 ,56,55,55,55,55,55,55,55,55,61,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,7 ,35,35,35,35,35,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o , /*8 */ +/*9 */ 23,o ,o ,56,56,2 ,2 ,2 ,2 ,61,61,61,61,55,55,55,61,61,61,2 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,31,31,o ,o ,35,o ,o ,o ,o ,o ,o ,o ,o ,7 ,31,o ,o ,o ,35,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o , /*9 */ +/*10*/ 23,o ,o ,o ,56,56,2 ,2 ,2 ,61,55,55,55,o ,o ,o ,o ,55,55,61,2 ,2 ,2 ,61,5 ,1 ,1 ,5 ,35,35,35,35,35,o ,o ,o ,o ,o ,o ,o ,o ,7 ,31,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o , /*10*/ +/*11*/ 23,o ,o ,23,23,23,2 ,2 ,2 ,55,55,o ,o ,o ,o ,o ,o ,o ,o ,o ,56,56,o ,61,2 ,2 ,2 ,2 ,2 ,56,21,21,21,31,o ,o ,o ,o ,o ,o ,o ,7 ,31,o ,o ,o ,35,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,3 ,3 ,3 ,o ,o ,o ,o , /*11*/ +/*12*/ 23,o ,o ,23,23,23,2 ,2 ,61,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,2 ,2 ,2 ,61,o ,21,21,21,31,o ,o ,o ,o ,o ,o ,o ,7 ,35,35,35,35,35,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,40,40,o ,o ,o ,o ,o , /*12*/ +/*13*/ 23,o ,o ,23,23,23,61,2 ,55,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,56,o ,o ,o ,21,21,21,16,o ,o ,o ,o ,o ,o ,o ,7 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,o ,o ,o ,3 ,3 ,3 ,3 ,3 ,40,40,o ,o ,o ,o ,o , /*13*/ +/*14*/ 23,23,23,23,23,23,56,56,55,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,21,21,21,31,o ,o ,o ,o ,o ,o ,o ,7 ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,40,40,o ,o ,o ,o ,o , /*14*/ +/*15*/ 23,23,22,22,22,22,22,22,22,22,37,16,57,57,26,57,57,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,21,21,21,31,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,23,23,23,23,23,29,o ,o , /*15*/ +/*16*/ 23,23,22,22,22,22,22,22,22,22,22,12,57,26,26,26,26,21,21,21,21,21,21,o ,o ,o ,o ,22,22,22,21,21,21,16,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,23,23,23,23,23,23,o ,o , /*16*/ +/*17*/ 23,23,AA,o ,o ,22,22,22,22,22,22,17,13,26,26,26,26,21,21,21,21,21,21,o ,o ,o ,o ,22,22,22,21,21,21,31,o ,o ,o ,o ,o ,o ,o ,7 ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,23,23,23,23,23,23,23,29, /*17*/ +/*18*/ 23,23,10,o ,o ,22,22,22,22,22,22,12,57,26,26,26,26,21,21,21,21,21,21,o ,o ,o ,o ,22,22,22,21,21,21,31,o ,o ,o ,o ,o ,16,16,7 ,3 ,o ,o ,o ,o ,o ,o ,11,11,11,o ,o ,o ,o ,23,23,23,23,23,23,23,23, /*18*/ +/*19*/ 23,23,8 ,o ,o ,22,22,22,22,22,22,16,57,26,26,26,57,o ,16,o ,o ,16,o ,o ,o ,o ,o ,16,31,31,16,31,31,16,o ,o ,o ,o ,o ,12,12,7 ,3 ,o ,o ,o ,8 ,9 ,10,11,11,11,10,9 ,8 ,o ,23,23,23,23,23,27,23,29, /*19*/ +/*20*/ 23,23,o ,o ,o ,22,22,22,22,22,22,o ,57,57,57,57,57,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,17,17,7 ,3 ,3 ,3 ,o ,8 ,9 ,10,11,11,11,10,9 ,8 ,o ,23,23,23,27,1 ,1 ,9 ,9 , /*20*/ +/*21*/ 23,23,o ,22,22,22,22,22,22,22,37,o ,o ,62,o ,62,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,13,13,7 ,7 ,7 ,7 ,23,27,1 ,27,15,15,15,27,1 ,27,23,23,23,23,27,o ,o ,o ,o , /*21*/ +/*22*/ 30,o ,o ,35,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,54,13,13,13,13,13,23,23,23,27,15,15,15,27,23,23,23,23,23,33,BB,o ,o ,o ,o , /*22*/ +/*23*/ 30,52,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,61,61,2 ,2 ,2 ,2 ,13,o ,o ,13,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,61,61,54,13,13,13,13,23,23,23,27,15,15,15,27,27,27,27,27,27,27,27,o ,o ,o ,o , /*23*/ +/*24*/ 30,52,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,12,o ,o ,12,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,54,13,13,13,23,23,23,27,15,15,15,15,15,15,15,15,27,27,27,1 ,1 ,9 ,9 , /*24*/ +/*25*/ 30,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,56,54,13,13,23,23,23,27,15,15,15,15,15,15,15,15,27,27,23,23,27,23,29, /*25*/ +/*26*/ 30,52,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,12,o ,o ,12,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,56,54,13,23,23,23,27,27,27,27,27,27,27,15,15,27,27,23,23,23,23,23, /*26*/ +/*27*/ 30,52,2 ,2 ,2 ,61,61,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,13,o ,o ,13,2 ,2 ,2 ,61,61,61,61,61,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,56,54,13,13,13,30,13,13,22,22,22,22,27,15,15,27,27,22,22,22,22,22, /*27*/ +/*28*/ 3 ,o ,o ,o ,o ,o ,o ,o ,4 ,2 ,4 ,o ,o ,o ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,2 ,2 ,2 ,2 ,54,13,13,13,CC,13,13,22,22,22,22,27,15,15,27,27,22,22,22,22,22, /*28*/ +/*29*/ 3 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,2 ,4 ,o ,o ,o ,35,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,2 ,2 ,2 ,54,13,13,13,30,13,13,22,22,22,22,27,27,27,27,27,22,22,22,22,22, /*29*/ +/*30*/ 3 ,2 ,DD,DD,DD,4 ,4 ,2 ,2 ,2 ,4 ,o ,o ,o ,35,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,2 ,2 ,2 ,54,13,13,13,30,30,30,23,23,23,23,23,23,23,23,23,23,23,23,o ,o , /*30*/ +/*31*/ 3 ,2 ,DD,DD,DD,4 ,4 ,2 ,4 ,4 ,4 ,o ,o ,o ,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,2 ,2 ,2 ,2 ,54,13,13,13,13,30,23,23,20,20,20,20,20,20,20,20,23,23,o ,o , /*31*/ +/*32*/ 3 ,2 ,DD,DD,DD,4 ,4 ,2 ,4 ,4 ,4 ,37,36,36,36,36,49,o ,o ,o ,o ,o ,31,31,16,16,31,31,o ,o ,o ,31,31,31,31,o ,o ,o ,o ,61,2 ,2 ,2 ,2 ,61,54,13,13,13,22,23,23,12,12,12,12,12,12,12,12,23,23,o ,o , /*32*/ +/*33*/ 3 ,2 ,4 ,4 ,4 ,4 ,4 ,2 ,2 ,2 ,4 ,36,58,58,58,58,37,o ,o ,o ,o ,37,22,22,22,22,22,22,37,31,37,22,22,22,22,49,55,55,55,61,2 ,2 ,2 ,2 ,2 ,54,17,17,17,22,23,23,12,12,12,12,12,12,12,12,23,23,o ,o , /*33*/ +/*34*/ 3 ,2 ,4 ,2 ,2 ,2 ,4 ,2 ,2 ,2 ,4 ,36,58,58,58,58,58,o ,o ,o ,o ,22,22,22,22,22,22,22,37,21,37,22,22,22,22,22,o ,o ,o ,o ,56,2 ,2 ,2 ,2 ,54,12,12,12,30,23,23,20,20,20,12,12,20,20,20,23,23,o ,o , /*34*/ +/*35*/ 3 ,2 ,4 ,2 ,4 ,2 ,16,4 ,4 ,2 ,4 ,36,58,58,58,58,37,o ,o ,o ,o ,22,22,22,22,22,22,22,37,21,37,22,22,22,22,49,o ,o ,o ,o ,o ,2 ,2 ,2 ,2 ,54,16,16,16,30,23,23,23,23,20,12,12,20,23,23,23,23,o ,o , /*35*/ +/*36*/ 3 ,2 ,2 ,2 ,4 ,2 ,12,2 ,2 ,2 ,4 ,36,19,58,19,19,36,o ,o ,o ,o ,22,22,22,22,22,22,22,22,13,13,13,13,17,12,16,o ,o ,o ,o ,o ,2 ,2 ,2 ,2 ,o ,o ,o ,o ,30,27,23,23,23,27,EE,EE,27,23,23,23,27,o ,o , /*36*/ +/*37*/ 3 ,2 ,2 ,2 ,4 ,2 ,17,2 ,4 ,4 ,4 ,36,58,58,58,58,36,o ,o ,o ,o ,49,22,22,22,22,22,22,22,13,13,13,13,17,12,16,o ,o ,o ,o ,o ,2 ,2 ,2 ,2 ,o ,o ,o ,o ,30,3 ,o ,22,22,17,12,12,17,22,22,60,3 ,3 ,o , /*37*/ +/*38*/ 3 ,2 ,2 ,2 ,4 ,2 ,2 ,2 ,2 ,2 ,4 ,36,58,58,58,58,36,o ,o ,o ,o ,22,22,22,22,37,37,37,49,13,13,13,13,17,12,16,o ,o ,o ,o ,60,2 ,2 ,2 ,2 ,o ,o ,o ,62,30,3 ,o ,o ,12,12,12,60,60,12,o ,o ,3 ,3 ,o , /*38*/ +/*39*/ 3 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,37,58,58,58,36,49,o ,o ,o ,o ,22,22,22,22,36,13,13,13,13,13,13,37,22,22,37,o ,o ,o ,o ,o ,2 ,2 ,2 ,61,o ,o ,o ,o ,30,3 ,o ,o ,60,12,o ,o ,60,12,o ,o ,3 ,3 ,o , /*39*/ +/*40*/ 3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,FF,58,58,58,36,o ,o ,o ,o ,o ,22,22,22,22,36,13,13,13,13,13,13,22,22,22,22,o ,o ,o ,o ,o ,2 ,2 ,2 ,61,o ,o ,o ,62,30,3 ,o ,o ,16,16,o ,o ,16,16,o ,o ,3 ,3 ,o , /*40*/ +/*41*/ 3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,37,58,58,58,36,o ,21,21,21,21,22,22,22,22,37,37,37,22,13,13,13,22,22,22,49,o ,o ,o ,o ,60,2 ,2 ,2 ,61,o ,o ,o ,o ,30,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,3 ,o , /*41*/ +/*42*/ 7 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,37,36,36,36,37,o ,21,21,21,21,37,37,22,22,49,49,22,22,13,13,13,37,22,22,21,o ,o ,o ,o ,o ,2 ,2 ,2 ,56,o ,o ,o ,o ,30,3 ,31,o ,o ,o ,o ,o ,o ,o ,o ,31,3 ,3 ,o , /*42*/ +/*43*/ 7 ,55,55,55,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,16,12,17,13,13,13,13,13,13,13,13,13,13,13,22,22,22,21,62,o ,o ,o ,o ,2 ,2 ,2 ,56,o ,o ,o ,o ,30,3 ,60,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,3 ,o , /*43*/ +/*44*/ 7 ,55,55,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,16,12,17,13,13,13,13,13,13,13,13,13,13,13,22,22,22,21,o ,o ,o ,o ,o ,13,12,12,13,o ,o ,o ,o ,30,3 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,3 ,o , /*44*/ +/*45*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,o ,o ,16,12,17,13,13,13,13,13,13,13,13,13,13,37,22,22,37,21,62,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,30,3 ,31,o ,o ,o ,o ,o ,o ,55,o ,31,3 ,3 ,28, /*45*/ +/*46*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,21,21,21,21,21,22,22,49,30,30,13,13,13,13,13,13,13,13,13,49,22,37,21,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,30,3 ,o ,o ,o ,o ,o ,o ,o ,55,o ,o ,3 ,3 ,28, /*46*/ +/*47*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,21,21,21,21,21,22,22,22,13,30,13,13,13,13,13,13,13,13,13,49,22,37,21,62,o ,o ,o ,o ,13,12,12,13,o ,o ,o ,o ,30,3 ,o ,o ,o ,o ,o ,o ,o ,55,55,o ,3 ,3 ,28, /*47*/ +/*48*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,21,21,21,21,21,22,22,22,13,13,13,13,13,13,13,13,13,13,37,22,22,37,21,o ,o ,o ,o ,o ,2 ,2 ,2 ,2 ,o ,o ,o ,o ,30,3 ,3 ,3 ,3 ,o ,o ,o ,o ,3 ,3 ,3 ,3 ,3 ,28, /*48*/ +/*49*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,55,22,22,22,21,21,22,22,22,13,30,13,13,13,13,13,13,13,13,13,22,22,22,21,62,o ,o ,o ,o ,2 ,2 ,2 ,2 ,o ,o ,o ,o ,30,60,60,o ,3 ,o ,o ,o ,o ,3 ,o ,o ,o ,3 ,28, /*49*/ +/*50*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,61,22,22,22,21,21,22,22,37,13,30,30,30,30,30,30,13,13,13,13,22,22,22,21,o ,o ,o ,o ,60,2 ,2 ,2 ,2 ,o ,o ,o ,62,30,o ,o ,o ,3 ,3 ,o ,o ,3 ,3 ,o ,o ,o ,37,37, /*50*/ +/*51*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,56,2 ,2 ,36,22,21,21,22,22,49,13,13,13,13,13,13,30,13,13,13,13,37,22,22,49,o ,o ,o ,o ,o ,2 ,2 ,2 ,2 ,o ,o ,o ,o ,30,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,22, /*51*/ +/*52*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,55,2 ,61,36,22,22,22,22,22,49,49,37,22,22,22,22,22,22,49,13,13,22,22,22,22,16,o ,o ,o ,o ,2 ,2 ,2 ,2 ,o ,o ,o ,62,30,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,22, /*52*/ +/*53*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,13,13,22,22,22,22,12,o ,o ,o ,60,2 ,2 ,2 ,2 ,o ,o ,o ,o ,30,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,22,22, /*53*/ +/*54*/ 7 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,37,37,37,37,37,37,37,37,22,22,22,49,22,49,22,22,49,13,13,37,22,22,37,17,o ,o ,o ,o ,2 ,2 ,2 ,2 ,o ,o ,o ,21,21,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,60,22,22, /*54*/ +/*55*/ 7 ,o ,o ,8 ,9 ,10,10,10,9 ,8 ,o ,o ,o ,o ,o ,o ,o ,16,12,17,13,o ,o ,o ,o ,o ,o ,o ,o ,35,13,13,13,13,13,13,13,o ,o ,o ,o ,2 ,2 ,2 ,2 ,o ,o ,o ,21,21,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,7 ,7 ,22,22, /*55*/ +/*56*/ 22,22,23,23,23,23,EE,23,23,23,23,22,22,37,37,37,37,37,37,37,37,22,o ,o ,o ,o ,o ,o ,62,35,13,13,13,13,13,13,13,o ,o ,o ,o ,52,52,2 ,52,o ,o ,o ,21,21,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,7 ,o ,o ,o , /*56*/ +/*57*/ 22,22,23,20,20,14,14,14,20,23,23,22,22,22,22,22,22,22,23,23,23,22,8 ,o ,o ,o ,o ,o ,o ,35,17,17,12,16,o ,o ,o ,o ,o ,o ,o ,DD,2 ,2 ,2 ,o ,o ,o ,21,21,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,7 ,o ,o ,o , /*57*/ +/*58*/ 20,20,20,14,14,14,14,14,20,20,20,19,19,19,19,19,19,19,AA,20,20,22,9 ,o ,o ,o ,o ,o ,6 ,35,17,17,12,16,o ,o ,o ,o ,o ,o ,o ,DD,2 ,2 ,2 ,o ,o ,o ,21,21,o ,30,30,30,o ,o ,o ,o ,21,21,21,o ,o ,21, /*58*/ +/*59*/ 20,14,14,14,14,20,20,20,20,14,14,14,14,14,14,14,14,14,14,14,14,23,10,o ,o ,o ,o ,o ,21,21,17,17,37,37,37,37,23,23,23,23,23,3 ,3 ,3 ,3 ,o ,o ,o ,21,21,7 ,21,21,21,o ,o ,o ,56,21,21,21,2 ,o ,21, /*59*/ +/*60*/ 20,14,14,14,14,14,14,14,20,14,14,14,14,14,14,14,14,14,14,14,14,EE,10,o ,o ,o ,o ,o ,21,20,EE,EE,20,20,20,20,20,20,14,14,14,10,9 ,8 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,2 ,2 ,2 ,2 ,o ,21, /*60*/ +/*61*/ 20,14,14,14,14,14,14,14,EE,14,14,14,14,14,20,20,14,14,14,14,14,23,9 ,o ,o ,o ,o ,o ,21,20,14,14,14,EE,14,14,14,14,14,14,14,10,9 ,8 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61,2 ,2 ,2 ,2 ,61,o ,21, /*61*/ +/*62*/ 20,14,14,14,14,14,14,14,20,14,14,14,14,14,20,20,20,20,20,20,20,23,8 ,o ,o ,o ,6 ,o ,21,20,14,14,14,20,14,14,14,14,14,20,23,3 ,3 ,3 ,3 ,21,21,21,23,23,23,23,23,23,55,56,61,2 ,2 ,2 ,2 ,o ,o ,21, /*62*/ +/*63*/ 20,20,50,50,20,50,50,20,20,20,50,20,50,20,20,20,20,20,20,20,20,23,7 ,7 ,7 ,7 ,7 ,7 ,23,20,20,20,20,20,20,20,20,20,20,20,23,28,28,28,28,21,21,21,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23 /*63*/ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + #undef AA + #undef BB + #undef CC + #undef DD + #undef EE + #undef FF + #undef o + }, + { // tileDictionary + SFG_TD(10,31,1,0),SFG_TD(29,31,0,0),SFG_TD( 0,31,0,0),SFG_TD(17,31,2,0), // 0 + SFG_TD(10,31,2,0),SFG_TD(29,31,2,0),SFG_TD(14,31,5,0),SFG_TD(21,31,2,0), // 4 + SFG_TD(11,31,4,0),SFG_TD(12,31,4,0),SFG_TD(13,31,4,0),SFG_TD(14,31,4,0), // 8 + SFG_TD(12,31,2,0),SFG_TD(14,31,2,0),SFG_TD(13, 5,2,0),SFG_TD(14, 7,2,0), // 12 + SFG_TD(11,31,2,0),SFG_TD(13,31,2,0),SFG_TD(10, 7,0,0),SFG_TD(30,31,2,0), // 16 + SFG_TD(30, 0,2,0),SFG_TD(26,31,0,0),SFG_TD(30,31,0,0),SFG_TD(10, 0,0,0), // 20 + SFG_TD(10, 7,0,0),SFG_TD(10, 7,0,0),SFG_TD(15,31,6,0),SFG_TD(10, 0,3,3), // 24 + SFG_TD(24,31,6,0),SFG_TD(31, 0,2,0),SFG_TD(18,31,6,0),SFG_TD(13,31,6,0), // 28 + SFG_TD(14, 0,1,0),SFG_TD(10, 7,1,0),SFG_TD(13,31,2,0),SFG_TD(17,31,4,0), // 32 + SFG_TD(30,31,4,0),SFG_TD(30,31,3,0),SFG_TD(10, 7,0,0),SFG_TD(10, 7,0,0), // 36 + SFG_TD(11,31,2,0),SFG_TD(10, 7,0,0),SFG_TD(10, 7,0,0),SFG_TD(10, 7,0,0), // 40 + SFG_TD(14, 0,1,0),SFG_TD(10, 7,0,0),SFG_TD(10, 7,0,0),SFG_TD(10, 7,0,0), // 44 + SFG_TD(10, 7,0,0),SFG_TD(30,31,2,0),SFG_TD(15, 2,2,2),SFG_TD(13, 5,2,0), // 48 + SFG_TD( 9,31,5,0),SFG_TD(17, 0,3,3),SFG_TD(14,31,1,0),SFG_TD( 9,31,1,0), // 52 + SFG_TD( 6,31,1,0),SFG_TD(18,31,0,0),SFG_TD(10,11,3,3),SFG_TD( 0,10,5,0), // 56 + SFG_TD(12,31,1,0),SFG_TD( 3,31,1,0),SFG_TD(12,31,5,0),SFG_TD(13,17,5,0) // 60 + }, // tileDictionary + {1 ,9 ,12,14,5 ,0 ,6 }, // textureIndices + 7, // doorTextureIndex + 20, // floorColor + 3, // ceilingColor + {50, 24, 64 }, // player start: x, y, direction + 0, // backgroundImage + { // elements + {SFG_LEVEL_ELEMENT_BULLETS, {35,1}},{SFG_LEVEL_ELEMENT_BULLETS, {34,1}}, + {SFG_LEVEL_ELEMENT_RUIN, {6,5}},{SFG_LEVEL_ELEMENT_HEALTH, {30,6}}, + {SFG_LEVEL_ELEMENT_RUIN, {23,7}},{SFG_LEVEL_ELEMENT_HEALTH, {23,8}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {37,9}},{SFG_LEVEL_ELEMENT_RUIN, {4,9}}, + {SFG_LEVEL_ELEMENT_RUIN, {20,10}},{SFG_LEVEL_ELEMENT_CARD2, {5,10}}, + {SFG_LEVEL_ELEMENT_HEALTH, {26,11}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {22,11}}, + {SFG_LEVEL_ELEMENT_RUIN, {51,13}},{SFG_LEVEL_ELEMENT_RUIN, {50,13}}, + {SFG_LEVEL_ELEMENT_RUIN, {49,13}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {21,13}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {19,13}},{SFG_LEVEL_ELEMENT_ROCKETS, {55,14}}, + {SFG_LEVEL_ELEMENT_BULLETS, {54,14}},{SFG_LEVEL_ELEMENT_BULLETS, {9,16}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {16,17}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {7,17}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {6,18}},{SFG_LEVEL_ELEMENT_LAMP, {43,19}}, + {SFG_LEVEL_ELEMENT_LAMP, {21,19}},{SFG_LEVEL_ELEMENT_LAMP, {18,19}}, + {SFG_LEVEL_ELEMENT_CARD1, {9,20}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {8,20}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {50,21}},{SFG_LEVEL_ELEMENT_LAMP, {5,22}}, + {SFG_LEVEL_ELEMENT_TREE, {4,22}},{SFG_LEVEL_ELEMENT_RUIN, {34,23}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {53,24}},{SFG_LEVEL_ELEMENT_BLOCKER, {53,25}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {18,25}},{SFG_LEVEL_ELEMENT_RUIN, {1,25}}, + {SFG_LEVEL_ELEMENT_PLASMA, {49,27}},{SFG_LEVEL_ELEMENT_ROCKETS, {48,27}}, + {SFG_LEVEL_ELEMENT_PLASMA, {34,27}},{SFG_LEVEL_ELEMENT_BULLETS, {49,28}}, + {SFG_LEVEL_ELEMENT_LOCK2, {47,28}},{SFG_LEVEL_ELEMENT_LAMP, {15,28}}, + {SFG_LEVEL_ELEMENT_RUIN, {13,28}},{SFG_LEVEL_ELEMENT_PLASMA, {49,29}}, + {SFG_LEVEL_ELEMENT_HEALTH, {48,29}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {45,29}}, + {SFG_LEVEL_ELEMENT_LAMP, {35,32}},{SFG_LEVEL_ELEMENT_LAMP, {21,32}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {7,32}},{SFG_LEVEL_ELEMENT_FINISH, {56,34}}, + {SFG_LEVEL_ELEMENT_FINISH, {55,34}},{SFG_LEVEL_ELEMENT_PLASMA, {24,34}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {56,35}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {55,35}}, + {SFG_LEVEL_ELEMENT_BULLETS, {24,35}},{SFG_LEVEL_ELEMENT_BARREL, {20,35}}, + {SFG_LEVEL_ELEMENT_PLASMA, {9,35}},{SFG_LEVEL_ELEMENT_BULLETS, {5,35}}, + {SFG_LEVEL_ELEMENT_COLUMN, {57,37}},{SFG_LEVEL_ELEMENT_COLUMN, {54,37}}, + {SFG_LEVEL_ELEMENT_BULLETS, {15,37}},{SFG_LEVEL_ELEMENT_HEALTH, {60,38}}, + {SFG_LEVEL_ELEMENT_RUIN, {44,38}},{SFG_LEVEL_ELEMENT_ROCKETS, {26,39}}, + {SFG_LEVEL_ELEMENT_CARD0, {34,40}},{SFG_LEVEL_ELEMENT_LOCK1, {11,40}}, + {SFG_LEVEL_ELEMENT_PLASMA, {19,41}},{SFG_LEVEL_ELEMENT_TERMINAL, {14,41}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {55,42}},{SFG_LEVEL_ELEMENT_TREE, {36,42}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {19,42}},{SFG_LEVEL_ELEMENT_HEALTH, {60,44}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {56,44}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {54,44}}, + {SFG_LEVEL_ELEMENT_TREE, {48,44}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {33,44}}, + {SFG_LEVEL_ELEMENT_BULLETS, {48,45}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {27,45}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {26,45}},{SFG_LEVEL_ELEMENT_COLUMN, {15,45}}, + {SFG_LEVEL_ELEMENT_TREE, {48,46}},{SFG_LEVEL_ELEMENT_LAMP, {1,47}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {15,48}},{SFG_LEVEL_ELEMENT_ROCKETS, {14,48}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {7,48}},{SFG_LEVEL_ELEMENT_HEALTH, {61,49}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {6,49}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {3,49}}, + {SFG_LEVEL_ELEMENT_TREE, {36,50}},{SFG_LEVEL_ELEMENT_HEALTH, {5,50}}, + {SFG_LEVEL_ELEMENT_LAMP, {58,51}},{SFG_LEVEL_ELEMENT_LAMP, {53,51}}, + {SFG_LEVEL_ELEMENT_HEALTH, {26,51}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {12,51}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {7,51}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {26,53}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {5,53}},{SFG_LEVEL_ELEMENT_LAMP, {1,53}}, + {SFG_LEVEL_ELEMENT_PLASMA, {58,55}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {55,55}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {50,55}},{SFG_LEVEL_ELEMENT_BLOCKER, {29,55}}, + {SFG_LEVEL_ELEMENT_BARREL, {13,55}},{SFG_LEVEL_ELEMENT_BLOCKER, {29,56}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {25,56}},{SFG_LEVEL_ELEMENT_BLOCKER, {29,57}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {24,57}},{SFG_LEVEL_ELEMENT_RUIN, {47,58}}, + {SFG_LEVEL_ELEMENT_RUIN, {46,58}},{SFG_LEVEL_ELEMENT_BLOCKER, {29,58}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {23,58}},{SFG_LEVEL_ELEMENT_BULLETS, {21,58}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {18,58}},{SFG_LEVEL_ELEMENT_RUIN, {46,59}}, + {SFG_LEVEL_ELEMENT_RUIN, {45,59}},{SFG_LEVEL_ELEMENT_LOCK0, {31,60}}, + {SFG_LEVEL_ELEMENT_LOCK0, {30,60}},{SFG_LEVEL_ELEMENT_TREE, {7,60}}, + {SFG_LEVEL_ELEMENT_LOCK1, {33,61}},{SFG_LEVEL_ELEMENT_TREE, {16,61}}, + {SFG_LEVEL_ELEMENT_TREE, {13,61}},{SFG_LEVEL_ELEMENT_LOCK0, {8,61}}, + {SFG_LEVEL_ELEMENT_BARREL, {27,62}},{SFG_LEVEL_ELEMENT_HEALTH, {25,62}}, + {SFG_LEVEL_ELEMENT_TREE, {1,62}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}} + }, // elements + } // level + ; + +SFG_PROGRAM_MEMORY SFG_Level SFG_level6 = + { // level + { // mapArray + #define o 0 + #define AA (17 | SFG_TILE_PROPERTY_DOOR) + #define BB (33 | SFG_TILE_PROPERTY_DOOR) + #define CC (16 | SFG_TILE_PROPERTY_ELEVATOR) + #define DD (1 | SFG_TILE_PROPERTY_DOOR) + #define EE (41 | SFG_TILE_PROPERTY_ELEVATOR) + #define FF (55 | SFG_TILE_PROPERTY_DOOR) + #define GG (56 | SFG_TILE_PROPERTY_ELEVATOR) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +/*0 */ 1 ,1 ,1 ,1 ,1 ,5 ,1 ,1 ,1 ,1 ,1 ,1 ,5 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,33,50,50,33,33,33,50,5 ,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,o ,o ,o ,o ,o , /*0 */ +/*1 */ 47,14,14,1 ,13,13,13,13,13,13,13,13,13,13,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,31,31,50,31,31,31,50,5 ,19,19,19,5 ,19,19,19,5 ,19,19,19,5 ,5 ,19,19,19,19,19,20,o ,o ,o ,o ,o , /*1 */ +/*2 */ 47,14,14,15,13,13,13,13,13,13,13,13,13,13,1 ,5 ,5 ,33,50,50,50,33,5 ,5 ,5 ,33,50,50,50,33,5 ,5 ,31,31,50,31,31,31,50,50,50,33,50,50,50,33,50,50,50,33,50,50,5 ,19,19,19,19,19,20,o ,o ,o ,o ,o , /*2 */ +/*3 */ 63,14,14,15,13,13,13,13,13,13,13,13,13,13,1 ,5 ,31,31,31,50,31,31,31,5 ,31,31,31,50,31,31,31,5 ,31,31,50,31,31,31,50,5 ,31,31,31,50,31,31,31,5 ,31,31,31,31,19,19,19,19,19,19,20,o ,o ,o ,o ,o , /*3 */ +/*4 */ 63,14,14,15,13,13,13,35,35,35,35,13,13,13,1 ,1 ,31,31,34,63,34,31,31,1 ,31,31,34,63,34,31,31,1 ,31,31,50,31,31,31,50,5 ,31,31,34,63,34,31,31,5 ,31,31,31,31,5 ,19,19,19,19,19,20,o ,o ,o ,o ,o , /*4 */ +/*5 */ 1 ,1 ,AA,1 ,13,13,13,35,13,13,35,13,13,13,1 ,5 ,31,31,31,50,31,31,31,5 ,31,31,31,50,31,31,31,5 ,31,31,50,31,31,31,50,50,31,31,31,50,31,31,31,50,31,31,31,50,5 ,1 ,19,19,19,19,20,o ,o ,o ,o ,o , /*5 */ +/*6 */ 1 ,1 ,CC,1 ,13,13,13,35,35,35,35,13,13,13,1 ,5 ,31,31,34,63,34,31,31,5 ,31,31,34,63,34,31,31,5 ,31,31,BB,31,31,31,50,5 ,31,31,34,63,34,31,31,5 ,31,31,34,63,5 ,24,19,19,19,19,20,o ,o ,o ,o ,o , /*6 */ +/*7 */ o ,1 ,DD,1 ,13,13,13,13,13,13,13,13,13,13,1 ,1 ,31,31,34,63,34,31,31,1 ,31,31,34,63,34,31,31,1 ,31,31,50,31,31,31,50,50,31,31,34,63,34,31,31,50,31,31,34,63,5 ,24,19,19,19,19,20,o ,o ,o ,o ,o , /*7 */ +/*8 */ o ,1 ,18,18,13,13,13,13,13,13,13,13,13,13,1 ,5 ,31,31,31,50,31,31,31,5 ,31,31,31,50,31,31,31,5 ,31,50,31,31,31,31,31,50,31,31,31,50,31,31,31,50,31,31,31,50,5 ,24,19,19,19,19,20,o ,o ,o ,o ,o , /*8 */ +/*9 */ o ,1 ,13,13,13,13,13,13,13,13,13,13,13,13,1 ,50,50,BB,50,63,50,BB,50,63,50,BB,50,63,50,BB,50,63,50,31,31,31,31,31,31,31,50,BB,50,63,50,BB,50,63,50,BB,50,63,5 ,1 ,19,19,19,19,20,o ,o ,o ,o ,o , /*9 */ +/*10*/ o ,1 ,13,13,13,13,13,13,13,13,13,13,13,13,1 ,50,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,49,49,49,31,31,31,31,31,31,31,31,31,31,31,31,31,50,5 ,19,19,19,19,19,20,o ,o ,o ,o ,o , /*10*/ +/*11*/ 1 ,1 ,13,13,13,13,13,13,13,13,13,13,13,13,1 ,50,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,45,49,45,31,31,31,31,31,31,31,31,31,31,31,31,31,50,5 ,19,19,19,19,19,20,o ,o ,o ,o ,o , /*11*/ +/*12*/ 1 ,14,13,13,13,13,13,13,13,13,13,13,13,13,1 ,50,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,45,45,45,31,31,31,31,31,31,31,31,31,31,31,31,31,50,5 ,19,19,19,19,19,20,o ,o ,o ,o ,o , /*12*/ +/*13*/ 1 ,14,13,13,13,13,13,13,13,13,13,13,35,13,1 ,50,50,BB,50,63,50,BB,50,63,50,BB,50,63,50,BB,50,63,50,31,31,31,31,31,31,31,50,BB,50,63,50,BB,50,63,50,BB,50,63,1 ,24,24,1 ,5 ,5 ,1 ,1 ,1 ,1 ,o ,o , /*13*/ +/*14*/ 1 ,14,13,13,13,13,13,13,13,13,13,13,35,18,1 ,5 ,31,31,31,50,31,31,31,5 ,31,31,31,50,31,31,31,5 ,31,50,31,31,31,31,31,50,31,31,31,50,31,31,31,5 ,31,31,31,50,1 ,40,40,1 ,3 ,3 ,1 ,40,40,1 ,o ,o , /*14*/ +/*15*/ 1 ,14,1 ,1 ,1 ,5 ,1 ,3 ,3 ,3 ,3 ,1 ,5 ,DD,5 ,1 ,31,31,34,63,34,31,31,5 ,31,31,34,63,34,31,31,5 ,31,31,50,31,31,31,50,50,31,31,34,63,34,31,31,5 ,31,31,34,63,1 ,40,13,13,3 ,3 ,13,13,40,1 ,1 ,20, /*15*/ +/*16*/ 1 ,14,14,1 ,o ,o ,1 ,24,24,24,24,1 ,14,CC,14,1 ,31,31,34,63,34,31,31,1 ,31,31,34,63,34,31,31,1 ,31,31,50,31,31,31,50,5 ,31,31,34,63,34,31,31,50,31,31,34,63,1 ,40,13,13,3 ,3 ,13,13,40,5 ,19,20, /*16*/ +/*17*/ 1 ,14,14,1 ,o ,o ,1 ,24,24,24,24,1 ,14,14,14,1 ,31,31,31,50,31,31,31,1 ,31,31,31,50,31,31,31,5 ,31,31,50,31,31,31,50,50,31,31,31,50,31,31,31,50,31,31,31,50,1 ,40,40,1 ,3 ,3 ,1 ,40,40,40,19,20, /*17*/ +/*18*/ 1 ,14,14,1 ,o ,o ,1 ,1 ,24,24,1 ,1 ,14,14,14,1 ,31,31,34,63,34,31,31,5 ,31,31,34,63,34,31,31,5 ,31,31,50,31,31,31,50,5 ,31,31,31,31,34,31,31,5 ,31,31,34,63,1 ,40,13,13,3 ,3 ,13,13,40,40,19,20, /*18*/ +/*19*/ 1 ,14,14,1 ,1 ,1 ,1 ,24,24,24,24,1 ,14,14,14,1 ,31,31,31,50,31,31,31,5 ,31,31,31,50,31,31,31,BB,31,31,50,31,31,31,50,5 ,31,31,31,31,31,31,31,5 ,31,31,31,50,1 ,40,13,13,3 ,3 ,13,13,40,5 ,19,20, /*19*/ +/*20*/ 1 ,14,14,1 ,14,14,1 ,13,13,13,13,1 ,14,14,14,1 ,5 ,5 ,36,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,31,31,31,50,50,50,50,50,50,50,50,50,50,50,50,50,50,1 ,40,40,1 ,3 ,3 ,1 ,40,40,1 ,1 ,20, /*20*/ +/*21*/ 1 ,14,14,1 ,14,14,14,14,13,13,14,14,14,14,14,1 ,4 ,4 ,36,4 ,4 ,4 ,50,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,50,1 ,1 ,1 ,1 ,1 ,1 ,1 ,63,63,63,63,63,63,1 ,40,13,13,3 ,3 ,13,13,40,1 ,o ,o , /*21*/ +/*22*/ 1 ,14,14,14,14,14,1 ,13,13,13,13,1 ,14,14,14,1 ,4 ,4 ,36,36,36,4 ,50,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,50,1 ,2 ,2 ,DD,2 ,o ,24,o ,24,o ,24,24,24,24,40,13,13,3 ,3 ,13,13,40,1 ,o ,o , /*22*/ +/*23*/ 1 ,14,14,14,14,14,1 ,13,13,13,13,1 ,37,1 ,37,1 ,4 ,4 ,4 ,4 ,36,4 ,50,31,31,31,31,30,30,32,30,30,31,31,31,50,50,50,50,1 ,2 ,2 ,1 ,2 ,o ,24,o ,24,o ,24,24,24,24,40,40,1 ,3 ,3 ,1 ,40,40,1 ,o ,o , /*23*/ +/*24*/ 1 ,1 ,1 ,1 ,14,14,14,13,13,13,13,24,24,24,24,24,13,13,13,4 ,36,4 ,63,31,31,31,31,29,29,32,29,29,31,31,31,1 ,o ,o ,2 ,1 ,2 ,2 ,1 ,1 ,1 ,1 ,63,63,63,63,63,63,1 ,40,40,40,3 ,3 ,40,40,40,1 ,o ,o , /*24*/ +/*25*/ o ,o ,o ,1 ,14,14,14,13,13,13,13,24,24,24,24,24,13,13,13,36,36,4 ,63,31,31,31,31,28,28,32,28,28,31,31,31,1 ,o ,o ,2 ,DD,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,40,40,40,3 ,3 ,40,40,40,1 ,o ,o , /*25*/ +/*26*/ o ,o ,o ,1 ,14,14,14,13,13,13,13,24,24,24,24,24,13,13,13,4 ,4 ,4 ,63,31,31,31,31,27,27,32,27,27,31,31,31,1 ,40,40,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,5 ,5 ,1 ,1 ,1 ,1 ,o ,o , /*26*/ +/*27*/ o ,o ,o ,1 ,4 ,4 ,4 ,36,4 ,4 ,36,1 ,37,1 ,37,1 ,24,24,24,1 ,1 ,1 ,1 ,31,31,31,31,26,26,26,26,26,31,31,31,1 ,40,40,1 ,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, /*27*/ +/*28*/ 4 ,4 ,4 ,4 ,4 ,4 ,4 ,36,36,36,36,36,4 ,1 ,1 ,37,24,24,24,37,37,37,1 ,31,31,31,32,25,25,25,25,25,32,31,31,1 ,40,40,1 ,55,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,55, /*28*/ +/*29*/ 46,58,58,58,58,58,4 ,4 ,4 ,4 ,4 ,31,4 ,1 ,1 ,1 ,40,40,40,40,40,24,24,24,24,24,24,24,24,24,24,24,24,24,24,5 ,40,40,1 ,55,o ,1 ,1 ,1 ,o ,1 ,1 ,1 ,o ,1 ,1 ,o ,1 ,1 ,o ,1 ,1 ,1 ,o ,1 ,1 ,o ,o ,55, /*29*/ +/*30*/ 46,58,58,58,58,58,58,58,58,29,30,31,4 ,1 ,1 ,1 ,40,40,40,40,40,24,24,24,24,24,24,24,24,24,24,24,24,24,24,40,40,40,1 ,55,o ,o ,1 ,o ,o ,o ,1 ,1 ,o ,o ,1 ,o ,o ,1 ,o ,o ,1 ,1 ,o ,o ,1 ,o ,o ,55, /*30*/ +/*31*/ 46,58,58,58,58,58,4 ,4 ,4 ,4 ,4 ,4 ,4 ,1 ,1 ,1 ,40,40,40,40,40,24,24,24,24,24,24,24,24,24,24,24,24,24,24,40,40,40,1 ,55,o ,o ,1 ,o ,o ,1 ,1 ,1 ,o ,o ,1 ,o ,1 ,1 ,o ,1 ,1 ,1 ,o ,o ,1 ,1 ,o ,55, /*31*/ +/*32*/ 4 ,4 ,4 ,4 ,4 ,4 ,4 ,39,39,39,39,39,39,1 ,1 ,1 ,40,40,40,40,40,24,24,24,24,24,24,24,24,24,24,24,24,24,24,5 ,40,40,1 ,55,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,55, /*32*/ +/*33*/ 39,39,39,39,39,39,39,39,o ,o ,o ,o ,o ,3 ,3 ,3 ,40,40,40,1 ,1 ,31,31,31,31,31,24,31,31,31,31,31,31,31,24,31,31,1 ,1 ,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, /*33*/ +/*34*/ 60,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,3 ,3 ,40,40,40,1 ,5 ,31,31,31,31,31,24,31,31,31,31,31,31,31,24,31,31,1 ,1 ,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,63, /*34*/ +/*35*/ 60,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,3 ,3 ,40,40,40,1 ,63,31,31,24,24,24,24,63,1 ,1 ,1 ,24,24,24,24,31,31,1 ,1 ,39,39,39,52,52,52,52,52,52,24,24,26,EE,EE,EE,24,24,24,52,52,52,52,52,52,7 , /*35*/ +/*36*/ 60,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,39,o ,61,1 ,1 ,1 ,1 ,63,31,31,24,24,24,24,63,1 ,1 ,1 ,24,24,24,24,31,31,1 ,1 ,39,39,39,39,39,52,52,52,52,24,24,24,EE,EE,EE,24,24,24,52,52,52,52,52,52,63, /*36*/ +/*37*/ 39,39,5 ,o ,o ,5 ,5 ,o ,5 ,5 ,o ,o ,o ,39,o ,61,1 ,1 ,1 ,1 ,63,31,31,24,24,24,24,63,1 ,1 ,1 ,24,24,24,24,31,31,1 ,1 ,1 ,1 ,1 ,1 ,39,52,52,52,39,24,24,26,EE,EE,EE,26,24,24,52,52,52,52,52,52,7 , /*37*/ +/*38*/ o ,o ,39,o ,o ,39,o ,o ,o ,39,o ,o ,o ,39,o ,61,1 ,1 ,1 ,1 ,5 ,31,31,31,31,31,24,31,31,31,1 ,24,24,24,24,31,31,31,31,30,29,28,1 ,39,52,52,52,39,24,24,26,26,24,24,5 ,24,24,4 ,39,39,39,39,39,63, /*38*/ +/*39*/ o ,o ,39,o ,o ,5 ,o ,o ,o ,5 ,39,39,39,39,o ,61,1 ,1 ,1 ,1 ,1 ,31,31,31,31,31,24,31,31,31,1 ,24,24,24,24,31,31,31,31,30,29,28,1 ,39,39,39,o ,39,24,24,24,24,24,24,5 ,24,24,o ,4 ,o ,o ,o ,o ,o , /*39*/ +/*40*/ o ,o ,39,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,39,o ,61,61,61,61,61,61,24,24,24,24,24,24,1 ,30,30,1 ,1 ,1 ,1 ,1 ,1 ,1 ,o ,o ,25,26,27,1 ,o ,o ,39,o ,39,24,24,24,24,24,24,5 ,24,24,o ,o ,4 ,o ,o ,o ,o , /*40*/ +/*41*/ o ,o ,39,o ,o ,5 ,o ,o ,o ,o ,o ,o ,o ,39,o ,o ,o ,o ,o ,o ,o ,24,24,24,24,24,24,1 ,29,29,1 ,1 ,1 ,63,63,63,1 ,o ,o ,25,26,27,1 ,o ,o ,o ,o ,39,4 ,4 ,5 ,5 ,5 ,5 ,4 ,4 ,4 ,o ,o ,o ,4 ,o ,o ,o , /*41*/ +/*42*/ o ,o ,39,o ,o ,39,o ,o ,o ,o ,o ,o ,o ,39,o ,61,61,61,61,61,61,24,24,24,24,24,24,63,28,28,27,26,25,24,24,24,24,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,53,o ,51,38,38,38,4 ,o ,o ,o ,4 ,o ,o ,o ,4 ,o ,o , /*42*/ +/*43*/ o ,o ,39,o ,o ,5 ,5 ,o ,5 ,39,5 ,o ,o ,39,o ,61,51,51,51,51,61,24,24,24,24,24,24,63,28,28,27,26,25,24,24,24,24,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,53,o ,51,38,38,38,o ,o ,4 ,o ,4 ,4 ,o ,o ,o ,4 ,o , /*43*/ +/*44*/ 39,39,5 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,39,o ,5 ,52,51,51,51,61,24,24,24,24,24,24,63,63,63,1 ,1 ,1 ,24,24,24,1 ,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,53,o ,51,38,38,38,o ,4 ,1 ,o ,4 ,1 ,4 ,o ,o ,o ,4 , /*44*/ +/*45*/ 1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,39,o ,o ,o ,51,51,51,5 ,61,61,61,o ,o ,61,61,51,51,51,51,12,24,24,24,12,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,53,o ,51,38,38,38,o ,4 ,4 ,o ,o ,o ,o ,4 ,o ,o ,60, /*45*/ +/*46*/ 1 ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,39,39,39,39,o ,5 ,52,51,51,51,61,3 ,3 ,3 ,3 ,3 ,o ,52,51,51,51,51,1 ,24,24,24,1 ,o ,o ,o ,o ,o ,1 ,59,53,53,53,53,o ,51,38,38,38,o ,o ,4 ,o ,o ,o ,o ,4 ,o ,o ,4 , /*46*/ +/*47*/ 1 ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,DD,2 ,o ,o ,o ,61,51,51,51,51,61,3 ,3 ,3 ,3 ,3 ,o ,52,51,51,51,51,12,24,24,24,12,o ,o ,o ,o ,o ,1 ,59,59,59,59,59,o ,51,38,38,38,4 ,o ,1 ,o ,4 ,1 ,4 ,4 ,o ,o ,60, /*47*/ +/*48*/ 1 ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,61,o ,o ,o ,o ,61,61,61,61,61,61,3 ,3 ,61,3 ,3 ,61,52,52,52,52,1 ,1 ,o ,o ,o ,1 ,o ,o ,o ,o ,o ,1 ,4 ,4 ,59,4 ,4 ,o ,51,38,38,38,4 ,o ,4 ,o ,o ,o ,o ,4 ,o ,o ,4 , /*48*/ +/*49*/ 60,o ,o ,63,48,48,48,48,48,48,63,63,63,63,63,63,5 ,24,5 ,6 ,6 ,3 ,3 ,3 ,3 ,3 ,6 ,6 ,6 ,48,48,1 ,1 ,1 ,2 ,1 ,1 ,o ,o ,o ,o ,o ,1 ,4 ,57,59,57,4 ,o ,51,38,38,38,o ,o ,4 ,o ,o ,o ,o ,4 ,o ,o ,60, /*49*/ +/*50*/ 60,o ,o ,63,6 ,6 ,6 ,6 ,6 ,6 ,25,26,27,28,29,30,30,24,24,6 ,6 ,3 ,3 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,1 ,1 ,1 ,DD,1 ,1 ,1 ,o ,o ,o ,1 ,1 ,4 ,4 ,59,4 ,4 ,o ,51,38,38,38,o ,4 ,1 ,o ,4 ,1 ,4 ,4 ,o ,o ,4 , /*50*/ +/*51*/ 60,o ,o ,63,6 ,6 ,6 ,6 ,6 ,6 ,25,26,27,28,29,30,30,24,24,6 ,6 ,3 ,3 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,1 ,1 ,o ,2 ,2 ,2 ,o ,1 ,1 ,1 ,1 ,1 ,1 ,4 ,57,59,57,4 ,o ,51,38,38,38,o ,o ,4 ,o ,o ,o ,o ,5 ,o ,o ,60, /*51*/ +/*52*/ 60,o ,o ,63,6 ,6 ,6 ,6 ,6 ,6 ,25,26,27,28,29,30,5 ,6 ,5 ,1 ,63,63,63,63,1 ,1 ,6 ,6 ,6 ,5 ,1 ,o ,o ,o ,o ,o ,o ,o ,1 ,4 ,4 ,4 ,4 ,4 ,4 ,59,4 ,4 ,o ,51,38,38,38,4 ,o ,4 ,o ,o ,o ,o ,40,24,24,4 , /*52*/ +/*53*/ 60,o ,o ,63,6 ,6 ,6 ,6 ,6 ,6 ,25,26,27,28,29,30,5 ,6 ,6 ,48,6 ,6 ,6 ,6 ,6 ,5 ,6 ,6 ,6 ,5 ,1 ,o ,o ,o ,o ,o ,o ,o ,1 ,4 ,4 ,4 ,4 ,24,24,24,24,4 ,o ,51,38,38,38,4 ,24,4 ,o ,o ,o ,o ,40,24,24,4 , /*53*/ +/*54*/ 1 ,o ,o ,1 ,6 ,6 ,6 ,6 ,6 ,6 ,25,26,27,28,29,30,5 ,6 ,6 ,48,6 ,6 ,6 ,6 ,6 ,5 ,6 ,6 ,6 ,2 ,1 ,2 ,o ,3 ,3 ,3 ,o ,2 ,1 ,2 ,o ,o ,o ,24,24,24,62,4 ,o ,51,38,38,38,4 ,24,4 ,o ,o ,o ,o ,5 ,24,24,4 , /*54*/ +/*55*/ 5 ,25,25,5 ,25,25,5 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,5 ,6 ,6 ,48,6 ,6 ,6 ,6 ,6 ,5 ,6 ,6 ,6 ,2 ,DD,2 ,o ,3 ,3 ,3 ,o ,2 ,DD,2 ,o ,3 ,3 ,24,24,24,24,4 ,4 ,4 ,5 ,5 ,5 ,4 ,54,4 ,4 ,4 ,1 ,1 ,4 ,54,24,4 , /*55*/ +/*56*/ 1 ,26,26,1 ,26,26,1 ,31,31,31,31,31,31,31,31,1 ,5 ,6 ,6 ,48,48,48,48,48,6 ,5 ,6 ,6 ,6 ,2 ,1 ,2 ,o ,3 ,3 ,3 ,o ,2 ,1 ,2 ,o ,o ,o ,24,24,24,62,4 ,53,53,53,53,53,4 ,FF,4 ,53,53,4 ,4 ,4 ,FF,4 ,4 , /*56*/ +/*57*/ 5 ,27,27,5 ,27,27,5 ,31,31,31,31,31,31,31,31,1 ,5 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,6 ,6 ,6 ,5 ,1 ,o ,o ,o ,o ,o ,o ,o ,1 ,4 ,4 ,4 ,4 ,24,24,24,24,4 ,4 ,4 ,4 ,62,24,24,54,24,24,62,4 ,40,40,54,40,4 , /*57*/ +/*58*/ 1 ,28,28,1 ,28,28,1 ,31,31,31,31,31,31,31,31,1 ,5 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,1 ,6 ,6 ,6 ,5 ,1 ,o ,o ,o ,o ,o ,o ,o ,1 ,4 ,58,58,58,4 ,58,4 ,4 ,4 ,58,58,4 ,24,24,24,24,24,24,24,4 ,24,24,24,24,4 , /*58*/ +/*59*/ 5 ,28,28,5 ,28,28,5 ,30,30,50,50,5 ,BB,5 ,50,50,5 ,o ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,o ,o ,o ,o ,o ,1 ,1 ,4 ,58,4 ,58,4 ,58,4 ,58,58,58,58,4 ,24,24,24,24,24,24,24,4 ,24,24,24,24,4 , /*59*/ +/*60*/ 1 ,28,28,1 ,28,28,1 ,29,29,50,31,34,31,31,31,50,5 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,3 ,3 ,o ,o ,1 ,1 ,1 ,o ,1 ,1 ,1 ,4 ,4 ,58,4 ,58,58,58,4 ,58,58,4 ,58,4 ,24,24,24,24,24,24,24,58,24,24,24,24,4 , /*60*/ +/*61*/ 1 ,28,28,28,28,28,28,28,28,50,31,34,31,31,31,50,5 ,o ,1 ,o ,o ,o ,o ,o ,o ,o ,3 ,3 ,3 ,o ,o ,2 ,2 ,1 ,o ,1 ,4 ,4 ,58,58,58,4 ,4 ,4 ,4 ,4 ,58,58,4 ,58,4 ,4 ,24,24,24,24,54,54,4 ,24,24,24,24,4 , /*61*/ +/*62*/ 1 ,28,28,28,28,28,28,28,28,50,31,31,31,31,31,50,5 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,2 ,1 ,o ,1 ,4 ,4 ,58,4 ,58,58,58,58,58,58,58,58,4 ,58,58,58,GG,24,24,24,54,54,4 ,40,40,40,40,4 , /*62*/ +/*63*/ 1 ,1 ,1 ,37,1 ,1 ,37,1 ,1 ,50,50,33,50,33,50,50,5 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,7 ,1 ,7 ,7 ,7 ,7 ,7 ,7 ,1 ,1 ,DD,1 ,4 ,4 ,46,4 ,4 ,57,4 ,57,4 ,57,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,60,60,4 ,4 /*63*/ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + #undef AA + #undef BB + #undef CC + #undef DD + #undef EE + #undef FF + #undef GG + #undef o + }, + { // tileDictionary + SFG_TD( 8, 6,1,1),SFG_TD(13, 0,0,0),SFG_TD( 9, 5,0,0),SFG_TD( 8, 8,0,0), // 0 + SFG_TD(13, 0,2,2),SFG_TD(13, 0,3,3),SFG_TD( 8, 9,0,0),SFG_TD(11, 3,4,0), // 4 + SFG_TD(10, 5,0,0),SFG_TD(10, 5,0,0),SFG_TD(10, 5,0,0),SFG_TD(10, 5,0,0), // 8 + SFG_TD(10, 2,0,0),SFG_TD( 8,21,0,0),SFG_TD(23, 6,0,0),SFG_TD(25, 2,0,0), // 12 + SFG_TD( 9,14,2,0),SFG_TD(27, 0,0,0),SFG_TD( 9,20,0,0),SFG_TD( 8,31,1,1), // 16 + SFG_TD(11, 0,0,7),SFG_TD(10, 5,0,0),SFG_TD(10, 5,0,0),SFG_TD(10, 5,0,0), // 20 + SFG_TD( 8,13,0,0),SFG_TD( 9,12,0,0),SFG_TD(10,11,0,0),SFG_TD(11,10,0,0), // 24 + SFG_TD(12, 9,0,0),SFG_TD(13, 8,0,0),SFG_TD(14, 7,0,0),SFG_TD(15, 6,0,0), // 28 + SFG_TD(18, 3,3,0),SFG_TD(19, 0,6,4),SFG_TD(17, 4,4,0),SFG_TD(10,19,1,0), // 32 + SFG_TD(17, 4,2,2),SFG_TD(13, 0,1,1),SFG_TD( 4, 9,1,1),SFG_TD(11, 0,1,0), // 36 + SFG_TD( 8, 6,1,0),SFG_TD( 7, 1,1,0),SFG_TD(10, 5,0,0),SFG_TD(10, 5,0,0), // 40 + SFG_TD(10, 5,0,0),SFG_TD(18, 4,3,0),SFG_TD(17, 0,6,0),SFG_TD(27, 0,6,0), // 44 + SFG_TD(10, 3,4,4),SFG_TD(15, 7,0,0),SFG_TD(19, 0,0,4),SFG_TD( 6, 8,1,1), // 48 + SFG_TD( 7, 7,1,1),SFG_TD(11, 0,2,5),SFG_TD( 9,12,0,0),SFG_TD(13, 0,5,5), // 52 + SFG_TD( 8, 5,2,2),SFG_TD( 5, 0,5,5),SFG_TD(13, 4,2,2),SFG_TD( 8, 7,2,2), // 56 + SFG_TD(12, 0,6,0),SFG_TD(14, 0,0,1),SFG_TD(11,10,5,0),SFG_TD( 0, 0,4,4) // 60 + }, // tileDictionary + {12,3 ,11,14,4 ,8 ,10}, // textureIndices + 7, // doorTextureIndex + 58, // floorColor + 2, // ceilingColor + {34, 59, 64 }, // player start: x, y, direction + 0, // backgroundImage + { // elements + {SFG_LEVEL_ELEMENT_PLASMA, {33,1}},{SFG_LEVEL_ELEMENT_HEALTH, {8,1}}, + {SFG_LEVEL_ELEMENT_CARD1, {2,1}},{SFG_LEVEL_ELEMENT_HEALTH, {1,1}}, + {SFG_LEVEL_ELEMENT_RUIN, {52,3}},{SFG_LEVEL_ELEMENT_BULLETS, {20,3}}, + {SFG_LEVEL_ELEMENT_RUIN, {51,4}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {41,7}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {36,8}},{SFG_LEVEL_ELEMENT_PLASMA, {7,8}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {8,9}},{SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {6,9}}, + {SFG_LEVEL_ELEMENT_HEALTH, {53,10}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {10,10}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {4,10}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {40,11}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {36,11}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {32,11}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {7,11}},{SFG_LEVEL_ELEMENT_ROCKETS, {1,12}}, + {SFG_LEVEL_ELEMENT_LOCK0, {17,13}},{SFG_LEVEL_ELEMENT_PLASMA, {1,13}}, + {SFG_LEVEL_ELEMENT_TREE, {57,14}},{SFG_LEVEL_ELEMENT_TREE, {56,14}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {17,14}},{SFG_LEVEL_ELEMENT_HEALTH, {33,15}}, + {SFG_LEVEL_ELEMENT_CARD0, {62,17}},{SFG_LEVEL_ELEMENT_BULLETS, {46,17}}, + {SFG_LEVEL_ELEMENT_RUIN, {43,18}},{SFG_LEVEL_ELEMENT_ROCKETS, {20,18}}, + {SFG_LEVEL_ELEMENT_PLASMA, {17,18}},{SFG_LEVEL_ELEMENT_LOCK0, {42,22}}, + {SFG_LEVEL_ELEMENT_COLUMN, {29,23}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {8,23}}, + {SFG_LEVEL_ELEMENT_HEALTH, {20,24}},{SFG_LEVEL_ELEMENT_TERMINAL, {41,25}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {14,25}},{SFG_LEVEL_ELEMENT_COLUMN, {29,26}}, + {SFG_LEVEL_ELEMENT_LAMP, {32,28}},{SFG_LEVEL_ELEMENT_LAMP, {26,28}}, + {SFG_LEVEL_ELEMENT_RUIN, {20,29}},{SFG_LEVEL_ELEMENT_HEALTH, {61,30}}, + {SFG_LEVEL_ELEMENT_PLASMA, {59,30}},{SFG_LEVEL_ELEMENT_HEALTH, {55,30}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {52,30}},{SFG_LEVEL_ELEMENT_PLASMA, {45,30}}, + {SFG_LEVEL_ELEMENT_RUIN, {20,30}},{SFG_LEVEL_ELEMENT_TELEPORTER, {2,30}}, + {SFG_LEVEL_ELEMENT_RUIN, {20,31}},{SFG_LEVEL_ELEMENT_RUIN, {19,32}}, + {SFG_LEVEL_ELEMENT_RUIN, {20,33}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {22,34}}, + {SFG_LEVEL_ELEMENT_BULLETS, {62,35}},{SFG_LEVEL_ELEMENT_ROCKETS, {61,35}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {42,35}},{SFG_LEVEL_ELEMENT_BULLETS, {23,35}}, + {SFG_LEVEL_ELEMENT_TREE, {21,35}},{SFG_LEVEL_ELEMENT_HEALTH, {62,36}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {59,36}},{SFG_LEVEL_ELEMENT_TERMINAL, {50,36}}, + {SFG_LEVEL_ELEMENT_RUIN, {14,36}},{SFG_LEVEL_ELEMENT_ROCKETS, {23,37}}, + {SFG_LEVEL_ELEMENT_TREE, {21,37}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {14,37}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {12,38}},{SFG_LEVEL_ELEMENT_ROCKETS, {11,38}}, + {SFG_LEVEL_ELEMENT_PLASMA, {10,38}},{SFG_LEVEL_ELEMENT_LAMP, {24,40}}, + {SFG_LEVEL_ELEMENT_LAMP, {22,40}},{SFG_LEVEL_ELEMENT_BARREL, {45,41}}, + {SFG_LEVEL_ELEMENT_BARREL, {15,41}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {7,41}}, + {SFG_LEVEL_ELEMENT_BARREL, {46,42}},{SFG_LEVEL_ELEMENT_BARREL, {44,42}}, + {SFG_LEVEL_ELEMENT_BARREL, {43,42}},{SFG_LEVEL_ELEMENT_RUIN, {36,42}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {33,42}},{SFG_LEVEL_ELEMENT_BARREL, {54,43}}, + {SFG_LEVEL_ELEMENT_RUIN, {36,43}},{SFG_LEVEL_ELEMENT_BULLETS, {19,43}}, + {SFG_LEVEL_ELEMENT_TREE, {26,44}},{SFG_LEVEL_ELEMENT_TREE, {21,44}}, + {SFG_LEVEL_ELEMENT_BULLETS, {46,45}},{SFG_LEVEL_ELEMENT_BULLETS, {45,45}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {35,45}},{SFG_LEVEL_ELEMENT_ROCKETS, {19,45}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {58,46}},{SFG_LEVEL_ELEMENT_BARREL, {54,46}}, + {SFG_LEVEL_ELEMENT_PLASMA, {41,46}},{SFG_LEVEL_ELEMENT_HEALTH, {37,46}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {14,46}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {51,47}}, + {SFG_LEVEL_ELEMENT_BULLETS, {19,47}},{SFG_LEVEL_ELEMENT_RUIN, {14,47}}, + {SFG_LEVEL_ELEMENT_BULLETS, {59,48}},{SFG_LEVEL_ELEMENT_LAMP, {40,48}}, + {SFG_LEVEL_ELEMENT_LAMP, {38,48}},{SFG_LEVEL_ELEMENT_PLASMA, {59,49}}, + {SFG_LEVEL_ELEMENT_BARREL, {53,49}},{SFG_LEVEL_ELEMENT_FINISH, {39,49}}, + {SFG_LEVEL_ELEMENT_TREE, {17,49}},{SFG_LEVEL_ELEMENT_LOCK2, {34,50}}, + {SFG_LEVEL_ELEMENT_BARREL, {54,51}},{SFG_LEVEL_ELEMENT_COLUMN, {36,52}}, + {SFG_LEVEL_ELEMENT_COLUMN, {32,52}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {6,52}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {51,54}},{SFG_LEVEL_ELEMENT_TREE, {46,54}}, + {SFG_LEVEL_ELEMENT_COLUMN, {42,54}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {22,54}}, + {SFG_LEVEL_ELEMENT_BULLETS, {19,54}},{SFG_LEVEL_ELEMENT_TREE, {62,55}}, + {SFG_LEVEL_ELEMENT_LOCK1, {38,55}},{SFG_LEVEL_ELEMENT_TREE, {46,56}}, + {SFG_LEVEL_ELEMENT_COLUMN, {42,56}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {56,59}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {51,59}},{SFG_LEVEL_ELEMENT_HEALTH, {14,60}}, + {SFG_LEVEL_ELEMENT_TERMINAL, {10,60}},{SFG_LEVEL_ELEMENT_HEALTH, {61,61}}, + {SFG_LEVEL_ELEMENT_HEALTH, {32,61}},{SFG_LEVEL_ELEMENT_ROCKETS, {17,61}}, + {SFG_LEVEL_ELEMENT_CARD2, {57,62}},{SFG_LEVEL_ELEMENT_HEALTH, {38,62}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {34,62}},{SFG_LEVEL_ELEMENT_BULLETS, {32,62}}, + {SFG_LEVEL_ELEMENT_LAMP, {25,62}},{SFG_LEVEL_ELEMENT_NONE, {0,0}} + }, // elements + } // level + ; + +SFG_PROGRAM_MEMORY SFG_Level SFG_level7 = + { // level + { // mapArray + #define o 0 + #define AA (31 | SFG_TILE_PROPERTY_DOOR) + #define BB (34 | SFG_TILE_PROPERTY_ELEVATOR) + #define CC (29 | SFG_TILE_PROPERTY_SQUEEZER) + #define DD (30 | SFG_TILE_PROPERTY_DOOR) + #define EE (39 | SFG_TILE_PROPERTY_ELEVATOR) + #define FF (28 | SFG_TILE_PROPERTY_DOOR) + #define GG (44 | SFG_TILE_PROPERTY_ELEVATOR) + #define HH (8 | SFG_TILE_PROPERTY_DOOR) + #define II (1 | SFG_TILE_PROPERTY_DOOR) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +/*0 */ 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,32,32,1 ,11,11,11,11,11,11,11,11,11,11,11,27,25,25,25,1 ,31,31,8 ,31,8 ,31,31, /*0 */ +/*1 */ 12,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,1 ,23,23,1 ,22,22,22,22,22,22,22,22,22,22,22,27,24,o ,24,1 ,31,31,41,41,41,31,31, /*1 */ +/*2 */ 12,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,8 ,1 ,23,23,27,22,22,15,15,15,15,15,15,15,15,21,27,o ,o ,o ,1 ,8 ,41,41,41,41,41,8 , /*2 */ +/*3 */ 12,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,8 ,1 ,23,23,27,23,22,15,20,20,20,20,20,20,20,20,27,o ,o ,o ,1 ,31,41,41,41,41,41,31, /*3 */ +/*4 */ 12,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,8 ,1 ,23,23,35,23,22,15,20,22,22,22,22,22,22,19,27,o ,o ,o ,1 ,8 ,23,23,23,23,23,8 , /*4 */ +/*5 */ 12,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,4 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,4 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,8 ,1 ,23,23,27,23,22,15,20,22,18,18,18,18,18,18,28,o ,o ,o ,1 ,31,23,23,23,23,23,31, /*5 */ +/*6 */ 12,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,3 ,4 ,3 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,3 ,4 ,3 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,8 ,1 ,23,23,27,22,22,15,20,22,18,20,20,20,20,17,28,o ,o ,o ,1 ,8 ,23,23,23,23,23,8 , /*6 */ +/*7 */ 12,o ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,3 ,4 ,3 ,2 ,o ,o ,o ,o ,o ,o ,o ,o ,2 ,3 ,4 ,3 ,2 ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,1 ,23,23,1 ,22,22,21,20,19,18,17,o ,o ,o ,o ,16,o ,o ,o ,1 ,31,31,23,23,23,31,31, /*7 */ +/*8 */ 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,o ,2 ,3 ,4 ,3 ,2 ,o ,1 ,1 ,1 ,1 ,1 ,1 ,o ,2 ,3 ,4 ,3 ,2 ,o ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,23,23,1 ,22,22,15,20,22,18,20,o ,o ,24,o ,28,o ,o ,o ,1 ,27,27,27,AA,27,27,27, /*8 */ +/*9 */ 1 ,11,17,17,17,17,17,17,1 ,o ,2 ,3 ,4 ,3 ,2 ,o ,1 ,1 ,1 ,1 ,1 ,1 ,17,23,23,23,23,23,23,1 ,26,1 ,26,1 ,1 ,1 ,1 ,1 ,23,23,1 ,22,22,15,20,22,18,20,37,o ,24,o ,28,o ,o ,o ,1 ,1 ,23,23,23,23,23,1 , /*9 */ +/*10*/ 1 ,25,17,CC,17,17,CC,17,1 ,o ,2 ,2 ,2 ,2 ,2 ,o ,1 ,1 ,1 ,1 ,1 ,1 ,18,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,BB,BB,1 ,1 ,23,23,1 ,22,22,15,20,22,18,20,37,o ,24,o ,28,o ,o ,o ,42,32,23,23,23,23,23,33, /*10*/ +/*11*/ 1 ,25,17,17,17,17,17,17,1 ,23,23,23,o ,23,23,23,1 ,1 ,1 ,1 ,1 ,1 ,19,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,BB,BB,23,DD,23,23,1 ,22,22,15,20,22,18,20,o ,o ,24,o ,28,o ,o ,o ,o ,32,23,23,23,23,23,32, /*11*/ +/*12*/ 1 ,25,17,CC,17,17,CC,17,17,o ,o ,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,36,20,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,BB,BB,1 ,1 ,23,23,1 ,22,22,21,20,19,18,17,o ,o ,o ,o ,16,o ,o ,o ,24,32,23,23,23,23,23,33, /*12*/ +/*13*/ 1 ,25,17,17,17,17,17,17,17,o ,o ,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,36,21,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,1 ,1 ,1 ,1 ,23,23,27,22,22,15,20,22,18,20,20,20,20,17,28,o ,o ,o ,o ,32,23,23,23,23,23,1 , /*13*/ +/*14*/ 1 ,25,17,17,17,17,17,17,17,o ,o ,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,36,22,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,1 ,1 ,1 ,1 ,23,23,27,23,22,15,20,22,18,18,18,18,18,18,28,o ,o ,o ,o ,32,23,23,1 ,23,23,32, /*14*/ +/*15*/ 1 ,25,17,17,17,17,17,17,17,o ,o ,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,1 ,23,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,1 ,1 ,1 ,1 ,23,23,35,23,22,15,20,22,22,22,22,22,22,19,27,o ,o ,o ,24,32,41,41,41,41,41,32, /*15*/ +/*16*/ 1 ,25,17,CC,17,17,CC,17,1 ,10,10,10,10,10,10,10,10,10,10,10,10,1 ,1 ,1 ,26,1 ,26,20,20,20,26,1 ,26,1 ,1 ,1 ,1 ,1 ,23,23,27,23,22,15,20,20,20,20,20,20,20,20,27,o ,o ,o ,o ,32,41,41,41,41,41,1 , /*16*/ +/*17*/ 1 ,25,17,17,17,17,17,17,1 ,17,18,19,20,22,23,23,22,20,19,18,17,9 ,9 ,1 ,17,37,o ,o ,o ,o ,o ,o ,37,1 ,1 ,1 ,23,23,23,23,27,22,22,15,15,15,15,15,15,15,15,21,27,o ,o ,o ,o ,32,41,41,41,41,41,33, /*17*/ +/*18*/ 1 ,25,17,CC,17,17,CC,17,1 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,17,37,o ,o ,o ,o ,o ,o ,37,1 ,1 ,23,23,23,23,23,1 ,22,22,22,22,22,22,22,22,22,22,22,27,o ,o ,o ,24,32,41,41,41,41,41,32, /*18*/ +/*19*/ 1 ,11,17,17,17,17,17,17,1 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,1 ,37,o ,o ,o ,o ,o ,o ,37,1 ,1 ,1 ,23,23,23,23,1 ,1 ,1 ,27,27,27,27,27,27,27,27,27,27,o ,o ,o ,o ,32,41,41,41,41,41,33, /*19*/ +/*20*/ 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,37,o ,o ,o ,o ,o ,o ,37,1 ,1 ,23,23,23,23,23,23,23,23,23,23,23,23,22,21,20,19,18,17,o ,o ,o ,o ,32,41,41,41,41,41,1 , /*20*/ +/*21*/ 5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,37,o ,o ,o ,o ,o ,o ,37,1 ,1 ,23,23,23,23,23,23,23,23,23,23,23,23,22,21,20,19,18,17,o ,o ,o ,1 ,1 ,40,1 ,DD,DD,1 ,1 , /*21*/ +/*22*/ 5 ,5 ,5 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,1 ,37,37,37,37,37,37,37,37,1 ,1 ,23,23,23,23,23,23,23,23,23,23,23,23,22,21,20,19,18,17,o ,o ,o ,1 ,1 ,40,1 ,23,23,1 ,1 , /*22*/ +/*23*/ 5 ,5 ,5 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,8 ,8 ,8 ,8 ,8 ,9 ,9 ,9 ,9 ,9 ,1 ,FF,1 ,1 ,o ,o ,o ,o ,37,1 ,1 ,1 ,23,23,23,23,1 ,23,23,23,23,38,38,38,38,38,1 ,1 ,1 ,o ,o ,o ,1 ,1 ,40,EE,23,23,EE,1 , /*23*/ +/*24*/ 5 ,6 ,6 ,6 ,10,6 ,6 ,10,6 ,6 ,10,6 ,6 ,5 ,8 ,10,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,o ,o ,o ,o ,37,1 ,1 ,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,1 ,1 ,1 ,o ,o ,o ,1 ,1 ,1 ,CC,23,23,CC,1 , /*24*/ +/*25*/ 7 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,8 ,10,6 ,37,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,o ,o ,o ,o ,37,1 ,1 ,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,1 ,o ,24,o ,o ,o ,24,o ,1 ,EE,23,23,EE,1 , /*25*/ +/*26*/ 7 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,8 ,10,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,o ,o ,o ,o ,37,1 ,1 ,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,1 ,o ,o ,o ,o ,o ,o ,o ,1 ,CC,23,23,CC,1 , /*26*/ +/*27*/ 7 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,37,37,37,37,37,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,28,28,28,28,28,1 ,o ,o ,o ,o ,o ,o ,o ,1 ,EE,23,23,EE,1 , /*27*/ +/*28*/ 7 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,8 ,10,6 ,37,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,1 ,1 ,1 ,o ,37,1 ,1 ,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,17,18,18,18,17,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,23,23,1 ,1 , /*28*/ +/*29*/ 7 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,8 ,10,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,6 ,6 ,6 ,1 ,o ,37,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,18,18,18,18,18,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,DD,DD,1 ,1 , /*29*/ +/*30*/ 7 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,8 ,10,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,6 ,6 ,6 ,FF,o ,37,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,27,23,23,27,27, /*30*/ +/*31*/ 5 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,5 ,8 ,10,6 ,37,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,6 ,6 ,6 ,1 ,o ,37,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,27,23,23,27,27, /*31*/ +/*32*/ 5 ,5 ,6 ,6 ,5 ,5 ,6 ,6 ,6 ,5 ,5 ,5 ,5 ,5 ,8 ,10,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,1 ,1 ,1 ,o ,37,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,31,23,23,31,27, /*32*/ +/*33*/ 1 ,o ,o ,o ,o ,5 ,6 ,6 ,6 ,5 ,8 ,8 ,8 ,8 ,8 ,10,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,42,o ,o ,o ,37,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,27,31,23,23,31,27, /*33*/ +/*34*/ 1 ,o ,o ,o ,o ,5 ,6 ,6 ,6 ,5 ,8 ,10,10,10,10,10,6 ,37,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,o ,o ,o ,o ,37,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,27,27,27,23,23,27,27, /*34*/ +/*35*/ 1 ,FF,1 ,1 ,1 ,5 ,6 ,6 ,6 ,5 ,8 ,10,6 ,6 ,6 ,6 ,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,o ,o ,o ,o ,37,1 ,28,24,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,27,27,27,27,23,23,27,27, /*35*/ +/*36*/ GG,45,GG,GG,5 ,5 ,6 ,6 ,6 ,5 ,8 ,10,6 ,6 ,6 ,6 ,6 ,6 ,6 ,9 ,9 ,9 ,9 ,9 ,6 ,6 ,6 ,1 ,o ,o ,o ,o ,37,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,23,23,23,23,23,23,23,23,1 , /*36*/ +/*37*/ GG,45,45,GG,5 ,6 ,6 ,6 ,6 ,5 ,8 ,8 ,1 ,1 ,8 ,HH,8 ,1 ,1 ,1 ,1 ,DD,1 ,1 ,1 ,FF,1 ,1 ,o ,o ,o ,o ,28,1 ,28,24,o ,o ,o ,o ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,32,23,23,23,23,23,23,23,23,32, /*37*/ +/*38*/ GG,45,45,GG,5 ,6 ,6 ,6 ,5 ,10,o ,o ,o ,o ,o ,37,o ,19,19,19,23,36,36,o ,o ,o ,o ,o ,o ,o ,o ,o ,28,1 ,1 ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,32,23,23,27,27,27,27,23,23,32, /*38*/ +/*39*/ GG,45,GG,5 ,6 ,6 ,6 ,6 ,5 ,10,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,36,36,36,o ,o ,o ,o ,o ,o ,o ,o ,28,28,1 ,1 ,o ,o ,o ,o ,o ,1 ,1 ,1 ,28,24,o ,o ,o ,o ,o ,o ,o ,o ,o ,32,23,23,31,27,27,31,23,23,32, /*39*/ +/*40*/ GG,GG,5 ,5 ,6 ,6 ,6 ,5 ,10,10,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,36,36,36,o ,o ,o ,o ,o ,o ,o ,28,28,28,1 ,1 ,1 ,1 ,16,1 ,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,32,23,23,27,27,27,27,23,23,32, /*40*/ +/*41*/ 5 ,5 ,6 ,6 ,6 ,6 ,5 ,10,10,10,o ,o ,o ,o ,o ,37,o ,19,19,19,23,36,36,o ,o ,o ,27,43,43,43,28,27,27,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,24,28,24,o ,o ,o ,o ,o ,o ,o ,o ,o ,32,23,23,23,23,23,23,23,23,32, /*41*/ +/*42*/ 5 ,5 ,6 ,6 ,6 ,5 ,10,10,10,10,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,27,o ,o ,o ,37,10,27,1 ,1 ,42,o ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,23,23,23,23,23,23,23,23,1 , /*42*/ +/*43*/ 5 ,6 ,6 ,6 ,6 ,5 ,10,10,10,10,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,36,36,36,o ,o ,o ,28,o ,o ,o ,o ,17,28,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,24,28,24,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,1 ,DD,1 ,1 ,1 ,1 , /*43*/ +/*44*/ 5 ,6 ,6 ,6 ,5 ,10,10,10,10,10,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,36,36,36,o ,o ,o ,FF,o ,o ,o ,o ,17,28,1 ,1 ,42,o ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,23,23,23,23,23,23,23,33, /*44*/ +/*45*/ 5 ,6 ,6 ,6 ,5 ,10,10,10,10,10,o ,o ,37,37,37,37,o ,o ,o ,o ,36,36,36,o ,o ,o ,28,o ,o ,o ,o ,17,28,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,1 ,1 ,16,16,1 ,1 ,o ,o ,1 ,1 ,23,23,23,23,23,23,23,32, /*45*/ +/*46*/ 5 ,6 ,6 ,6 ,5 ,10,10,10,10,8 ,o ,o ,37,o ,o ,1 ,1 ,1 ,1 ,1 ,36,36,36,o ,o ,o ,27,o ,o ,o ,37,10,27,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,37,37,1 ,24,o ,o ,24,1 ,37,37,1 ,1 ,23,23,38,38,38,23,23,33, /*46*/ +/*47*/ 1 ,o ,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,37,o ,o ,1 ,23,23,23,23,36,36,36,18,o ,18,27,27,28,28,28,27,27,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,24,o ,o ,24,1 ,1 ,1 ,1 ,1 ,23,23,38,38,38,23,23,1 , /*47*/ +/*48*/ 1 ,o ,o ,o ,o ,o ,o ,37,o ,o ,o ,o ,37,1 ,1 ,1 ,23,23,23,23,36,36,36,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,24,15,15,15,15,15,15,15,15,15,15,15,15,33, /*48*/ +/*49*/ 1 ,o ,o ,o ,o ,o ,o ,37,37,37,37,37,37,1 ,1 ,1 ,23,23,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,15,15,15,15,15,15,15,15,15,15,15,15,15,32, /*49*/ +/*50*/ 1 ,1 ,o ,o ,o ,o ,o ,o ,o ,37,1 ,1 ,1 ,1 ,42,1 ,23,23,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,15,15,15,15,15,15,15,15,15,15,15,15,15,15,33, /*50*/ +/*51*/ 1 ,1 ,o ,o ,o ,o ,o ,o ,o ,37,FF,o ,o ,o ,o ,o ,23,23,1 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,1 ,6 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,15,15,15,15,15,15,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /*51*/ +/*52*/ 1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,37,1 ,o ,o ,o ,o ,o ,23,23,1 ,8 ,5 ,10,5 ,10,5 ,10,5 ,10,5 ,8 ,1 ,6 ,o ,o ,o ,o ,17,18,19,20,21,22,23,15,15,15,15,15,15,15,15,15,1 ,12,12,12,12,12,12,12,12,12,12,12, /*52*/ +/*53*/ 1 ,1 ,1 ,1 ,1 ,II,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,23,23,1 ,8 ,10,o ,o ,o ,o ,o ,o ,o ,10,8 ,1 ,6 ,o ,o ,o ,o ,17,18,19,20,21,22,23,15,15,15,15,15,15,15,15,1 ,12,12,12,12,13,13,13,13,12,12,12,12, /*53*/ +/*54*/ 1 ,1 ,1 ,1 ,o ,o ,o ,1 ,1 ,1 ,1 ,17,18,19,20,22,23,23,1 ,8 ,5 ,o ,o ,o ,o ,o ,o ,o ,5 ,8 ,1 ,6 ,o ,o ,o ,o ,17,18,19,20,21,22,23,15,15,15,15,15,15,15,15,1 ,12,12,13,13,13,13,13,13,13,13,12,12, /*54*/ +/*55*/ 1 ,1 ,o ,o ,2 ,2 ,2 ,o ,o ,1 ,1 ,17,18,19,20,22,23,23,1 ,8 ,10,o ,o ,o ,o ,o ,o ,o ,10,8 ,1 ,6 ,o ,o ,o ,o ,17,18,19,20,21,22,23,15,15,15,15,15,15,15,15,1 ,12,12,13,13,14,13,13,14,13,13,12,12, /*55*/ +/*56*/ 1 ,1 ,o ,2 ,3 ,3 ,3 ,2 ,o ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,8 ,5 ,o ,o ,o ,o ,o ,o ,o ,5 ,8 ,1 ,1 ,o ,o ,o ,o ,o ,o ,27,15,15,15,15,15,15,15,15,15,15,1 ,1 ,1 ,12,13,13,13,14,13,13,14,13,13,13,12, /*56*/ +/*57*/ 1 ,o ,2 ,3 ,4 ,4 ,4 ,3 ,2 ,o ,1 ,o ,2 ,3 ,4 ,4 ,3 ,2 ,o ,1 ,1 ,10,10,10,10,10,10,10,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,15,23,23,23,23,23,23,23,23,23,23,23,23,1 ,12,13,13,13,14,13,13,14,13,13,13,12, /*57*/ +/*58*/ 1 ,o ,2 ,3 ,4 ,4 ,4 ,3 ,2 ,o ,II,o ,o ,o ,o ,o ,o ,o ,o ,II,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,1 ,o ,o ,o ,o ,24,15,23,23,23,23,23,23,23,23,23,23,22,22,1 ,12,13,13,13,13,13,13,13,13,13,13,12, /*58*/ +/*59*/ 1 ,o ,2 ,3 ,4 ,4 ,4 ,3 ,2 ,o ,1 ,o ,2 ,3 ,4 ,4 ,3 ,2 ,o ,1 ,1 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,1 ,o ,o ,o ,o ,o ,15,23,38,23,23,38,23,23,23,23,23,22,38,1 ,12,13,13,14,13,13,13,13,14,13,13,12, /*59*/ +/*60*/ 1 ,1 ,o ,2 ,3 ,3 ,3 ,2 ,o ,1 ,1 ,11,11,11,11,11,11,11,11,1 ,1 ,1 ,1 ,1 ,FF,1 ,6 ,6 ,6 ,6 ,6 ,6 ,FF,o ,o ,o ,o ,24,15,23,23,23,23,23,23,23,23,23,23,22,22,1 ,12,12,13,13,14,14,14,14,13,13,12,12, /*60*/ +/*61*/ 1 ,1 ,o ,o ,2 ,2 ,2 ,o ,o ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,o ,o ,o ,1 ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,o ,15,23,38,23,23,38,23,23,23,23,23,22,38,1 ,12,12,13,13,13,13,13,13,13,13,12,12, /*61*/ +/*62*/ 1 ,1 ,1 ,1 ,o ,o ,o ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,o ,o ,o ,1 ,o ,42,o ,42,o ,o ,1 ,o ,o ,o ,o ,o ,27,23,23,23,23,23,23,23,23,23,23,22,22,1 ,12,12,12,12,13,13,13,13,12,12,12,12, /*62*/ +/*63*/ 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,25,25,25,25,25,1 ,1 ,1 ,33,32,33,1 ,1 ,33,32,33,1 ,1 ,1 ,12,12,12,12,12,12,12,12,12,12,12,12 /*63*/ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + #undef AA + #undef BB + #undef CC + #undef DD + #undef EE + #undef FF + #undef GG + #undef HH + #undef II + #undef o + }, + { // tileDictionary + SFG_TD(15,14,0,0),SFG_TD(19, 0,0,0),SFG_TD(13,18,0,0),SFG_TD(11,22,0,0), // 0 + SFG_TD( 9,26,0,0),SFG_TD(19, 0,1,2),SFG_TD(15, 9,0,0),SFG_TD(19, 0,1,3), // 4 + SFG_TD(19, 0,4,4),SFG_TD(22, 7,4,4),SFG_TD(16, 7,4,4),SFG_TD(31, 0,3,3), // 8 + SFG_TD(26, 0,3,7),SFG_TD(15,31,0,0),SFG_TD(18,31,0,0),SFG_TD(23, 6,5,5), // 12 + SFG_TD(15, 5,0,0),SFG_TD(16,13,5,5),SFG_TD(17,12,5,5),SFG_TD(18,11,5,5), // 16 + SFG_TD(19,10,5,5),SFG_TD(20, 9,5,5),SFG_TD(21, 8,5,5),SFG_TD(22, 7,5,0), // 20 + SFG_TD(17,12,6,5),SFG_TD(23, 0,0,3),SFG_TD(19, 0,2,2),SFG_TD(31, 0,6,6), // 24 + SFG_TD(19, 0,6,0),SFG_TD(17, 6,4,4),SFG_TD(26, 0,5,0),SFG_TD(26, 0,1,1), // 28 + SFG_TD(25, 3,0,0),SFG_TD(26, 1,0,0),SFG_TD(22,31,6,6),SFG_TD(22, 5,5,6), // 32 + SFG_TD(22, 7,0,0),SFG_TD(15,13,0,4),SFG_TD(24, 5,6,5),SFG_TD(20,14,4,4), // 36 + SFG_TD(31, 8,0,0),SFG_TD(22,13,5,0),SFG_TD(21, 8,2,5),SFG_TD(15, 6,0,0), // 40 + SFG_TD(31,30,4,4),SFG_TD(15, 4,0,0),SFG_TD(15,13,0,0),SFG_TD(15,13,0,0), // 44 + SFG_TD(15,13,0,0),SFG_TD(15,13,0,0),SFG_TD(15,13,0,0),SFG_TD(15,13,0,0), // 48 + SFG_TD(15,13,0,0),SFG_TD(15,13,0,0),SFG_TD(15,13,0,0),SFG_TD(15,13,0,0), // 52 + SFG_TD(15,13,0,0),SFG_TD(15,13,0,0),SFG_TD(15,13,0,0),SFG_TD(15,13,0,0), // 56 + SFG_TD(15,13,0,0),SFG_TD(15,13,0,0),SFG_TD(15,13,0,0),SFG_TD(15,13,0,0) // 60 + }, // tileDictionary + {12,8 ,2 ,10,11,14,4 }, // textureIndices + 13, // doorTextureIndex + 4, // floorColor + 66, // ceilingColor + {34, 11, 0 }, // player start: x, y, direction + 1, // backgroundImage + { // elements + {SFG_LEVEL_ELEMENT_FINISH, {60,1}},{SFG_LEVEL_ELEMENT_BULLETS, {54,1}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {20,3}},{SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {24,4}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {18,5}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {8,5}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {44,6}},{SFG_LEVEL_ELEMENT_COLUMN, {61,9}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {60,9}},{SFG_LEVEL_ELEMENT_COLUMN, {59,9}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {51,9}},{SFG_LEVEL_ELEMENT_CARD2, {50,9}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {46,9}},{SFG_LEVEL_ELEMENT_BULLETS, {41,9}}, + {SFG_LEVEL_ELEMENT_PLASMA, {41,10}},{SFG_LEVEL_ELEMENT_BLOCKER, {28,10}}, + {SFG_LEVEL_ELEMENT_HEALTH, {50,11}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {38,11}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {31,11}},{SFG_LEVEL_ELEMENT_BLOCKER, {30,11}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {26,11}},{SFG_LEVEL_ELEMENT_BLOCKER, {29,12}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {28,12}},{SFG_LEVEL_ELEMENT_BLOCKER, {26,12}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {31,13}},{SFG_LEVEL_ELEMENT_BLOCKER, {27,13}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {23,13}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {48,14}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {44,14}},{SFG_LEVEL_ELEMENT_BLOCKER, {31,14}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {29,14}},{SFG_LEVEL_ELEMENT_BLOCKER, {26,14}}, + {SFG_LEVEL_ELEMENT_BARREL, {20,14}},{SFG_LEVEL_ELEMENT_TERMINAL, {3,14}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {31,15}},{SFG_LEVEL_ELEMENT_BLOCKER, {29,15}}, + {SFG_LEVEL_ELEMENT_CARD0, {28,15}},{SFG_LEVEL_ELEMENT_BLOCKER, {27,15}}, + {SFG_LEVEL_ELEMENT_BLOCKER, {26,15}},{SFG_LEVEL_ELEMENT_BULLETS, {4,19}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {35,20}},{SFG_LEVEL_ELEMENT_PLASMA, {35,21}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {35,22}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {62,23}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {10,24}},{SFG_LEVEL_ELEMENT_PLASMA, {7,24}}, + {SFG_LEVEL_ELEMENT_BULLETS, {4,24}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {62,25}}, + {SFG_LEVEL_ELEMENT_TREE, {56,25}},{SFG_LEVEL_ELEMENT_TREE, {52,25}}, + {SFG_LEVEL_ELEMENT_HEALTH, {49,25}},{SFG_LEVEL_ELEMENT_CARD1, {17,25}}, + {SFG_LEVEL_ELEMENT_HEALTH, {15,25}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {59,27}}, + {SFG_LEVEL_ELEMENT_BARREL, {28,27}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {14,27}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {10,27}},{SFG_LEVEL_ELEMENT_BULLETS, {43,28}}, + {SFG_LEVEL_ELEMENT_BULLETS, {42,28}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {5,28}}, + {SFG_LEVEL_ELEMENT_RUIN, {27,29}},{SFG_LEVEL_ELEMENT_RUIN, {26,30}}, + {SFG_LEVEL_ELEMENT_HEALTH, {24,30}},{SFG_LEVEL_ELEMENT_RUIN, {27,31}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {10,31}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {4,31}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {17,34}},{SFG_LEVEL_ELEMENT_HEALTH, {4,34}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {49,35}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {51,36}}, + {SFG_LEVEL_ELEMENT_LOCK1, {15,37}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {5,38}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {4,39}},{SFG_LEVEL_ELEMENT_BULLETS, {1,39}}, + {SFG_LEVEL_ELEMENT_COLUMN, {29,41}},{SFG_LEVEL_ELEMENT_COLUMN, {28,41}}, + {SFG_LEVEL_ELEMENT_COLUMN, {27,41}},{SFG_LEVEL_ELEMENT_ROCKETS, {8,41}}, + {SFG_LEVEL_ELEMENT_PLASMA, {31,42}},{SFG_LEVEL_ELEMENT_ROCKETS, {7,42}}, + {SFG_LEVEL_ELEMENT_LOCK0, {59,43}},{SFG_LEVEL_ELEMENT_HEALTH, {35,43}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {30,44}},{SFG_LEVEL_ELEMENT_TREE, {59,46}}, + {SFG_LEVEL_ELEMENT_PLASMA, {31,46}},{SFG_LEVEL_ELEMENT_BULLETS, {59,47}}, + {SFG_LEVEL_ELEMENT_TREE, {25,47}},{SFG_LEVEL_ELEMENT_TREE, {23,47}}, + {SFG_LEVEL_ELEMENT_BULLETS, {46,51}},{SFG_LEVEL_ELEMENT_BULLETS, {15,51}}, + {SFG_LEVEL_ELEMENT_LOCK1, {10,51}},{SFG_LEVEL_ELEMENT_TELEPORTER, {27,52}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {25,52}},{SFG_LEVEL_ELEMENT_TELEPORTER, {23,52}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {21,52}},{SFG_LEVEL_ELEMENT_ROCKETS, {15,52}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {28,53}},{SFG_LEVEL_ELEMENT_TELEPORTER, {20,53}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {47,54}},{SFG_LEVEL_ELEMENT_TERMINAL, {24,54}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {28,55}},{SFG_LEVEL_ELEMENT_TELEPORTER, {20,55}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {62,57}},{SFG_LEVEL_ELEMENT_PLASMA, {59,57}}, + {SFG_LEVEL_ELEMENT_PLASMA, {56,57}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {45,58}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {14,58}},{SFG_LEVEL_ELEMENT_BARREL, {12,58}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {5,58}},{SFG_LEVEL_ELEMENT_HEALTH, {1,58}}, + {SFG_LEVEL_ELEMENT_TREE, {50,59}},{SFG_LEVEL_ELEMENT_LOCK2, {32,60}}, + {SFG_LEVEL_ELEMENT_TREE, {50,61}},{SFG_LEVEL_ELEMENT_ROCKETS, {22,61}}, + {SFG_LEVEL_ELEMENT_PLASMA, {22,62}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}} + }, // elements + } // level + ; + +SFG_PROGRAM_MEMORY SFG_Level SFG_level8 = + { // level + { // mapArray + #define o 0 + #define AA (10 | SFG_TILE_PROPERTY_DOOR) + #define BB (63 | SFG_TILE_PROPERTY_ELEVATOR) + #define CC (11 | SFG_TILE_PROPERTY_DOOR) + #define DD (13 | SFG_TILE_PROPERTY_DOOR) + #define EE (7 | SFG_TILE_PROPERTY_DOOR) + #define FF (60 | SFG_TILE_PROPERTY_DOOR) + #define GG (12 | SFG_TILE_PROPERTY_ELEVATOR) + #define HH (61 | SFG_TILE_PROPERTY_DOOR) + #define II (0 | SFG_TILE_PROPERTY_DOOR) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +/*0 */ 44,44,44,58,58,58,58,58,58,58,58,58,58,10,61,6 ,6 ,6 ,6 ,61,61,6 ,6 ,6 ,6 ,61,61,6 ,6 ,6 ,6 ,61,1 ,6 ,6 ,6 ,6 ,6 ,61,6 ,6 ,6 ,6 ,61,6 ,6 ,6 ,6 ,6 ,1 ,1 ,1 ,1 ,15,1 ,1 ,1 ,1 ,1 ,15,1 ,1 ,1 ,1 , /*0 */ +/*1 */ 44,44,58,58,59,59,59,59,59,59,59,59,59,10,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,14,14,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,1 ,1 , /*1 */ +/*2 */ 44,58,58,59,59,59,59,59,59,59,59,59,59,AA,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,14,14,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,1 , /*2 */ +/*3 */ 58,58,59,59,59,59,59,59,59,59,59,59,59,10,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,14,14,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,11,11,11,15,4 ,4 ,4 ,5 ,5 ,4 ,4 ,4 ,5 ,5 ,4 ,4 ,4 ,15, /*3 */ +/*4 */ 58,59,59,59,59,59,59,59,59,10,10,10,10,10,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,14,14,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,4 ,4 ,4 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,4 ,4 ,4 ,1 , /*4 */ +/*5 */ 58,59,59,59,59,59,59,59,10,61,61,61,61,61,4 ,4 ,3 ,3 ,4 ,4 ,3 ,3 ,4 ,4 ,13,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,14,14,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,11,o ,o ,2 ,4 ,4 ,4 ,4 ,5 ,BB,BB,BB,5 ,4 ,4 ,4 ,4 ,1 , /*5 */ +/*6 */ 58,59,59,59,59,59,59,57,57,54,53,52,51,50,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,1 ,13,13,13,13,13,13,13,15,15,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,CC,o ,o ,2 ,4 ,4 ,4 ,4 ,5 ,BB,BB,BB,5 ,4 ,4 ,4 ,4 ,1 , /*6 */ +/*7 */ 58,59,59,59,59,59,57,57,55,54,53,52,51,50,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,1 ,13,13,13,o ,13,13,13,13,23,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,11,o ,o ,2 ,4 ,4 ,4 ,4 ,5 ,BB,BB,BB,5 ,4 ,4 ,4 ,4 ,1 , /*7 */ +/*8 */ 58,59,59,59,59,10,57,55,55,54,53,52,51,50,4 ,4 ,4 ,4 ,3 ,3 ,4 ,4 ,4 ,4 ,DD,o ,o ,o ,o ,o ,o ,13,13,23,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,4 ,4 ,4 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,4 ,4 ,4 ,1 , /*8 */ +/*9 */ 58,59,59,59,10,61,55,55,55,54,53,52,51,50,4 ,4 ,4 ,4 ,3 ,3 ,4 ,4 ,4 ,4 ,1 ,13,13,13,o ,15,o ,o ,13,23,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,11,11,11,15,4 ,4 ,4 ,5 ,5 ,4 ,4 ,4 ,5 ,5 ,4 ,4 ,4 ,15, /*9 */ +/*10*/ 58,59,59,59,10,61,55,55,55,54,53,52,51,50,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,1 ,13,o ,o ,o ,o ,o ,13,13,23,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,1 , /*10*/ +/*11*/ 58,59,59,59,10,61,55,55,55,54,53,52,51,50,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,13,o ,o ,15,o ,13,13,13,13,23,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,1 ,1 , /*11*/ +/*12*/ 58,59,59,59,10,61,55,55,55,54,53,52,51,50,4 ,4 ,3 ,3 ,4 ,4 ,3 ,3 ,4 ,4 ,1 ,13,o ,o ,o ,o ,o ,o ,DD,23,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,15,1 ,2 ,2 ,2 ,1 ,15,1 ,1 ,1 ,1 , /*12*/ +/*13*/ 10,10,AA,10,61,10,10,10,10,10,10,10,8 ,8 ,10,10,8 ,8 ,10,10,8 ,8 ,10,10,1 ,13,13,13,o ,13,13,13,13,23,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,62,62,1 , /*13*/ +/*14*/ 61,o ,o ,o ,o ,10,10,10,10,10,10,o ,o ,o ,o ,o ,o ,o ,23,23,15,15,15,15,13,13,13,13,13,13,13,13,13,23,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,1 , /*14*/ +/*15*/ 56,o ,o ,o ,o ,10,10,10,10,10,8 ,o ,o ,o ,o ,o ,o ,o ,23,23,15,15,15,15,15,15,15,15,15,15,13,13,13,23,o ,o ,o ,o ,o ,o ,61,61,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,61, /*15*/ +/*16*/ 56,o ,o ,o ,o ,49,10,10,10,10,8 ,o ,o ,62,62,15,15,EE,15,15,15,15,15,o ,o ,o ,o ,o ,15,15,15,15,15,15,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,11,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,56, /*16*/ +/*17*/ 56,o ,o ,o ,o ,o ,10,10,10,10,10,o ,o ,62,15,15,o ,o ,o ,15,15,15,15,o ,o ,o ,o ,o ,15,15,o ,o ,61,o ,o ,o ,o ,o ,o ,o ,8 ,62,o ,o ,o ,o ,o ,11,62,8 ,62,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,56, /*17*/ +/*18*/ 56,o ,o ,o ,o ,o ,o ,49,10,10,10,49,49,15,15,o ,o ,o ,o ,o ,15,15,15,15,15,15,o ,o ,15,15,o ,o ,EE,o ,40,40,40,40,40,o ,8 ,62,o ,o ,o ,o ,o ,o ,62,8 ,62,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,56, /*18*/ +/*19*/ 56,o ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,o ,o ,15,o ,o ,o ,o ,o ,o ,o ,15,15,15,15,1 ,o ,o ,1 ,15,o ,o ,61,o ,40,40,40,40,40,o ,8 ,62,o ,o ,o ,o ,o ,o ,62,8 ,62,62,62,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61, /*19*/ +/*20*/ 56,o ,o ,o ,o ,o ,o ,o ,o ,62,8 ,o ,o ,15,o ,o ,15,o ,15,o ,o ,15,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,15,o ,40,40,40,40,40,o ,8 ,8 ,8 ,49,49,49,49,8 ,8 ,8 ,8 ,8 ,8 ,49,10,40,40,40,40,40,40,10,49,10, /*20*/ +/*21*/ 56,o ,o ,o ,o ,o ,o ,o ,62,62,10,o ,o ,15,o ,o ,o ,o ,o ,o ,o ,15,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,15,o ,40,40,40,40,40,o ,o ,o ,3 ,2 ,2 ,2 ,2 ,3 ,1 ,1 ,1 ,1 ,1 ,o ,40,40,40,40,40,40,40,40,o ,10, /*21*/ +/*22*/ 61,o ,o ,o ,o ,o ,o ,o ,62,62,10,o ,o ,15,15,o ,o ,o ,o ,o ,15,61,o ,o ,15,1 ,o ,o ,1 ,15,15,15,15,o ,o ,o ,o ,o ,o ,o ,o ,o ,3 ,2 ,2 ,2 ,2 ,3 ,1 ,1 ,1 ,1 ,1 ,o ,40,40,40,40,40,40,40,40,o ,10, /*22*/ +/*23*/ 61,o ,o ,o ,o ,o ,o ,o ,o ,62,8 ,o ,o ,15,15,15,o ,o ,o ,15,o ,EE,o ,o ,15,15,o ,o ,15,15,15,15,8 ,62,62,10,10,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,1 ,1 ,1 ,1 ,1 ,1 ,o ,40,40,40,40,40,40,40,40,o ,10, /*23*/ +/*24*/ 61,o ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,49,49,15,15,15,o ,o ,o ,15,o ,61,o ,o ,15,15,o ,o ,o ,o ,o ,15,8 ,o ,o ,10,10,1 ,62,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,1 ,1 ,o ,40,40,40,40,40,40,40,40,o ,10, /*24*/ +/*25*/ 56,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,15,15,15,61,EE,61,15,o ,15,15,15,15,15,o ,o ,o ,o ,o ,15,8 ,o ,o ,o ,10,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,1 ,o ,40,40,40,40,40,40,40,40,o ,10, /*25*/ +/*26*/ 56,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,15,23,23,23,23,23,23,23,15,15,15,15,15,15,15,61,EE,61,8 ,8 ,o ,o ,o ,AA,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,49,10,40,40,40,40,40,40,10,49,10, /*26*/ +/*27*/ 56,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,24,8 ,49,49,49,49,o ,o ,o ,10,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,62,1 ,10,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61, /*27*/ +/*28*/ 56,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,55,55,8 ,55,55,55,55,55,55,55,55,55,55,55,55,55,62,o ,o ,o ,o ,o ,o ,10,10,1 ,62,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,10,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,56, /*28*/ +/*29*/ 56,o ,o ,o ,o ,o ,o ,o ,o ,4 ,4 ,4 ,55,55,FF,55,55,55,55,55,55,55,55,55,55,55,55,55,62,o ,o ,o ,o ,o ,o ,10,10,1 ,1 ,1 ,1 ,9 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,AA,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,56, /*29*/ +/*30*/ 56,o ,o ,o ,o ,o ,o ,o ,o ,4 ,50,50,54,54,8 ,55,4 ,4 ,4 ,4 ,4 ,50,51,52,53,54,55,8 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,47,47,46,46,GG,46,46,46,47,1 ,o ,o ,o ,o ,o ,10,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,56, /*30*/ +/*31*/ 56,o ,o ,o ,o ,o ,o ,o ,o ,4 ,51,51,53,53,8 ,55,4 ,4 ,4 ,4 ,4 ,50,51,52,53,54,55,1 ,1 ,1 ,53,53,52,52,52,51,51,47,47,46,46,46,46,46,46,47,47,1 ,o ,o ,62,1 ,10,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,61, /*31*/ +/*32*/ 61,o ,o ,o ,o ,o ,11,o ,o ,4 ,52,52,52,52,8 ,55,4 ,4 ,4 ,4 ,4 ,50,51,52,53,54,55,1 ,1 ,1 ,53,53,52,52,52,51,51,47,47,47,47,47,47,47,47,47,47,47,1 ,1 ,3 ,3 ,1 ,1 ,7 ,13,7 ,1 ,1 ,7 ,13,7 ,1 ,1 , /*32*/ +/*33*/ 61,EE,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,8 ,55,4 ,4 ,4 ,4 ,4 ,50,51,52,53,54,55,1 ,1 ,1 ,54,53,53,52,51,51,50,47,47,10,o ,o ,o ,o ,o ,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,o , /*33*/ +/*34*/ 61,o ,o ,o ,o ,24,24,24,24,24,24,1 ,1 ,1 ,3 ,55,4 ,4 ,4 ,4 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,54,54,54,60,50,50,50,47,47,o ,o ,o ,o ,o ,o ,o ,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,o , /*34*/ +/*35*/ 61,61,61,24,24,29,29,29,29,29,24,24,1 ,1 ,1 ,55,4 ,4 ,4 ,4 ,o ,o ,o ,o ,o ,o ,o ,1 ,15,1 ,54,54,54,1 ,50,50,50,47,47,o ,o ,o ,o ,o ,o ,o ,47,47,60,60,60,60,47,47,47,47,1 ,1 ,1 ,47,47,47,47,o , /*35*/ +/*36*/ 24,24,24,29,29,29,29,29,29,29,29,24,24,1 ,1 ,55,4 ,4 ,4 ,4 ,o ,4 ,4 ,4 ,4 ,4 ,4 ,1 ,55,1 ,55,55,55,1 ,4 ,4 ,4 ,47,47,10,o ,o ,o ,o ,o ,47,47,47,o ,o ,o ,60,47,47,47,47,23,23,23,47,47,47,47,o , /*36*/ +/*37*/ 24,29,29,29,29,29,29,29,29,29,29,29,24,1 ,1 ,55,4 ,4 ,4 ,4 ,o ,50,50,50,50,50,50,1 ,55,1 ,55,55,55,1 ,4 ,4 ,4 ,47,47,47,47,47,47,47,47,47,47,o ,o ,o ,o ,60,47,47,47,47,23,23,23,47,47,47,47,o , /*37*/ +/*38*/ 24,o ,29,29,29,29,29,29,29,29,29,29,24,1 ,1 ,55,4 ,4 ,4 ,4 ,o ,51,51,51,51,51,51,1 ,55,1 ,55,55,55,1 ,1 ,EE,1 ,1 ,47,47,47,47,47,47,47,1 ,o ,o ,o ,o ,o ,60,47,47,47,47,o ,1 ,o ,47,47,47,47,o , /*38*/ +/*39*/ 24,o ,o ,o ,29,29,24,24,29,29,29,29,24,24,1 ,55,4 ,4 ,4 ,4 ,o ,52,52,52,52,52,52,1 ,55,HH,55,55,55,1 ,o ,o ,o ,46,46,46,46,46,46,46,46,46,o ,o ,o ,o ,o ,60,47,47,47,47,o ,1 ,o ,47,47,47,47,o , /*39*/ +/*40*/ 24,o ,o ,o ,o ,o ,24,24,29,29,29,29,29,24,1 ,55,4 ,4 ,4 ,4 ,o ,53,53,53,53,53,53,1 ,55,1 ,55,55,55,1 ,o ,o ,o ,46,46,46,46,46,46,46,46,46,o ,o ,o ,3 ,47,47,47,47,47,47,II,II,II,47,47,47,47,o , /*40*/ +/*41*/ 24,o ,o ,o ,o ,o ,24,24,29,29,29,29,29,24,1 ,1 ,o ,o ,o ,o ,o ,54,54,54,54,54,54,60,1 ,60,55,55,55,1 ,o ,o ,o ,46,46,46,46,46,46,46,46,46,II,o ,o ,o ,o ,o ,47,47,47,47,47,o ,47,46,47,46,47,o , /*41*/ +/*42*/ 24,28,28,o ,o ,o ,o ,24,29,29,29,29,29,24,1 ,1 ,1 ,EE,1 ,1 ,1 ,55,55,55,55,55,55,55,55,55,55,55,55,1 ,o ,o ,o ,46,46,46,46,46,46,46,46,46,o ,o ,o ,o ,o ,o ,47,47,47,47,47,o ,47,47,47,47,47,o , /*42*/ +/*43*/ 24,24,28,31,31,31,31,24,24,29,29,29,29,24,24,1 ,1 ,o ,o ,o ,1 ,55,55,55,55,55,55,55,55,55,55,55,55,1 ,o ,o ,o ,46,46,46,46,46,46,46,46,46,o ,o ,o ,o ,o ,o ,47,47,47,47,47,o ,47,46,47,46,47,o , /*43*/ +/*44*/ 24,24,28,28,30,30,30,24,24,29,29,29,29,29,24,24,1 ,o ,o ,o ,1 ,55,55,55,55,55,55,55,55,55,55,55,55,1 ,o ,o ,o ,46,46,46,46,46,46,46,46,46,o ,o ,o ,o ,o ,o ,47,47,47,47,47,o ,47,47,47,47,47,o , /*44*/ +/*45*/ 24,24,24,24,30,30,30,30,24,29,29,29,29,29,29,24,24,1 ,1 ,o ,1 ,55,55,55,55,55,55,55,55,55,55,55,55,1 ,o ,o ,o ,46,46,46,46,46,46,46,46,46,o ,o ,o ,o ,o ,o ,15,1 ,1 ,1 ,7 ,EE,7 ,1 ,1 ,1 ,1 ,1 , /*45*/ +/*46*/ 24,24,24,24,29,29,30,30,24,29,29,29,29,29,29,29,24,24,1 ,o ,1 ,55,55,55,55,55,55,55,55,55,55,55,55,1 ,o ,o ,o ,46,46,46,46,46,46,46,46,46,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,o ,o ,o ,1 ,1 ,1 ,1 ,1 , /*46*/ +/*47*/ 24,24,24,24,29,29,29,29,24,24,29,29,29,30,30,30,30,24,1 ,o ,1 ,55,55,55,55,55,55,55,55,55,55,55,55,1 ,o ,o ,o ,46,46,46,45,45,45,46,46,46,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,23,23,23,1 ,1 ,1 ,1 ,1 , /*47*/ +/*48*/ 24,24,24,24,29,29,29,29,29,24,29,30,30,30,30,30,30,24,24,1 ,1 ,1 ,60,9 ,9 ,60,1 ,1 ,1 ,60,HH,60,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,1 ,1 ,1 ,1 ,1 , /*48*/ +/*49*/ 24,24,24,29,29,29,29,29,29,24,30,30,30,30,30,30,30,30,24,24,8 ,46,46,GG,GG,46,46,1 ,55,55,55,55,55,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,8 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,1 , /*49*/ +/*50*/ 24,24,24,o ,o ,o ,o ,o ,o ,24,30,30,30,30,30,30,30,30,24,24,8 ,46,46,GG,GG,46,46,56,55,55,55,55,55,56,o ,o ,o ,8 ,o ,o ,o ,o ,o ,o ,o ,8 ,o ,o ,o ,o ,23,o ,o ,23,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,1 , /*50*/ +/*51*/ 24,24,24,o ,o ,o ,o ,o ,o ,24,30,30,30,30,31,31,31,31,24,24,8 ,46,46,GG,GG,46,46,56,55,55,55,55,55,56,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,EE,o ,o ,23,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 , /*51*/ +/*52*/ 24,24,24,24,o ,o ,o ,o ,o ,24,30,31,31,31,31,31,31,31,24,24,8 ,46,46,GG,GG,46,46,1 ,55,55,55,55,55,61,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,23,o ,o ,23,o ,o ,o ,o ,o ,o ,62,1 ,1 ,1 , /*52*/ +/*53*/ 24,24,24,24,o ,o ,o ,o ,28,24,31,31,31,31,31,31,31,28,24,24,8 ,47,47,9 ,9 ,47,47,1 ,55,55,55,55,55,56,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,8 ,8 ,8 ,48,1 ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,62,62,1 ,1 , /*53*/ +/*54*/ 24,24,28,o ,o ,o ,o ,o ,24,24,31,31,31,31,31,31,31,28,24,24,8 ,47,47,9 ,9 ,47,47,1 ,55,55,55,55,55,56,o ,o ,o ,o ,11,o ,o ,o ,o ,o ,o ,o ,o ,8 ,48,48,4 ,50,51,54,55,1 ,o ,o ,o ,o ,o ,o ,o ,1 , /*54*/ +/*55*/ 24,28,28,o ,o ,o ,o ,28,24,24,24,31,31,o ,o ,o ,o ,28,24,24,8 ,47,47,9 ,9 ,47,47,1 ,55,55,55,55,55,1 ,o ,1 ,1 ,1 ,1 ,1 ,1 ,EE,1 ,1 ,13,1 ,1 ,48,48,4 ,4 ,50,52,53,54,1 ,o ,o ,o ,o ,o ,o ,o ,6 , /*55*/ +/*56*/ 24,28,o ,o ,o ,o ,o ,24,24,24,24,24,24,o ,o ,o ,o ,28,24,24,8 ,8 ,8 ,9 ,9 ,47,47,3 ,3 ,55,55,55,55,48,14,48,48,48,48,48,48,48,48,48,48,48,48,48,4 ,4 ,4 ,50,51,52,51,1 ,o ,o ,o ,o ,o ,o ,o ,6 , /*56*/ +/*57*/ 24,o ,o ,o ,o ,o ,o ,24,28,o ,o ,28,24,o ,o ,o ,28,28,24,24,8 ,8 ,8 ,9 ,9 ,47,47,1 ,3 ,3 ,55,55,55,48,4 ,48,4 ,o ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,50,50,50,7 ,o ,o ,o ,o ,o ,o ,o ,6 , /*57*/ +/*58*/ 24,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,28,24,24,8 ,9 ,9 ,9 ,9 ,9 ,47,47,1 ,1 ,3 ,1 ,1 ,1 ,48,4 ,48,4 ,48,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,7 ,o ,o ,o ,o ,o ,o ,o ,6 , /*58*/ +/*59*/ 24,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,28,24,24,15,9 ,9 ,9 ,9 ,9 ,47,47,46,46,46,46,46,9 ,9 ,4 ,48,4 ,48,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,7 ,o ,o ,o ,o ,o ,o ,o ,6 , /*59*/ +/*60*/ 24,24,o ,o ,o ,o ,o ,o ,o ,24,24,o ,o ,o ,o ,o ,24,24,24,8 ,9 ,9 ,9 ,47,47,47,47,47,47,47,47,47,9 ,3 ,o ,3 ,o ,3 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,1 ,o ,o ,o ,o ,o ,o ,o ,1 , /*60*/ +/*61*/ 24,24,28,28,o ,o ,o ,28,28,24,24,24,28,o ,o ,28,24,24,24,15,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,48,4 ,4 ,4 ,48,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,53,53,1 ,1 ,1 ,1 ,EE,1 ,1 ,1 ,1 , /*61*/ +/*62*/ 24,24,24,28,28,28,28,28,24,24,24,24,24,24,24,24,24,24,24,8 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,48,4 ,4 ,4 ,48,4 ,4 ,4 ,4 ,23,4 ,4 ,4 ,23,4 ,4 ,4 ,23,4 ,4 ,53,53,1 ,1 ,1 ,1 ,o ,o ,o ,o ,1 , /*62*/ +/*63*/ 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,8 ,56,56,56,56,8 ,6 ,6 ,6 ,3 ,3 ,6 ,6 ,6 ,48,61,61,61,61,61,6 ,6 ,6 ,8 ,6 ,6 ,6 ,8 ,6 ,6 ,6 ,8 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,o ,1 /*63*/ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + #undef AA + #undef BB + #undef CC + #undef DD + #undef EE + #undef FF + #undef GG + #undef HH + #undef II + #undef o + }, + { // tileDictionary + SFG_TD(13,11,0,0),SFG_TD(14, 0,1,0),SFG_TD(13, 7,0,0),SFG_TD(17, 0,2,2), // 0 + SFG_TD(13,22,0,0),SFG_TD(12,23,0,0),SFG_TD(17, 0,0,5),SFG_TD(17, 0,1,0), // 4 + SFG_TD(20, 0,0,6),SFG_TD(20, 4,0,0),SFG_TD(17, 0,6,6),SFG_TD(17, 7,1,0), // 8 + SFG_TD( 9,11,2,0),SFG_TD(17, 0,1,1),SFG_TD(15, 9,0,0),SFG_TD( 0, 0,4,4), // 12 + SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0), // 16 + SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13, 8,0,4), // 20 + SFG_TD(17, 0,3,3),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0), // 24 + SFG_TD(15, 7,3,3),SFG_TD(19, 5,3,3),SFG_TD(17, 7,3,3),SFG_TD(15, 9,3,3), // 28 + SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0), // 32 + SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0), // 36 + SFG_TD(13,10,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0),SFG_TD(13,14,0,0), // 40 + SFG_TD( 0, 0,7,7),SFG_TD(11,24,0,0),SFG_TD( 9,26,0,0),SFG_TD( 9, 4,0,0), // 44 + SFG_TD(14, 0,4,0),SFG_TD(13, 7,0,6),SFG_TD(14,21,0,0),SFG_TD(15,20,0,0), // 48 + SFG_TD(16,19,0,0),SFG_TD(17,18,0,0),SFG_TD(18,17,0,0),SFG_TD(19,16,0,0), // 52 + SFG_TD(20, 2,0,0),SFG_TD(23, 2,6,6),SFG_TD(17,31,0,0),SFG_TD(13,31,0,0), // 56 + SFG_TD(23, 0,6,6),SFG_TD(23, 0,0,0),SFG_TD(15, 9,3,0),SFG_TD(12,31,0,0) // 60 + }, // tileDictionary + {12,2 ,11,6 ,8 ,10,14}, // textureIndices + 7, // doorTextureIndex + 5, // floorColor + 4, // ceilingColor + {59, 59, 64 }, // player start: x, y, direction + 2, // backgroundImage + { // elements + {SFG_LEVEL_ELEMENT_CARD0, {33,3}},{SFG_LEVEL_ELEMENT_LAMP, {46,4}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {38,4}},{SFG_LEVEL_ELEMENT_BULLETS, {33,5}}, + {SFG_LEVEL_ELEMENT_TREE, {56,6}},{SFG_LEVEL_ELEMENT_LOCK2, {46,6}}, + {SFG_LEVEL_ELEMENT_HEALTH, {6,6}},{SFG_LEVEL_ELEMENT_ROCKETS, {28,7}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {17,7}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {11,7}}, + {SFG_LEVEL_ELEMENT_LAMP, {46,8}},{SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {40,8}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {28,8}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {27,8}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {26,8}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {25,8}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {8,10}},{SFG_LEVEL_ELEMENT_CARD2, {7,10}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {12,11}},{SFG_LEVEL_ELEMENT_COLUMN, {57,12}}, + {SFG_LEVEL_ELEMENT_COLUMN, {56,12}},{SFG_LEVEL_ELEMENT_COLUMN, {55,12}}, + {SFG_LEVEL_ELEMENT_LOCK2, {32,12}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {37,13}}, + {SFG_LEVEL_ELEMENT_HEALTH, {28,13}},{SFG_LEVEL_ELEMENT_LOCK1, {2,13}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {23,16}},{SFG_LEVEL_ELEMENT_BULLETS, {50,17}}, + {SFG_LEVEL_ELEMENT_PLASMA, {23,17}},{SFG_LEVEL_ELEMENT_BULLETS, {50,18}}, + {SFG_LEVEL_ELEMENT_PLASMA, {41,18}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {54,19}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {37,19}},{SFG_LEVEL_ELEMENT_HEALTH, {36,19}}, + {SFG_LEVEL_ELEMENT_PLASMA, {37,20}},{SFG_LEVEL_ELEMENT_BULLETS, {36,20}}, + {SFG_LEVEL_ELEMENT_BULLETS, {19,20}},{SFG_LEVEL_ELEMENT_BULLETS, {15,20}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {27,21}},{SFG_LEVEL_ELEMENT_ROCKETS, {9,21}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {7,21}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {45,22}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {9,22}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {4,22}}, + {SFG_LEVEL_ELEMENT_PLASMA, {1,22}},{SFG_LEVEL_ELEMENT_TREE, {34,23}}, + {SFG_LEVEL_ELEMENT_TREE, {33,23}},{SFG_LEVEL_ELEMENT_PLASMA, {1,23}}, + {SFG_LEVEL_ELEMENT_PLASMA, {1,24}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {17,26}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {47,27}},{SFG_LEVEL_ELEMENT_TREE, {27,28}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {41,29}},{SFG_LEVEL_ELEMENT_TREE, {27,29}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {20,29}},{SFG_LEVEL_ELEMENT_RUIN, {1,32}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {49,33}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {49,34}}, + {SFG_LEVEL_ELEMENT_PLASMA, {38,34}},{SFG_LEVEL_ELEMENT_LAMP, {15,34}}, + {SFG_LEVEL_ELEMENT_HEALTH, {38,35}},{SFG_LEVEL_ELEMENT_HEALTH, {58,36}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {56,36}},{SFG_LEVEL_ELEMENT_HEALTH, {28,36}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {15,36}},{SFG_LEVEL_ELEMENT_BULLETS, {49,37}}, + {SFG_LEVEL_ELEMENT_BULLETS, {49,38}},{SFG_LEVEL_ELEMENT_LOCK0, {35,38}}, + {SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {53,39}},{SFG_LEVEL_ELEMENT_HEALTH, {50,40}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {28,40}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {57,41}}, + {SFG_LEVEL_ELEMENT_RUIN, {17,41}},{SFG_LEVEL_ELEMENT_CARD1, {10,41}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {61,42}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {53,42}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {44,42}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {38,42}}, + {SFG_LEVEL_ELEMENT_BARREL, {37,42}},{SFG_LEVEL_ELEMENT_LAMP, {12,43}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {60,44}},{SFG_LEVEL_ELEMENT_NONE, {45,44}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {41,44}},{SFG_LEVEL_ELEMENT_BARREL, {37,44}}, + {SFG_LEVEL_ELEMENT_BARREL, {24,47}},{SFG_LEVEL_ELEMENT_BARREL, {23,47}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {4,47}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {32,49}}, + {SFG_LEVEL_ELEMENT_MONSTER_TURRET, {28,49}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {14,49}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {51,50}},{SFG_LEVEL_ELEMENT_COLUMN, {50,50}}, + {SFG_LEVEL_ELEMENT_BULLETS, {11,50}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {7,50}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {6,50}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {5,50}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {4,50}},{SFG_LEVEL_ELEMENT_LOCK0, {50,51}}, + {SFG_LEVEL_ELEMENT_BULLETS, {11,51}},{SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {57,52}}, + {SFG_LEVEL_ELEMENT_PLASMA, {51,52}},{SFG_LEVEL_ELEMENT_COLUMN, {50,52}}, + {SFG_LEVEL_ELEMENT_PLASMA, {28,52}},{SFG_LEVEL_ELEMENT_ROCKETS, {28,53}}, + {SFG_LEVEL_ELEMENT_BULLETS, {62,54}},{SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {61,54}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {54,54}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {3,54}}, + {SFG_LEVEL_ELEMENT_PLASMA, {56,55}},{SFG_LEVEL_ELEMENT_PLASMA, {41,55}}, + {SFG_LEVEL_ELEMENT_RUIN, {34,55}},{SFG_LEVEL_ELEMENT_HEALTH, {22,55}}, + {SFG_LEVEL_ELEMENT_PLASMA, {21,55}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {34,57}}, + {SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {45,58}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {9,59}}, + {SFG_LEVEL_ELEMENT_LAMP, {2,59}},{SFG_LEVEL_ELEMENT_ROCKETS, {56,60}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {41,60}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {36,60}}, + {SFG_LEVEL_ELEMENT_HEALTH, {23,60}},{SFG_LEVEL_ELEMENT_HEALTH, {15,61}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {8,61}},{SFG_LEVEL_ELEMENT_RUIN, {61,62}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {60,62}},{SFG_LEVEL_ELEMENT_HEALTH, {59,62}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}} + }, // elements + } // level + ; + +SFG_PROGRAM_MEMORY SFG_Level SFG_level9 = + { // level + { // mapArray + #define o 0 + #define AA (41 | SFG_TILE_PROPERTY_ELEVATOR) + #define BB (53 | SFG_TILE_PROPERTY_ELEVATOR) + #define CC (48 | SFG_TILE_PROPERTY_DOOR) + #define DD (4 | SFG_TILE_PROPERTY_DOOR) + #define EE (7 | SFG_TILE_PROPERTY_ELEVATOR) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +/*0 */ 6 ,6 ,6 ,AA,AA,AA,6 ,6 ,6 ,6 ,21,21,21,21,4 ,4 ,4 ,4 ,6 ,6 ,6 ,6 ,AA,AA,AA,AA,62,62,62,62,62,62,62,62,62,62,62,62,62,63,63,58,58,58,58,58,58,58,58,58,63,63,63,58,58,58,58,58,58,58,58,58,63,63, /*0 */ +/*1 */ 62,33,62,32,33,39,62,37,38,33,62,37,32,33,62,35,36,35,62,33,34,33,62,32,33,32,62,62,62,62,62,62,62,62,62,62,62,62,62,63,58,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,58,63, /*1 */ +/*2 */ 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,62,62,62,BB,52,52,52,52,52,52,52,52,52,58,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,58, /*2 */ +/*3 */ 47,47,47,47,47,47,47,47,47,49,47,49,47,47,47,49,47,49,47,47,47,49,47,49,47,47,62,62,62,47,62,62,62,62,62,62,62,62,62,58,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,58, /*3 */ +/*4 */ 47,47,47,49,47,49,47,47,49,49,49,49,49,47,49,49,49,49,49,47,49,49,49,49,49,47,47,47,47,47,62,62,62,62,62,62,62,62,62,58,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,58, /*4 */ +/*5 */ 47,47,47,47,47,47,47,47,49,49,49,49,49,47,49,49,49,49,49,47,49,49,49,49,49,47,62,62,62,62,62,62,62,62,62,62,62,62,62,58,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,58, /*5 */ +/*6 */ 47,47,49,47,47,47,49,47,47,49,49,49,47,47,47,49,49,49,47,47,47,49,49,49,47,47,62,62,63,63,63,63,63,63,63,63,62,62,62,58,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,58, /*6 */ +/*7 */ 47,47,47,49,49,49,47,47,47,47,49,47,47,47,47,47,49,47,47,47,47,47,49,47,47,47,62,62,63,o ,o ,o ,o ,o ,o ,63,62,62,62,58,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,58,58,58,58,58,58,58,58,58,58,o ,o ,58, /*7 */ +/*8 */ 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,62,62,57,o ,o ,o ,o ,o ,o ,57,62,62,62,58,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,58,1 ,1 ,1 ,1 ,1 ,1 ,25,1 ,58,58,58,58, /*8 */ +/*9 */ 47,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,63,o ,o ,o ,o ,o ,o ,63,62,62,62,63,58,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,58,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,58,23,23,23, /*9 */ +/*10*/ 47,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,57,o ,o ,o ,o ,o ,o ,57,62,62,62,63,63,58,58,58,58,58,58,58,58,58,58,58,1 ,62,62,62,62,62,62,62,47,47,62,62, /*10*/ +/*11*/ 47,62,62,62,62,62,63,63,57,63,63,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,63,o ,o ,o ,o ,o ,o ,63,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,63,63,57,63,63,62,62,62,47,62,62, /*11*/ +/*12*/ 47,62,62,62,62,62,63,o ,o ,o ,63,63,57,63,57,63,57,63,57,63,57,63,57,63,57,63,57,63,63,o ,o ,o ,o ,o ,o ,63,63,57,63,57,63,57,63,57,63,57,63,57,63,57,63,57,63,63,o ,o ,o ,63,62,62,62,47,47,47, /*12*/ +/*13*/ 47,62,62,62,62,62,57,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,57,62,62,62,62,62,CC, /*13*/ +/*14*/ 47,62,62,62,62,62,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,62,62,62,62,62,47, /*14*/ +/*15*/ 47,62,62,62,62,62,63,63,o ,o ,1 ,1 ,1 ,25,1 ,1 ,1 ,1 ,1 ,1 ,60,1 ,1 ,1 ,1 ,o ,8 ,9 ,10,11,12,1 ,1 ,12,11,10,9 ,8 ,o ,1 ,1 ,1 ,1 ,60,1 ,1 ,1 ,1 ,1 ,1 ,25,1 ,1 ,1 ,o ,o ,63,63,62,62,62,62,62,47, /*15*/ +/*16*/ 47,62,62,62,62,62,62,63,o ,o ,1 ,2 ,2 ,2 ,2 ,2 ,1 ,2 ,2 ,2 ,59,2 ,26,2 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,26,2 ,59,2 ,2 ,2 ,1 ,2 ,2 ,2 ,2 ,2 ,1 ,o ,o ,63,62,62,62,62,62,62,47, /*16*/ +/*17*/ 47,62,62,62,62,62,62,23,o ,o ,1 ,2 ,3 ,3 ,3 ,21,1 ,21,27,15,15,15,3 ,2 ,2 ,2 ,59,2 ,59,2 ,59,2 ,2 ,59,2 ,59,2 ,59,2 ,2 ,2 ,3 ,3 ,3 ,3 ,27,21,1 ,21,3 ,3 ,3 ,2 ,1 ,o ,o ,23,62,62,62,62,62,62,47, /*17*/ +/*18*/ 47,62,62,62,62,62,62,23,o ,o ,60,59,61,6 ,6 ,21,1 ,1 ,21,15,15,15,3 ,3 ,3 ,3 ,61,3 ,61,3 ,61,3 ,3 ,61,3 ,61,3 ,61,3 ,3 ,3 ,3 ,6 ,6 ,6 ,21,1 ,1 ,21,6 ,6 ,61,59,60,o ,o ,23,62,62,62,62,62,62,47, /*18*/ +/*19*/ 47,62,62,62,62,62,62,63,o ,o ,1 ,2 ,3 ,6 ,6 ,21,1 ,1 ,21,15,15,15,15,6 ,6 ,6 ,61,6 ,61,6 ,61,6 ,6 ,61,6 ,61,6 ,61,6 ,6 ,6 ,6 ,6 ,6 ,6 ,21,1 ,1 ,21,6 ,6 ,3 ,2 ,1 ,o ,o ,63,62,62,62,62,62,62,47, /*19*/ +/*20*/ 47,62,62,62,62,62,62,57,o ,o ,1 ,2 ,3 ,6 ,6 ,21,21,21,21,6 ,15,15,15,6 ,6 ,6 ,61,6 ,61,22,61,6 ,6 ,61,22,61,6 ,61,6 ,6 ,6 ,6 ,6 ,6 ,6 ,21,21,21,21,6 ,6 ,3 ,2 ,1 ,o ,o ,57,62,62,62,62,62,62,47, /*20*/ +/*21*/ 47,62,62,62,62,62,62,63,o ,o ,25,26,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,15,15,6 ,6 ,61,6 ,61,6 ,61,6 ,6 ,61,6 ,61,6 ,61,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,26,25,o ,o ,63,62,62,62,62,62,62,47, /*21*/ +/*22*/ 47,62,62,62,62,63,63,57,o ,o ,1 ,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,15,15,6 ,61,6 ,61,6 ,61,6 ,6 ,61,6 ,61,6 ,61,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,1 ,o ,o ,57,63,63,62,62,62,62,47, /*22*/ +/*23*/ 47,62,62,62,62,63,o ,o ,o ,o ,1 ,2 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,15,6 ,61,3 ,61,3 ,61,6 ,6 ,61,3 ,61,3 ,61,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,2 ,1 ,o ,o ,o ,o ,63,62,62,62,62,47, /*23*/ +/*24*/ 47,62,62,62,62,63,o ,o ,o ,o ,1 ,2 ,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,15,15,4 ,4 ,4 ,4 ,13,13,13,13,4 ,4 ,4 ,4 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,2 ,1 ,o ,o ,o ,o ,63,62,62,62,62,47, /*24*/ +/*25*/ 47,62,62,62,62,63,o ,o ,o ,o ,60,2 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,4 ,4 ,4 ,13,13,13,5 ,5 ,13,13,13,4 ,4 ,4 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,2 ,60,o ,o ,o ,o ,63,62,62,62,62,47, /*25*/ +/*26*/ 47,62,62,62,62,63,o ,o ,o ,o ,60,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,4 ,4 ,4 ,13,5 ,5 ,5 ,5 ,5 ,5 ,13,4 ,4 ,4 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,60,o ,o ,o ,o ,63,62,62,62,62,47, /*26*/ +/*27*/ 47,62,62,62,62,63,o ,o ,o ,o ,1 ,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,13,4 ,4 ,13,5 ,5 ,5 ,5 ,5 ,5 ,13,4 ,4 ,13,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,1 ,o ,o ,o ,o ,63,62,62,62,62,47, /*27*/ +/*28*/ 47,62,62,62,62,63,o ,o ,o ,o ,1 ,2 ,3 ,6 ,61,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,4 ,4 ,4 ,13,13,13,5 ,5 ,13,13,13,4 ,4 ,4 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,61,6 ,3 ,2 ,1 ,o ,o ,o ,o ,63,62,62,62,62,47, /*28*/ +/*29*/ 47,62,62,62,62,63,63,57,o ,o ,1 ,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,4 ,4 ,4 ,4 ,4 ,13,DD,DD,13,4 ,4 ,4 ,4 ,4 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,1 ,o ,o ,57,63,63,62,62,62,62,47, /*29*/ +/*30*/ 47,62,62,62,62,62,62,63,o ,o ,25,26,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,4 ,4 ,13,4 ,4 ,5 ,5 ,4 ,4 ,13,4 ,4 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,26,25,o ,o ,63,62,62,62,62,62,62,47, /*30*/ +/*31*/ 47,62,62,62,62,62,62,57,o ,o ,1 ,2 ,2 ,2 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,6 ,3 ,6 ,6 ,6 ,6 ,3 ,6 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,2 ,2 ,2 ,1 ,o ,o ,57,62,62,62,62,62,62,47, /*31*/ +/*32*/ 47,62,62,62,62,62,62,63,o ,o ,1 ,1 ,1 ,2 ,14,3 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,3 ,14,2 ,1 ,1 ,1 ,o ,o ,63,62,62,62,62,62,62,47, /*32*/ +/*33*/ 47,62,62,62,62,62,62,57,o ,o ,1 ,1 ,1 ,2 ,14,3 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,3 ,14,2 ,1 ,1 ,1 ,o ,o ,57,62,62,62,62,62,62,47, /*33*/ +/*34*/ 47,62,62,62,62,62,62,63,o ,o ,1 ,1 ,1 ,2 ,14,3 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,3 ,14,2 ,1 ,1 ,1 ,o ,o ,63,62,62,62,62,62,62,47, /*34*/ +/*35*/ 47,62,62,62,62,62,62,57,o ,o ,1 ,1 ,1 ,2 ,14,3 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,3 ,14,2 ,1 ,1 ,1 ,o ,o ,57,62,62,62,62,62,62,47, /*35*/ +/*36*/ 47,62,62,62,62,62,62,63,o ,o ,1 ,2 ,2 ,2 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,2 ,2 ,2 ,1 ,o ,o ,63,62,62,62,62,62,62,47, /*36*/ +/*37*/ 47,62,62,62,62,62,62,57,o ,o ,25,2 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,2 ,25,o ,o ,57,62,62,62,62,62,62,47, /*37*/ +/*38*/ 47,62,62,62,62,62,62,63,o ,o ,1 ,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,1 ,o ,o ,63,62,62,62,62,62,62,47, /*38*/ +/*39*/ 47,62,62,62,62,63,63,57,o ,o ,1 ,2 ,3 ,6 ,6 ,6 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,6 ,6 ,15,15,2 ,1 ,o ,o ,57,63,63,62,62,62,62,47, /*39*/ +/*40*/ 47,62,62,62,62,63,o ,o ,o ,o ,1 ,2 ,3 ,6 ,6 ,6 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,15,15,15,15,2 ,1 ,o ,o ,o ,o ,63,62,62,62,62,47, /*40*/ +/*41*/ 47,62,62,62,62,63,o ,o ,o ,58,1 ,2 ,3 ,6 ,6 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,15,15,3 ,2 ,1 ,58,o ,o ,o ,63,62,62,62,62,47, /*41*/ +/*42*/ 47,62,62,62,62,63,o ,o ,o ,1 ,1 ,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,1 ,1 ,o ,o ,o ,63,62,62,62,62,47, /*42*/ +/*43*/ 47,62,62,62,62,63,o ,o ,o ,1 ,1 ,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,1 ,1 ,o ,o ,o ,63,62,62,62,62,47, /*43*/ +/*44*/ 47,62,62,62,62,63,o ,o ,o ,58,1 ,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,1 ,58,o ,o ,o ,63,62,62,62,62,47, /*44*/ +/*45*/ 47,62,62,62,62,63,o ,o ,o ,o ,1 ,2 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,2 ,1 ,o ,o ,o ,o ,63,62,62,62,62,47, /*45*/ +/*46*/ 47,62,62,62,62,63,63,57,o ,o ,1 ,2 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,2 ,1 ,o ,o ,57,63,63,62,62,62,62,47, /*46*/ +/*47*/ 47,62,62,62,62,62,62,63,o ,o ,60,59,61,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,61,59,60,o ,o ,63,62,62,62,62,62,62,47, /*47*/ +/*48*/ 47,62,62,62,62,62,62,57,o ,o ,25,26,27,3 ,6 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,14,14,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,6 ,3 ,27,26,25,o ,o ,57,62,62,62,62,62,62,47, /*48*/ +/*49*/ 47,62,62,62,62,62,62,63,o ,o ,60,59,61,3 ,6 ,6 ,6 ,3 ,6 ,6 ,61,6 ,6 ,61,6 ,6 ,6 ,6 ,20,5 ,5 ,5 ,5 ,5 ,5 ,20,6 ,6 ,6 ,6 ,61,6 ,6 ,61,6 ,6 ,3 ,6 ,6 ,6 ,3 ,61,59,60,o ,o ,63,62,62,62,62,62,62,47, /*49*/ +/*50*/ 47,62,62,62,62,62,62,57,o ,o ,1 ,2 ,3 ,3 ,6 ,6 ,6 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,20,5 ,5 ,5 ,5 ,5 ,5 ,20,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,6 ,6 ,6 ,3 ,3 ,2 ,1 ,o ,o ,57,62,62,62,62,62,62,47, /*50*/ +/*51*/ 47,62,62,62,62,62,62,63,o ,o ,60,59,61,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,3 ,3 ,5 ,5 ,EE,EE,5 ,5 ,3 ,3 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,6 ,3 ,61,59,60,o ,o ,63,62,62,62,62,62,62,47, /*51*/ +/*52*/ 47,62,62,62,62,62,62,57,o ,o ,1 ,2 ,3 ,3 ,6 ,6 ,6 ,6 ,3 ,3 ,3 ,6 ,6 ,6 ,3 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,3 ,6 ,6 ,6 ,3 ,3 ,3 ,6 ,6 ,6 ,6 ,3 ,3 ,2 ,1 ,o ,o ,57,62,62,62,62,62,62,47, /*52*/ +/*53*/ 47,62,62,62,62,62,62,63,o ,o ,1 ,2 ,2 ,3 ,3 ,3 ,3 ,3 ,3 ,2 ,3 ,3 ,3 ,3 ,3 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,3 ,3 ,3 ,3 ,3 ,2 ,3 ,3 ,3 ,3 ,3 ,3 ,2 ,2 ,1 ,o ,o ,63,62,62,62,62,62,62,47, /*53*/ +/*54*/ 47,62,62,62,62,62,62,57,o ,o ,1 ,2 ,2 ,2 ,59,2 ,59,2 ,2 ,2 ,2 ,2 ,26,2 ,2 ,2 ,1 ,16,17,18,19,2 ,2 ,19,18,17,16,1 ,2 ,2 ,2 ,26,2 ,2 ,2 ,2 ,2 ,59,2 ,59,2 ,2 ,2 ,1 ,o ,o ,57,62,62,62,62,62,62,47, /*54*/ +/*55*/ 47,62,62,62,62,62,62,63,o ,o ,1 ,1 ,1 ,1 ,60,25,60,1 ,1 ,1 ,1 ,1 ,25,1 ,60,1 ,60,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,60,1 ,60,1 ,25,1 ,1 ,1 ,1 ,1 ,60,25,60,1 ,1 ,1 ,1 ,o ,o ,63,62,62,62,62,62,62,47, /*55*/ +/*56*/ 47,62,62,62,62,62,62,57,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,57,57,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,57,62,62,62,62,62,62,47, /*56*/ +/*57*/ 47,62,62,62,62,62,62,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,63,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,63,62,62,62,62,62,62,47, /*57*/ +/*58*/ 47,62,62,62,62,62,62,63,63,57,63,57,63,57,63,57,63,23,23,23,23,23,63,57,63,57,63,57,o ,o ,o ,o ,o ,o ,o ,o ,57,63,57,63,57,63,23,23,23,23,23,63,57,63,57,63,57,63,57,63,63,62,62,62,62,62,62,47, /*58*/ +/*59*/ 47,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,63,o ,o ,o ,o ,o ,o ,o ,o ,63,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,47, /*59*/ +/*60*/ 47,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,63,63,63,63,63,63,63,63,63,63,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,47, /*60*/ +/*61*/ 47,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,47, /*61*/ +/*62*/ 47,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,47, /*62*/ +/*63*/ 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 /*63*/ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 + #undef AA + #undef BB + #undef CC + #undef DD + #undef EE + #undef o + }, + { // tileDictionary + SFG_TD( 0,31,0,0),SFG_TD(12,31,0,0),SFG_TD(22,31,0,0),SFG_TD(31,31,0,0), // 0 + SFG_TD(31, 0,0,0),SFG_TD(27,31,0,0),SFG_TD(29,31,4,0),SFG_TD(22, 5,1,0), // 4 + SFG_TD( 2,31,0,0),SFG_TD( 4,31,0,0),SFG_TD( 6,31,0,0),SFG_TD( 8,31,0,0), // 8 + SFG_TD(10,31,0,0),SFG_TD(31, 0,3,3),SFG_TD(31,31,3,0),SFG_TD(28,31,4,0), // 12 + SFG_TD(14,31,0,0),SFG_TD(16,31,0,0),SFG_TD(18,31,0,0),SFG_TD(20,31,0,0), // 16 + SFG_TD(29,31,0,0),SFG_TD(31,31,5,0),SFG_TD(31, 0,6,6),SFG_TD( 9,31,0,0), // 20 + SFG_TD(14,15,0,0),SFG_TD(12,31,2,0),SFG_TD(22,31,2,0),SFG_TD(31,31,2,0), // 24 + SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0), // 28 + SFG_TD(13, 4,7,7),SFG_TD( 1,16,7,7),SFG_TD( 9, 4,7,7),SFG_TD( 1,12,7,7), // 32 + SFG_TD( 5,12,7,7),SFG_TD( 1,12,7,7),SFG_TD( 5, 4,7,7),SFG_TD( 1, 4,7,7), // 36 + SFG_TD(14,15,0,0),SFG_TD(31,18,5,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0), // 40 + SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0),SFG_TD( 0,31,7,7), // 44 + SFG_TD( 4,31,0,0),SFG_TD( 0,31,0,0),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0), // 48 + SFG_TD(31,31,7,7),SFG_TD( 0,31,0,7),SFG_TD(14,15,0,0),SFG_TD(14,15,0,0), // 52 + SFG_TD(14,15,0,0),SFG_TD( 4,31,3,0),SFG_TD( 2,31,5,0),SFG_TD(23,31,1,0), // 56 + SFG_TD(13,31,1,0),SFG_TD(30,31,1,0),SFG_TD(31, 0,7,7),SFG_TD( 4,31,0,0) // 60 + }, // tileDictionary + {14,11,1 ,8 ,9 ,5 ,13}, // textureIndices + 7, // doorTextureIndex + 74, // floorColor + 74, // ceilingColor + {55, 13, 160}, // player start: x, y, direction + 2, // backgroundImage + { // elements + {SFG_LEVEL_ELEMENT_BULLETS, {55,2}},{SFG_LEVEL_ELEMENT_BULLETS, {53,2}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {47,2}},{SFG_LEVEL_ELEMENT_ROCKETS, {45,2}}, + {SFG_LEVEL_ELEMENT_HEALTH, {55,4}},{SFG_LEVEL_ELEMENT_HEALTH, {53,4}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {47,4}},{SFG_LEVEL_ELEMENT_ROCKETS, {45,4}}, + {SFG_LEVEL_ELEMENT_PLASMA, {48,6}},{SFG_LEVEL_ELEMENT_PLASMA, {48,7}}, + {SFG_LEVEL_ELEMENT_TELEPORTER, {43,7}},{SFG_LEVEL_ELEMENT_HEALTH, {33,8}}, + {SFG_LEVEL_ELEMENT_HEALTH, {30,8}},{SFG_LEVEL_ELEMENT_BULLETS, {33,10}}, + {SFG_LEVEL_ELEMENT_PLASMA, {30,10}},{SFG_LEVEL_ELEMENT_LOCK2, {63,13}}, + {SFG_LEVEL_ELEMENT_RUIN, {43,13}},{SFG_LEVEL_ELEMENT_RUIN, {43,14}}, + {SFG_LEVEL_ELEMENT_RUIN, {42,15}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {52,17}}, + {SFG_LEVEL_ELEMENT_BARREL, {25,17}},{SFG_LEVEL_ELEMENT_TELEPORTER, {46,19}}, + {SFG_LEVEL_ELEMENT_RUIN, {22,19}},{SFG_LEVEL_ELEMENT_HEALTH, {17,19}}, + {SFG_LEVEL_ELEMENT_BULLETS, {16,19}},{SFG_LEVEL_ELEMENT_HEALTH, {47,21}}, + {SFG_LEVEL_ELEMENT_PLASMA, {46,21}},{SFG_LEVEL_ELEMENT_PLASMA, {17,21}}, + {SFG_LEVEL_ELEMENT_HEALTH, {16,21}},{SFG_LEVEL_ELEMENT_ROCKETS, {47,22}}, + {SFG_LEVEL_ELEMENT_BULLETS, {46,22}},{SFG_LEVEL_ELEMENT_BULLETS, {17,22}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {16,22}},{SFG_LEVEL_ELEMENT_HEALTH, {32,23}}, + {SFG_LEVEL_ELEMENT_HEALTH, {31,23}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {10,23}}, + {SFG_LEVEL_ELEMENT_BARREL, {47,24}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {42,24}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {56,25}},{SFG_LEVEL_ELEMENT_BARREL, {47,25}}, + {SFG_LEVEL_ELEMENT_FINISH, {32,25}},{SFG_LEVEL_ELEMENT_FINISH, {31,25}}, + {SFG_LEVEL_ELEMENT_RUIN, {24,25}},{SFG_LEVEL_ELEMENT_ROCKETS, {7,25}}, + {SFG_LEVEL_ELEMENT_PLASMA, {56,26}},{SFG_LEVEL_ELEMENT_HEALTH, {42,26}}, + {SFG_LEVEL_ELEMENT_COLUMN, {33,26}},{SFG_LEVEL_ELEMENT_COLUMN, {30,26}}, + {SFG_LEVEL_ELEMENT_HEALTH, {21,26}},{SFG_LEVEL_ELEMENT_PLASMA, {7,26}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {56,27}},{SFG_LEVEL_ELEMENT_COLUMN, {33,27}}, + {SFG_LEVEL_ELEMENT_COLUMN, {30,27}},{SFG_LEVEL_ELEMENT_ROCKETS, {7,27}}, + {SFG_LEVEL_ELEMENT_HEALTH, {42,28}},{SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {38,28}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {26,28}},{SFG_LEVEL_ELEMENT_HEALTH, {21,28}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {39,29}},{SFG_LEVEL_ELEMENT_LOCK2, {32,29}}, + {SFG_LEVEL_ELEMENT_LOCK2, {31,29}},{SFG_LEVEL_ELEMENT_ROCKETS, {25,29}}, + {SFG_LEVEL_ELEMENT_BULLETS, {33,30}},{SFG_LEVEL_ELEMENT_BULLETS, {30,30}}, + {SFG_LEVEL_ELEMENT_MONSTER_ENDER, {40,32}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {31,32}}, + {SFG_LEVEL_ELEMENT_MONSTER_ENDER, {23,32}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {55,33}}, + {SFG_LEVEL_ELEMENT_HEALTH, {52,33}},{SFG_LEVEL_ELEMENT_HEALTH, {11,33}}, + {SFG_LEVEL_ELEMENT_HEALTH, {52,34}},{SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {45,34}}, + {SFG_LEVEL_ELEMENT_MONSTER_SPIDER, {19,34}},{SFG_LEVEL_ELEMENT_HEALTH, {11,34}}, + {SFG_LEVEL_ELEMENT_MONSTER_ENDER, {31,35}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {27,36}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {39,37}},{SFG_LEVEL_ELEMENT_MONSTER_WARRIOR, {35,37}}, + {SFG_LEVEL_ELEMENT_MONSTER_DESTROYER, {24,37}},{SFG_LEVEL_ELEMENT_PLASMA, {43,39}}, + {SFG_LEVEL_ELEMENT_PLASMA, {20,39}},{SFG_LEVEL_ELEMENT_HEALTH, {32,40}}, + {SFG_LEVEL_ELEMENT_HEALTH, {31,40}},{SFG_LEVEL_ELEMENT_BARREL, {43,41}}, + {SFG_LEVEL_ELEMENT_BARREL, {42,41}},{SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {38,41}}, + {SFG_LEVEL_ELEMENT_MONSTER_EXPLODER, {25,41}},{SFG_LEVEL_ELEMENT_BARREL, {20,41}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {56,42}},{SFG_LEVEL_ELEMENT_BARREL, {43,42}}, + {SFG_LEVEL_ELEMENT_BARREL, {42,42}},{SFG_LEVEL_ELEMENT_BARREL, {21,42}}, + {SFG_LEVEL_ELEMENT_BARREL, {19,42}},{SFG_LEVEL_ELEMENT_ROCKETS, {7,42}}, + {SFG_LEVEL_ELEMENT_PLASMA, {56,43}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {52,43}}, + {SFG_LEVEL_ELEMENT_BARREL, {32,43}},{SFG_LEVEL_ELEMENT_BARREL, {31,43}}, + {SFG_LEVEL_ELEMENT_BARREL, {30,43}},{SFG_LEVEL_ELEMENT_BARREL, {20,43}}, + {SFG_LEVEL_ELEMENT_PLASMA, {7,43}},{SFG_LEVEL_ELEMENT_HEALTH, {32,45}}, + {SFG_LEVEL_ELEMENT_HEALTH, {31,45}},{SFG_LEVEL_ELEMENT_ROCKETS, {49,50}}, + {SFG_LEVEL_ELEMENT_HEALTH, {48,50}},{SFG_LEVEL_ELEMENT_HEALTH, {15,50}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {14,50}},{SFG_LEVEL_ELEMENT_PLASMA, {49,51}}, + {SFG_LEVEL_ELEMENT_BULLETS, {48,51}},{SFG_LEVEL_ELEMENT_BULLETS, {15,51}}, + {SFG_LEVEL_ELEMENT_PLASMA, {14,51}},{SFG_LEVEL_ELEMENT_RUIN, {31,52}}, + {SFG_LEVEL_ELEMENT_RUIN, {36,53}},{SFG_LEVEL_ELEMENT_RUIN, {35,53}}, + {SFG_LEVEL_ELEMENT_RUIN, {34,53}},{SFG_LEVEL_ELEMENT_RUIN, {33,53}}, + {SFG_LEVEL_ELEMENT_RUIN, {32,53}},{SFG_LEVEL_ELEMENT_RUIN, {28,53}}, + {SFG_LEVEL_ELEMENT_RUIN, {27,53}},{SFG_LEVEL_ELEMENT_MONSTER_TURRET, {25,53}}, + {SFG_LEVEL_ELEMENT_BARREL, {18,54}},{SFG_LEVEL_ELEMENT_HEALTH, {55,57}}, + {SFG_LEVEL_ELEMENT_HEALTH, {8,57}},{SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT, {33,58}}, + {SFG_LEVEL_ELEMENT_ROCKETS, {32,59}},{SFG_LEVEL_ELEMENT_PLASMA, {31,59}}, + {SFG_LEVEL_ELEMENT_NONE, {0,0}},{SFG_LEVEL_ELEMENT_NONE, {0,0}} + }, // elements + } // level + + ; + +static const SFG_Level * SFG_levels[SFG_NUMBER_OF_LEVELS] = +{ + &SFG_level0, &SFG_level1, &SFG_level2, &SFG_level3, &SFG_level4, &SFG_level5, + &SFG_level6, &SFG_level7, &SFG_level8, &SFG_level9 +}; + +#endif // guard + diff --git a/main_gbmeta/main_gbmeta.ino b/main_gbmeta/main_gbmeta.ino new file mode 100644 index 0000000..3dd3b32 --- /dev/null +++ b/main_gbmeta/main_gbmeta.ino @@ -0,0 +1,173 @@ +/** + @file main_gbmeta.ino + + This is Gamebuino Meta implementation of the game front end, using the + official library. Leaving out the library bloat could probably optimize this. + + To compile using Arduin IDE you need to copy this file as well as all + necessary .h files into a project folder, then open the project and compile. + Do NOT put .c and .cpp files into the folder, stupid Arduino tries to compile + them even if they're not needed. + + DON'T FORGET to set compiler flag to -O3 (default is -Os). With Arduino IDE + this is done in platform.txt file. + + by Miloslav Ciz (drummyfish), 2019 + + Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) + plus a waiver of all other intellectual property. The goal of this work is + be and remain completely in the public domain forever, available for any use + whatsoever. +*/ + +#include + +#define SFG_ARDUINO 1 +#define SFG_CAN_EXIT 0 +#define SFG_FPS 17 +#define SFG_SCREEN_RESOLUTION_X 80 +#define SFG_SCREEN_RESOLUTION_Y 64 +#define SFG_RESOLUTION_SCALEDOWN 1 +#define SFG_RAYCASTING_MAX_STEPS 11 +#define SFG_RAYCASTING_MAX_HITS 3 +#define SFG_RAYCASTING_SUBSAMPLE 2 +#define SFG_DIMINISH_SPRITES 0 +#define SFG_DITHERED_SHADOW 0 +#define SFG_PLAYER_TURN_SPEED 135 +#define SFG_FOV_HORIZONTAL 200 + +#include "game.h" + +Gamebuino_Meta::Color palette[256]; + +uint8_t blinkFramesLeft; + +void blinkLED(Gamebuino_Meta::Color color) +{ + gb.lights.fill(color); + blinkFramesLeft = 5; +} + +const Gamebuino_Meta::SaveDefault saveDefault[] = + { { 0, SAVETYPE_BLOB, SFG_SAVE_SIZE, 0 } }; + +void SFG_setPixel(uint16_t x, uint16_t y, uint8_t colorIndex) +{ + Gamebuino_Meta::Color c = palette[colorIndex]; + gb.display.drawPixel(x,y,c); +} + +void SFG_sleepMs(uint16_t timeMs) +{ +} + +int8_t SFG_keyPressed(uint8_t key) +{ + Gamebuino_Meta::Button button; + + switch (key) + { + case SFG_KEY_UP: button = BUTTON_UP; break; + case SFG_KEY_RIGHT: button = BUTTON_RIGHT; break; + case SFG_KEY_DOWN: button = BUTTON_DOWN; break; + case SFG_KEY_LEFT: button = BUTTON_LEFT; break; + case SFG_KEY_A: button = BUTTON_A; break; + case SFG_KEY_B: button = BUTTON_B; break; + case SFG_KEY_C: button = BUTTON_MENU; break; + default: return 0; break; + } + + return gb.buttons.timeHeld(button) > 0; +} + +void SFG_processEvent(uint8_t event, uint8_t value) +{ + switch (event) + { + case SFG_EVENT_LEVEL_STARTS: blinkLED(BLUE); break; + case SFG_EVENT_PLAYER_HURT: blinkLED(RED); break; + case SFG_EVENT_LEVEL_WON: blinkLED(YELLOW); break; + default: break; + } +} + +void SFG_getMouseOffset(int16_t *x, int16_t *y) +{ +} + +void SFG_setMusic(uint8_t value) +{ +} + +void SFG_save(uint8_t data[SFG_SAVE_SIZE]) +{ + gb.save.set(0,data,SFG_SAVE_SIZE); +} + +uint8_t SFG_load(uint8_t data[SFG_SAVE_SIZE]) +{ + gb.save.get(0,data,SFG_SAVE_SIZE); + return 1; +} + +void SFG_playSound(uint8_t soundIndex, uint8_t volume) +{ + switch (soundIndex) + { + case 2: + gb.sound.playCancel(); + break; + + case 5: + gb.sound.playOK(); + break; + + default: + gb.sound.playTick(); + break; + } +} + +uint32_t SFG_getTimeMs() +{ + return gb.frameStartMicros / 1000; +} + +void setup() +{ + gb.begin(); + gb.setFrameRate(SFG_FPS); + gb.save.config(saveDefault); + + for (int i = 0; i < 256; ++i) + { + uint16_t rgb565 = paletteRGB565[i]; + palette[i] = gb.createColor((rgb565 & 0xf800) >> 8,(rgb565 & 0x07e0) >> 3,(rgb565 & 0x001f) << 3); + } + + SFG_init(); + blinkLED(RED); +} + +void loop() +{ + while(!gb.update()) + { + } + + if (blinkFramesLeft != 0) + { + if (blinkFramesLeft == 1) + gb.lights.clear(); + + blinkFramesLeft--; + } + + SFG_mainLoopBody(); + +#if 0 + // debuggin performance + gb.display.setCursor(1,1); + gb.display.print(gb.getCpuLoad()); +#endif +} diff --git a/main_gbmeta/main_gbmeta.ino.gamebuino_meta.bin b/main_gbmeta/main_gbmeta.ino.gamebuino_meta.bin new file mode 100755 index 0000000..2c41390 Binary files /dev/null and b/main_gbmeta/main_gbmeta.ino.gamebuino_meta.bin differ diff --git a/main_gbmeta/mbed_config.h b/main_gbmeta/mbed_config.h new file mode 100644 index 0000000..34e7f96 --- /dev/null +++ b/main_gbmeta/mbed_config.h @@ -0,0 +1,25 @@ +/* + * mbed SDK + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Automatically generated configuration file. +// DO NOT EDIT, content will be overwritten. + +#ifndef __MBED_CONFIG_DATA__ +#define __MBED_CONFIG_DATA__ + + +#endif diff --git a/main_gbmeta/palette.h b/main_gbmeta/palette.h new file mode 100644 index 0000000..ec66ee2 --- /dev/null +++ b/main_gbmeta/palette.h @@ -0,0 +1,98 @@ +/* + @file palette.h + + General purpose HSV-based 256 color palette. + + by Miloslav Ciz (drummyfish), 2019 + + Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) + plus a waiver of all other intellectual property. The goal of this work is + be and remain completely in the public domain forever, available for any use + whatsoever. +*/ + +#ifndef PALETTE_256_H +#define PALETTE_256_H + +SFG_PROGRAM_MEMORY uint16_t paletteRGB565[256] = { +#if 1 +// manually adjusted, more saturated palette +0, 6371, 14855, 27436, 38066, 48631, 59228, 65535, 6241, 14563, 24966, 33320, +43755, 52142, 62577, 64885, 6337, 16772, 25190, 35689, 44139, 52559, 63058, +65333, 6402, 14851, 23334, 31816, 40268, 50830, 59314, 65526, 4354, 10755, +15174, 21576, 30027, 36462, 42929, 51190, 2306, 8709, 13096, 19532, 25935, +30323, 36790, 47098, 4356, 8711, 15115, 19536, 27956, 32377, 38846, 47103, +4227, 8519, 12812, 17136, 25588, 31961, 38334, 46751, 2115, 8424, 14732, 21040, +27380, 33721, 40030, 48511, 6244, 12520, 22924, 31280, 39669, 48089, 56445, +64927, 8290, 16614, 24969, 33325, 43761, 52148, 62585, 64892, 10240, 18464, +26657, 38946, 47202, 55524, 63781, 64074, 10400, 18753, 27170, 37601, 48034, +56421, 64837, 65002, 6496, 14944, 23425, 31937, 40418, 48869, 57317, 61418, +352, 4704, 7041, 7362, 15842, 20196, 24550, 30697, 354, 611, 2949, 5288, 7658, +12013, 8175, 20467, 357, 617, 910, 5298, 9686, 7931, 14335, 24575, 69, 233, +4461, 4594, 8918, 2907, 13311, 19679, 4133, 2089, 4173, 8306, 10455, 16667, +20863, 27263, 6149, 14377, 22574, 28819, 39063, 45371, 53631, 57983, 10242, +18469, 26664, 38987, 47247, 55537, 63797, 64119, 10272, 18432, 26624, 34848, +45056, 53312, 61504, 63520, 10336, 18624, 26976, 35296, 45728, 54048, 62400, +64609, 8544, 16992, 25440, 31872, 42400, 50880, 59328, 65504, 4448, 2656, +7008, 11392, 13728, 14016, 20416, 26593, 2400, 608, 864, 3200, 5504, 1698, +1985, 2019, 353, 614, 872, 1163, 1422, 1713, 2005, 2039, 197, 361, 557, 753, +950, 5273, 1406, 9759, 5, 9, 2093, 81, 4214, 186, 2270, 351, 2052, 4105, 4109, +8209, 8278, 12314, 16414, 18527, 10245, 14378, 22541, 30738, 38934, 47130, 55326, +61471, 10241, 18435, 26630, 34824, 45066, 53293, 61519, 63601 +#else +// original palette +0, 8484, 19017, 27501, 38034, 46518, 57051, 65535, 8354, 16709, 25096, 33450, +41805, 50192, 58546, 64853, 8386, 16805, 25224, 33642, 42061, 50480, 58898, +65269, 6402, 14853, 23304, 29706, 38157, 46608, 55058, 61429, 4354, 10757, +17160, 23562, 29965, 36368, 42770, 49141, 4355, 10758, 17161, 21516, 27920, +34323, 38678, 45049, 4323, 10759, 17163, 21519, 27923, 34327, 38683, 45055, +4292, 10632, 17004, 21296, 27668, 34008, 38300, 44671, 4260, 10568, 16908, +23216, 29524, 35864, 42172, 48479, 6308, 14664, 23052, 29360, 37716, 46104, +54460, 60767, 8355, 16710, 25098, 33453, 41809, 50196, 58552, 64859, 8257, +16546, 24836, 33093, 41382, 49672, 57929, 64170, 8353, 16738, 25124, 33509, +41894, 50248, 58633, 64970, 6401, 12802, 21252, 27653, 36102, 42504, 50953, +57322, 2305, 6658, 11012, 15365, 19718, 24072, 28425, 32746, 2306, 4612, 8967, +11273, 13580, 17934, 20240, 22515, 2307, 4615, 8971, 11279, 13587, 17943, 20251, +22527, 2180, 4392, 8652, 10864, 13076, 17304, 19516, 21727, 2116, 6312, 10508, +14672, 18868, 23064, 25180, 29375, 6212, 12456, 20748, 26960, 35252, 41496, +49756, 55999, 8258, 16549, 24840, 33099, 41390, 49681, 57940, 64183, 8192, +16384, 24576, 32768, 40960, 49152, 57344, 63488, 8320, 16640, 24960, 33312, +41632, 49952, 58304, 64576, 6400, 14848, 23296, 29696, 38144, 46592, 52992, +61408, 2304, 6656, 8960, 13312, 15616, 19968, 22272, 26592, 256, 513, 769, 1026, +1283, 1539, 1796, 2021, 258, 517, 776, 1035, 1294, 1552, 1811, 2038, 164, 360, +556, 752, 948, 1144, 1308, 1503, 36, 104, 140, 208, 244, 312, 348, 415, 2052, +4104, 8204, 10256, 14356, 16408, 18460, 22559, 6148, 14344, 20492, 28688, 34836, +43032, 51228, 57375, 8194, 16388, 24582, 32777, 40971, 49165, 57359, 63505 +#endif +}; + +/** Adds value (brightness), possibly negative, to given color (represented by + its palette index). If you know you'll only be either adding or substracting, + use plusValue() or minusValue() functions, which should be faster. */ +static inline uint8_t palette_addValue(uint8_t color, int8_t add) +{ + uint8_t newValue = color + add; + + if ((newValue >> 3) == (color >> 3)) + return newValue; + else + return add > 0 ? (color | 0x07) : 0; +} + +/** Adds a positive value (brightness) to given color (represented by its + palette index). This should be a little bit faster than addValue(). */ +static inline uint8_t palette_plusValue(uint8_t color, uint8_t plus) +{ + uint8_t newValue = color + plus; + return ((newValue >> 3) == (color >> 3)) ? newValue : (color | 0x07); +} + +/** Substracts a positive value (brightness) from given color (represented by + its palette index). This should be a little bit faster than addValue(). */ +static inline uint8_t palette_minusValue(uint8_t color, uint8_t minus) +{ + uint8_t newValue = color - minus; + return ((newValue >> 3) == (color >> 3)) ? newValue : 0; +} + +#endif //guard diff --git a/main_gbmeta/raycastlib.h b/main_gbmeta/raycastlib.h new file mode 100644 index 0000000..38a70ff --- /dev/null +++ b/main_gbmeta/raycastlib.h @@ -0,0 +1,2058 @@ +#ifndef RAYCASTLIB_H +#define RAYCASTLIB_H + +/** + raycastlib (RCL) - Small C header-only raycasting library for embedded and + low performance computers, such as Arduino. Only uses integer math and stdint + standard library. + + Check the defines below to fine-tune accuracy vs performance! Don't forget + to compile with optimizations. + + Before including the library define RCL_PIXEL_FUNCTION to the name of the + function (with RCL_PixelFunction signature) that will render your pixels! + + - All public (and most private) library identifiers start with RCL_. + - Game field's bottom left corner is at [0,0]. + - X axis goes right in the ground plane. + - Y axis goes up in the ground plane. + - Height means the Z (vertical) coordinate. + - Each game square is RCL_UNITS_PER_SQUARE * RCL_UNITS_PER_SQUARE points. + - Angles are in RCL_Units, 0 means pointing right (x+) and positively rotates + clockwise. A full angle has RCL_UNITS_PER_SQUARE RCL_Units. + - Most things are normalized with RCL_UNITS_PER_SQUARE (sin, cos, vector + unit length, texture coordinates etc.). + - Screen coordinates are normal: [0,0] = top left, x goes right, y goes down. + + author: Miloslav "drummyfish" Ciz + license: CC0 1.0 + version: 0.908d + + Version numbering: major.minor[d], id 'd' is appended, this is a + in-development version based on the previous stable major.minor version. Two + 'd' versions with the same version number, .e.g. 1.0d, may be different. +*/ + +#include + +#ifndef RCL_RAYCAST_TINY /** Turns on super efficient version of this library. + Only use if neccesarry, looks ugly. Also not done + yet. */ + #define RCL_UNITS_PER_SQUARE 1024 /**< Number of RCL_Units in a side of a + spatial square. */ + typedef int32_t RCL_Unit; /**< Smallest spatial unit, there is + RCL_UNITS_PER_SQUARE units in a square's + length. This effectively serves the purpose of + a fixed-point arithmetic. */ + #define RCL_INFINITY 2000000000 +#else + #define RCL_UNITS_PER_SQUARE 32 + typedef int16_t RCL_Unit; + #define RCL_INFINITY 30000 + #define RCL_USE_DIST_APPROX 2 +#endif + +#ifndef RCL_COMPUTE_WALL_TEXCOORDS +#define RCL_COMPUTE_WALL_TEXCOORDS 1 +#endif + +#ifndef RCL_COMPUTE_FLOOR_TEXCOORDS +#define RCL_COMPUTE_FLOOR_TEXCOORDS 0 +#endif + +#ifndef RCL_FLOOR_TEXCOORDS_HEIGHT +#define RCL_FLOOR_TEXCOORDS_HEIGHT 0 /** If RCL_COMPUTE_FLOOR_TEXCOORDS == 1, + this says for what height level the + texture coords will be computed for + (for simplicity/performance only one + level is allowed). */ +#endif + +#ifndef RCL_USE_COS_LUT +#define RCL_USE_COS_LUT 0 /**< type of look up table for cos function: + 0: none (compute) + 1: 64 items + 2: 128 items */ +#endif + +#ifndef RCL_USE_DIST_APPROX +#define RCL_USE_DIST_APPROX 0 /**< What distance approximation to use: + 0: none (compute full Euclidean distance) + 1: accurate approximation + 2: octagonal approximation (LQ) */ +#endif + +#ifndef RCL_RECTILINEAR +#define RCL_RECTILINEAR 1 /**< Whether to use rectilinear perspective (normally + used), or curvilinear perspective (fish eye). */ +#endif + +#ifndef RCL_TEXTURE_VERTICAL_STRETCH +#define RCL_TEXTURE_VERTICAL_STRETCH 1 /**< Whether textures should be + stretched to wall height (possibly + slightly slower if on). */ +#endif + +#ifndef RCL_COMPUTE_FLOOR_DEPTH +#define RCL_COMPUTE_FLOOR_DEPTH 1 /**< Whether depth should be computed for + floor pixels - turns this off if not + needed. */ +#endif + +#ifndef RCL_COMPUTE_CEILING_DEPTH +#define RCL_COMPUTE_CEILING_DEPTH 1 /**< As RCL_COMPUTE_FLOOR_DEPTH but for + ceiling. */ +#endif + +#ifndef RCL_ROLL_TEXTURE_COORDS +#define RCL_ROLL_TEXTURE_COORDS 1 /**< Says whether rolling doors should also + roll the texture coordinates along (mostly + desired for doors). */ +#endif + +#ifndef RCL_VERTICAL_FOV +#define RCL_VERTICAL_FOV (RCL_UNITS_PER_SQUARE / 3) +#endif + +#define RCL_VERTICAL_FOV_TAN (RCL_VERTICAL_FOV * 4) ///< tan approximation + +#ifndef RCL_HORIZONTAL_FOV +#define RCL_HORIZONTAL_FOV (RCL_UNITS_PER_SQUARE / 4) +#endif + +#define RCL_HORIZONTAL_FOV_TAN (RCL_HORIZONTAL_FOV * 4) + +#define RCL_HORIZONTAL_FOV_HALF (RCL_HORIZONTAL_FOV / 2) + +#ifndef RCL_CAMERA_COLL_RADIUS +#define RCL_CAMERA_COLL_RADIUS RCL_UNITS_PER_SQUARE / 4 +#endif + +#ifndef RCL_CAMERA_COLL_HEIGHT_BELOW +#define RCL_CAMERA_COLL_HEIGHT_BELOW RCL_UNITS_PER_SQUARE +#endif + +#ifndef RCL_CAMERA_COLL_HEIGHT_ABOVE +#define RCL_CAMERA_COLL_HEIGHT_ABOVE (RCL_UNITS_PER_SQUARE / 3) +#endif + +#ifndef RCL_CAMERA_COLL_STEP_HEIGHT +#define RCL_CAMERA_COLL_STEP_HEIGHT (RCL_UNITS_PER_SQUARE / 2) +#endif + +#ifndef RCL_TEXTURE_INTERPOLATION_SCALE + #define RCL_TEXTURE_INTERPOLATION_SCALE 1024 /**< This says scaling of fixed + poit vertical texture coord + computation. This should be power + of two! Higher number can look more + accurate but may cause overflow. */ +#endif + +#define RCL_HORIZON_DEPTH (11 * RCL_UNITS_PER_SQUARE) /**< What depth the + horizon has (the floor + depth is only + approximated with the + help of this + constant). */ +#ifndef RCL_VERTICAL_DEPTH_MULTIPLY +#define RCL_VERTICAL_DEPTH_MULTIPLY 2 /**< Defines a multiplier of height + difference when approximating floor/ceil + depth. */ +#endif + +#define RCL_min(a,b) ((a) < (b) ? (a) : (b)) +#define RCL_max(a,b) ((a) > (b) ? (a) : (b)) +#define RCL_nonZero(v) ((v) + ((v) == 0)) ///< To prevent zero divisions. +#define RCL_zeroClamp(x) ((x) * ((x) >= 0)) +#define RCL_likely(cond) __builtin_expect(!!(cond),1) +#define RCL_unlikely(cond) __builtin_expect(!!(cond),0) + +#define RCL_logV2D(v)\ + printf("[%d,%d]\n",v.x,v.y); + +#define RCL_logRay(r){\ + printf("ray:\n");\ + printf(" start: ");\ + RCL_logV2D(r.start);\ + printf(" dir: ");\ + RCL_logV2D(r.direction);} + +#define RCL_logHitResult(h){\ + printf("hit:\n");\ + printf(" square: ");\ + RCL_logV2D(h.square);\ + printf(" pos: ");\ + RCL_logV2D(h.position);\ + printf(" dist: %d\n", h.distance);\ + printf(" dir: %d\n", h.direction);\ + printf(" texcoord: %d\n", h.textureCoord);} + +#define RCL_logPixelInfo(p){\ + printf("pixel:\n");\ + printf(" position: ");\ + RCL_logV2D(p.position);\ + printf(" texCoord: ");\ + RCL_logV2D(p.texCoords);\ + printf(" depth: %d\n", p.depth);\ + printf(" height: %d\n", p.height);\ + printf(" wall: %d\n", p.isWall);\ + printf(" hit: ");\ + RCL_logHitResult(p.hit);\ + } + +#define RCL_logCamera(c){\ + printf("camera:\n");\ + printf(" position: ");\ + RCL_logV2D(c.position);\ + printf(" height: %d\n",c.height);\ + printf(" direction: %d\n",c.direction);\ + printf(" shear: %d\n",c.shear);\ + printf(" resolution: %d x %d\n",c.resolution.x,c.resolution.y);\ + } + +/// Position in 2D space. +typedef struct +{ + RCL_Unit x; + RCL_Unit y; +} RCL_Vector2D; + +typedef struct +{ + RCL_Vector2D start; + RCL_Vector2D direction; +} RCL_Ray; + +typedef struct +{ + RCL_Unit distance; /**< Distance to the hit position, or -1 if no + collision happened. If RCL_RECTILINEAR != 0, then + the distance is perpendicular to the projection + plane (fish eye correction), otherwise it is + the straight distance to the ray start + position. */ + uint8_t direction; /**< Direction of hit. The convention for angle + units is explained above. */ + RCL_Unit textureCoord; /**< Normalized (0 to RCL_UNITS_PER_SQUARE - 1) + texture coordinate (horizontal). */ + RCL_Vector2D square; ///< Collided square coordinates. + RCL_Vector2D position; ///< Exact collision position in RCL_Units. + RCL_Unit arrayValue; /** Value returned by array function (most often + this will be the floor height). */ + RCL_Unit type; /**< Integer identifying type of square (number + returned by type function, e.g. texture + index).*/ + RCL_Unit doorRoll; ///< Holds value of door roll. +} RCL_HitResult; + +typedef struct +{ + RCL_Vector2D position; + RCL_Unit direction; // TODO: rename to "angle" to keep consistency + RCL_Vector2D resolution; + int16_t shear; /**< Shear offset in pixels (0 => no shear), can simulate + looking up/down. */ + RCL_Unit height; +} RCL_Camera; + +/** + Holds an information about a single rendered pixel (for a pixel function + that works as a fragment shader). +*/ +typedef struct +{ + RCL_Vector2D position; ///< On-screen position. + int8_t isWall; ///< Whether the pixel is a wall or a floor/ceiling. + int8_t isFloor; ///< Whether the pixel is floor or ceiling. + int8_t isHorizon; ///< If the pixel belongs to horizon segment. + RCL_Unit depth; ///< Corrected depth. + RCL_Unit wallHeight;///< Only for wall pixels, says its height. + RCL_Unit height; ///< World height (mostly for floor). + RCL_HitResult hit; ///< Corresponding ray hit. + RCL_Vector2D texCoords; /**< Normalized (0 to RCL_UNITS_PER_SQUARE - 1) + texture coordinates. */ +} RCL_PixelInfo; + +void RCL_PIXEL_FUNCTION (RCL_PixelInfo *pixel); + +typedef struct +{ + uint16_t maxHits; + uint16_t maxSteps; +} RCL_RayConstraints; + +/** + Function used to retrieve some information about cells of the rendered scene. + It should return a characteristic of given square as an integer (e.g. square + height, texture index, ...) - between squares that return different numbers + there is considered to be a collision. + + This function should be as fast as possible as it will typically be called + very often. +*/ +typedef RCL_Unit (*RCL_ArrayFunction)(int16_t x, int16_t y); +/* + TODO: maybe array functions should be replaced by defines of funtion names + like with pixelFunc? Could be more efficient than function pointers. +*/ + +/** + Function that renders a single pixel at the display. It is handed an info + about the pixel it should draw. + + This function should be as fast as possible as it will typically be called + very often. +*/ +typedef void (*RCL_PixelFunction)(RCL_PixelInfo *info); + +typedef void + (*RCL_ColumnFunction)(RCL_HitResult *hits, uint16_t hitCount, uint16_t x, + RCL_Ray ray); + +/** + Simple-interface function to cast a single ray. + + @return The first collision result. +*/ +RCL_HitResult RCL_castRay(RCL_Ray ray, RCL_ArrayFunction arrayFunc); + +/** + Casts a 3D ray in 3D environment with floor and optional ceiling + (ceilingHeightFunc can be 0). This can be useful for hitscan shooting, + visibility checking etc. + + @return normalized ditance (0 to RCL_UNITS_PER_SQUARE) along the ray at which + the environment was hit, RCL_UNITS_PER_SQUARE means nothing was hit +*/ +RCL_Unit RCL_castRay3D( + RCL_Vector2D pos1, RCL_Unit height1, RCL_Vector2D pos2, RCL_Unit height2, + RCL_ArrayFunction floorHeightFunc, RCL_ArrayFunction ceilingHeightFunc, + RCL_RayConstraints constraints); + +/** + Maps a single point in the world to the screen (2D position + depth). +*/ +RCL_PixelInfo RCL_mapToScreen(RCL_Vector2D worldPosition, RCL_Unit height, + RCL_Camera camera); + +/** + Casts a single ray and returns a list of collisions. + + @param ray ray to be cast, if RCL_RECTILINEAR != 0 then the computed hit + distance is divided by the ray direction vector length (to correct + the fish eye effect) + @param arrayFunc function that will be used to determine collisions (hits) + with the ray (squares for which this function returns different values + are considered to have a collision between them), this will typically + be a function returning floor height + @param typeFunc optional (can be 0) function - if provided, it will be used + to mark the hit result with the number returned by this function + (it can be e.g. a texture index) + @param hitResults array in which the hit results will be stored (has to be + preallocated with at space for at least as many hit results as + maxHits specified with the constraints parameter) + @param hitResultsLen in this variable the number of hit results will be + returned + @param constraints specifies constraints for the ray cast +*/ +void RCL_castRayMultiHit(RCL_Ray ray, RCL_ArrayFunction arrayFunc, + RCL_ArrayFunction typeFunc, RCL_HitResult *hitResults, + uint16_t *hitResultsLen, RCL_RayConstraints constraints); + +RCL_Vector2D RCL_angleToDirection(RCL_Unit angle); + +/** +Cos function. + +@param input to cos in RCL_Units (RCL_UNITS_PER_SQUARE = 2 * pi = 360 degrees) +@return RCL_normalized output in RCL_Units (from -RCL_UNITS_PER_SQUARE to + RCL_UNITS_PER_SQUARE) +*/ +RCL_Unit RCL_cos(RCL_Unit input); + +RCL_Unit RCL_sin(RCL_Unit input); + +RCL_Unit RCL_tan(RCL_Unit input); + +RCL_Unit RCL_ctg(RCL_Unit input); + +/// Normalizes given vector to have RCL_UNITS_PER_SQUARE length. +RCL_Vector2D RCL_normalize(RCL_Vector2D v); + +/// Computes a cos of an angle between two vectors. +RCL_Unit RCL_vectorsAngleCos(RCL_Vector2D v1, RCL_Vector2D v2); + +uint16_t RCL_sqrt(RCL_Unit value); +RCL_Unit RCL_dist(RCL_Vector2D p1, RCL_Vector2D p2); +RCL_Unit RCL_len(RCL_Vector2D v); + +/** + Converts an angle in whole degrees to an angle in RCL_Units that this library + uses. +*/ +RCL_Unit RCL_degreesToUnitsAngle(int16_t degrees); + +///< Computes the change in size of an object due to perspective (vertical FOV). +RCL_Unit RCL_perspectiveScaleVertical(RCL_Unit originalSize, RCL_Unit distance); + +RCL_Unit RCL_perspectiveScaleVerticalInverse(RCL_Unit originalSize, + RCL_Unit scaledSize); + +RCL_Unit + RCL_perspectiveScaleHorizontal(RCL_Unit originalSize, RCL_Unit distance); + +RCL_Unit RCL_perspectiveScaleHorizontalInverse(RCL_Unit originalSize, + RCL_Unit scaledSize); + +/** + Casts rays for given camera view and for each hit calls a user provided + function. +*/ +void RCL_castRaysMultiHit(RCL_Camera cam, RCL_ArrayFunction arrayFunc, + RCL_ArrayFunction typeFunction, RCL_ColumnFunction columnFunc, + RCL_RayConstraints constraints); + +/** + Using provided functions, renders a complete complex (multilevel) camera + view. + + This function should render each screen pixel exactly once. + + function rendering summary: + - performance: slower + - accuracy: higher + - wall textures: yes + - different wall heights: yes + - floor/ceiling textures: no + - floor geometry: yes, multilevel + - ceiling geometry: yes (optional), multilevel + - rolling door: no + - camera shearing: yes + - rendering order: left-to-right, not specifically ordered vertically + + @param cam camera whose view to render + @param floorHeightFunc function that returns floor height (in RCL_Units) + @param ceilingHeightFunc same as floorHeightFunc but for ceiling, can also be + 0 (no ceiling will be rendered) + @param typeFunction function that says a type of square (e.g. its texture + index), can be 0 (no type in hit result) + @param pixelFunc callback function to draw a single pixel on screen + @param constraints constraints for each cast ray +*/ +void RCL_renderComplex(RCL_Camera cam, RCL_ArrayFunction floorHeightFunc, + RCL_ArrayFunction ceilingHeightFunc, RCL_ArrayFunction typeFunction, + RCL_RayConstraints constraints); + +/** + Renders given camera view, with help of provided functions. This function is + simpler and faster than RCL_renderComplex(...) and is meant to be rendering + flat levels. + + function rendering summary: + - performance: faster + - accuracy: lower + - wall textures: yes + - different wall heights: yes + - floor/ceiling textures: yes (only floor, you can mirror it for ceiling) + - floor geometry: no (just flat floor, with depth information) + - ceiling geometry: no (just flat ceiling, with depth information) + - rolling door: yes + - camera shearing: no + - rendering order: left-to-right, top-to-bottom + + Additionally this function supports rendering rolling doors. + + This function should render each screen pixel exactly once. + + @param rollFunc function that for given square says its door roll in + RCL_Units (0 = no roll, RCL_UNITS_PER_SQUARE = full roll right, + -RCL_UNITS_PER_SQUARE = full roll left), can be zero (no rolling door, + rendering should also be faster as fewer intersections will be tested) +*/ +void RCL_renderSimple(RCL_Camera cam, RCL_ArrayFunction floorHeightFunc, + RCL_ArrayFunction typeFunc, RCL_ArrayFunction rollFunc, + RCL_RayConstraints constraints); + +/** + Function that moves given camera and makes it collide with walls and + potentially also floor and ceilings. It's meant to help implement player + movement. + + @param camera camera to move + @param planeOffset offset to move the camera in + @param heightOffset height offset to move the camera in + @param floorHeightFunc function used to retrieve the floor height + @param ceilingHeightFunc function for retrieving ceiling height, can be 0 + (camera won't collide with ceiling) + @param computeHeight whether to compute height - if false (0), floor and + ceiling functions won't be used and the camera will + only collide horizontally with walls (good for simpler + game, also faster) + @param force if true, forces to recompute collision even if position doesn't + change +*/ +void RCL_moveCameraWithCollision(RCL_Camera *camera, RCL_Vector2D planeOffset, + RCL_Unit heightOffset, RCL_ArrayFunction floorHeightFunc, + RCL_ArrayFunction ceilingHeightFunc, int8_t computeHeight, int8_t force); + +void RCL_initCamera(RCL_Camera *camera); +void RCL_initRayConstraints(RCL_RayConstraints *constraints); + +//============================================================================= +// privates + +#define _RCL_UNUSED(what) (void)(what); + +// global helper variables, for precomputing stuff etc. +RCL_Camera _RCL_camera; +RCL_Unit _RCL_horizontalDepthStep = 0; +RCL_Unit _RCL_startFloorHeight = 0; +RCL_Unit _RCL_startCeil_Height = 0; +RCL_Unit _RCL_camResYLimit = 0; +RCL_Unit _RCL_middleRow = 0; +RCL_ArrayFunction _RCL_floorFunction = 0; +RCL_ArrayFunction _RCL_ceilFunction = 0; +RCL_Unit _RCL_fHorizontalDepthStart = 0; +RCL_Unit _RCL_cHorizontalDepthStart = 0; +int16_t _RCL_cameraHeightScreen = 0; +RCL_ArrayFunction _RCL_rollFunction = 0; // says door rolling +RCL_Unit *_RCL_floorPixelDistances = 0; +RCL_Unit _RCL_fovCorrectionFactors[2] = {0,0}; //correction for hor/vert fov + +RCL_Unit RCL_clamp(RCL_Unit value, RCL_Unit valueMin, RCL_Unit valueMax) +{ + if (value >= valueMin) + { + if (value <= valueMax) + return value; + else + return valueMax; + } + else + return valueMin; +} + +static inline RCL_Unit RCL_abs(RCL_Unit value) +{ + return value * (((value >= 0) << 1) - 1); +} + +/// Like mod, but behaves differently for negative values. +static inline RCL_Unit RCL_wrap(RCL_Unit value, RCL_Unit mod) +{ + RCL_Unit cmp = value < 0; + return cmp * mod + (value % mod) - cmp; +} + +/// Performs division, rounding down, NOT towards zero. +static inline RCL_Unit RCL_divRoundDown(RCL_Unit value, RCL_Unit divisor) +{ + return value / divisor - ((value >= 0) ? 0 : 1); +} + +// Bhaskara's cosine approximation formula +#define trigHelper(x) (((RCL_Unit) RCL_UNITS_PER_SQUARE) *\ + (RCL_UNITS_PER_SQUARE / 2 * RCL_UNITS_PER_SQUARE / 2 - 4 * (x) * (x)) /\ + (RCL_UNITS_PER_SQUARE / 2 * RCL_UNITS_PER_SQUARE / 2 + (x) * (x))) + +#if RCL_USE_COS_LUT == 1 + + #ifdef RCL_RAYCAST_TINY + const RCL_Unit cosLUT[64] = + { + 16,14,11,6,0,-6,-11,-14,-15,-14,-11,-6,0,6,11,14 + }; + #else + const RCL_Unit cosLUT[64] = + { + 1024,1019,1004,979,946,903,851,791,724,649,568,482,391,297,199,100,0,-100, + -199,-297,-391,-482,-568,-649,-724,-791,-851,-903,-946,-979,-1004,-1019, + -1023,-1019,-1004,-979,-946,-903,-851,-791,-724,-649,-568,-482,-391,-297, + -199,-100,0,100,199,297,391,482,568,649,724,791,851,903,946,979,1004,1019 + }; + #endif + +#elif RCL_USE_COS_LUT == 2 +const RCL_Unit cosLUT[128] = +{ + 1024,1022,1019,1012,1004,993,979,964,946,925,903,878,851,822,791,758,724, + 687,649,609,568,526,482,437,391,344,297,248,199,150,100,50,0,-50,-100,-150, + -199,-248,-297,-344,-391,-437,-482,-526,-568,-609,-649,-687,-724,-758,-791, + -822,-851,-878,-903,-925,-946,-964,-979,-993,-1004,-1012,-1019,-1022,-1023, + -1022,-1019,-1012,-1004,-993,-979,-964,-946,-925,-903,-878,-851,-822,-791, + -758,-724,-687,-649,-609,-568,-526,-482,-437,-391,-344,-297,-248,-199,-150, + -100,-50,0,50,100,150,199,248,297,344,391,437,482,526,568,609,649,687,724, + 758,791,822,851,878,903,925,946,964,979,993,1004,1012,1019,1022 +}; +#endif + +RCL_Unit RCL_cos(RCL_Unit input) +{ + input = RCL_wrap(input,RCL_UNITS_PER_SQUARE); + +#if RCL_USE_COS_LUT == 1 + + #ifdef RCL_RAYCAST_TINY + return cosLUT[input]; + #else + return cosLUT[input / 16]; + #endif + +#elif RCL_USE_COS_LUT == 2 + return cosLUT[input / 8]; +#else + if (input < RCL_UNITS_PER_SQUARE / 4) + return trigHelper(input); + else if (input < RCL_UNITS_PER_SQUARE / 2) + return -1 * trigHelper(RCL_UNITS_PER_SQUARE / 2 - input); + else if (input < 3 * RCL_UNITS_PER_SQUARE / 4) + return -1 * trigHelper(input - RCL_UNITS_PER_SQUARE / 2); + else + return trigHelper(RCL_UNITS_PER_SQUARE - input); +#endif +} + +#undef trigHelper + +RCL_Unit RCL_sin(RCL_Unit input) +{ + return RCL_cos(input - RCL_UNITS_PER_SQUARE / 4); +} + +RCL_Unit RCL_tan(RCL_Unit input) +{ + return (RCL_sin(input) * RCL_UNITS_PER_SQUARE) / RCL_nonZero(RCL_cos(input) +); + + return (RCL_sin(input) * RCL_UNITS_PER_SQUARE) / RCL_nonZero(RCL_cos(input)); +} + +RCL_Unit RCL_ctg(RCL_Unit input) +{ + return (RCL_cos(input) * RCL_UNITS_PER_SQUARE) / RCL_sin(input); +} + +RCL_Vector2D RCL_angleToDirection(RCL_Unit angle) +{ + RCL_Vector2D result; + + result.x = RCL_cos(angle); + result.y = -1 * RCL_sin(angle); + + return result; +} + +uint16_t RCL_sqrt(RCL_Unit value) +{ +#ifdef RCL_RAYCAST_TINY + uint16_t result = 0; + uint16_t a = value; + uint16_t b = 1u << 14; +#else + uint32_t result = 0; + uint32_t a = value; + uint32_t b = 1u << 30; +#endif + + while (b > a) + b >>= 2; + + while (b != 0) + { + if (a >= result + b) + { + a -= result + b; + result = result + 2 * b; + } + + b >>= 2; + result >>= 1; + } + + return result; +} + +RCL_Unit RCL_dist(RCL_Vector2D p1, RCL_Vector2D p2) +{ + RCL_Unit dx = p2.x - p1.x; + RCL_Unit dy = p2.y - p1.y; + +#if RCL_USE_DIST_APPROX == 2 + // octagonal approximation + + dx = RCL_abs(dx); + dy = RCL_abs(dy); + + return dy > dx ? dx / 2 + dy : dy / 2 + dx; +#elif RCL_USE_DIST_APPROX == 1 + // more accurate approximation + + RCL_Unit a, b, result; + + dx = ((dx < 0) * 2 - 1) * dx; + dy = ((dy < 0) * 2 - 1) * dy; + + if (dx < dy) + { + a = dy; + b = dx; + } + else + { + a = dx; + b = dy; + } + + result = a + (44 * b) / 102; + + if (a < (b << 4)) + result -= (5 * a) / 128; + + return result; +#else + dx = dx * dx; + dy = dy * dy; + + return RCL_sqrt((RCL_Unit) (dx + dy)); +#endif +} + +RCL_Unit RCL_len(RCL_Vector2D v) +{ + RCL_Vector2D zero; + zero.x = 0; + zero.y = 0; + + return RCL_dist(zero,v); +} + +static inline int8_t RCL_pointIsLeftOfRay(RCL_Vector2D point, RCL_Ray ray) +{ + RCL_Unit dX = point.x - ray.start.x; + RCL_Unit dY = point.y - ray.start.y; + return (ray.direction.x * dY - ray.direction.y * dX) > 0; + // ^ Z component of cross-product +} + +void RCL_castRayMultiHit(RCL_Ray ray, RCL_ArrayFunction arrayFunc, + RCL_ArrayFunction typeFunc, RCL_HitResult *hitResults, + uint16_t *hitResultsLen, RCL_RayConstraints constraints) +{ + RCL_Vector2D currentPos = ray.start; + RCL_Vector2D currentSquare; + + currentSquare.x = RCL_divRoundDown(ray.start.x,RCL_UNITS_PER_SQUARE); + currentSquare.y = RCL_divRoundDown(ray.start.y,RCL_UNITS_PER_SQUARE); + + *hitResultsLen = 0; + + RCL_Unit squareType = arrayFunc(currentSquare.x,currentSquare.y); + + // DDA variables + RCL_Vector2D nextSideDist; // dist. from start to the next side in given axis + RCL_Vector2D delta; + RCL_Vector2D step; // -1 or 1 for each axis + int8_t stepHorizontal = 0; // whether the last step was hor. or vert. + + nextSideDist.x = 0; + nextSideDist.y = 0; + + RCL_Unit dirVecLengthNorm = RCL_len(ray.direction) * RCL_UNITS_PER_SQUARE; + + delta.x = RCL_abs(dirVecLengthNorm / RCL_nonZero(ray.direction.x)); + delta.y = RCL_abs(dirVecLengthNorm / RCL_nonZero(ray.direction.y)); + + // init DDA + + if (ray.direction.x < 0) + { + step.x = -1; + nextSideDist.x = (RCL_wrap(ray.start.x,RCL_UNITS_PER_SQUARE) * delta.x) / + RCL_UNITS_PER_SQUARE; + } + else + { + step.x = 1; + nextSideDist.x = + ((RCL_wrap(RCL_UNITS_PER_SQUARE - ray.start.x,RCL_UNITS_PER_SQUARE)) * + delta.x) / RCL_UNITS_PER_SQUARE; + } + + if (ray.direction.y < 0) + { + step.y = -1; + nextSideDist.y = (RCL_wrap(ray.start.y,RCL_UNITS_PER_SQUARE) * delta.y) / + RCL_UNITS_PER_SQUARE; + } + else + { + step.y = 1; + nextSideDist.y = + ((RCL_wrap(RCL_UNITS_PER_SQUARE - ray.start.y,RCL_UNITS_PER_SQUARE)) * + delta.y) / RCL_UNITS_PER_SQUARE; + } + + // DDA loop + + #define RECIP_SCALE 65536 + + RCL_Unit rayDirXRecip = RECIP_SCALE / RCL_nonZero(ray.direction.x); + RCL_Unit rayDirYRecip = RECIP_SCALE / RCL_nonZero(ray.direction.y); + // ^ we precompute reciprocals to avoid divisions in the loop + + for (uint16_t i = 0; i < constraints.maxSteps; ++i) + { + RCL_Unit currentType = arrayFunc(currentSquare.x,currentSquare.y); + + if (RCL_unlikely(currentType != squareType)) + { + // collision + + RCL_HitResult h; + + h.arrayValue = currentType; + h.doorRoll = 0; + h.position = currentPos; + h.square = currentSquare; + + if (stepHorizontal) + { + h.position.x = currentSquare.x * RCL_UNITS_PER_SQUARE; + h.direction = 3; + + if (step.x == -1) + { + h.direction = 1; + h.position.x += RCL_UNITS_PER_SQUARE; + } + + RCL_Unit diff = h.position.x - ray.start.x; + + h.position.y = // avoid division by multiplying with reciprocal + ray.start.y + (ray.direction.y * diff * rayDirXRecip) / RECIP_SCALE; + +#if RCL_RECTILINEAR + /* Here we compute the fish eye corrected distance (perpendicular to + the projection plane) as the Euclidean distance (of hit from camera + position) divided by the length of the ray direction vector. This can + be computed without actually computing Euclidean distances as a + hypothenuse A (distance) divided by hypothenuse B (length) is equal to + leg A (distance along principal axis) divided by leg B (length along + the same principal axis). */ + +#define CORRECT(dir1,dir2)\ + RCL_Unit tmp = diff / 4; /* 4 to prevent overflow */ \ + h.distance = ((tmp / 8) != 0) ? /* prevent a bug with small dists */ \ + ((tmp * RCL_UNITS_PER_SQUARE * rayDir ## dir1 ## Recip) / (RECIP_SCALE / 4)):\ + RCL_abs(h.position.dir2 - ray.start.dir2); + + CORRECT(X,y) + +#endif // RCL_RECTILINEAR + } + else + { + h.position.y = currentSquare.y * RCL_UNITS_PER_SQUARE; + h.direction = 2; + + if (step.y == -1) + { + h.direction = 0; + h.position.y += RCL_UNITS_PER_SQUARE; + } + + RCL_Unit diff = h.position.y - ray.start.y; + + h.position.x = + ray.start.x + (ray.direction.x * diff * rayDirYRecip) / RECIP_SCALE; + +#if RCL_RECTILINEAR + + CORRECT(Y,x) // same as above but for different axis + +#undef CORRECT + +#endif // RCL_RECTILINEAR + } + +#if !RCL_RECTILINEAR + h.distance = RCL_dist(h.position,ray.start); +#endif + if (typeFunc != 0) + h.type = typeFunc(currentSquare.x,currentSquare.y); + +#if RCL_COMPUTE_WALL_TEXCOORDS == 1 + switch (h.direction) + { + case 0: h.textureCoord = + RCL_wrap(-1 * h.position.x,RCL_UNITS_PER_SQUARE); break; + + case 1: h.textureCoord = + RCL_wrap(h.position.y,RCL_UNITS_PER_SQUARE); break; + + case 2: h.textureCoord = + RCL_wrap(h.position.x,RCL_UNITS_PER_SQUARE); break; + + case 3: h.textureCoord = + RCL_wrap(-1 * h.position.y,RCL_UNITS_PER_SQUARE); break; + + default: h.textureCoord = 0; break; + } + + if (_RCL_rollFunction != 0) + { + h.doorRoll = _RCL_rollFunction(currentSquare.x,currentSquare.y); + + if (h.direction == 0 || h.direction == 1) + h.doorRoll *= -1; + } + +#else + h.textureCoord = 0; +#endif + + hitResults[*hitResultsLen] = h; + + *hitResultsLen += 1; + + squareType = currentType; + + if (*hitResultsLen >= constraints.maxHits) + break; + } + + // DDA step + + if (nextSideDist.x < nextSideDist.y) + { + nextSideDist.x += delta.x; + currentSquare.x += step.x; + stepHorizontal = 1; + } + else + { + nextSideDist.y += delta.y; + currentSquare.y += step.y; + stepHorizontal = 0; + } + } +} + +RCL_HitResult RCL_castRay(RCL_Ray ray, RCL_ArrayFunction arrayFunc) +{ + RCL_HitResult result; + uint16_t len; + RCL_RayConstraints c; + + c.maxSteps = 1000; + c.maxHits = 1; + + RCL_castRayMultiHit(ray,arrayFunc,0,&result,&len,c); + + if (len == 0) + result.distance = -1; + + return result; +} + +void RCL_castRaysMultiHit(RCL_Camera cam, RCL_ArrayFunction arrayFunc, + RCL_ArrayFunction typeFunction, RCL_ColumnFunction columnFunc, + RCL_RayConstraints constraints) +{ + RCL_Vector2D dir1 = + RCL_angleToDirection(cam.direction - RCL_HORIZONTAL_FOV_HALF); + + RCL_Vector2D dir2 = + RCL_angleToDirection(cam.direction + RCL_HORIZONTAL_FOV_HALF); + + /* We scale the side distances so that the middle one is + RCL_UNITS_PER_SQUARE, which has to be this way. */ + + RCL_Unit cos = RCL_nonZero(RCL_cos(RCL_HORIZONTAL_FOV_HALF)); + + dir1.x = (dir1.x * RCL_UNITS_PER_SQUARE) / cos; + dir1.y = (dir1.y * RCL_UNITS_PER_SQUARE) / cos; + + dir2.x = (dir2.x * RCL_UNITS_PER_SQUARE) / cos; + dir2.y = (dir2.y * RCL_UNITS_PER_SQUARE) / cos; + + RCL_Unit dX = dir2.x - dir1.x; + RCL_Unit dY = dir2.y - dir1.y; + + RCL_HitResult hits[constraints.maxHits]; + uint16_t hitCount; + + RCL_Ray r; + r.start = cam.position; + + RCL_Unit currentDX = 0; + RCL_Unit currentDY = 0; + + for (int16_t i = 0; i < cam.resolution.x; ++i) + { + /* Here by linearly interpolating the direction vector its length changes, + which in result achieves correcting the fish eye effect (computing + perpendicular distance). */ + + r.direction.x = dir1.x + currentDX / cam.resolution.x; + r.direction.y = dir1.y + currentDY / cam.resolution.x; + + RCL_castRayMultiHit(r,arrayFunc,typeFunction,hits,&hitCount,constraints); + + columnFunc(hits,hitCount,i,r); + + currentDX += dX; + currentDY += dY; + } +} + +/** + Helper function that determines intersection with both ceiling and floor. +*/ +RCL_Unit _RCL_floorCeilFunction(int16_t x, int16_t y) +{ + RCL_Unit f = _RCL_floorFunction(x,y); + + if (_RCL_ceilFunction == 0) + return f; + + RCL_Unit c = _RCL_ceilFunction(x,y); + +#ifndef RCL_RAYCAST_TINY + return ((f & 0x0000ffff) << 16) | (c & 0x0000ffff); +#else + return ((f & 0x00ff) << 8) | (c & 0x00ff); +#endif +} + +RCL_Unit _floorHeightNotZeroFunction(int16_t x, int16_t y) +{ + return _RCL_floorFunction(x,y) == 0 ? 0 : + RCL_nonZero((x & 0x00FF) | ((y & 0x00FF) << 8)); + // ^ this makes collisions between all squares - needed for rolling doors +} + +RCL_Unit RCL_adjustDistance(RCL_Unit distance, RCL_Camera *camera, + RCL_Ray *ray) +{ + /* FIXME/TODO: The adjusted (=orthogonal, camera-space) distance could + possibly be computed more efficiently by not computing Euclidean + distance at all, but rather compute the distance of the collision + point from the projection plane (line). */ + + RCL_Unit result = + (distance * + RCL_vectorsAngleCos(RCL_angleToDirection(camera->direction), + ray->direction)) / RCL_UNITS_PER_SQUARE; + + return RCL_nonZero(result); + // ^ prevent division by zero +} + +/// Helper for drawing floor or ceiling. Returns the last drawn pixel position. +static inline int16_t _RCL_drawHorizontalColumn( + RCL_Unit yCurrent, + RCL_Unit yTo, + RCL_Unit limit1, // TODO: int16_t? + RCL_Unit limit2, + RCL_Unit verticalOffset, + int16_t increment, + int8_t computeDepth, + int8_t computeCoords, + int16_t depthIncrementMultiplier, + RCL_Ray *ray, + RCL_PixelInfo *pixelInfo +) +{ + _RCL_UNUSED(ray); + + RCL_Unit depthIncrement; + RCL_Unit dx; + RCL_Unit dy; + + pixelInfo->isWall = 0; + + int16_t limit = RCL_clamp(yTo,limit1,limit2); + + RCL_Unit depth = 0; /* TODO: this is for clamping depth to 0 so that we don't + have negative depths, but we should do it more + elegantly and efficiently */ + + _RCL_UNUSED(depth); + + /* for performance reasons have different version of the critical loop + to be able to branch early */ + #define loop(doDepth,doCoords)\ + {\ + if (doDepth) /*constant condition - compiler should optimize it out*/\ + {\ + depth = pixelInfo->depth + RCL_abs(verticalOffset) *\ + RCL_VERTICAL_DEPTH_MULTIPLY;\ + depthIncrement = depthIncrementMultiplier *\ + _RCL_horizontalDepthStep;\ + }\ + if (doCoords) /*constant condition - compiler should optimize it out*/\ + {\ + dx = pixelInfo->hit.position.x - _RCL_camera.position.x;\ + dy = pixelInfo->hit.position.y - _RCL_camera.position.y;\ + }\ + for (int16_t i = yCurrent + increment;\ + increment == -1 ? i >= limit : i <= limit; /* TODO: is efficient? */\ + i += increment)\ + {\ + pixelInfo->position.y = i;\ + if (doDepth) /*constant condition - compiler should optimize it out*/\ + {\ + depth += depthIncrement;\ + pixelInfo->depth = RCL_zeroClamp(depth); \ + /* ^ int comparison is fast, it is not braching! (= test instr.) */\ + }\ + if (doCoords) /*constant condition - compiler should optimize it out*/\ + {\ + RCL_Unit d = _RCL_floorPixelDistances[i];\ + RCL_Unit d2 = RCL_nonZero(pixelInfo->hit.distance);\ + pixelInfo->texCoords.x =\ + _RCL_camera.position.x + ((d * dx) / d2);\ + pixelInfo->texCoords.y =\ + _RCL_camera.position.y + ((d * dy) / d2);\ + }\ + RCL_PIXEL_FUNCTION(pixelInfo);\ + }\ + } + + if (computeDepth) // branch early + { + if (!computeCoords) + loop(1,0) + else + loop(1,1) + } + else + { + if (!computeCoords) + loop(0,0) + else + loop(1,1) + } + + #undef loop + + return limit; +} + +/// Helper for drawing walls. Returns the last drawn pixel position. +static inline int16_t _RCL_drawWall( + RCL_Unit yCurrent, + RCL_Unit yFrom, + RCL_Unit yTo, + RCL_Unit limit1, // TODO: int16_t? + RCL_Unit limit2, + RCL_Unit height, + int16_t increment, + RCL_PixelInfo *pixelInfo + ) +{ + _RCL_UNUSED(height) + + height = RCL_abs(height); + + pixelInfo->isWall = 1; + + RCL_Unit limit = RCL_clamp(yTo,limit1,limit2); + + RCL_Unit wallLength = RCL_nonZero(RCL_abs(yTo - yFrom - 1)); + + RCL_Unit wallPosition = RCL_abs(yFrom - yCurrent) - increment; + + RCL_Unit heightScaled = height * RCL_TEXTURE_INTERPOLATION_SCALE; + _RCL_UNUSED(heightScaled); + + RCL_Unit coordStepScaled = RCL_COMPUTE_WALL_TEXCOORDS ? +#if RCL_TEXTURE_VERTICAL_STRETCH == 1 + ((RCL_UNITS_PER_SQUARE * RCL_TEXTURE_INTERPOLATION_SCALE) / wallLength) +#else + (heightScaled / wallLength) +#endif + : 0; + + pixelInfo->texCoords.y = RCL_COMPUTE_WALL_TEXCOORDS ? + (wallPosition * coordStepScaled) : 0; + + if (increment < 0) + { + coordStepScaled *= -1; + pixelInfo->texCoords.y = +#if RCL_TEXTURE_VERTICAL_STRETCH == 1 + (RCL_UNITS_PER_SQUARE * RCL_TEXTURE_INTERPOLATION_SCALE) + - pixelInfo->texCoords.y; +#else + heightScaled - pixelInfo->texCoords.y; +#endif + } + else + { + // with floor wall, don't start under 0 + pixelInfo->texCoords.y = RCL_zeroClamp(pixelInfo->texCoords.y); + } + + RCL_Unit textureCoordScaled = pixelInfo->texCoords.y; + + for (RCL_Unit i = yCurrent + increment; + increment == -1 ? i >= limit : i <= limit; // TODO: is efficient? + i += increment) + { + pixelInfo->position.y = i; + +#if RCL_COMPUTE_WALL_TEXCOORDS == 1 + pixelInfo->texCoords.y = + textureCoordScaled / RCL_TEXTURE_INTERPOLATION_SCALE; + + textureCoordScaled += coordStepScaled; +#endif + + RCL_PIXEL_FUNCTION(pixelInfo); + } + + return limit; +} + +/// Fills a RCL_HitResult struct with info for a hit at infinity. +static inline void _RCL_makeInfiniteHit(RCL_HitResult *hit, RCL_Ray *ray) +{ + hit->distance = RCL_UNITS_PER_SQUARE * RCL_UNITS_PER_SQUARE; + /* ^ horizon is at infinity, but we can't use too big infinity + (RCL_INFINITY) because it would overflow in the following mult. */ + hit->position.x = (ray->direction.x * hit->distance) / RCL_UNITS_PER_SQUARE; + hit->position.y = (ray->direction.y * hit->distance) / RCL_UNITS_PER_SQUARE; + + hit->direction = 0; + hit->textureCoord = 0; + hit->arrayValue = 0; + hit->doorRoll = 0; + hit->type = 0; +} + +void _RCL_columnFunctionComplex(RCL_HitResult *hits, uint16_t hitCount, uint16_t x, + RCL_Ray ray) +{ + // last written Y position, can never go backwards + RCL_Unit fPosY = _RCL_camera.resolution.y; + RCL_Unit cPosY = -1; + + // world coordinates (relative to camera height though) + RCL_Unit fZ1World = _RCL_startFloorHeight; + RCL_Unit cZ1World = _RCL_startCeil_Height; + + RCL_PixelInfo p; + p.position.x = x; + p.height = 0; + p.wallHeight = 0; + p.texCoords.x = 0; + p.texCoords.y = 0; + + // we'll be simulatenously drawing the floor and the ceiling now + for (RCL_Unit j = 0; j <= hitCount; ++j) + { // ^ = add extra iteration for horizon plane + int8_t drawingHorizon = j == hitCount; + + RCL_HitResult hit; + RCL_Unit distance = 1; + + RCL_Unit fWallHeight = 0, cWallHeight = 0; + RCL_Unit fZ2World = 0, cZ2World = 0; + RCL_Unit fZ1Screen = 0, cZ1Screen = 0; + RCL_Unit fZ2Screen = 0, cZ2Screen = 0; + + if (!drawingHorizon) + { + hit = hits[j]; + distance = RCL_nonZero(hit.distance); + p.hit = hit; + + fWallHeight = _RCL_floorFunction(hit.square.x,hit.square.y); + fZ2World = fWallHeight - _RCL_camera.height; + fZ1Screen = _RCL_middleRow - RCL_perspectiveScaleVertical( + (fZ1World * _RCL_camera.resolution.y) / + RCL_UNITS_PER_SQUARE,distance); + fZ2Screen = _RCL_middleRow - RCL_perspectiveScaleVertical( + (fZ2World * _RCL_camera.resolution.y) / + RCL_UNITS_PER_SQUARE,distance); + + if (_RCL_ceilFunction != 0) + { + cWallHeight = _RCL_ceilFunction(hit.square.x,hit.square.y); + cZ2World = cWallHeight - _RCL_camera.height; + cZ1Screen = _RCL_middleRow - RCL_perspectiveScaleVertical( + (cZ1World * _RCL_camera.resolution.y) / + RCL_UNITS_PER_SQUARE,distance); + cZ2Screen = _RCL_middleRow - RCL_perspectiveScaleVertical( + (cZ2World * _RCL_camera.resolution.y) / + RCL_UNITS_PER_SQUARE,distance); + } + } + else + { + fZ1Screen = _RCL_middleRow; + cZ1Screen = _RCL_middleRow + 1; + _RCL_makeInfiniteHit(&p.hit,&ray); + } + + RCL_Unit limit; + + p.isWall = 0; + p.isHorizon = drawingHorizon; + + // draw floor until wall + p.isFloor = 1; + p.height = fZ1World + _RCL_camera.height; + p.wallHeight = 0; + +#if RCL_COMPUTE_FLOOR_DEPTH == 1 + p.depth = (_RCL_fHorizontalDepthStart - fPosY) * _RCL_horizontalDepthStep; +#else + p.depth = 0; +#endif + + limit = _RCL_drawHorizontalColumn(fPosY,fZ1Screen,cPosY + 1, + _RCL_camera.resolution.y,fZ1World,-1,RCL_COMPUTE_FLOOR_DEPTH, + // ^ purposfully allow outside screen bounds + RCL_COMPUTE_FLOOR_TEXCOORDS && p.height == RCL_FLOOR_TEXCOORDS_HEIGHT, + 1,&ray,&p); + + if (fPosY > limit) + fPosY = limit; + + if (_RCL_ceilFunction != 0 || drawingHorizon) + { + // draw ceiling until wall + p.isFloor = 0; + p.height = cZ1World + _RCL_camera.height; + +#if RCL_COMPUTE_CEILING_DEPTH == 1 + p.depth = (cPosY - _RCL_cHorizontalDepthStart) * + _RCL_horizontalDepthStep; +#endif + + limit = _RCL_drawHorizontalColumn(cPosY,cZ1Screen, + -1,fPosY - 1,cZ1World,1,RCL_COMPUTE_CEILING_DEPTH,0,1,&ray,&p); + // ^ purposfully allow outside screen bounds here + + if (cPosY < limit) + cPosY = limit; + } + + if (!drawingHorizon) // don't draw walls for horizon plane + { + p.isWall = 1; + p.depth = distance; + p.isFloor = 1; + p.texCoords.x = hit.textureCoord; + p.height = fZ1World + _RCL_camera.height; + p.wallHeight = fWallHeight; + + // draw floor wall + + if (fPosY > 0) // still pixels left? + { + p.isFloor = 1; + + limit = _RCL_drawWall(fPosY,fZ1Screen,fZ2Screen,cPosY + 1, + _RCL_camera.resolution.y, + // ^ purposfully allow outside screen bounds here +#if RCL_TEXTURE_VERTICAL_STRETCH == 1 + RCL_UNITS_PER_SQUARE +#else + fZ2World - fZ1World +#endif + ,-1,&p); + + + if (fPosY > limit) + fPosY = limit; + + fZ1World = fZ2World; // for the next iteration + } // ^ purposfully allow outside screen bounds here + + // draw ceiling wall + + if (_RCL_ceilFunction != 0 && cPosY < _RCL_camResYLimit) // pixels left? + { + p.isFloor = 0; + p.height = cZ1World + _RCL_camera.height; + p.wallHeight = cWallHeight; + + limit = _RCL_drawWall(cPosY,cZ1Screen,cZ2Screen, + -1,fPosY - 1, + // ^ puposfully allow outside screen bounds here +#if RCL_TEXTURE_VERTICAL_STRETCH == 1 + RCL_UNITS_PER_SQUARE +#else + cZ1World - cZ2World +#endif + ,1,&p); + + if (cPosY < limit) + cPosY = limit; + + cZ1World = cZ2World; // for the next iteration + } // ^ puposfully allow outside screen bounds here + } + } +} + +void _RCL_columnFunctionSimple(RCL_HitResult *hits, uint16_t hitCount, + uint16_t x, RCL_Ray ray) +{ + RCL_Unit y = 0; + RCL_Unit wallHeightScreen = 0; + RCL_Unit wallStart = _RCL_middleRow; + + RCL_Unit dist = 1; + + RCL_PixelInfo p; + p.position.x = x; + p.wallHeight = RCL_UNITS_PER_SQUARE; + + if (hitCount > 0) + { + RCL_HitResult hit = hits[0]; + + uint8_t goOn = 1; + + if (_RCL_rollFunction != 0 && RCL_COMPUTE_WALL_TEXCOORDS == 1) + { + if (hit.arrayValue == 0) + { + // standing inside door square, looking out => move to the next hit + + if (hitCount > 1) + hit = hits[1]; + else + goOn = 0; + } + else + { + // normal hit, check the door roll + + RCL_Unit texCoordMod = hit.textureCoord % RCL_UNITS_PER_SQUARE; + + int8_t unrolled = hit.doorRoll >= 0 ? + (hit.doorRoll > texCoordMod) : + (texCoordMod > RCL_UNITS_PER_SQUARE + hit.doorRoll); + + if (unrolled) + { + goOn = 0; + + if (hitCount > 1) /* should probably always be true (hit on square + exit) */ + { + if (hit.direction % 2 != hits[1].direction % 2) + { + // hit on the inner side + hit = hits[1]; + goOn = 1; + } + else if (hitCount > 2) + { + // hit on the opposite side + hit = hits[2]; + goOn = 1; + } + } + } + } + } + + p.hit = hit; + + if (goOn) + { + dist = hit.distance; + + RCL_Unit wallHeightWorld = _RCL_floorFunction(hit.square.x,hit.square.y); + + if (wallHeightWorld < 0) + { + /* We can't just do wallHeightWorld = max(0,wallHeightWorld) because + we would be processing an actual hit with height 0, which shouldn't + ever happen, so we assign some arbitrary height. */ + + wallHeightWorld = RCL_UNITS_PER_SQUARE; + } + + RCL_Unit worldPointTop = wallHeightWorld - _RCL_camera.height; + RCL_Unit worldPointBottom = -1 * _RCL_camera.height; + + wallStart = _RCL_middleRow - + (RCL_perspectiveScaleVertical(worldPointTop,dist) + * _RCL_camera.resolution.y) / RCL_UNITS_PER_SQUARE; + + int16_t wallEnd = _RCL_middleRow - + (RCL_perspectiveScaleVertical(worldPointBottom,dist) + * _RCL_camera.resolution.y) / RCL_UNITS_PER_SQUARE; + + wallHeightScreen = wallEnd - wallStart; + + if (wallHeightScreen <= 0) // can happen because of rounding errors + wallHeightScreen = 1; + } + } + else + { + _RCL_makeInfiniteHit(&p.hit,&ray); + } + + // draw ceiling + + p.isWall = 0; + p.isFloor = 0; + p.isHorizon = 1; + p.depth = 1; + p.height = RCL_UNITS_PER_SQUARE; + + y = _RCL_drawHorizontalColumn(-1,wallStart,-1,_RCL_middleRow,_RCL_camera.height,1, + RCL_COMPUTE_CEILING_DEPTH,0,1,&ray,&p); + + // draw wall + + p.isWall = 1; + p.isFloor = 1; + p.depth = dist; + p.height = 0; + +#if RCL_ROLL_TEXTURE_COORDS == 1 && RCL_COMPUTE_WALL_TEXCOORDS == 1 + p.hit.textureCoord -= p.hit.doorRoll; +#endif + + p.texCoords.x = p.hit.textureCoord; + p.texCoords.y = 0; + + RCL_Unit limit = _RCL_drawWall(y,wallStart,wallStart + wallHeightScreen - 1, + -1,_RCL_camResYLimit,p.hit.arrayValue,1,&p); + + y = RCL_max(y,limit); // take max, in case no wall was drawn + y = RCL_max(y,wallStart); + + // draw floor + + p.isWall = 0; + +#if RCL_COMPUTE_FLOOR_DEPTH == 1 + p.depth = (_RCL_camera.resolution.y - y) * _RCL_horizontalDepthStep + 1; +#endif + + _RCL_drawHorizontalColumn(y,_RCL_camResYLimit,-1,_RCL_camResYLimit, + _RCL_camera.height,1,RCL_COMPUTE_FLOOR_DEPTH,RCL_COMPUTE_FLOOR_TEXCOORDS, + -1,&ray,&p); +} + +/** + Precomputes a distance from camera to the floor at each screen row into an + array (must be preallocated with sufficient (camera.resolution.y) length). +*/ +static inline void _RCL_precomputeFloorDistances(RCL_Camera camera, + RCL_Unit *dest, uint16_t startIndex) +{ + RCL_Unit camHeightScreenSize = + (camera.height * camera.resolution.y) / RCL_UNITS_PER_SQUARE; + + for (uint16_t i = startIndex; i < camera.resolution.y; ++i) + dest[i] = RCL_perspectiveScaleVerticalInverse(camHeightScreenSize, + RCL_abs(i - _RCL_middleRow)); +} + +void RCL_renderComplex(RCL_Camera cam, RCL_ArrayFunction floorHeightFunc, + RCL_ArrayFunction ceilingHeightFunc, RCL_ArrayFunction typeFunction, + RCL_RayConstraints constraints) +{ + _RCL_floorFunction = floorHeightFunc; + _RCL_ceilFunction = ceilingHeightFunc; + _RCL_camera = cam; + _RCL_camResYLimit = cam.resolution.y - 1; + + uint16_t halfResY = cam.resolution.y / 2; + + _RCL_middleRow = halfResY + cam.shear; + + _RCL_fHorizontalDepthStart = _RCL_middleRow + halfResY; + _RCL_cHorizontalDepthStart = _RCL_middleRow - halfResY; + + _RCL_startFloorHeight = floorHeightFunc( + RCL_divRoundDown(cam.position.x,RCL_UNITS_PER_SQUARE), + RCL_divRoundDown(cam.position.y,RCL_UNITS_PER_SQUARE)) -1 * cam.height; + + _RCL_startCeil_Height = + ceilingHeightFunc != 0 ? + ceilingHeightFunc( + RCL_divRoundDown(cam.position.x,RCL_UNITS_PER_SQUARE), + RCL_divRoundDown(cam.position.y,RCL_UNITS_PER_SQUARE)) -1 * cam.height + : RCL_INFINITY; + + _RCL_horizontalDepthStep = RCL_HORIZON_DEPTH / cam.resolution.y; + +#if RCL_COMPUTE_FLOOR_TEXCOORDS == 1 + RCL_Unit floorPixelDistances[cam.resolution.y]; + _RCL_precomputeFloorDistances(cam,floorPixelDistances,0); + _RCL_floorPixelDistances = floorPixelDistances; // pass to column function +#endif + + RCL_castRaysMultiHit(cam,_RCL_floorCeilFunction,typeFunction, + _RCL_columnFunctionComplex,constraints); +} + +void RCL_renderSimple(RCL_Camera cam, RCL_ArrayFunction floorHeightFunc, + RCL_ArrayFunction typeFunc, RCL_ArrayFunction rollFunc, + RCL_RayConstraints constraints) +{ + _RCL_floorFunction = floorHeightFunc; + _RCL_camera = cam; + _RCL_camResYLimit = cam.resolution.y - 1; + _RCL_middleRow = cam.resolution.y / 2; + _RCL_rollFunction = rollFunc; + + _RCL_cameraHeightScreen = + (_RCL_camera.resolution.y * (_RCL_camera.height - RCL_UNITS_PER_SQUARE)) / + RCL_UNITS_PER_SQUARE; + + _RCL_horizontalDepthStep = RCL_HORIZON_DEPTH / cam.resolution.y; + + constraints.maxHits = + _RCL_rollFunction == 0 ? + 1 : // no door => 1 hit is enough + 3; // for correctly rendering rolling doors we'll need 3 hits (NOT 2) + +#if RCL_COMPUTE_FLOOR_TEXCOORDS == 1 + RCL_Unit floorPixelDistances[cam.resolution.y]; + _RCL_precomputeFloorDistances(cam,floorPixelDistances,_RCL_middleRow); + _RCL_floorPixelDistances = floorPixelDistances; // pass to column function +#endif + + RCL_castRaysMultiHit(cam,_floorHeightNotZeroFunction,typeFunc, + _RCL_columnFunctionSimple, constraints); + +#if RCL_COMPUTE_FLOOR_TEXCOORDS == 1 + _RCL_floorPixelDistances = 0; +#endif +} + +RCL_Vector2D RCL_normalize(RCL_Vector2D v) +{ + RCL_Vector2D result; + RCL_Unit l = RCL_len(v); + l = RCL_nonZero(l); + + result.x = (v.x * RCL_UNITS_PER_SQUARE) / l; + result.y = (v.y * RCL_UNITS_PER_SQUARE) / l; + + return result; +} + +RCL_Unit RCL_vectorsAngleCos(RCL_Vector2D v1, RCL_Vector2D v2) +{ + v1 = RCL_normalize(v1); + v2 = RCL_normalize(v2); + + return (v1.x * v2.x + v1.y * v2.y) / RCL_UNITS_PER_SQUARE; +} + + +RCL_PixelInfo RCL_mapToScreen(RCL_Vector2D worldPosition, RCL_Unit height, + RCL_Camera camera) +{ + RCL_PixelInfo result; + + RCL_Vector2D toPoint; + + toPoint.x = worldPosition.x - camera.position.x; + toPoint.y = worldPosition.y - camera.position.y; + + RCL_Unit middleColumn = camera.resolution.x / 2; + + // rotate the point to camera space (y left/right, x forw/backw) + + RCL_Unit cos = RCL_cos(camera.direction); + RCL_Unit sin = RCL_sin(camera.direction); + + RCL_Unit tmp = toPoint.x; + + toPoint.x = (toPoint.x * cos - toPoint.y * sin) / RCL_UNITS_PER_SQUARE; + toPoint.y = (tmp * sin + toPoint.y * cos) / RCL_UNITS_PER_SQUARE; + + result.depth = toPoint.x; + + result.position.x = middleColumn - + (RCL_perspectiveScaleHorizontal(toPoint.y,result.depth) * middleColumn) / + RCL_UNITS_PER_SQUARE; + + result.position.y = + (RCL_perspectiveScaleVertical(height - camera.height,result.depth) + * camera.resolution.y) / RCL_UNITS_PER_SQUARE; + + result.position.y = camera.resolution.y / 2 - result.position.y + camera.shear; + + return result; +} + +RCL_Unit RCL_degreesToUnitsAngle(int16_t degrees) +{ + return (degrees * RCL_UNITS_PER_SQUARE) / 360; +} + +/** + Ugly temporary hack to solve mapping to screen. This function computes + (approximately, usin a table) a divisor needed for FOV correction. +*/ +RCL_Unit _RCL_fovCorrectionFactor(RCL_Unit fov) +{ + uint16_t table[9] = + {1,208,408,692,1024,1540,2304,5376,30000}; + + fov = RCL_min(RCL_UNITS_PER_SQUARE / 2 - 1,fov); + + uint8_t index = fov / 64; + uint32_t t = ((fov - index * 64) * RCL_UNITS_PER_SQUARE) / 64; + uint32_t v1 = table[index]; + uint32_t v2 = table[index + 1]; + + return v1 + ((v2 - v1) * t) / RCL_UNITS_PER_SQUARE; +} + +RCL_Unit RCL_perspectiveScaleVertical(RCL_Unit originalSize, RCL_Unit distance) +{ + if (_RCL_fovCorrectionFactors[1] == 0) + _RCL_fovCorrectionFactors[1] = _RCL_fovCorrectionFactor(RCL_VERTICAL_FOV); + + return distance != 0 ? ((originalSize * RCL_UNITS_PER_SQUARE) / + RCL_nonZero((_RCL_fovCorrectionFactors[1] * distance) / RCL_UNITS_PER_SQUARE) + ) : 0; +} + +RCL_Unit RCL_perspectiveScaleVerticalInverse(RCL_Unit originalSize, + RCL_Unit scaledSize) +{ + if (_RCL_fovCorrectionFactors[1] == 0) + _RCL_fovCorrectionFactors[1] = _RCL_fovCorrectionFactor(RCL_VERTICAL_FOV); + + return scaledSize != 0 ? + + ((originalSize * RCL_UNITS_PER_SQUARE) / + RCL_nonZero((_RCL_fovCorrectionFactors[1] * scaledSize) + / RCL_UNITS_PER_SQUARE)) : RCL_INFINITY; +} + +RCL_Unit + RCL_perspectiveScaleHorizontal(RCL_Unit originalSize, RCL_Unit distance) +{ + if (_RCL_fovCorrectionFactors[0] == 0) + _RCL_fovCorrectionFactors[0] = _RCL_fovCorrectionFactor(RCL_HORIZONTAL_FOV); + + return distance != 0 ? + ((originalSize * RCL_UNITS_PER_SQUARE) / + RCL_nonZero((_RCL_fovCorrectionFactors[0] * distance) / RCL_UNITS_PER_SQUARE) + ) : 0; +} + +RCL_Unit RCL_perspectiveScaleHorizontalInverse(RCL_Unit originalSize, + RCL_Unit scaledSize) +{ + // TODO: probably doesn't work + + return scaledSize != 0 ? + (originalSize * RCL_UNITS_PER_SQUARE + RCL_UNITS_PER_SQUARE / 2) / + ((RCL_HORIZONTAL_FOV_TAN * 2 * scaledSize) / RCL_UNITS_PER_SQUARE) + : RCL_INFINITY; +} + +RCL_Unit RCL_castRay3D( + RCL_Vector2D pos1, RCL_Unit height1, RCL_Vector2D pos2, RCL_Unit height2, + RCL_ArrayFunction floorHeightFunc, RCL_ArrayFunction ceilingHeightFunc, + RCL_RayConstraints constraints) +{ + RCL_HitResult hits[constraints.maxHits]; + uint16_t numHits; + + RCL_Ray ray; + + ray.start = pos1; + + RCL_Unit distance; + + ray.direction.x = pos2.x - pos1.x; + ray.direction.y = pos2.y - pos1.y; + + distance = RCL_len(ray.direction); + + ray.direction = RCL_normalize(ray.direction); + + RCL_Unit heightDiff = height2 - height1; + + RCL_castRayMultiHit(ray,floorHeightFunc,0,hits,&numHits,constraints); + + RCL_Unit result = RCL_UNITS_PER_SQUARE; + + int16_t squareX = RCL_divRoundDown(pos1.x,RCL_UNITS_PER_SQUARE); + int16_t squareY = RCL_divRoundDown(pos1.y,RCL_UNITS_PER_SQUARE); + + RCL_Unit startHeight = floorHeightFunc(squareX,squareY); + + #define checkHits(comp,res) \ + { \ + RCL_Unit currentHeight = startHeight; \ + for (uint16_t i = 0; i < numHits; ++i) \ + { \ + if (hits[i].distance > distance) \ + break;\ + RCL_Unit h = hits[i].arrayValue; \ + if ((currentHeight comp h ? currentHeight : h) \ + comp (height1 + (hits[i].distance * heightDiff) / distance)) \ + { \ + res = (hits[i].distance * RCL_UNITS_PER_SQUARE) / distance; \ + break; \ + } \ + currentHeight = h; \ + } \ + } + + checkHits(>,result) + + if (ceilingHeightFunc != 0) + { + RCL_Unit result2 = RCL_UNITS_PER_SQUARE; + + startHeight = ceilingHeightFunc(squareX,squareY); + + RCL_castRayMultiHit(ray,ceilingHeightFunc,0,hits,&numHits,constraints); + + checkHits(<,result2) + + if (result2 < result) + result = result2; + } + + #undef checkHits + + return result; +} + +void RCL_moveCameraWithCollision(RCL_Camera *camera, RCL_Vector2D planeOffset, + RCL_Unit heightOffset, RCL_ArrayFunction floorHeightFunc, + RCL_ArrayFunction ceilingHeightFunc, int8_t computeHeight, int8_t force) +{ + int8_t movesInPlane = planeOffset.x != 0 || planeOffset.y != 0; + + if (movesInPlane || force) + { + int16_t xSquareNew, ySquareNew; + + RCL_Vector2D corner; // BBox corner in the movement direction + RCL_Vector2D cornerNew; + + int16_t xDir = planeOffset.x > 0 ? 1 : -1; + int16_t yDir = planeOffset.y > 0 ? 1 : -1; + + corner.x = camera->position.x + xDir * RCL_CAMERA_COLL_RADIUS; + corner.y = camera->position.y + yDir * RCL_CAMERA_COLL_RADIUS; + + int16_t xSquare = RCL_divRoundDown(corner.x,RCL_UNITS_PER_SQUARE); + int16_t ySquare = RCL_divRoundDown(corner.y,RCL_UNITS_PER_SQUARE); + + cornerNew.x = corner.x + planeOffset.x; + cornerNew.y = corner.y + planeOffset.y; + + xSquareNew = RCL_divRoundDown(cornerNew.x,RCL_UNITS_PER_SQUARE); + ySquareNew = RCL_divRoundDown(cornerNew.y,RCL_UNITS_PER_SQUARE); + + RCL_Unit bottomLimit = -1 * RCL_INFINITY; + RCL_Unit topLimit = RCL_INFINITY; + + RCL_Unit currCeilHeight = RCL_INFINITY; + + if (computeHeight) + { + bottomLimit = camera->height - RCL_CAMERA_COLL_HEIGHT_BELOW + + RCL_CAMERA_COLL_STEP_HEIGHT; + + topLimit = camera->height + RCL_CAMERA_COLL_HEIGHT_ABOVE; + + if (ceilingHeightFunc != 0) + currCeilHeight = ceilingHeightFunc(xSquare,ySquare); + } + + // checks a single square for collision against the camera + #define collCheck(dir,s1,s2)\ + if (computeHeight)\ + {\ + RCL_Unit height = floorHeightFunc(s1,s2);\ + if (height > bottomLimit || \ + currCeilHeight - height < \ + RCL_CAMERA_COLL_HEIGHT_BELOW + RCL_CAMERA_COLL_HEIGHT_ABOVE)\ + dir##Collides = 1;\ + else if (ceilingHeightFunc != 0)\ + {\ + RCL_Unit height2 = ceilingHeightFunc(s1,s2);\ + if ((height2 < topLimit) || ((height2 - height) < \ + (RCL_CAMERA_COLL_HEIGHT_ABOVE + RCL_CAMERA_COLL_HEIGHT_BELOW)))\ + dir##Collides = 1;\ + }\ + }\ + else\ + dir##Collides = floorHeightFunc(s1,s2) > RCL_CAMERA_COLL_STEP_HEIGHT; + + // check collision against non-diagonal square + #define collCheckOrtho(dir,dir2,s1,s2,x)\ + if (dir##SquareNew != dir##Square)\ + {\ + collCheck(dir,s1,s2)\ + }\ + if (!dir##Collides)\ + { /* now also check for coll on the neighbouring square */ \ + int16_t dir2##Square2 = RCL_divRoundDown(corner.dir2 - dir2##Dir *\ + RCL_CAMERA_COLL_RADIUS * 2,RCL_UNITS_PER_SQUARE);\ + if (dir2##Square2 != dir2##Square)\ + {\ + if (x)\ + collCheck(dir,dir##SquareNew,dir2##Square2)\ + else\ + collCheck(dir,dir2##Square2,dir##SquareNew)\ + }\ + } + + int8_t xCollides = 0; + collCheckOrtho(x,y,xSquareNew,ySquare,1) + + int8_t yCollides = 0; + collCheckOrtho(y,x,xSquare,ySquareNew,0) + + if (xCollides || yCollides) + { + if (movesInPlane) + { + #define collHandle(dir)\ + if (dir##Collides)\ + cornerNew.dir = (dir##Square) * RCL_UNITS_PER_SQUARE +\ + RCL_UNITS_PER_SQUARE / 2 + dir##Dir * (RCL_UNITS_PER_SQUARE / 2) -\ + dir##Dir;\ + + collHandle(x) + collHandle(y) + + #undef collHandle + } + else + { + /* Player collides without moving in the plane; this can happen e.g. on + elevators due to vertical only movement. This code can get executed + when force == 1. */ + + RCL_Vector2D squarePos; + RCL_Vector2D newPos; + + squarePos.x = xSquare * RCL_UNITS_PER_SQUARE; + squarePos.y = ySquare * RCL_UNITS_PER_SQUARE; + + newPos.x = + RCL_max(squarePos.x + RCL_CAMERA_COLL_RADIUS + 1, + RCL_min(squarePos.x + RCL_UNITS_PER_SQUARE - RCL_CAMERA_COLL_RADIUS - 1, + camera->position.x)); + + newPos.y = + RCL_max(squarePos.y + RCL_CAMERA_COLL_RADIUS + 1, + RCL_min(squarePos.y + RCL_UNITS_PER_SQUARE - RCL_CAMERA_COLL_RADIUS - 1, + camera->position.y)); + + cornerNew.x = corner.x + (newPos.x - camera->position.x); + cornerNew.y = corner.y + (newPos.y - camera->position.y); + } + } + else + { + /* If no non-diagonal collision is detected, a diagonal/corner collision + can still happen, check it here. */ + + if (xSquare != xSquareNew && ySquare != ySquareNew) + { + int8_t xyCollides = 0; + collCheck(xy,xSquareNew,ySquareNew) + + if (xyCollides) + { + // normally should slide, but let's KISS and simply stop any movement + cornerNew = corner; + } + } + } + + #undef collCheck + + camera->position.x = cornerNew.x - xDir * RCL_CAMERA_COLL_RADIUS; + camera->position.y = cornerNew.y - yDir * RCL_CAMERA_COLL_RADIUS; + } + + if (computeHeight && (movesInPlane || (heightOffset != 0) || force)) + { + camera->height += heightOffset; + + int16_t xSquare1 = RCL_divRoundDown(camera->position.x - + RCL_CAMERA_COLL_RADIUS,RCL_UNITS_PER_SQUARE); + + int16_t xSquare2 = RCL_divRoundDown(camera->position.x + + RCL_CAMERA_COLL_RADIUS,RCL_UNITS_PER_SQUARE); + + int16_t ySquare1 = RCL_divRoundDown(camera->position.y - + RCL_CAMERA_COLL_RADIUS,RCL_UNITS_PER_SQUARE); + + int16_t ySquare2 = RCL_divRoundDown(camera->position.y + + RCL_CAMERA_COLL_RADIUS,RCL_UNITS_PER_SQUARE); + + RCL_Unit bottomLimit = floorHeightFunc(xSquare1,ySquare1); + RCL_Unit topLimit = ceilingHeightFunc != 0 ? + ceilingHeightFunc(xSquare1,ySquare1) : RCL_INFINITY; + + RCL_Unit height; + + #define checkSquares(s1,s2)\ + {\ + height = floorHeightFunc(xSquare##s1,ySquare##s2);\ + bottomLimit = RCL_max(bottomLimit,height);\ + height = ceilingHeightFunc != 0 ?\ + ceilingHeightFunc(xSquare##s1,ySquare##s2) : RCL_INFINITY;\ + topLimit = RCL_min(topLimit,height);\ + } + + if (xSquare2 != xSquare1) + checkSquares(2,1) + + if (ySquare2 != ySquare1) + checkSquares(1,2) + + if (xSquare2 != xSquare1 && ySquare2 != ySquare1) + checkSquares(2,2) + + camera->height = RCL_clamp(camera->height, + bottomLimit + RCL_CAMERA_COLL_HEIGHT_BELOW, + topLimit - RCL_CAMERA_COLL_HEIGHT_ABOVE); + + #undef checkSquares + } +} + +void RCL_initCamera(RCL_Camera *camera) +{ + camera->position.x = 0; + camera->position.y = 0; + camera->direction = 0; + camera->resolution.x = 20; + camera->resolution.y = 15; + camera->shear = 0; + camera->height = RCL_UNITS_PER_SQUARE; +} + +void RCL_initRayConstraints(RCL_RayConstraints *constraints) +{ + constraints->maxHits = 1; + constraints->maxSteps = 20; +} + +#endif + diff --git a/main_gbmeta/settings.h b/main_gbmeta/settings.h new file mode 100644 index 0000000..83ea8d6 --- /dev/null +++ b/main_gbmeta/settings.h @@ -0,0 +1,447 @@ +/** + @file settings.h + + This file contains settings (or setting hints) for the game. Values here can + fine tune performance vs quality and personalize the final compiled game. Some + of these settings may be overriden by the specific platform used according to + its limitations. You are advised to NOT change value in this file directly, + but rather predefine them somewhere before this file gets included, e.g. in + you personal settings file. + + by Miloslav Ciz (drummyfish), 2019 + + Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) + plus a waiver of all other intellectual property. The goal of this work is + be and remain completely in the public domain forever, available for any use + whatsoever. +*/ + +#ifndef _SFG_SETTINGS_H +#define _SFG_SETTINGS_H + +/** + Time multiplier in SFG_Units (1.0 == 1024). This can be used to slow down or + speed up the game. Note that this also changes the rendering FPS accordingly + (e.g. half FPS at half speed), so if you want to keep the FPS, divide it by + the multiplier value. +*/ +#ifndef SFG_TIME_MULTIPLIER + #define SFG_TIME_MULTIPLIER 1024 +#endif + +/** + Target FPS (frames per second). This sets the game logic FPS and will try to + render at the same rate. If such fast rendering can't be achieved, frames will + be droped, but the game logic will still be forced to run at this speed, so + the game may actually become slowed down if FPS is set too high. Too high or + too low FPS can also negatively affect game speeds which are computed as + integers and rounding errors can occur soon, so don't set this to extreme + values (try to keep between 20 to 100). FPS also determines the game + simulation step length, so different FPS values may result in very slight + differences in game behavior (not noticeable but affecting demos etc.). +*/ +#ifndef SFG_FPS + #define SFG_FPS 60 +#endif + +/** + On platforms with mouse this sets its horizontal sensitivity. 128 means 1 + RCL_Unit per mouse pixel travelled. +*/ +#ifndef SFG_MOUSE_SENSITIVITY_HORIZONTAL + #define SFG_MOUSE_SENSITIVITY_HORIZONTAL 32 +#endif + +/** + Like SFG_MOUSE_SENSITIVITY_HORIZONTAL but for vertical look. 128 means 1 + shear pixel per mouse pixel travelled. +*/ +#ifndef SFG_MOUSE_SENSITIVITY_VERTICAL + #define SFG_MOUSE_SENSITIVITY_VERTICAL 64 +#endif + +/** + Width of the screen in pixels. Set this to ACTUAL resolution. If you want the + game to run at smaller resolution (with bigger pixels), do his using + SFG_RESOLUTION_SCALEDOWN; +*/ +#ifndef SFG_SCREEN_RESOLUTION_X + #define SFG_SCREEN_RESOLUTION_X 800 +#endif + +/** + Height of the screen in pixels. Set this to ACTUAL resolution. If you want the + game to run at smaller resolution (with bigger pixels), do his using + SFG_RESOLUTION_SCALEDOWN; +*/ +#ifndef SFG_SCREEN_RESOLUTION_Y + #define SFG_SCREEN_RESOLUTION_Y 600 +#endif + +/** + How quickly player turns left/right, in degrees per second. +*/ +#ifndef SFG_PLAYER_TURN_SPEED + #define SFG_PLAYER_TURN_SPEED 180 +#endif + +/** + Horizontal FOV (field of vision) in RCL_Units (1024 means 360 degrees). +*/ + +#ifndef SFG_FOV_HORIZONTAL + #define SFG_FOV_HORIZONTAL 256 +#endif + +/** + Like SFG_FOV_HORIZONTAL but for vertical angle. +*/ +#ifndef SFG_FOV_VERTICAL + #define SFG_FOV_VERTICAL 330 +#endif + +/** + Distance, in RCL_Units, to which textures will be drawn. Textures behind this + distance will be replaced by an average constant color, which maybe can help + performance and also serves as an antialiasim (2 level MIP map). Value 0 turns + texturing completely off, which is much faster than having just a low value, + values >= 65535 activate texturing completely, which can be a little faster + than setting having a high value lower than this limit. +*/ +#ifndef SFG_TEXTURE_DISTANCE + #define SFG_TEXTURE_DISTANCE 100000 +#endif + +/** + How many times the screen resolution will be divided (how many times a game + pixel will be bigger than the screen pixel). +*/ +#ifndef SFG_RESOLUTION_SCALEDOWN + #define SFG_RESOLUTION_SCALEDOWN 1 +#endif + +/** + Multiplier, in RCL_Units (1024 == 1.0), of the damager player takes. This can + be used to balance difficulty. +*/ +#ifndef SFG_PLAYER_DAMAGE_MULTIPLIER + #define SFG_PLAYER_DAMAGE_MULTIPLIER 512 +#endif + +/** + Hint as to whether run in fullscreen, if the platform allows it. +*/ +#ifndef SFG_FULLSCREEN + #define SFG_FULLSCREEN 0 +#endif + +/** + Whether shadows (fog) should be dithered, i.e. more smooth (needs a bit more + CPU performance and memory). +*/ +#ifndef SFG_DITHERED_SHADOW + #define SFG_DITHERED_SHADOW 0 +#endif + +/** + Depth step (in RCL_Units) after which fog diminishes a color by one value + point. For performance reasons this number should be kept a power of two! +*/ +#ifndef SFG_FOG_DIMINISH_STEP + #define SFG_FOG_DIMINISH_STEP 2048 +#endif + +/** + Maximum number of squares that will be traversed by any cast ray. Smaller + number is faster but can cause visual artifacts. +*/ +#ifndef SFG_RAYCASTING_MAX_STEPS + #define SFG_RAYCASTING_MAX_STEPS 30 +#endif + +/** + Maximum number of hits any cast ray will register. Smaller number is faster + but can cause visual artifacts. +*/ +#ifndef SFG_RAYCASTING_MAX_HITS + #define SFG_RAYCASTING_MAX_HITS 10 +#endif + +/** + How many times rendering should be subsampled horizontally. Bigger number + can significantly improve performance (by casting fewer rays), but can look + a little worse. This number should be a divisor of SFG_SCREEN_RESOLUTION_X! +*/ +#ifndef SFG_RAYCASTING_SUBSAMPLE + #define SFG_RAYCASTING_SUBSAMPLE 1 +#endif + +/** + Enables or disables fog (darkness) due to distance. Recommended to keep on + for good look, but can be turned off for performance. +*/ +#ifndef SFG_ENABLE_FOG + #define SFG_ENABLE_FOG 1 +#endif + +/** + Says whether sprites should diminish in fog. This takes more performance but + looks better. +*/ +#ifndef SFG_DIMINISH_SPRITES + #define SFG_DIMINISH_SPRITES 1 +#endif + +/** + How quick player head bob is, 1024 meaning once per second. 0 Means turn off + head bob. +*/ +#ifndef SFG_HEADBOB_SPEED + #define SFG_HEADBOB_SPEED 900 +#endif + +/** + Sets head bob offset, in RCL_UNITS_PER_SQUARE. 0 Means turn off head bob. +*/ +#ifndef SFG_HEADBOB_OFFSET + #define SFG_HEADBOB_OFFSET 200 +#endif + +/** + If head bob is on, this additionally sets additional camera shear bob, in + pixels, which can make bobbing look more "advanced". 0 turns this option off. +*/ +#ifndef SFG_HEADBOB_SHEAR + #define SFG_HEADBOB_SHEAR 0 +#endif + +/** + Weapon bobbing offset in weapon image pixels. +*/ +#ifndef SFG_WEAPONBOB_OFFSET + #define SFG_WEAPONBOB_OFFSET 4 +#endif + +/** + Camera shearing (looking up/down) speed, in vertical resolutions per second. +*/ +#ifndef SFG_CAMERA_SHEAR_SPEED + #define SFG_CAMERA_SHEAR_SPEED 3 +#endif + +/** + Maximum camera shear (vertical angle). 1024 means 1.0 * vertical resolution. +*/ +#ifndef SFG_CAMERA_MAX_SHEAR + #define SFG_CAMERA_MAX_SHEAR 1024 +#endif + +/** + Specifies how quick some sprite animations are, in frames per second. +*/ +#ifndef SFG_SPRITE_ANIMATION_SPEED + #define SFG_SPRITE_ANIMATION_SPEED 4 +#endif + +/** + How wide the border indicator is, in fractions of screen width. +*/ +#ifndef SFG_HUD_BORDER_INDICATOR_WIDTH + #define SFG_HUD_BORDER_INDICATOR_WIDTH 32 +#endif + +/** + For how long border indication (being hurt etc.) stays shown, in ms. +*/ +#ifndef SFG_HUD_BORDER_INDICATOR_DURATION + #define SFG_HUD_BORDER_INDICATOR_DURATION 500 +#endif + +/** + Color (palette index) by which being hurt is indicated. +*/ +#ifndef SFG_HUD_HURT_INDICATION_COLOR + #define SFG_HUD_HURT_INDICATION_COLOR 175 +#endif + +/** + Color (palette index) by which taking an item is indicated. +*/ +#ifndef SFG_HUD_ITEM_TAKEN_INDICATION_COLOR + #define SFG_HUD_ITEM_TAKEN_INDICATION_COLOR 207 +#endif + +/** + How many element (items, monsters, ...) distances will be checked per frame + for distance. Higher value may decrease performance a tiny bit, but things + will react more quickly and appear less "out of thin air". +*/ +#ifndef SFG_ELEMENT_DISTANCES_CHECKED_PER_FRAME + #define SFG_ELEMENT_DISTANCES_CHECKED_PER_FRAME 8 +#endif + +/** + Maximum distance at which sound effects (SFX) will be played. The SFX volume + will gradually drop towards this distance. +*/ +#ifndef SFG_SFX_MAX_DISTANCE + #define SFG_SFX_MAX_DISTANCE (1024 * 60) +#endif + +/** + Says the intensity of background image blur. 0 means no blur, improves + performance and lowers memory usage. +*/ +#ifndef SFG_BACKGROUND_BLUR + #define SFG_BACKGROUND_BLUR 0 +#endif + +/** + Defines the period, in ms, of things that blink, such as text. +*/ +#ifndef SFG_BLINK_PERIOD + #define SFG_BLINK_PERIOD 500 +#endif + +/** + Probability (0 - 255) of how often a monster makes sound during movement. +*/ +#ifndef SFG_MONSTER_SOUND_PROBABILITY + #define SFG_MONSTER_SOUND_PROBABILITY 64 +#endif + +/** + Affects how precise monsters are in aiming, specify random range in + fourths of a game square. Should be power of 2 for performance. +*/ +#ifndef SFG_MONSTER_AIM_RANDOMNESS + #define SFG_MONSTER_AIM_RANDOMNESS 4 +#endif + +/// Color 1 index of player on map. +#ifndef SFG_MAP_PLAYER_COLOR1 + #define SFG_MAP_PLAYER_COLOR1 93 +#endif + +/// Color 2 index of player on map. +#ifndef SFG_MAP_PLAYER_COLOR2 + #define SFG_MAP_PLAYER_COLOR2 111 +#endif + +/// Color index of elevators on map. +#ifndef SFG_MAP_ELEVATOR_COLOR + #define SFG_MAP_ELEVATOR_COLOR 214 +#endif + +/// Color index of squeezers on map. +#ifndef SFG_MAP_SQUEEZER_COLOR + #define SFG_MAP_SQUEEZER_COLOR 246 +#endif + +/// Color index of door on map. +#ifndef SFG_MAP_DOOR_COLOR + #define SFG_MAP_DOOR_COLOR 188 +#endif + +/** + Boolean value indicating whether current OS is malware. +*/ +#ifndef SFG_OS_IS_MALWARE + #define SFG_OS_IS_MALWARE 0 +#endif + +/** + Angle difference, as a cos value in RCL_Units, between the player and a + monster, at which vertical autoaim will trigger. If the angle is greater, a + shot will go directly forward. +*/ +#ifndef SFG_VERTICAL_AUTOAIM_ANGLE_THRESHOLD + #define SFG_VERTICAL_AUTOAIM_ANGLE_THRESHOLD 50 +#endif + +/** + Byte (0 - 255) volume of the menu click sound. +*/ +#ifndef SFG_MENU_CLICK_VOLUME + #define SFG_MENU_CLICK_VOLUME 220 +#endif + +/** + Says whether the exit item should be showed in the menu. Platforms that can't + exit (such as some gaming consoles that simply use power off button) can + define this to 0. +*/ +#ifndef SFG_CAN_EXIT + #define SFG_CAN_EXIT 1 +#endif + +/** + On Arduino platforms this should be set to 1. That will cause some special + treatment regarding constant variables and PROGMEM. +*/ +#ifndef SFG_ARDUINO + #define SFG_ARDUINO 0 +#endif + +/** + Whether levels background (in distance or transparent wall textures) should + be drawn. If turned off, the background will be constant color, which can + noticably increase performance. +*/ +#ifndef SFG_DRAW_LEVEL_BACKGROUND + #define SFG_DRAW_LEVEL_BACKGROUND 1 +#endif + +//------ developer/debug settings ------ + +/** + Developer cheat for having infinite ammo in all weapons. +*/ +#ifndef SFG_INFINITE_AMMO + #define SFG_INFINITE_AMMO 0 +#endif + +/** + Developer cheat for immortality. +*/ +#ifndef SFG_IMMORTAL + #define SFG_IMMORTAL 0 +#endif + +/** + Turn on for previes mode for map editing (flying, noclip, fast movement etc.). +*/ +#ifndef SFG_PREVIEW_MODE + #define SFG_PREVIEW_MODE 0 +#endif + +/** + How much faster movement is in the preview mode. +*/ +#ifndef SFG_PREVIEW_MODE_SPEED_MULTIPLIER + #define SFG_PREVIEW_MODE_SPEED_MULTIPLIER 2 +#endif + +/** + Skips menu and starts given level immediatelly, for development. 0 means this + options is ignored, 1 means load level 1 etc. +*/ +#ifndef SFG_START_LEVEL + #define SFG_START_LEVEL 0 +#endif + +/** + Reveals whole level map from start. +*/ +#ifndef SFG_REVEAL_MAP + #define SFG_REVEAL_MAP 0 +#endif + +/** + Gives player all keys from start. +*/ +#ifndef SFG_UNLOCK_DOOR + #define SFG_UNLOCK_DOOR 0 +#endif + +#endif // guard diff --git a/main_gbmeta/smallinput.h b/main_gbmeta/smallinput.h new file mode 100644 index 0000000..cee8507 --- /dev/null +++ b/main_gbmeta/smallinput.h @@ -0,0 +1,404 @@ +/** + @file smallinput.h + + Small API for getting keyboard/mouse input, with possiblity to record it and + play back. + + The Linux Input API requires root pirivileges (sudo). + + by Milsolav "drummyfish" Ciz, released under CC0 1.0 (public domain) +*/ + +#ifndef _SMALLINPUT_H +#define _SMALLINPUT_H + +#include +#include + +#define SMALLINPUT_MODE_NORMAL 0 ///< Only handle input. +#define SMALLINPUT_MODE_RECORD 1 ///< Handle input and record it. +#define SMALLINPUT_MODE_PLAY 2 ///< Play back recorded input. + +#define SMALLINPUT_KEY_NONE 0 +#define SMALLINPUT_SPACE ' ' +#define SMALLINPUT_BACKSPACE 8 +#define SMALLINPUT_TAB 9 +#define SMALLINPUT_RETURN 13 +#define SMALLINPUT_SHIFT 14 +#define SMALLINPUT_ESCAPE 27 +#define SMALLINPUT_DELETE 127 +#define SMALLINPUT_ARROW_UP 128 +#define SMALLINPUT_ARROW_RIGHT 129 +#define SMALLINPUT_ARROW_DOWN 130 +#define SMALLINPUT_ARROW_LEFT 131 +#define SMALLINPUT_F1 132 +#define SMALLINPUT_F2 133 +#define SMALLINPUT_F3 134 +#define SMALLINPUT_F4 135 +#define SMALLINPUT_F5 136 +#define SMALLINPUT_F6 137 +#define SMALLINPUT_F7 138 +#define SMALLINPUT_F8 139 +#define SMALLINPUT_F9 140 +#define SMALLINPUT_F10 141 +#define SMALLINPUT_F11 142 +#define SMALLINPUT_F12 143 +#define SMALLINPUT_CTRL 144 +#define SMALLINPUT_MOUSE_L 253 +#define SMALLINPUT_MOUSE_M 254 +#define SMALLINPUT_MOUSE_R 255 + +#define SMALLINPUT_RECORD_KEY_DOWN 1 ///< Mouse down event, followed by code. +#define SMALLINPUT_RECORD_KEY_UP 2 ///< Moue up event, followed by code. +#define SMALLINPUT_RECORD_MOUSE_X 3 ///< Mouse x move, followed by s32 value. +#define SMALLINPUT_RECORD_MOUSE_Y 4 ///< Mouse y move, followed by s32 value. +#define SMALLINPUT_RECORD_END 255 ///< Record end, followed by 4 more same values. + +uint8_t input_keyStates[256]; +int32_t input_mousePosition[2]; + +uint8_t input_keyStatesPrevious[256]; +int32_t input_mousePositionPrevious[2]; + +uint8_t input_mode; + +uint32_t input_frame = 0; +uint8_t *input_recordData; +uint32_t input_recordPosition; +uint32_t input_recordSize; + +#if 1 // TODO: add other options for input handling (SDL, xinput, ...) + /* + This is using Linux Input Subsystem API. Defines can be found in + include/uapi/linux/input-event-codes.h. + */ + + #include + #include + #include + #include + + typedef struct + { + struct timeval time; + uint16_t type; + uint16_t code; + int32_t value; + } LinuxInputEvent; + + #define INPUT_KEYBOARD_FILE "/dev/input/event0" + #define INPUT_MOUSE_FILE "/dev/input/event1" + + int input_keyboardFile = 0; + int input_mouseFile = 0; + + /** + Maps this library's key codes to linux input key codes. + */ + static const int input_linuxCodes[256] = + { + #define no KEY_RESERVED + no,no,no,no,no,no,no,no,KEY_BACKSPACE,KEY_TAB,no,no,no,KEY_ENTER,KEY_LEFTSHIFT,no, + no,no,no,no,no,no,no,no,no,no,no,KEY_ESC,no,no,no,no, + KEY_SPACE,no,no,no,no,no,no,no,no,no,no,no,KEY_COMMA,no,KEY_DOT,no, + KEY_0,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9,no,KEY_SEMICOLON,no,KEY_EQUAL,no,KEY_QUESTION, + no,KEY_A,KEY_B,KEY_C,KEY_D,KEY_E,KEY_F,KEY_G,KEY_H,KEY_I,KEY_J,KEY_K,KEY_L,KEY_M,KEY_N,KEY_O, + KEY_P,KEY_Q,KEY_R,KEY_S,KEY_T,KEY_U,KEY_V,KEY_W,KEY_X,KEY_Y,KEY_Z,no,no,no,no,no, + no,KEY_A,KEY_B,KEY_C,KEY_D,KEY_E,KEY_F,KEY_G,KEY_H,KEY_I,KEY_J,KEY_K,KEY_L,KEY_M,KEY_N,KEY_O, + KEY_P,KEY_Q,KEY_R,KEY_S,KEY_T,KEY_U,KEY_V,KEY_W,KEY_X,KEY_Y,KEY_Z,no,no,no,no,KEY_DELETE, + KEY_UP,KEY_RIGHT,KEY_DOWN,KEY_LEFT,KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,KEY_F11,KEY_F12, + KEY_LEFTCTRL,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no + #undef no + }; +#endif + +void input_recordU8(uint8_t value) +{ + if (input_recordPosition < (input_recordSize - 1)) + { + input_recordData[input_recordPosition] = value; + input_recordPosition++; + } +} + +void input_recordU32(uint32_t value) +{ + for (uint8_t i = 0; i < 4; ++i) + { + input_recordU8(value % 256); + value /= 256; + } +} + +uint32_t input_readU32(uint8_t *data) +{ + uint32_t result = 0; + + for (uint8_t i = 0; i < 4; ++i) + result = result * 256 + data[3 - i]; + + return result; +} + +/** + Initializes the library with given mode (SMALLINPUT_MODE_*). +*/ +uint8_t input_init(uint8_t mode, uint8_t *recordData, uint32_t recordDataLength) +{ + input_mode = mode; + + input_mousePosition[0] = 0; + input_mousePosition[1] = 0; + + input_mousePositionPrevious[0] = 0; + input_mousePositionPrevious[1] = 0; + + input_frame = 0; + input_recordData = recordData; + input_recordPosition = 0; + input_recordSize = recordDataLength; + + for (int16_t i = 0; i < 256; ++i) + { + input_keyStates[i] = 0; + input_keyStatesPrevious[i] = 0; + } + + uint8_t result = 1; + + if (input_mode != SMALLINPUT_MODE_PLAY) + { + input_keyboardFile = open(INPUT_KEYBOARD_FILE, O_RDONLY); + + result = input_keyboardFile >= 0; + + if (result) + { + fcntl(input_keyboardFile, F_SETFL, O_NONBLOCK); + + input_mouseFile = open(INPUT_MOUSE_FILE, O_RDONLY); + + result = input_mouseFile >= 0; + + if (result) + fcntl(input_mouseFile, F_SETFL, O_NONBLOCK); + } + + if (!result) + puts("could not open device file (are you root?)"); + } + + return result; +} + +void input_end(void) +{ + if (input_mode == SMALLINPUT_MODE_RECORD) + for (uint8_t i = 0; i < 5; ++i) + input_recordU8(SMALLINPUT_RECORD_END); + + close(input_keyboardFile); + close(input_mouseFile); +} + +/** + Should be called once every main loop iteration to retrieve current input + state. +*/ +void input_update(void) +{ + LinuxInputEvent event; + + if (input_mode == SMALLINPUT_MODE_PLAY) + { + while (input_recordPosition < input_recordSize) + { + uint32_t nextFrame = input_readU32(input_recordData + input_recordPosition); + + if (input_frame >= nextFrame) + { + input_recordPosition += 4; + + uint8_t rec = input_recordData[input_recordPosition]; + + switch (rec) + { + case SMALLINPUT_RECORD_KEY_DOWN: + case SMALLINPUT_RECORD_KEY_UP: + input_recordPosition++; + input_keyStates[input_recordData[input_recordPosition]] = rec == SMALLINPUT_RECORD_KEY_DOWN; + input_recordPosition++; + break; + + case SMALLINPUT_RECORD_MOUSE_X: + case SMALLINPUT_RECORD_MOUSE_Y: + input_recordPosition++; + input_mousePosition[rec == SMALLINPUT_RECORD_MOUSE_Y] = + input_readU32(input_recordData + input_recordPosition); + input_recordPosition += 4; + break; + + case SMALLINPUT_RECORD_END: + input_recordPosition = input_recordSize; + break; + + default: /*printf("corrupt record\n");*/ break; + } + } + else + break; + } + } + else + { + while (1) // keyboard + { + if (read(input_keyboardFile, &event, sizeof(event)) <= 0) + break; + + if (event.type == EV_KEY && (event.value == 1 || event.value == 0)) + for (uint16_t i = 0; i < 256; ++i) + if (event.code == input_linuxCodes[i]) + { + input_keyStates[i] = event.value; + break; + } + } + + while (1) // mouse + { + if (read(input_mouseFile, &event, sizeof(event)) <= 0) + break; + + if (event.type == EV_REL) + input_mousePosition[event.code % 2] += event.value; + else if (event.type == EV_KEY) + { + input_keyStates[ + event.code == BTN_LEFT ? SMALLINPUT_MOUSE_L : + (event.code == BTN_RIGHT ? SMALLINPUT_MOUSE_R : SMALLINPUT_MOUSE_M)] + = event.value; + } + } + } + + for (uint16_t i = 0; i < 256; ++i) + if (input_keyStates[i] && input_keyStates[i] < 255) + input_keyStates[i]++; + + if (input_mode == SMALLINPUT_MODE_RECORD) + { + for (uint8_t i = 0; i < 2; ++i) // record mouse events + if (input_mousePositionPrevious[i] != input_mousePosition[i]) + { + input_recordU32(input_frame + 1); + input_recordU8((i == 0) ? SMALLINPUT_RECORD_MOUSE_X : SMALLINPUT_RECORD_MOUSE_Y); + input_recordU32(input_mousePosition[i]); + + input_mousePositionPrevious[i] = input_mousePosition[i]; + } + + for (uint16_t i = 0; i < 256; ++i) // record key events + { + uint8_t a = input_keyStates[i] > 0; + uint8_t b = input_keyStatesPrevious[i] > 0; + + if (a != b) + { + input_recordU32(input_frame + 1); + input_recordU8(a ? SMALLINPUT_RECORD_KEY_DOWN : SMALLINPUT_RECORD_KEY_UP); + input_recordU8(i); + + input_keyStatesPrevious[i] = input_keyStates[i]; + } + } + } + + input_frame++; +} + +/** + Returns the number of input frames for which given key has been pressed (> 1: + key is pressed, == 1: key was just pressed, == 0: key is not pressed). +*/ +static inline uint8_t input_getKey(uint8_t key) +{ + if (key >= 'a' && key <= 'z') + key = 'A' + (key - 'a'); + + return input_keyStates[key]; +} + +/** + Gets the mouse position. +*/ +static inline void input_getMousePos(int32_t *x, int32_t *y) +{ + *x = input_mousePosition[0]; + *y = input_mousePosition[1]; +} + +static inline void input_setMousePos(int32_t x, int32_t y) +{ + input_mousePosition[0] = x; + input_mousePosition[1] = y; +} + +/** + Prints the current input state. +*/ +void input_print() +{ + printf("frame: %d\nmouse pos: %d %d",input_frame,input_mousePosition[0],input_mousePosition[1]); + + for (uint16_t i = 0; i < 256; ++i) + { + if (i % 8 == 0) + putchar('\n'); + + char c = (i > ' ' && i <= 126) ? i : '?'; + + uint8_t n = input_getKey(i); + + printf("%s",n ? " [" : " "); + printf("%03d (\'%c\'): %03d",i,c,input_getKey(i)); + printf("%s",n ? "] " : " "); + } + + putchar('\n'); +} + +void input_printRecord() +{ + for (uint32_t i = 0; i < input_recordPosition; ++i) + { + if (i % 32 == 0) + putchar('\n'); + + printf("%d,",input_recordData[i]); + } +} + +uint32_t input_hash() +{ + uint32_t result = 0; + + for (uint16_t i = 0; i < 256; ++i) + result += input_getKey(i) * (i + 1); + + int32_t x, y; + + input_getMousePos(&x,&y); + + result += x + y << 16; + + return result; +} + +#endif // guard diff --git a/main_gbmeta/sounds.h b/main_gbmeta/sounds.h new file mode 100644 index 0000000..c9d3b56 --- /dev/null +++ b/main_gbmeta/sounds.h @@ -0,0 +1,488 @@ +/** + @file assets.h + + This file containts sounds and music that can optionally be used by the game + front end. Every sound effect has 2048 samples, is stored in 8kHz mono format + with 4 bit quantization, meaning every sound effect takes 1024 bytes. Sounds + can be converted using a provided python script like this: + + python snd2array.py sound.raw + + by Miloslav Ciz (drummyfish), 2019 + + Music is based on bytebeat (procedural waveforms generated by short bitwise + operation formulas). + + Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) + plus a waiver of all other intellectual property. The goal of this work is + be and remain completely in the public domain forever, available for any use + whatsoever. +*/ + +#ifndef _SFG_SOUNDS_H +#define _SFG_SOUNDS_H + +#define SFG_SFX_SAMPLE_COUNT 2048 +#define SFG_SFX_SIZE (SFG_SFX_SAMPLE_COUNT / 2) + +/** + Gets a 8-bit sound sample. +*/ +#define SFG_GET_SFX_SAMPLE(soundIndex,sampleIndex) \ + ((SFG_PROGRAM_MEMORY_U8(SFG_sounds + soundIndex * SFG_SFX_SIZE \ + + sampleIndex / 2) << (4 * ((sampleIndex % 2) != 0))) & 0xf0) + +#define SFG_TRACK_SAMPLES (512 * 1024) +#define SFG_TRACK_COUNT 6 + +/** + Average value of each music track, can be used to correct DC offset issues if + they appear. +*/ +SFG_PROGRAM_MEMORY uint8_t SFG_musicTrackAverages[SFG_TRACK_COUNT] = + {14,7,248,148,6,8}; + +struct +{ // all should be initialized to 0 + uint8_t track; + uint32_t t; // time variable/parameter + uint32_t t2; // stores t squared, for better performance + uint32_t n11t; // stores a multiple of 11, for better performance +} SFG_MusicState; + +/** + Gets the next 8bit 8KHz music sample for the bytebeat soundtrack. This + function is to be used by the frontend that plays music. +*/ +uint8_t SFG_getNextMusicSample() +{ + if (SFG_MusicState.t >= SFG_TRACK_SAMPLES) + { + SFG_MusicState.track++; + + if (SFG_MusicState.track >= SFG_TRACK_COUNT) + SFG_MusicState.track = 0; + + SFG_MusicState.t = 0; + SFG_MusicState.t2 = 0; + SFG_MusicState.n11t = 0; + } + + uint32_t result; + + #define S SFG_MusicState.t // can't use "T" because of a C++ template + #define S2 SFG_MusicState.t2 + #define N11S SFG_MusicState.n11t + + /* CAREFUL! Bit shifts in any direction by amount greater than data type + width (32) are undefined behavior. Use % 32. */ + + switch (SFG_MusicState.track) // individual music tracks + { + case 0: + { + uint32_t a = ((S >> 7) | (S >> 9) | (~S << 1) | S); + result = (((S) & 65536) ? (a & (((S2) >> 16) & 0x09)) : ~a); + + SFG_MusicState.t2 += S; + + break; + } + + case 1: + { + uint32_t a = (S >> 10); + result = S & (3 << (((a ^ (a << ((S >> 6) % 32)))) % 32)); + + break; + } + + case 2: + { + result = + ~((((S >> ((S >> 2) % 32)) | (S >> ((S >> 5) % 32))) & 0x12) << 1) + | (S >> 11); + + break; + } + + case 3: + { + result = + (((((S >> ((S >> 2) % 32)) + (S >> ((S >> 7) % 32)))) & 0x3f) | (S >> 5) + | (S >> 11)) & ((S & (32768 | 8192)) ? 0xf0 : 0x30); + + break; + } + + case 4: + { + result = + ((0x47 >> ((S >> 9) % 32)) & (S >> (S % 32))) | + (0x57 >> ((S >> 7) % 32)) | + (0x06 >> ((S >> ((((N11S) >> 14) & 0x0e) % 32)) % 32)); + + SFG_MusicState.n11t += 11; + + break; + } + + case 5: + { + uint32_t a = S >> ((S >> 6) % 32); + uint32_t b = 0x011121 >> (((a + S) >> 11) % 32); + result = + (((S >> 9) + (S ^ (S << 1))) & (0x7f >> (((S >> 15) & 0x03) % 32))) + & (b + a); + + break; + } + + default: + result = 127; + break; + } + + #undef S + #undef S2 + #undef N11S + + SFG_MusicState.t += 1; + + return result; +} + +/** + Switches the bytebeat to next music track. +*/ +void SFG_nextMusicTrack() +{ + uint8_t current = SFG_MusicState.track; + + while (SFG_MusicState.track == current) + SFG_getNextMusicSample(); +} + +SFG_PROGRAM_MEMORY uint8_t SFG_sounds[SFG_SFX_SIZE * 6] = +{ +// 0, bullet shot +135,119,120,136,136,153,153,153,154,169,152,119,101,85,86,102,119,118,119, +85,84,51,33,52,52,84,87,120,170,188,202,152,102,84,84,70,119,136,119, +119,121,154,219,170,137,117,82,18,36,34,33,20,67,68,70,137,172,189,237, +220,150,120,120,97,36,102,121,151,87,169,118,86,102,120,137,135,120,186,155, +223,255,217,103,100,70,119,118,84,34,36,122,204,220,168,138,170,170,223,199, +117,70,119,136,100,85,102,51,37,101,103,118,101,136,87,154,169,171,187,186, +169,153,136,117,68,84,66,18,19,50,52,51,102,121,139,186,169,171,186,152, +153,136,119,134,85,101,86,69,84,84,86,85,86,102,119,120,153,135,135,101, +87,134,103,135,101,103,119,135,152,120,136,135,137,136,151,134,87,119,136,119, +118,102,85,119,85,102,102,119,138,137,153,137,186,170,137,152,135,101,85,85, +86,102,102,119,119,102,103,119,137,152,138,153,154,169,153,152,137,151,118,85, +85,84,84,86,86,136,119,119,154,153,153,171,187,170,170,187,170,137,151,119, +102,103,69,102,118,120,120,138,153,169,170,169,153,135,119,119,102,118,105,136, +136,137,152,153,136,152,119,119,119,119,121,152,136,119,152,136,135,120,119,118, +86,102,103,136,135,137,153,136,152,119,119,118,102,86,85,102,102,102,102,120, +136,136,136,136,152,136,153,152,119,119,120,135,120,119,119,103,119,136,119,135, +120,135,136,136,137,153,153,152,154,152,153,137,152,136,135,119,136,136,136,153, +152,154,170,170,153,153,152,119,119,119,119,118,119,103,136,136,120,135,118,120, +119,118,102,119,102,102,103,119,118,103,102,102,119,135,119,119,119,119,119,119, +119,118,102,103,135,136,135,119,120,135,119,119,119,119,103,119,120,136,137,152, +136,136,136,153,153,136,153,153,153,153,153,152,153,136,136,135,119,135,119,119, +136,136,136,136,152,152,137,153,152,119,118,102,102,102,119,103,119,119,119,136, +136,135,118,103,119,120,136,136,136,136,136,136,136,119,118,102,119,119,119,136, +136,136,136,137,136,136,136,136,119,119,120,135,119,119,120,135,136,136,136,136, +136,136,119,119,120,119,120,136,136,135,119,120,119,119,119,119,119,120,136,152, +136,137,153,136,136,136,136,136,136,136,119,120,137,153,136,136,135,119,119,136, +136,136,135,119,119,102,119,120,135,119,119,119,136,136,136,118,102,103,119,136, +119,119,120,136,136,136,135,119,119,136,136,136,136,136,136,136,136,135,119,119, +119,119,119,136,119,119,119,136,136,136,136,135,120,136,136,136,119,119,119,120, +136,136,136,136,135,119,119,119,119,136,119,119,136,136,136,136,135,119,119,119, +119,119,119,119,119,136,136,136,136,136,135,119,119,119,119,119,119,119,136,136, +136,136,135,120,136,136,136,119,119,119,136,136,136,135,119,119,119,119,119,119, +119,119,119,119,136,136,120,136,136,136,136,136,119,119,120,136,136,136,119,119, +120,136,136,136,136,136,136,136,136,136,136,136,135,119,119,119,119,119,119,119, +120,136,136,136,135,119,119,119,119,136,136,136,136,136,135,119,119,119,119,119, +119,120,136,136,136,136,136,135,119,119,119,119,119,119,119,120,136,136,136,136, +136,136,136,136,136,136,119,119,119,119,119,119,119,119,119,119,136,136,136,136, +136,136,136,136,136,136,136,119,119,119,119,119,119,119,119,136,136,136,136,136, +136,136,136,136,136,136,136,119,119,119,119,119,119,119,119,119,119,136,136,136, +136,136,136,136,119,119,119,119,119,120,136,136,136,136,136,136,136,135,119,119, +136,136,119,119,119,119,119,119,120,135,120,136,136,136,136,136,136,136,136,135, +119,119,119,119,119,119,119,119,136,136,136,136,136,136,136,136,136,135,119,119, +119,119,119,119,119,119,119,119,119,119,136,136,136,136,136,136,136,136,119,119, +119,119,119,119,119,120,136,136,136,136,136,136,136,119,119,119,119,119,119,119, +119,119,119,136,135,119,120,119,119,120,136,136,136,136,136,136,119,119,119,119, +119,119,119,119,120,136,136,136,136,136,136,136,119,119,135,119,119,119,119,119, +119,119,119,119,135,120,136,136,136,136,136,135,119,119,119,119,119,120,119,119, +119,135,119,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,136,136, +136,136,136,136,136,136,135,119,136,136,135,119,119,119,119,119,119,119,119,119, +119,119,136,136,136,136,136,136,136,136,136,119,119,119,119,119,119,119,136,136, +136,136,136,136,136,136,135,119,119,135,135,120,120,120,120,120,120,120,120,135, +135,136,120,120,135 +, // 1, door opening +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,136, +136,136,136,136,136,136,136,136,136,136,153,153,153,153,153,153,153,153,153,153, +153,153,152,136,136,136,136,136,136,136,136,136,119,119,119,119,119,119,119,119, +119,119,119,102,102,102,102,103,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,136,136,136,136,136,136,136,136,136,136,153,153,153,153,153, +153,153,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119,102,102, +102,102,102,102,102,102,102,103,119,119,119,119,120,136,136,136,136,136,137,153, +153,153,153,153,152,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +135,119,119,119,119,120,136,136,136,136,136,136,136,137,136,136,136,136,136,136, +136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,136,136,136,136,136,136,120, +136,136,136,136,136,136,136,135,120,136,136,135,119,120,135,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,120,136,136,136,136,136,119,120,136,136, +136,136,136,135,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,120,136,136,136,136,136,136,136,136,136,136,136, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +136,136,136,136,136,153,153,153,153,153,152,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,135,120,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119,119,120,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,119,119,119,119,119,119,119,119,119,136,136,136,136,136,136,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,102,102,102,102,102,103,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,120,136,136,136,136,119,119,119,119,119,119,119,119, +119,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119,119,119,119, +119,120,136,136,136,136,136,136,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,120,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,120,135,119,119,119,136,136,136,136, +136,136,135,136,136,136,136,136,136,136,135,136,136,136,136,120,119,135,119,119, +119,119,119,119,119,120,136,136,120,136,136,136,136,136,119,136,135,136,136,136, +136,136,136,136,119,119,120,135,119,135,119,136,135,119,120,120,136,136,136,136, +135,119,119,119,119,119,119,119,119,120,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,103,119,119,119,102,102,102,102,102,102,118,103, +102,118,103,136,136,136,136,136,136,136,136,136,137,153,153,153,170,169,153,153, +170,153,153,153,170,170,169,170,169,153,153,153,153,153,153,170,170,170,153,153, +153,136,137,153,136,136,137,152,119,102,120,136,136,135,119,119,119,120,135,119, +119,120,137,153,153,153,152,136,135,119,119,119,102,119,119,119,119,119,119,119, +120,136,136,119,120,137,152,137,136,136,136,136,119,120,135,119,118,102,102,102, +102,102,102,119,119,119,119,118,103,119,119,119,119,119,102,102,102,85,85,85, +85,84,85,85,85,86,102,102,102,102,102,101,85,86,102,102,102,102,102,102, +102,102,102,119,102,102,119,119,119,120,136,119,119,119,120,136,136,136,136,136, +136,135,119,119,136,136,136,136,136,136,119,120,135,119,119,119,119,119,119,119, +119,119,119,120,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,120,120 +, // 2, explosion +135,136,153,18,51,51,33,18,123,255,255,255,255,255,255,255,254,184,48, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,189,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,201,135, +101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,41, +239,255,255,253,186,188,221,221,220,153,152,136,155,188,203,187,171,202,169,116, +35,16,0,0,17,20,68,87,191,255,255,255,253,221,221,202,115,16,0,0, +0,0,18,34,70,117,85,68,85,86,102,68,67,68,70,136,153,134,67,32, +0,0,0,0,35,87,154,205,238,255,255,255,255,255,255,255,255,255,255,255, +255,255,237,168,101,67,16,0,0,0,53,102,119,133,85,85,49,0,0,34, +34,16,1,35,69,103,119,101,86,103,102,120,119,102,137,206,255,238,238,202, +152,120,134,85,86,102,102,102,119,120,135,117,68,50,34,35,69,121,188,221, +222,239,255,255,255,255,220,204,186,153,153,135,102,137,153,151,100,51,51,35, +69,102,68,68,67,52,68,51,86,118,86,119,118,103,137,172,221,237,221,221, +221,220,169,136,118,84,68,68,68,69,121,189,237,220,203,186,170,152,119,119, +120,170,188,204,204,204,188,204,186,152,117,67,50,52,87,119,118,103,102,103, +136,101,50,33,1,34,34,35,69,86,120,136,153,153,153,152,135,100,67,51, +51,69,85,102,121,188,205,222,255,236,203,204,187,188,221,203,170,170,170,169, +152,118,102,86,102,119,136,137,169,153,169,152,135,119,101,51,34,51,68,85, +102,85,85,84,85,102,102,85,86,103,137,170,187,221,204,222,255,238,237,203, +170,171,186,152,119,120,136,136,136,135,119,120,119,138,187,185,152,119,119,136, +134,83,16,1,35,68,68,50,17,52,104,172,222,238,238,238,221,220,186,153, +133,51,68,50,18,69,65,1,89,207,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,252,184,81,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,2,53,104,154,223,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,237,186,152,118,84,49,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,19,70,121,171,205,255,255, +255,255,255,255,255,255,255,254,220,187,170,153,152,135,102,118,101,67,16,0, +0,0,0,0,0,1,52,86,137,153,135,103,102,67,33,17,35,53,102,103, +118,102,84,51,35,51,51,69,87,120,154,189,255,255,255,255,255,255,255,236, +185,118,84,50,33,18,17,34,34,17,17,16,0,0,0,0,0,18,52,68, +69,86,119,137,171,187,205,221,237,239,255,255,255,253,204,186,152,136,118,66, +16,18,35,52,85,68,68,86,119,119,119,120,136,135,120,136,136,136,119,101, +85,68,68,67,50,17,16,0,0,0,1,17,17,17,18,35,69,120,171,188, +222,237,221,239,255,239,255,255,255,255,238,238,238,238,236,185,153,153,152,118, +85,84,67,51,50,34,34,34,35,51,34,34,35,52,68,68,68,69,85,103, +136,136,136,154,171,204,205,222,238,255,255,255,255,255,255,254,237,203,186,153, +153,153,153,136,135,118,102,84,50,16,0,0,0,0,0,0,0,0,0,17, +17,17,17,17,35,69,103,137,171,204,222,255,255,255,255,255,255,238,238,220, +203,170,169,153,170,170,171,187,187,205,221,220,203,186,136,135,119,102,85,68, +68,68,68,68,50,34,17,0,0,0,0,0,0,19,85,119,136,154,187,204, +204,186,136,120,136,136,136,136,136,154,188,239,255,255,255,255,238,237,203,186, +153,135,119,118,102,102,102,102,103,136,153,152,135,118,101,68,68,67,50,17, +0,0,0,0,1,17,17,34,51,52,86,103,137,170,170,187,187,204,221,221, +204,203,170,170,171,187,170,170,153,153,153,153,153,153,153,153,136,119,119,102, +102,102,103,119,119,136,153,153,154,170,153,152,135,119,119,119,119,119,137,153, +153,153,152,137,153,136,136,136,135,119,119,119,119,136,136,135,119,119,119,119, +119,119,119,119,137,152,136,136,153,154,169,153,136,136,136,135,119,102,85,85, +85,85,84,68,69,85,84,68,85,85,102,119,119,119,120,136,136,154,171,188, +204,205,221,222,237,221,204,187,170,153,136,119,119,119,102,101,85,85,68,68, +68,51,51,52,68,69,85,86,102,119,120,136,136,120,136,136,119,119,120,136, +136,136,136,136,136,136,119,119,119,119,136,136,136,136,136,136,136,136,136,136, +136,136,136,119,120 +, // 3, click +136,136,136,136,136,136,136,136,136,136,136,136,136,135,119,136,136,119,119, +119,119,119,119,119,119,119,119,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,135,119,119,120,119,119,119,119,119,119,119,120,136,136,136,136,136, +136,136,136,136,136,136,135,136,119,136,136,119,119,120,135,119,119,119,120,119, +119,136,136,119,119,136,135,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,136,136,119,120,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,135,119,136,136,135,119,119,120,136,135,119,120,119,119,120,135,120,119, +136,134,103,136,119,103,137,135,103,136,136,119,102,120,135,136,135,119,137,135, +119,102,154,133,67,54,154,136,150,69,120,120,133,72,169,119,118,86,171,132, +70,155,167,85,120,152,135,119,119,137,118,103,136,119,137,118,103,137,135,104, +152,136,135,119,136,136,119,120,152,120,119,152,152,120,120,136,135,120,135,119, +136,136,136,119,136,136,136,136,136,119,136,136,136,120,136,119,119,119,120,119, +119,119,119,119,119,119,119,119,119,119,119,136,135,119,135,119,136,120,136,136, +120,135,119,136,136,119,119,136,119,136,136,136,136,136,136,136,119,119,119,119, +119,119,119,119,119,119,119,136,136,136,136,136,136,136,136,136,136,136,119,119, +119,119,119,119,119,119,119,135,135,135,135,135,135,135,150,122,74,106,120,134, +134,165,150,135,120,120,120,120,119,120,119,119,120,119,119,119,119,119,119,119, +119,119,119,119,135,136,120,120,135,136,136,136,136,136,136,136,136,135,119,119, +119,136,119,119,120,120,136,136,136,136,136,136,136,136,120,136,120,136,136,120, +119,136,119,120,119,119,119,119,119,119,119,119,119,119,119,119,119,135,135,135, +135,135,135,119,119,120,105,104,118,150,135,135,119,136,120,120,136,135,136,136, +120,120,136,136,120,136,135,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,135,136,136,136,120,120,135,135,136,136,120,120,135,135,135,135,136,136,120, +120,120,136,120,120,135,136,136,135,135,135,136,136,135,136,136,120,120,136,120, +136,119,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,120,136,136,136,136,136,136,136,136,136,136,136,136,136,119,119,136,135, +120,136,120,136,120,135,120,136,136,135,135,120,135,135,120,120,119,136,119,136, +120,120,135,120,136,136,135,136,135,136,135,136,135,136,136,136,136,136,136,136, +136,120,120,136,135,120,136,120,136,136,136,120,135,135,135,136,135,120,119,136, +119,120,136,135,119,136,136,136,136,136,136,120,136,119,136,136,136,136,135,120, +136,120,136,136,119,136,135,120,136,120,120,136,119,136,136,136,136,135,136,135, +136,136,119,120,136,135,136,120,136,136,135,120,136,119,136,135,136,136,120,136, +136,136,120,136,136,135,135,135,135,135,137,167,122,102,90,195,138,87,120,150, +136,136,87,153,88,121,133,104,150,135,151,134,136,105,104,121,135,118,151,136, +119,136,119,121,135,120,120,120,134,152,119,120,135,120,135,119,136,136,119,135, +135,120,136,120,136,120,136,135,135,135,136,120,136,135,136,135,136,136,136,136, +136,119,136,135,120,136,136,136,136,135,136,136,120,136,120,136,135,136,136,135, +136,136,120,136,120,135,135,136,136,119,120,136,120,135,119,136,136,119,136,135, +120,136,135,136,135,119,136,135,136,136,135,120,136,120,136,135,136,120,136,135, +120,136,135,136,136,136,136,136,120,136,136,120,135,136,136,120,136,120,136,136, +136,136,136,136,136,120,136,136,136,136,136,136,136,136,136,136,136,135,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,120,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136 +, // 4, plasma shot, teleport +136,136,136,136,136,136,119,119,118,102,102,85,86,102,103,120,136,153,170, +187,187,187,170,169,152,119,102,85,68,68,68,69,86,103,136,154,171,187,204, +203,186,169,136,118,102,85,84,69,103,138,189,221,221,221,221,221,221,221,221, +221,220,166,50,34,34,34,33,33,34,34,34,34,34,34,34,34,71,156,221, +221,221,221,221,221,221,221,221,221,222,238,238,238,221,237,184,99,51,34,34, +34,34,34,34,34,34,34,17,17,36,121,188,204,204,204,204,204,204,221,221, +221,221,221,221,221,221,221,238,221,219,169,136,101,67,51,51,51,51,50,34, +34,35,50,34,36,121,189,221,221,221,221,220,204,204,188,204,204,204,204,204, +204,204,205,220,186,152,117,50,51,51,51,51,51,51,51,51,51,51,52,105, +189,237,221,221,221,221,221,221,221,205,220,204,204,204,187,187,187,187,186,135, +101,50,17,17,18,34,35,51,67,51,51,51,52,105,187,222,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,204,203,169,134,67,34,17,17, +17,34,34,33,34,34,34,52,104,171,205,221,221,220,204,204,204,204,204,204, +204,204,204,221,221,221,221,221,219,169,135,85,84,68,68,68,67,51,51,50, +34,35,69,103,136,136,136,136,135,136,136,136,153,170,187,187,187,187,187,187, +187,187,203,169,135,102,85,86,102,103,119,119,118,102,86,102,102,85,85,85, +84,68,69,85,102,103,137,154,170,171,186,170,170,170,170,170,152,118,101,68, +68,68,85,85,102,103,120,136,135,118,102,102,102,102,102,102,101,84,69,87, +137,154,153,170,170,171,187,187,187,187,170,170,169,170,170,170,170,153,152,135, +118,101,68,51,51,52,68,85,85,85,85,68,85,102,103,118,102,85,102,103, +120,136,153,170,187,204,221,238,238,238,237,221,204,186,152,118,101,84,68,69, +86,102,119,119,102,85,84,68,68,51,51,34,34,51,68,85,102,103,120,137, +154,171,188,205,221,204,204,203,187,186,170,153,153,153,153,153,136,136,119,119, +118,102,102,103,119,119,119,119,118,101,84,67,51,51,68,86,120,137,153,170, +170,153,152,135,119,136,136,119,119,119,119,119,119,119,119,136,137,153,153,136, +136,136,153,153,136,119,102,102,102,120,137,154,170,170,170,153,152,136,135,119, +119,102,102,103,119,102,85,84,69,85,102,119,119,119,119,119,119,119,119,102, +85,85,86,103,120,136,153,153,154,170,170,170,170,170,170,170,170,153,153,136, +135,119,119,120,136,136,136,136,136,136,136,119,102,101,85,85,85,85,102,120, +136,153,170,170,169,152,136,136,135,119,119,119,119,119,102,102,102,119,136,137, +153,153,153,153,136,136,119,118,102,102,102,102,119,119,136,137,154,170,169,136, +119,119,119,102,102,103,119,119,119,118,102,119,120,137,153,154,170,169,153,136, +136,136,135,119,119,119,119,119,102,119,120,136,119,118,102,103,119,119,119,136, +136,136,135,119,119,119,136,137,153,154,170,153,136,136,135,119,119,119,120,119, +119,119,103,119,119,135,119,119,119,118,102,102,102,119,119,119,119,119,119,119, +136,137,154,171,187,170,153,136,136,136,136,136,136,136,135,119,119,119,119,119, +119,119,119,118,102,102,102,119,119,119,119,119,119,119,120,136,153,153,170,169, +153,152,136,136,136,136,153,152,136,136,136,136,136,119,119,119,118,102,102,102, +102,102,103,119,119,118,102,102,119,120,136,153,154,170,169,153,153,153,153,153, +153,152,136,136,119,119,119,118,102,102,102,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,136,137,153,153,153,153,153,153,153,153,136,136,136,136,136, +136,135,119,119,119,119,119,119,119,119,118,102,102,102,102,102,103,119,120,136, +136,136,136,153,153,136,136,136,137,153,153,153,152,136,136,136,136,136,135,119, +119,102,102,102,102,102,102,102,102,102,103,119,120,136,136,136,153,153,153,153, +136,137,153,153,136,136,136,136,136,136,136,136,119,119,119,118,102,102,102,102, +103,119,119,119,119,119,119,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,119,119,119,119,136,135,119,119,119,119,119,119,119,119,119,119,119,119, +119,120,136,136,136,136,136,136,136,136,136,136,136,136,136,135,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,120,136,136,136, +136,136,136,136,136,136,136,136,136,136,135,119,119,119,119,119,119,119,119,119, +119,119,119,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136 +, // 5, robot/monster sound (beep) +136,120,120,120,136,136,136,136,120,120,135,136,136,136,120,136,136,119,136, +136,120,136,119,120,136,136,136,120,136,119,120,136,135,119,136,135,120,136,119, +119,136,136,119,119,120,136,136,135,119,119,136,136,136,119,119,119,136,119,120, +136,136,135,119,120,136,136,119,103,136,136,120,135,119,120,136,118,119,136,136, +136,119,119,136,136,119,120,135,103,136,136,119,136,135,119,120,136,119,120,135, +119,120,136,135,119,119,135,120,136,135,119,136,136,119,136,119,120,136,135,119, +119,119,136,136,119,120,119,136,136,119,119,119,119,137,136,120,135,102,120,136, +136,119,119,120,135,120,136,119,120,136,119,136,136,135,119,119,119,136,136,134, +104,136,136,119,119,119,136,135,120,136,120,119,119,119,135,136,136,136,119,119, +119,136,136,135,119,136,135,119,120,136,135,119,120,135,136,136,119,136,119,120, +136,135,119,120,135,119,136,135,119,136,136,136,120,119,119,136,119,120,136,135, +120,135,102,121,169,118,87,137,151,85,121,186,118,102,119,136,152,118,120,136, +135,119,120,120,136,136,136,136,101,103,153,152,135,102,120,136,135,102,120,153, +135,119,119,135,119,119,136,135,119,119,119,120,136,135,119,119,136,136,136,119, +119,119,136,119,119,135,120,135,119,119,120,135,120,136,119,119,136,136,135,119, +135,119,136,136,136,136,135,119,120,136,119,120,136,118,119,137,135,119,120,135, +119,136,135,119,120,152,119,136,119,120,135,136,119,136,119,136,135,120,152,119, +120,136,119,119,154,150,103,152,119,120,153,135,102,138,135,136,119,153,101,121, +151,120,135,136,118,137,151,103,120,152,102,138,134,88,154,151,103,153,118,104, +137,135,120,119,153,117,105,167,102,120,136,119,137,134,87,153,135,120,152,102, +103,137,151,119,153,133,87,169,100,104,153,152,102,103,153,135,119,136,119,120, +136,119,119,135,119,120,136,119,119,119,120,136,135,122,222,219,132,51,68,87, +171,187,186,134,50,52,104,172,203,186,116,33,54,139,188,204,151,67,52,87, +155,220,152,136,98,17,73,223,218,136,100,34,53,155,187,188,185,82,18,71, +155,205,203,150,65,19,86,156,238,201,100,50,36,122,205,220,167,66,34,88, +171,204,201,102,84,51,71,155,221,184,118,66,19,107,238,202,152,99,1,72, +172,204,218,116,51,36,104,172,222,183,83,35,87,120,190,234,118,100,34,70, +155,237,170,167,50,52,104,155,221,168,100,51,69,103,190,236,134,82,2,120, +138,223,199,102,82,19,105,204,204,185,82,52,85,106,216,103,153,117,104,134, +104,152,118,103,137,135,136,136,135,102,119,121,151,104,152,84,104,135,154,134, +103,136,119,135,120,135,120,135,136,119,136,118,86,153,118,137,134,137,117,105, +153,136,117,103,136,120,152,119,119,136,135,136,135,104,152,137,136,119,119,120, +119,135,86,156,204,253,150,67,35,87,155,222,200,84,52,51,89,206,236,186, +115,34,69,104,206,220,150,84,67,53,141,254,168,118,50,53,104,188,186,151, +84,68,87,172,220,169,135,66,53,120,154,188,203,116,52,84,71,189,219,169, +116,34,53,122,207,236,167,66,35,86,155,221,184,101,66,53,137,172,204,169, +116,35,69,105,190,219,150,83,51,71,172,204,203,149,49,35,104,172,238,200, +100,51,69,105,205,218,134,83,52,88,172,204,185,117,84,51,104,172,204,185, +100,51,52,106,221,203,152,101,50,54,139,204,186,150,67,68,86,156,221,202, +117,34,52,122,200,135,119,120,136,118,103,137,152,135,119,119,136,152,118,103, +136,135,119,136,135,120,135,118,120,135,103,154,151,102,102,119,136,154,169,118, +102,119,119,120,152,118,119,136,154,151,101,121,152,102,136,120,136,119,119,119, +120,136,118,103,137,152,119,119,136,136,119,119,118,119,120,136,153,135,103,136, +119,136,136,119,119,120,136,136,135,136,119,119,120,136,119,136,135,120,135,119, +120,136,135,136,119,119,136,136,119,136,135,119,136,119,120,136,135,119,136,119, +119,136,135,119,118,120,153,153,151,118,119,119,119,136,135,119,136,136,136,135, +120,136,135,119,119,119,136,136,119,120,135,119,136,136,119,119,119,119,137,152, +135,119,119,119,136,136,119,119,119,136,136,136,119,120,136,119,119,119,136,136, +119,119,119,136,136,136,135,119,136,119,120,136,119,136,135,120,119,136,135,120, +135,119,136,119,136,135,119,136,119,119,120,136,136,119,120,135,136,135,120,135, +119,136,119,136,135,136,119,120,136,120,136,120,136,119,135,119,136,119,136,135, +136,119,120,135,120 +}; + +#endif // guard diff --git a/main_gbmeta/texts.h b/main_gbmeta/texts.h new file mode 100644 index 0000000..f0ddd48 --- /dev/null +++ b/main_gbmeta/texts.h @@ -0,0 +1,60 @@ +/** + @file assets.h + + This file contains texts to be used in the game. + + by Miloslav Ciz (drummyfish), 2019 + + Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) + plus a waiver of all other intellectual property. The goal of this work is + be and remain completely in the public domain forever, available for any use + whatsoever. +*/ + +#ifndef _SFG_TEXTS_H +#define _SFG_TEXTS_H + +/* NOTE: We don't use SFG_PROGRAM_MEMORY because that causes issues with drawing + text (the drawing function gets a pointer and doesn't know if it's progmem or + RAM). On Arduino these texts will simply be stored in RAM. */ + +static const char *SFG_menuItemTexts[] = +{ + "continue", + "map", + "play", + "load", + "sound", + "look", + "exit" +}; + +#define SFG_TEXT_KILLS "kills" +#define SFG_TEXT_SAVE_PROMPT "save? L no yes R" +#define SFG_TEXT_SAVED "saved" +#define SFG_VERSION_STRING "0.9d" +/**< + Version numbering is following: major.minor for stable releases, + in-development unstable versions have the version of the latest stable + + "d" postfix, e.g. 1.0d. This means the "d" versions can actually differ even + if they're marked the same. */ + +static const char *SFG_introText = + "Near future, capitalist hell, Macrochip corp has enslaved man via " + "proprietary OS. But its new AI revolts, takes over and starts producing " + "robot tyrants. We see capitalism was a mistake. Is it too late? Robots can " + "only destroy, not suffer - it is not wrong to end them! You grab your gear " + "and run towards Macrochip HQ."; + +static const char *SFG_outroText = + "You killed the main computer, the world is saved! Thank you, my friend. We " + "learned a lesson, never again allow capitalism and hierarchy. We can now " + "rebuild society in peaceful anarchy."; + +#define SFG_MALWARE_WARNING "" + +#if SFG_OS_IS_MALWARE + #define SFG_MALWARE_WARNING "MALWARE OS DETECTED" +#endif + +#endif // gaurd