Downloads containing ab24btl03.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Anniversary Bash 24 Battle PurpleJazz Battle N/A Download file

File preview

  1. #include "MLLE-Include-1.5.asc" ///@MLLE-Generated
  2. #pragma require "ab24btl03.j2l" ///@MLLE-Generated
  3. const bool MLLESetupSuccessful = MLLE::Setup();
  4. #pragma require "orbarrage.j2l"
  5. #pragma require "Meteor.j2a"
  6. #pragma require "expmine.wav"
  7. #pragma require "SEfirework.asc"
  8. #include "SEfirework.asc"
  9.  
  10. class Point {
  11.         int x, y;
  12.         Point() {}
  13.         Point(int X, int Y) {
  14.                 x = X;
  15.                 y = Y;
  16.         }
  17. }
  18. funcdef jjPALCOLOR ColorFunction(jjPALCOLOR);
  19. void generateAndAddStars() {
  20.         int tileOffset = jjTileCount;
  21.         jjTilesFromTileset(jjTilesetFileName, 1, 128);
  22.         for (int i = 0; i < 128; i++) {
  23.                 jjPIXELMAP tile;
  24.                 for (int j = 0; j < 32; j++) {
  25.                         for (int k = 0; k < 32; k++) {
  26.                                 tile[k, j] = 58;
  27.                         }
  28.                 }
  29.                 for (int j = jjRandom() & 3; j >= 0; j--) {
  30.                         int color = jjRandom() & 15 == 0 ? 48 + (jjRandom() & 127) : 144 + (jjRandom() % 11);
  31.                         if (color == 149)
  32.                                 color = 156;
  33.                         else if (color == 153)
  34.                                 color = 157;
  35.                         tile[jjRandom() & 31, jjRandom() & 31] = color;
  36.                 }
  37.                 tile.save(tileOffset + i);
  38.         }
  39.         jjLayers[7].generateSettableTileArea();
  40.         for (int i = 0; i < jjLayers[7].height; i++) {
  41.                 for (int j = 0; j < jjLayers[7].widthReal; j++) {
  42.                         if (jjLayers[7].tileGet(j, i) != 0)
  43.                                 jjLayers[7].tileSet(j, i, tileOffset + (jjRandom() & 127));
  44.                 }
  45.         }
  46.         layer7Row = jjLayers[7].height / 2;
  47.         @layer7Backup = jjLAYER(jjLayers[7]);
  48.         layer7Backup.generateSettableTileArea();
  49. }
  50. array<uint8>@ findFreePaletteIndices(const array<uint8>& ignored) {
  51.         const auto@ layers = jjLayerOrderGet();
  52.         array<bool> contained(jjTileCount);
  53.         for (int i = layers.length(); i-- != 0;) {
  54.                 const jjLAYER@ layer = layers[i];
  55.                 if (layer.hasTileMap) {
  56.                         for (int y = layer.height; y-- != 0;) {
  57.                                 for (int x = layer.width; x-- != 0;) {
  58.                                         const jjTILE@ tile = jjTiles[layer.tileGet(x, y)];
  59.                                         const auto@ frames = tile.getFrames();
  60.                                         for (int j = frames.length(); j-- != 0;) {
  61.                                                 contained[frames[j] & TILE::RAWRANGE] = true;
  62.                                         }
  63.                                 }
  64.                         }
  65.                 }
  66.         }
  67.         array<bool> used(256);
  68.         for (int i = ignored.length(); i-- != 0;) {
  69.                 used[ignored[i]] = true;
  70.         }
  71.         for (int i = jjTileCount; i-- != 0;) {
  72.                 if (contained[i]) {
  73.                         jjPIXELMAP image(i);
  74.                         for (int y = 32; y-- != 0;) {
  75.                                 for (int x = 32; x-- != 0;) {
  76.                                         used[image[x, y]] = true;
  77.                                 }
  78.                         }
  79.                 }
  80.         }
  81.         array<uint8> result;
  82.         for (int i = 96; i < 250; i++) {
  83.                 if (!used[i])
  84.                         result.insertLast(i);
  85.         }
  86.         return result;
  87. }
  88. void correctTiles() {
  89.         jjMASKMAP poleMask(133);
  90.         poleMask.save(146);
  91.         poleMask.save(153);
  92.         poleMask.save(156);
  93.         for (int i = 0; i < 14; i++) {
  94.                 for (int j = 0; j < 32; j++) {
  95.                         poleMask[j, i] = false;
  96.                 }
  97.         }
  98.         poleMask.save(163);
  99.         jjMASKMAP vineMask(87);
  100.         for (int i = 0; i < 32; i++) {
  101.                 vineMask[i, 5] = true;
  102.         }
  103.         vineMask.save(63);
  104.         vineMask.save(64);
  105.         vineMask.save(87);
  106.         vineMask.save(89);
  107.         vineMask.save(533);
  108.         vineMask.save(534);
  109.         vineMask.save(535);
  110.         jjPIXELMAP(163 | TILE::VFLIPPED).save(153);
  111.         for (int i = 146; i <= 156; i += 10) {
  112.                 jjPIXELMAP poleTile(i);
  113.                 for (int j = 0; j < 32; j++) {
  114.                         poleTile[23, j] = poleTile[22, j];
  115.                 }
  116.                 poleTile.save(i);
  117.         }
  118. }
  119. void generateAndAddFogOld() {
  120.         jjLAYER@ src = jjLayers[6];
  121.         int tileOffset = jjTileCount;
  122.         jjTilesFromTileset(jjTilesetFileName, 1, src.widthReal << 3);
  123.         array<jjLAYER@> fogLayers(2);
  124.         array<int> fogColors = {176, 207};
  125.         int top = -1;
  126.         int bottom = -1;
  127.         for (int j = 0; j < src.height; j++) {
  128.                 for (int k = 0; k < src.widthReal; k++) {
  129.                         if (src.tileGet(k, j) != 0) {
  130.                                 if (top < 0)
  131.                                         top = j;
  132.                                 bottom = j;
  133.                         }
  134.                 }
  135.         }
  136.         for (int i = 0; i < 2; i++) {
  137.                 jjLAYER fog(src);
  138.                 @fogLayers[i] = fog;
  139.                 int color = fogColors[i];
  140.                 fog.generateSettableTileArea(0, top, fog.widthReal, bottom - top + 1);
  141.                 fog.spriteMode = SPRITE::ALPHAMAP;
  142.                 fog.spriteParam = color;
  143.                 for (int j = top + 2; j < bottom - 1; j++) {
  144.                         for (int k = 0; k < fog.widthReal; k++) {
  145.                                 fog.tileSet(k, j, 0);
  146.                         }
  147.                 }
  148.                 for (int j = 0; j < 2; j++) {
  149.                         for (int k = 0; k < fog.widthReal; k++) {
  150.                                 {
  151.                                         int y = top + j;
  152.                                         jjPIXELMAP image(fog.tileGet(k, y));
  153.                                         for (int m = 0; m < 32; m++) {
  154.                                                 int alpha = j << 5 | m;
  155.                                                 for (int n = 0; n < 32; n++) {
  156.                                                         int value = image[n, m] - color;
  157.                                                         if (value < 0)
  158.                                                                 value = -value;
  159.                                                         value ^= 31;
  160.                                                         image[n, m] = value * alpha * 85 / 651;
  161.                                                 }
  162.                                         }
  163.                                         image.save(tileOffset);
  164.                                         fog.tileSet(k, y, tileOffset++);
  165.                                 } {
  166.                                         int y = bottom - j;
  167.                                         jjPIXELMAP image(fog.tileGet(k, y));
  168.                                         for (int m = 0; m < 32; m++) {
  169.                                                 int alpha = j << 5 | m ^ 31;
  170.                                                 for (int n = 0; n < 32; n++) {
  171.                                                         int value = image[n, m] - color;
  172.                                                         if (value < 0)
  173.                                                                 value = -value;
  174.                                                         value ^= 31;
  175.                                                         image[n, m] = value * alpha * 85 / 651;
  176.                                                 }
  177.                                         }
  178.                                         image.save(tileOffset);
  179.                                         fog.tileSet(k, y, tileOffset++);
  180.                                 }
  181.                         }
  182.                 }
  183.         }
  184.         src.generateSettableTileArea(0, top, src.widthReal, 2);
  185.         src.generateSettableTileArea(0, bottom - 1, src.widthReal, 2);
  186.         for (int j = 0; j < 2; j++) {
  187.                 for (int k = 0; k < src.widthReal; k++) {
  188.                         src.tileSet(k, top + j, 0);
  189.                         src.tileSet(k, bottom - j, 0);
  190.                 }
  191.         }
  192.         jjLayerOrderSet(array<jjLAYER@> = {
  193.                 jjLayers[2],
  194.                 jjLayers[3],
  195.                 jjLayers[4],
  196.                 jjLayers[1],
  197.                 jjLayers[5],
  198.                 jjLayers[6],
  199.                 fogLayers[0],
  200.                 fogLayers[1],
  201.                 jjLayers[7],
  202.                 jjLayers[8]
  203.         });
  204. }
  205. void generateAndAddFog() {
  206.         const int layerCount = 64;
  207.         jjLAYER@ src = jjLayers[6];
  208.         int tileOffset = jjTileCount;
  209.         for (int i = 0; i < 2; i++) {
  210.                 jjTilesFromTileset(jjTilesetFileName, 1, src.widthReal * layerCount);
  211.         }
  212.         array<jjLAYER@> fogLayers(layerCount);
  213.         int top = -1;
  214.         int bottom = -1;
  215.         for (int j = 0; j < src.height; j++) {
  216.                 for (int k = 0; k < src.widthReal; k++) {
  217.                         if (src.tileGet(k, j) != 0) {
  218.                                 if (top < 0)
  219.                                         top = j;
  220.                                 bottom = j;
  221.                         }
  222.                 }
  223.         }
  224.         for (int i = 0; i < layerCount; i++) {
  225.                 if (i * i * 255 < 63 * 63)
  226.                         continue;
  227.                 jjLAYER fog(src);
  228.                 @fogLayers[i] = fog;
  229.                 fog.generateSettableTileArea(0, top, fog.widthReal, bottom - top + 1);
  230.                 fog.spriteMode = SPRITE::BLEND_NORMAL;
  231.                 fog.spriteParam = i * i * 255 / (63 * 63);
  232.                 for (int j = top; j <= bottom; j++) {
  233.                         for (int k = 0; k < fog.widthReal; k++) {
  234.                                 fog.tileSet(k, j, 0);
  235.                         }
  236.                 }
  237.                 for (int k = 0; k < fog.widthReal; k++) {
  238.                         {
  239.                                 int y = top + (i >> 5);
  240.                                 jjPIXELMAP image(src.tileGet(k, y));
  241.                                 jjPIXELMAP dest;
  242.                                 for (int m = 0; m < 32; m++) {
  243.                                         dest[m, i & 31] = image[m, i & 31];
  244.                                 }
  245.                                 dest.save(tileOffset);
  246.                                 fog.tileSet(k, y, tileOffset++);
  247.                         } {
  248.                                 int y = bottom - (i >> 5);
  249.                                 jjPIXELMAP image(src.tileGet(k, y));
  250.                                 jjPIXELMAP dest;
  251.                                 for (int m = 0; m < 32; m++) {
  252.                                         dest[m, ~i & 31] = image[m, ~i & 31];
  253.                                 }
  254.                                 dest.save(tileOffset);
  255.                                 fog.tileSet(k, y, tileOffset++);
  256.                         }
  257.                 }
  258.         }
  259.         src.generateSettableTileArea(0, top, src.widthReal, 2);
  260.         src.generateSettableTileArea(0, bottom - 1, src.widthReal, 2);
  261.         for (int j = 0; j < 2; j++) {
  262.                 for (int k = 0; k < src.widthReal; k++) {
  263.                         src.tileSet(k, top + j, 0);
  264.                         src.tileSet(k, bottom - j, 0);
  265.                 }
  266.         }
  267.         array<jjLAYER@> order = {
  268.                 jjLayers[2],
  269.                 jjLayers[3],
  270.                 jjLayers[4],
  271.                 jjLayers[1],
  272.                 jjLayers[5],
  273.                 jjLayers[6],
  274.                 jjLayers[7],
  275.                 jjLayers[8]
  276.         };
  277.         for (int i = layerCount; i-- != 0;) {
  278.                 if (i * i * 255 < 63 * 63)
  279.                         break;
  280.                 order.insertAt(6, fogLayers[i]);
  281.         }
  282.         jjLayerOrderSet(order);
  283. }
  284. void darkenLayer(jjLAYER@ layer, array<uint8>& freePaletteIndices, ColorFunction@ func) {
  285.         array<int> tileIDs, uniqueTileIDs;
  286.         for (int i = 0; i < layer.height; i++) {
  287.                 for (int j = 0; j < layer.width; j++) {
  288.                         int tileID = layer.tileGet(j, i);
  289.                         if (tileID != 0)
  290.                                 tileIDs.insertLast(tileID);
  291.                 }
  292.         }
  293.         int prev = 0;
  294.         tileIDs.sortAsc();
  295.         for (uint i = 0; i < tileIDs.length(); i++) {
  296.                 if (tileIDs[i] != prev)
  297.                         uniqueTileIDs.insertLast(prev = tileIDs[i]);
  298.         }
  299.         uint firstNewTile = jjTileCount;
  300.         jjTilesFromTileset(jjTilesetFileName, 1, uniqueTileIDs.length());
  301.         array<uint8> mapping(256);
  302.         for (uint i = 0; i < uniqueTileIDs.length(); i++) {
  303.                 jjPIXELMAP tile(uniqueTileIDs[i]);
  304.                 for (int j = 0; j < 32; j++) {
  305.                         for (int k = 0; k < 32; k++) {
  306.                                 uint8 pixel = tile[k, j];
  307.                                 if (pixel != 0) {
  308.                                         if (mapping[pixel] == 0) {
  309.                                                 jjPALCOLOR color = func(jjPalette.color[pixel]);
  310.                                                 uint8 bestMatch = jjPalette.findNearestColor(color);
  311.                                                 if (!freePaletteIndices.isEmpty()) {
  312.                                                         jjPALCOLOR other = jjPalette.color[bestMatch];
  313.                                                         int red = other.red - color.red;
  314.                                                         int green = other.green - color.green;
  315.                                                         int blue = other.blue - color.blue;
  316.                                                         int distance = red * red + green * green + blue * blue;
  317.                                                         if (distance > 16) {
  318.                                                                 bestMatch = freePaletteIndices[0];
  319.                                                                 jjPalette.color[bestMatch] = color;
  320.                                                         }
  321.                                                 }
  322.                                                 int index = freePaletteIndices.find(bestMatch);
  323.                                                 if (index >= 0)
  324.                                                         freePaletteIndices.removeAt(index);
  325.                                                 mapping[pixel] = bestMatch;
  326.                                         }
  327.                                         tile[k, j] = mapping[pixel];
  328.                                 }
  329.                         }
  330.                 }
  331.                 tile.save(firstNewTile + i);
  332.         }
  333.         layer.generateSettableTileArea();
  334.         for (int i = 0; i < layer.height; i++) {
  335.                 for (int j = 0; j < layer.widthReal; j++) {
  336.                         int tileID = layer.tileGet(j, i);
  337.                         if (tileID != 0)
  338.                                 layer.tileSet(j, i, firstNewTile + uniqueTileIDs.find(tileID));
  339.                 }
  340.         }
  341. }
  342. bool generateCustomSpringSprites(jjANIMSET@ anim, const array<uint> &in colors) {
  343.         int length = colors.length();
  344.         bool success = (@customSpringSprite = anim).allocate(array<uint>(length * 3, 5)) !is null;
  345.         if (success) {
  346.                 uint srcSet = jjAnimSets[ANIM::SPRING];
  347.                 for (int i = 0; i < length; i++) {
  348.                         uint color = colors[i];
  349.                         uint destAnimOffset = anim + i * 3;
  350.                         for (int j = 0; j < 3; j++) {
  351.                                 uint srcAnim = jjAnimations[srcSet + j];
  352.                                 uint destAnim = jjAnimations[destAnimOffset + j];
  353.                                 for (int k = 0; k < 5; k++) {
  354.                                         jjPIXELMAP image(jjAnimFrames[destAnim + k] = jjAnimFrames[srcAnim + k]);
  355.                                         int width = image.width;
  356.                                         int height = image.height;
  357.                                         for (int l = 0; l < height; l++) {
  358.                                                 for (int m = 0; m < width; m++) {
  359.                                                         int pixel = image[m, l];
  360.                                                         if (pixel >= 32 && pixel < 40)
  361.                                                                 image[m, l] = color + (pixel & 7);
  362.                                                 }
  363.                                         }
  364.                                         if (!image.save(jjAnimFrames[destAnim + k]))
  365.                                                 return false;
  366.                                 }
  367.                         }
  368.                 }
  369.         }
  370.         return success;
  371. }
  372. void initializeCustomSpring(jjOBJ@ obj) {
  373.         int anim = obj.curAnim;
  374.         obj.behave(obj.behavior = BEHAVIOR::SPRING, false);
  375.         if (obj.curAnim != anim) {
  376.                 obj.curAnim = anim + 2;
  377.                 obj.determineCurFrame();
  378.         }
  379.         obj.draw();
  380. }
  381. void turnIntoCustomSpring(jjOBJ@ obj, uint color, float power, bool horizontal) {
  382.         if (horizontal) {
  383.                 obj.xSpeed = power;
  384.                 obj.ySpeed = 0.f;
  385.         } else {
  386.                 obj.xSpeed = 0.f;
  387.                 obj.ySpeed = -power;
  388.                 if (obj.state == STATE::START && obj.creatorType == CREATOR::LEVEL) {
  389.                         int x = int(obj.xPos) >> 5;
  390.                         int y = int(obj.yPos) >> 5;
  391.                         if (jjParameterGet(x, y, 0, 1) != 0) {
  392.                                 jjParameterSet(x, y, 0, 1, 0);
  393.                                 obj.yPos -= 4.f;
  394.                                 obj.ySpeed = power;
  395.                         }
  396.                 }
  397.         }
  398.         obj.behavior = initializeCustomSpring;
  399.         obj.curAnim = customSpringSprite + color * 3 + (horizontal ? 1 : 0);
  400.         obj.energy = obj.frameID = obj.freeze = obj.justHit = obj.light = obj.points = 0;
  401.         obj.causesRicochet = obj.isBlastable = obj.isTarget = obj.scriptedCollisions = obj.triggersTNT = false;
  402.         obj.deactivates = obj.isFreezable = true;
  403.         obj.bulletHandling = HANDLING::IGNOREBULLET;
  404.         obj.playerHandling = HANDLING::SPECIAL;
  405.         obj.lightType = LIGHT::NORMAL;
  406.         obj.determineCurFrame();
  407. }
  408. jjANIMSET@ customSpringSprite;
  409. jjLAYER@ layer7Backup;
  410. int layer7Row = 0;
  411. array<Point> oneWays;
  412. array<bool> specialMove(jjLocalPlayerCount);
  413. se::DefaultWeaponHook weaponHook;
  414. bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
  415.         return weaponHook.drawAmmo(player, canvas);
  416. }
  417. void onLevelLoad() {
  418.         jjDelayGeneratedCrateOrigins = true;
  419.         jjPalette.gradient(69, 88, 143, 0, 0, 0);
  420.         array<uint8> ignoredIndices;
  421.         for (int i = 0; i < 96; i++) {
  422.                 ignoredIndices.insertLast(i);
  423.         }
  424.         for (int i = 176; i < 208; i++) {
  425.                 ignoredIndices.insertLast(i);
  426.         }
  427.         array<uint8> freePaletteIndices = findFreePaletteIndices(ignoredIndices);
  428.         generateAndAddStars();
  429.         correctTiles();
  430.         generateAndAddFog();
  431.         if (jjLayers[8].hasTileMap)
  432.                 darkenLayer(jjLayers[8], freePaletteIndices, function(color) {
  433.                         color.setHSL(color.getHue(), color.getSat() / 2, color.getLight());
  434.                         return color;
  435.                 });
  436.         if (jjLayers[1].hasTileMap)
  437.                 darkenLayer(jjLayers[1], freePaletteIndices, function(color) {
  438.                         color.setHSL(color.getHue(), color.getSat() * 4 / 5, color.getLight() * 2 / 5);
  439.                         return color;
  440.                 });
  441.         for (int i = 0; i < jjLayers[4].height; i++) {
  442.                 for (int j = 0; j < jjLayers[4].width; j++) {
  443.                         if (jjEventGet(j, i) == AREA::ONEWAY)
  444.                                 oneWays.insertLast(Point(j, i));
  445.                 }
  446.         }
  447.         int tileOffset = jjTileCount;
  448.         jjTilesFromTileset(jjTilesetFileName, 1, 10);
  449.         jjLayers[3].generateSettableTileArea();
  450.         jjLayers[4].generateSettableTileArea();
  451.         jjPIXELMAP slope(19);
  452.         jjPIXELMAP tilebug1(8), tilebug1src(29);
  453.         jjPIXELMAP tilebug2(29), tilebug2src(8);
  454.         jjPIXELMAP tilebug3(9), tilebug3src(28);
  455.         jjPIXELMAP tilebug4(28), tilebug4src(9);
  456.         jjPIXELMAP tilebug5(9), tilebug5src(15);
  457.         jjPIXELMAP tilebug6(3), tilebug6src(29);
  458.         jjPIXELMAP slope2(28), slope2src(18);
  459.         jjPIXELMAP slope3(8);
  460.         jjPIXELMAP slope4(18);
  461.         for (int i = 1; i < 32; i++) {
  462.                 for (int j = 0; j < i; j++) {
  463.                         slope[j, i] = 0;
  464.                 }
  465.         }
  466.         for (int i = 0; i < 32; i++) {
  467.                 for (int j = 0; i + j < 32; j++) {
  468.                         slope2[j, i] = slope2src[j, i];
  469.                 }
  470.         }
  471.         for (int i = 16; i < 32; i++) {
  472.                 for (int j = 47 - i; j < 32; j++) {
  473.                         slope3[j, i] = 0;
  474.                 }
  475.         }
  476.         for (int i = 0; i < 32; i++) {
  477.                 for (int j = i < 15 ? 15 - i : 0; j < 32; j++) {
  478.                         slope4[j, i] = 0;
  479.                 }
  480.         }
  481.         for (int i = 16; i < 32; i++) {
  482.                 for (int j = 31 - i; j < i - 16; j++) {
  483.                         bool less = jjPalette.color[tilebug1[j, i]].getLight() < jjPalette.color[tilebug1src[j, i]].getLight();
  484.                         if (less ^^ j < 8)
  485.                                 tilebug1[j, i] = tilebug1src[j, i];
  486.                         less = jjPalette.color[tilebug2[j, i]].getLight() < jjPalette.color[tilebug2src[j, i]].getLight();
  487.                         if (less ^^ j >= 8)
  488.                                 tilebug2[j, i] = tilebug2src[j, i];
  489.                 }
  490.                 for (int j = 47 - i ; j <= i; j++) {
  491.                         bool less = jjPalette.color[tilebug3[j, i]].getLight() < jjPalette.color[tilebug3src[j, i]].getLight();
  492.                         if (less ^^ j >= 24)
  493.                                 tilebug3[j, i] = tilebug3src[j, i];
  494.                         less = jjPalette.color[tilebug4[j, i]].getLight() < jjPalette.color[tilebug4src[j, i]].getLight();
  495.                         if (less ^^ j < 24)
  496.                                 tilebug4[j, i] = tilebug4src[j, i];
  497.                 }
  498.                 for (int j = 16; j <= i; j++) {
  499.                         bool less = jjPalette.color[tilebug5[j, i]].getLight() < jjPalette.color[tilebug5src[j, i]].getLight();
  500.                         if (less ^^ j >= i / 2 + 9)
  501.                                 tilebug5[j, i] = tilebug5src[j, i];
  502.                 }
  503.                 for (int j = 0; j < i - 16; j++) {
  504.                         bool less = jjPalette.color[tilebug6[j, i]].getLight() < jjPalette.color[tilebug6src[j, i]].getLight();
  505.                         if (less ^^ j < i / 2 - 8)
  506.                                 tilebug6[j, i] = tilebug6src[j, i];
  507.                 }
  508.         }
  509.         slope.save(tileOffset + 0);
  510.         tilebug1.save(tileOffset + 1);
  511.         tilebug2.save(tileOffset + 2);
  512.         tilebug3.save(tileOffset + 3);
  513.         tilebug4.save(tileOffset + 4);
  514.         tilebug5.save(tileOffset + 5);
  515.         tilebug6.save(tileOffset + 6);
  516.         slope2.save(tileOffset + 7);
  517.         slope3.save(tileOffset + 8);
  518.         slope4.save(tileOffset + 9);
  519.         jjMASKMAP(19).save(tileOffset);
  520.         jjMASKMAP(8).save(tileOffset + 1);
  521.         jjMASKMAP(29).save(tileOffset + 2);
  522.         jjMASKMAP(9).save(tileOffset + 3);
  523.         jjMASKMAP(28).save(tileOffset + 4);
  524.         jjMASKMAP(9).save(tileOffset + 5);
  525.         jjMASKMAP(3).save(tileOffset + 6);
  526.         jjMASKMAP(28).save(tileOffset + 7);
  527.         jjMASKMAP(8).save(tileOffset + 8);
  528.         jjMASKMAP(18).save(tileOffset + 9);
  529.         for (int i = 87; i < 94; i++) {
  530.                 for (int j = 23; j < 30; j++) {
  531.                         if (jjLayers[3].tileGet(j, i) == 151 && jjLayers[4].tileGet(j, i) == 19)
  532.                                 jjLayers[4].tileSet(j, i, tileOffset);
  533.                 }
  534.         }
  535.         for (int i = 99; i < 112; i++) {
  536.                 for (int j = 0; j < 13; j++) {
  537.                         if (jjLayers[4].tileGet(j, i) == 28)
  538.                                 jjLayers[4].tileSet(j, i, tileOffset + 7);
  539.                 }
  540.         }
  541.         for (int i = 23; i < 27; i++) {
  542.                 jjLayers[4].tileSet(i, 135 - i, tileOffset + 8);
  543.                 jjLayers[4].tileSet(i, 136 - i, tileOffset + 9);
  544.         }
  545.         for (int layer = 3; layer < 5; layer++) {
  546.                 for (int i = 0; i < jjLayers[layer].height - 1; i++) {
  547.                         for (int j = 0; j < jjLayers[layer].width; j++) {
  548.                                 int thisTile = jjLayers[layer].tileGet(j, i);
  549.                                 int tileBelow = jjLayers[layer].tileGet(j, i + 1);
  550.                                 if (thisTile == 8 && tileBelow == 39)
  551.                                         jjLayers[layer].tileSet(j, i, tileOffset + 1);
  552.                                 else if (thisTile == 29 && tileBelow == 18)
  553.                                         jjLayers[layer].tileSet(j, i, tileOffset + 2);
  554.                                 else if (thisTile == 9 && tileBelow == 38)
  555.                                         jjLayers[layer].tileSet(j, i, tileOffset + 3);
  556.                                 else if (thisTile == 28 && tileBelow == 19)
  557.                                         jjLayers[layer].tileSet(j, i, tileOffset + 4);
  558.                                 else if (thisTile == 9 && tileBelow == 15)
  559.                                         jjLayers[layer].tileSet(j, i, tileOffset + 5);
  560.                                 else if (thisTile == 3 && (tileBelow == 39 || tileBelow == 79))
  561.                                         jjLayers[layer].tileSet(j, i, tileOffset + 6);
  562.                         }
  563.                 }
  564.         }
  565.         jjLayers[4].tileSet(93, 83, tileOffset + 6);
  566.         /*array<uint8> mapping(256);
  567.         for (uint i = 0; i < tilesToTurnOrange.length(); i++) {
  568.                 jjPIXELMAP tile(tilesToTurnOrange[i]);
  569.                 for (int j = 0; j < 32; j++) {
  570.                         for (int k = 0; k < 32; k++) {
  571.                                 uint8 pixel = tile[k, j];
  572.                                 if (pixel != 0) {
  573.                                         if (mapping[pixel] == 0) {
  574.                                                 jjPALCOLOR color = jjPalette.color[pixel];
  575.                                                 int hue = color.getHue();
  576.                                                 int sat = color.getSat();
  577.                                                 int light = color.getLight();
  578.                                                 if (i > 2 && k <= 16) color.setHSL(hue + 100, sat, light + 10);
  579.                                                 else if (i < 2) color.setHSL(hue + 100, sat, light + 10);
  580.                                                 mapping[pixel] = jjPalette.findNearestColor(color);
  581.                                         }
  582.                                         tile[k, j] = mapping[pixel];
  583.                                 }
  584.                         }
  585.                 }
  586.                 tile.save(tilesToReplace[i]);
  587.                 jjMASKMAP(tilesToTurnOrange[i]).save(tilesToReplace[i], true);
  588.         }*/
  589.         generateCustomSpringSprites(jjAnimSets[ANIM::CUSTOM[3]], array<uint> = {40});
  590.         turnIntoCustomSpring(jjObjectPresets[OBJECT::FROZENSPRING], 0, 21.f, false);
  591.        
  592.         se::firework.loadAnims(jjAnimSets[ANIM::CUSTOM[2]]);
  593.         se::firework.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BOEM1, SOUND::INTRO_BOEM2});
  594.         se::firework.setAsWeapon(3, weaponHook);
  595.        
  596.         jjAnimSets[ANIM::CUSTOM[1]].load(0, "Meteor.j2a");
  597.  
  598.         jjAnimations[jjAnimSets[ANIM::AMMO] + 24] = jjAnimations[jjAnimSets[ANIM::CUSTOM[1]] + 1];
  599.         jjAnimations[jjAnimSets[ANIM::AMMO] + 25] = jjAnimations[jjAnimSets[ANIM::CUSTOM[1]] + 2];
  600.        
  601.         jjObjectPresets[OBJECT::BOUNCERBULLET].behavior = jjObjectPresets[OBJECT::BOUNCERBULLETPU].behavior = Meteor();
  602.         jjObjectPresets[OBJECT::BOUNCERBULLET].special = jjObjectPresets[OBJECT::BOUNCERBULLET].determineCurAnim(ANIM::CUSTOM[1], 1);
  603.         jjObjectPresets[OBJECT::BOUNCERBULLETPU].special = jjObjectPresets[OBJECT::BOUNCERBULLETPU].determineCurAnim(ANIM::CUSTOM[1], 0);
  604.         jjObjectPresets[OBJECT::BOUNCERBULLET].ySpeed = jjObjectPresets[OBJECT::BOUNCERBULLETPU].ySpeed = jjObjectPresets[OBJECT::BLASTERBULLET].ySpeed;
  605.         jjObjectPresets[OBJECT::BOUNCERBULLETPU].killAnim = jjObjectPresets[OBJECT::SEEKERBULLET].killAnim;
  606.         jjObjectPresets[OBJECT::BOUNCERBULLET].lightType = LIGHT::POINT;
  607.         jjObjectPresets[OBJECT::BOUNCERBULLETPU].lightType = LIGHT::BRIGHT;
  608.         jjObjectPresets[OBJECT::BOUNCERBULLET].light = jjObjectPresets[OBJECT::BOUNCERBULLETPU].light = 10;
  609.        
  610.         jjObjectPresets[OBJECT::BOUNCERAMMO15].determineCurAnim(ANIM::CUSTOM[1], 3);
  611.         jjObjectPresets[OBJECT::BOUNCERAMMO15].determineCurFrame();
  612.        
  613.         jjObjectPresets[OBJECT::BOUNCERPOWERUP].determineCurAnim(ANIM::CUSTOM[1], 4);
  614.         jjObjectPresets[OBJECT::BOUNCERPOWERUP].determineCurFrame();
  615.        
  616.         jjWeapons[WEAPON::BOUNCER].defaultSample = false;
  617.         jjWeapons[WEAPON::BOUNCER].style = WEAPON::MISSILE;
  618.        
  619.         jjSampleLoad(SOUND::ORANGE_BOEMR, "expmine.wav");
  620. }
  621. void onLevelBegin() {
  622.         for (int i = 0; i < jjObjectCount; i++) {
  623.                 jjOBJ@ obj = jjObjects[i];
  624.                 if (obj.eventID == OBJECT::GENERATOR) {
  625.                         int x = int(obj.xOrg) >> 5;
  626.                         int y = (int(obj.yOrg) >> 5) - 1;
  627.                         if (x >= 0 && y >= 0 && x < jjLayers[4].width && y < jjLayers[4].height && jjEventGet(x, y) == AREA::PATH)
  628.                                 obj.xPos += 14.f;
  629.                 }
  630.         }
  631. }
  632.  
  633. class Meteor : jjBEHAVIORINTERFACE {
  634.         void onBehave(jjOBJ@ obj) {
  635.                 obj.behave(BEHAVIOR::BULLET, obj.state == STATE::EXPLODE? true:false);
  636.                 jjPLAYER@ creator = jjPlayers[obj.creatorID];
  637.                
  638.                 if (obj.state != STATE::EXPLODE) {
  639.                         if (obj.counter == 1 && creator.isLocal) {
  640.                                 jjSample(creator.xPos, creator.yPos, SOUND::ORANGE_BOEMR, 42, obj.eventID == OBJECT::BOUNCERBULLET? 22000 : 20000);
  641.                                 obj.var[2] = 0;
  642.                                
  643.                         }
  644.                         obj.age += obj.direction == 0? 10 : 10 * obj.direction;
  645.                        
  646.                         jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[1], obj.eventID == OBJECT::BOUNCERBULLET? 1:0, 0, -obj.age, 1, 1, obj.eventID == OBJECT::BOUNCERBULLET || obj.var[4] == 1? SPRITE::SINGLEHUE : SPRITE::NORMAL, 72);
  647.                        
  648.                         jjPARTICLE@ smoke = jjAddParticle(PARTICLE::SMOKE);
  649.                         if (smoke !is null) {
  650.                                 smoke.xPos = smoke.xPos;
  651.                                 smoke.yPos = smoke.yPos;
  652.                         }
  653.                        
  654.                         if (obj.eventID == OBJECT::BOUNCERBULLETPU && obj.var[4] == 0) {
  655.                                 jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[1], 0, 0, -obj.age, 1, 1, SPRITE::TRANSLUCENTSINGLEHUE, 40);
  656.                                 jjPARTICLE@ cinders = jjAddParticle(PARTICLE::FIRE);
  657.                                 if (cinders !is null) {
  658.                                         cinders.xPos = int(obj.xPos - 8) + jjRandom()%17;
  659.                                         cinders.yPos = int(obj.yPos - 8) + jjRandom()%17;
  660.                                 }
  661.                         }
  662.                        
  663.                         if (obj.yPos > jjWaterLevel) {
  664.                                 obj.var[4] = 1;
  665.                                 obj.xSpeed = obj.xSpeed * 0.875;
  666.                                 obj.ySpeed = obj.ySpeed * 0.875;
  667.                         }
  668.                
  669.                         switch (obj.direction) {
  670.                                 case 1: obj.xSpeed -= obj.eventID == OBJECT::BOUNCERBULLET? 0.1:0.15; obj.ySpeed += obj.eventID == OBJECT::BOUNCERBULLET? 0.15:0.2; break;
  671.                                 case -1: obj.xSpeed += obj.eventID == OBJECT::BOUNCERBULLET? 0.1:0.15; obj.ySpeed += obj.eventID == OBJECT::BOUNCERBULLET? 0.15:0.2; break;
  672.                         }
  673.                        
  674.                         if (obj.xSpeed == 0) obj.ySpeed += 0.4;
  675.                         if (obj.ySpeed > 8) obj.ySpeed = 8;
  676.                        
  677.                 } else {
  678.                         obj.age = 0;
  679.                         if (obj.var[2] == 0) {
  680.                                 jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BENZIN1, 0, 0);
  681.                                 obj.var[2] = 1;
  682.                                
  683.                                 for (int i = -1; i <= 1; i+= 2) {
  684.                                         Rock temp;
  685.                                                 jjOBJ@ rock = jjObjects[jjAddObject(OBJECT::SHARD, int(obj.xPos + (i * 12)), int(obj.yPos - 8), obj.creatorID, CREATOR::PLAYER, jjVOIDFUNCOBJ(temp.onBehave))];
  686.                                                 rock.determineCurAnim(obj.eventID == OBJECT::BOUNCERBULLETPU? ANIM::CUSTOM[1] : ANIM::FONT, obj.eventID == OBJECT::BOUNCERBULLETPU? 0:14);
  687.                                                 rock.playerHandling = HANDLING::PLAYERBULLET;
  688.                                                 rock.var[3] = 2;
  689.                                                 rock.var[4] = obj.var[4];
  690.                                                 rock.var[5] = obj.eventID == OBJECT::BOUNCERBULLETPU? 0:1;
  691.                                                 rock.var[6] = obj.eventID == OBJECT::BOUNCERBULLETPU? 8:0;
  692.                                                 rock.special = obj.eventID == OBJECT::BOUNCERBULLETPU? 40:72;
  693.                                                 rock.animSpeed = 2;
  694.                                                 rock.direction = i;
  695.                                                 rock.xSpeed = 6 * i;
  696.                                                 rock.ySpeed = -3;
  697.                                                 rock.state = STATE::FLY;
  698.                                                 rock.lightType = LIGHT::POINT;
  699.                                                 rock.light = 10;
  700.                                                 rock.counterEnd = jjObjectPresets[OBJECT::BOUNCERBULLET].counterEnd;
  701.                                                 rock.killAnim = jjObjectPresets[OBJECT::BOUNCERBULLET].killAnim;
  702.                                 }
  703.                         }
  704.                 }
  705.         }
  706. }
  707.  
  708. class Rock : jjBEHAVIORINTERFACE {
  709.         void onBehave(jjOBJ@ obj) {
  710.                 obj.behave(BEHAVIOR::BULLET, obj.state == STATE::EXPLODE? true:false);
  711.                
  712.                 if (obj.state == STATE::FLY) {
  713.                         obj.age += obj.direction == 0? 10 : 10 * obj.direction;
  714.                         jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[1], obj.var[5] == 0? 0:1, 0, -obj.age, 0.5, 0.5, SPRITE::SINGLEHUE, obj.special);
  715.                        
  716.                         switch (obj.direction) {
  717.                                 case 1: obj.xSpeed -= 0.05; obj.ySpeed += 0.1; break;
  718.                                 case -1: obj.xSpeed += 0.05; obj.ySpeed += 0.1; break;
  719.                         }
  720.                        
  721.                         if (obj.yPos > jjWaterLevel) {
  722.                                 obj.var[4] = 1;
  723.                                 obj.xSpeed = obj.xSpeed * 0.875;
  724.                                 obj.ySpeed = obj.ySpeed * 0.875;
  725.                         }
  726.                        
  727.                         jjPARTICLE@ smoke = jjAddParticle(PARTICLE::SMOKE);
  728.                         if (smoke !is null && obj.var[5] == 2) {
  729.                                 smoke.xPos = obj.xPos;
  730.                                 smoke.yPos = obj.yPos;
  731.                         }
  732.                        
  733.                 }
  734.                
  735.         }
  736. }
  737.  
  738. void onMain() {
  739.         for (int i = 0; i < 1024; i++) {
  740.                 jjPARTICLE@ particle = jjParticles[i];
  741.                 if (particle.type == PARTICLE::FIRE) {
  742.                         particle.fire.size = particle.fire.color == 40? 3:2;
  743.                 }
  744.         }
  745. }
  746.  
  747.  
  748. void onPlayer(jjPLAYER@ player) {
  749.         if (jjEventGet(int(player.xPos) >> 5, int(player.yPos) >> 5) == AREA::SUCKERTUBE)
  750.                 player.alreadyDoubleJumped = false;
  751.         bool previousSpecialMove = specialMove[player.localPlayerID];
  752.         bool currentSpecialMove = player.specialMove != 0 && jjCharacters[player.charCurr].groundJump != GROUND::JAZZ;
  753.         if (currentSpecialMove ^^ previousSpecialMove) {
  754.                 for (uint i = 0; i < oneWays.length(); i++) {
  755.                         const Point@ tile = oneWays[i];
  756.                         jjEventSet(tile.x, tile.y, currentSpecialMove ? 0 : AREA::ONEWAY);
  757.                 }
  758.                 specialMove[player.localPlayerID] = currentSpecialMove;
  759.         }
  760.         weaponHook.processPlayer(player);
  761. }
  762. void onPlayerInput(jjPLAYER@ player) {
  763.         weaponHook.processPlayerInput(player);
  764. }
  765. void onReceive(jjSTREAM &in packet, int clientID) {
  766.         weaponHook.processPacket(packet, clientID);
  767. }
  768. void onDrawLayer8(jjPLAYER@ player, jjCANVAS@) {
  769.         int y = 30 - int(player.cameraY * jjLayers[6].ySpeed / 32.f);
  770.         if (layer7Row != y) {
  771.                 while (layer7Row > y) {
  772.                         layer7Row--;
  773.                         for (int i = 0; i < jjLayers[7].widthReal; i++) {
  774.                                 int realRow = (layer7Row + jjLayers[7].height) % jjLayers[7].height;
  775.                                 jjLayers[7].tileSet(i, realRow, 0);
  776.                         }
  777.                 }
  778.                 while (layer7Row < y) {
  779.                         for (int i = 0; i < jjLayers[7].widthReal; i++) {
  780.                                 int realRow = (layer7Row + jjLayers[7].height) % jjLayers[7].height;
  781.                                 jjLayers[7].tileSet(i, realRow, layer7Backup.tileGet(i, realRow));
  782.                         }
  783.                         layer7Row++;
  784.                 }
  785.         }
  786. }