Downloads containing ab20ctf12.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Anniversary Bash 20 Levels Jazz2Online Multiple N/A Download file

File preview

  1. #include "MLLE-Include-1.4.asc"
  2. const bool MLLESetupSuccessful = MLLE::Setup();
  3. #pragma require "wbrg.j2t"
  4. #pragma require "Corrupted Sanctuary.j2t"
  5. #pragma require "Damn1.j2t"
  6. #pragma require "ab20ctf12-MLLE-Data-2.j2l"
  7. #pragma require "ab20ctf12-MLLE-Data-1.j2l"
  8. #pragma require "ab20ctf12.j2l"
  9. #pragma require "Waz18.j2t"
  10. #pragma require "BurningTowers3.j2t"
  11. #pragma require "Thermal.j2t"
  12. #pragma require "Rootalopicus.j2t"
  13. #pragma require "Volcano.j2t"
  14. #pragma require "lavaflow.wav"
  15. #pragma require "Rumble1.wav"
  16. #pragma require "Rumble3.wav"
  17. #pragma require "lavadrop.wav"
  18. #pragma require "Meteor.j2a"
  19. #pragma require "expmine.wav"
  20. #pragma require "efatt1.wav"
  21. #pragma require "weaponMega.j2a"
  22. #pragma require "SEfirework.asc"
  23. #include "weaponMega.asc"
  24. #include "SEfirework.asc"
  25. se::DefaultWeaponHook weaponHook;
  26. bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
  27.         return weaponHook.drawAmmo(player, canvas);
  28. }
  29. funcdef jjPALCOLOR ColorFunction(jjPALCOLOR);
  30.  
  31. class vector2i {
  32.         int x, y;
  33. }
  34. array<vector2i> oneWays;
  35. array<bool> inside(4, false);
  36.  
  37. class Level {
  38.         private int sample = 0;
  39.        
  40.         void alignObjects() {
  41.                 for (int i = 1; i < jjObjectCount; i++) {
  42.                         jjOBJ@ obj = jjObjects[i];
  43.                         if (obj.eventID == OBJECT::FULLENERGY) obj.xPos = obj.xOrg + 4;
  44.                 }
  45.         }
  46.        
  47.         void ashFallout() {
  48.                 for (int i = 0; i < 1024; i++) {
  49.                         jjPARTICLE@ particle = jjParticles[i];
  50.                         if (particle.type == PARTICLE::FLOWER) {
  51.                                 particle.xSpeed = 0.25;
  52.                                 particle.ySpeed = 3;
  53.                                 particle.type = PARTICLE::SMOKE;
  54.                         }
  55.                         if (particle.type == PARTICLE::SMOKE) {
  56.                                 particle.ySpeed = jjLocalPlayers[0].ySpeed < 0? 3 : int(3 + jjLocalPlayers[0].ySpeed);
  57.                                 if (jjMaskedPixel(int(particle.xPos), int(particle.yPos))) {
  58.                                         particle.type = PARTICLE::INACTIVE;
  59.                                 }
  60.                         }
  61.                         if (particle.type == PARTICLE::FIRE) {
  62.                                 particle.fire.size = particle.fire.color == 40? 3:2;
  63.                         }
  64.                 }
  65.         }
  66.  
  67.         void createCustomObjects() {
  68.                 generateCustomSpringSprites(jjAnimSets[ANIM::CUSTOM[2]], array<uint> = {88});
  69.                 turnIntoCustomSpring(jjObjectPresets[OBJECT::FROZENSPRING], 0, 30.f, false);
  70.                
  71.                 for (int i = 1; i < 255; i++) {
  72.                         if (jjObjectPresets[i].playerHandling == HANDLING::PICKUP || jjObjects[i].eventID == OBJECT::SEEKERAMMO3) {
  73.                                 jjObjectPresets[i].behavior = CannotBeShotDown(jjObjectPresets[i].behavior);
  74.                         }
  75.                 }
  76.                 jjAnimSets[ANIM::CUSTOM[22]].load(0, "Meteor.j2a");
  77.  
  78.                 jjAnimations[jjAnimSets[ANIM::AMMO] + 24] = jjAnimations[jjAnimSets[ANIM::CUSTOM[22]] + 1];
  79.                 jjAnimations[jjAnimSets[ANIM::AMMO] + 25] = jjAnimations[jjAnimSets[ANIM::CUSTOM[22]] + 2];
  80.                
  81.                 jjObjectPresets[OBJECT::BOUNCERBULLET].behavior = jjObjectPresets[OBJECT::BOUNCERBULLETPU].behavior = Meteor();
  82.                 jjObjectPresets[OBJECT::BOUNCERBULLET].special = jjObjectPresets[OBJECT::BOUNCERBULLET].determineCurAnim(ANIM::CUSTOM[22], 1);
  83.                 jjObjectPresets[OBJECT::BOUNCERBULLETPU].special = jjObjectPresets[OBJECT::BOUNCERBULLETPU].determineCurAnim(ANIM::CUSTOM[22], 0);
  84.                 jjObjectPresets[OBJECT::BOUNCERBULLET].ySpeed = jjObjectPresets[OBJECT::BOUNCERBULLETPU].ySpeed = jjObjectPresets[OBJECT::BLASTERBULLET].ySpeed;
  85.                 jjObjectPresets[OBJECT::BOUNCERBULLETPU].killAnim = jjObjectPresets[OBJECT::SEEKERBULLET].killAnim;
  86.                 jjObjectPresets[OBJECT::BOUNCERBULLET].lightType = LIGHT::POINT;
  87.                 jjObjectPresets[OBJECT::BOUNCERBULLETPU].lightType = LIGHT::BRIGHT;
  88.                 jjObjectPresets[OBJECT::BOUNCERBULLET].light = jjObjectPresets[OBJECT::BOUNCERBULLETPU].light = 10;
  89.                
  90.                 jjObjectPresets[OBJECT::BOUNCERAMMO15].determineCurAnim(ANIM::CUSTOM[22], 3);
  91.                 jjObjectPresets[OBJECT::BOUNCERAMMO15].determineCurFrame();
  92.                
  93.                 jjObjectPresets[OBJECT::BOUNCERPOWERUP].determineCurAnim(ANIM::CUSTOM[22], 4);
  94.                 jjObjectPresets[OBJECT::BOUNCERPOWERUP].determineCurFrame();
  95.                
  96.                 jjWeapons[WEAPON::BOUNCER].defaultSample = false;
  97.                 jjWeapons[WEAPON::BOUNCER].style = WEAPON::MISSILE;
  98.                
  99.                 jjObjectPresets[OBJECT::TOASTERBULLET].behavior =
  100.                 jjObjectPresets[OBJECT::TOASTERBULLETPU].behavior = SuperToaster();
  101.                 jjObjectPresets[OBJECT::TOASTERBULLET].lightType =
  102.                 jjObjectPresets[OBJECT::TOASTERBULLETPU].lightType = LIGHT::FLICKER;
  103.                 jjObjectPresets[OBJECT::TOASTERBULLET].light =
  104.                 jjObjectPresets[OBJECT::TOASTERBULLETPU].light = 12;
  105.                
  106.                 jjWeapons[WEAPON::TOASTER].multiplier = 12;
  107.                 jjWeapons[WEAPON::TOASTER].gradualAim = true;
  108.                
  109.                 jjObjectPresets[OBJECT::FIREBALLBULLET].behavior =
  110.                 jjObjectPresets[OBJECT::FIREBALLBULLETPU].behavior = SuperFireball();
  111.                 jjObjectPresets[OBJECT::FIREBALLBULLET].killAnim =
  112.                 jjObjectPresets[OBJECT::FIREBALLBULLETPU].killAnim = jjObjectPresets[OBJECT::SEEKERBULLET].killAnim;
  113.                 jjObjectPresets[OBJECT::FIREBALLBULLET].lightType =
  114.                 jjObjectPresets[OBJECT::FIREBALLBULLETPU].lightType = LIGHT::FLICKER;
  115.                 jjObjectPresets[OBJECT::FIREBALLBULLET].light =
  116.                 jjObjectPresets[OBJECT::FIREBALLBULLETPU].light = 12;
  117.                 jjObjectPresets[OBJECT::FIREBALLBULLET].special = jjObjectPresets[OBJECT::FIREBALLBULLET].determineCurAnim(ANIM::BILSBOSS, 3);
  118.                 jjObjectPresets[OBJECT::FIREBALLBULLET].xSpeed = 6;
  119.                 jjObjectPresets[OBJECT::FIREBALLBULLETPU].xSpeed = 7.5;
  120.                
  121.                 jjWeapons[WEAPON::GUN8].spread = SPREAD::NORMAL;
  122.                
  123.                
  124.                 se::firework.loadAnims(jjAnimSets[ANIM::CUSTOM[1]]);
  125.                 se::firework.loadSamples(array<SOUND::Sample> = {SOUND::P2_PINCH1, SOUND::P2_PINCH2});
  126.                 se::firework.setAsWeapon(4, weaponHook);
  127.                
  128.                 jjANIMATION@ anim = jjAnimations[jjAnimSets[ANIM::COMMON] + 3];
  129.                 for (uint i = 0; i < anim.frameCount; ++i) {
  130.                         jjANIMFRAME@ frame = jjAnimFrames[anim + i];
  131.                         jjPIXELMAP sprite(frame);
  132.                         for (uint x = 0; x < sprite.width; ++x)
  133.                                 for (uint y = 0; y < sprite.height; ++y)
  134.                                 if (sprite[x,y] != 0) sprite[x,y] -= 32;
  135.                         sprite.save(frame);
  136.                 }
  137.                
  138.                 jjDelayGeneratedCrateOrigins = true;
  139.         }
  140.        
  141.         void darkenLayer(jjLAYER@ layer, array<uint8>& freePaletteIndices, ColorFunction@ func) {
  142.                 array<int> tileIDs, uniqueTileIDs;
  143.                 for (int i = 0; i < layer.height; i++) {
  144.                         for (int j = 0; j < layer.width; j++) {
  145.                                 int tileID = layer.tileGet(j, i);
  146.                                 if (tileID != 0)
  147.                                         tileIDs.insertLast(tileID);
  148.                         }
  149.                 }
  150.                 int prev = 0;
  151.                 tileIDs.sortAsc();
  152.                 for (uint i = 0; i < tileIDs.length(); i++) {
  153.                         if (tileIDs[i] != prev)
  154.                                 uniqueTileIDs.insertLast(prev = tileIDs[i]);
  155.                 }
  156.                 uint firstNewTile = jjTileCount;
  157.                 jjTilesFromTileset(jjTilesetFileName, 1, uniqueTileIDs.length());
  158.                 array<uint8> mapping(256);
  159.                 for (uint i = 0; i < uniqueTileIDs.length(); i++) {
  160.                         jjPIXELMAP tile(uniqueTileIDs[i]);
  161.                         for (int j = 0; j < 32; j++) {
  162.                                 for (int k = 0; k < 32; k++) {
  163.                                         uint8 pixel = tile[k, j];
  164.                                         if (pixel != 0) {
  165.                                                 if (mapping[pixel] == 0) {
  166.                                                         jjPALCOLOR color = func(jjPalette.color[pixel]);
  167.                                                         uint8 bestMatch = jjPalette.findNearestColor(color);
  168.                                                         if (!freePaletteIndices.isEmpty()) {
  169.                                                                 jjPALCOLOR other = jjPalette.color[bestMatch];
  170.                                                                 int red = other.red - color.red;
  171.                                                                 int green = other.green - color.green;
  172.                                                                 int blue = other.blue - color.blue;
  173.                                                                 int distance = red * red + green * green + blue * blue;
  174.                                                                 if (distance > 16) {
  175.                                                                         bestMatch = freePaletteIndices[freePaletteIndices.length() - 1];
  176.                                                                         jjPalette.color[bestMatch] = color;
  177.                                                                         freePaletteIndices.removeLast();
  178.                                                                 }
  179.                                                         }
  180.                                                         mapping[pixel] = bestMatch;
  181.                                                 }
  182.                                                 tile[k, j] = mapping[pixel];
  183.                                         }
  184.                                 }
  185.                         }
  186.                         tile.save(firstNewTile + i);
  187.                 }
  188.                 layer.generateSettableTileArea();
  189.                 for (int i = 0; i < layer.height; i++) {
  190.                         for (int j = 0; j < layer.widthReal; j++) {
  191.                                 int tileID = layer.tileGet(j, i);
  192.                                 if (tileID != 0)
  193.                                         layer.tileSet(j, i, firstNewTile + uniqueTileIDs.find(tileID));
  194.                         }
  195.                 }
  196.         }
  197.        
  198.         void drawFlyCarrotTimer(jjPLAYER@ play, jjCANVAS@ canvas) {
  199.                 if (play.fly == FLIGHT::FLYCARROT) {
  200.                 canvas.drawString(
  201.                         jjSubscreenWidth - 55,
  202.                         jjSubscreenHeight - 284,
  203.                         "" + (play.timerTime + 70) / 70,
  204.                         STRING::LARGE,
  205.                         STRING::PALSHIFT,
  206.                         play.timerTime > 3*70?
  207.                                 0 :
  208.                                 jjGameTicks % 28 > 14?
  209.                                         -40 :
  210.                                         -24
  211.                 );
  212.                
  213.                 canvas.drawSprite(
  214.                         jjSubscreenWidth - 72,
  215.                         jjSubscreenHeight - 270,
  216.                         ANIM::PICKUPS,
  217.                         40,
  218.                         jjGameTicks >> 2
  219.                 );
  220.                 }
  221.         }
  222.        
  223.         void handleLevelBoundaries(jjPLAYER@ play) {
  224.                 const int bounds = 16;
  225.        
  226.                 if (play.xPos > ((jjLayerWidth[4]*32) - bounds) || play.xPos < bounds) {
  227.                         play.xPos = play.xPos < (bounds+1)? bounds : (jjLayerWidth[4]*32) - bounds;
  228.                         play.xSpeed = 0;
  229.                         play.specialMove = 0;
  230.                 }
  231.         }
  232.        
  233.         void handleLevelEffects(jjPLAYER@ play) {
  234.                 play.lightType = LIGHT::NONE;
  235.                 if (play.health == 0) inside[play.localPlayerID] = false;
  236.                
  237.                 if (!jjLowDetail) {
  238.                         if (inside[play.localPlayerID]) {
  239.                                 jjIsSnowing = false;
  240.                                 play.lighting = 80;
  241.                         } else {
  242.                                 jjIsSnowing = true;
  243.                                 play.lighting = 100;
  244.                         }
  245.                 } else {
  246.                         jjIsSnowing = false;
  247.                         play.lighting = 100;
  248.                 }
  249.                
  250.                 if (jjEventGet(int(play.xPos/32), int(play.yPos/32)) == AREA::WATERBLOCK) {
  251.                         play.fly = FLIGHT::NONE;
  252.                 }
  253.                
  254.                 array<jjLAYER@> layers = jjLayerOrderGet();
  255.                 layers[0].xOffset -= 1;
  256.                 if (layers[0].xOffset % (layers[0].widthReal*32) == 0) layers[0].xOffset = 0;
  257.                 for (int i = 0; i < 5; i++) {
  258.                         layers[12 + i].xOffset -= 0.25f * (2 + i);
  259.                         if (layers[12 + i].xOffset % (layers[12 + i].widthReal*32) == 0) layers[12 + i].xOffset = 0;
  260.                 }
  261.                
  262.                 if (!jjLowDetail) {
  263.                         if (jjGameTicks > 7) {
  264.                                 sample = jjSampleLooped(play.xPos, play.yPos, SOUND::WIND_WIND2A, sample, inside[play.localPlayerID]? 60:40, 0);
  265.                                 if (jjGameTicks % 1200 == 0) jjSample(play.xPos, play.yPos, SOUND::BILSBOSS_THUNDER, inside[play.localPlayerID]? 60:40, 0);
  266.                                 if (jjGameTicks % 3600 == 0 && inside[play.playerID]) jjSample(play.xPos, play.yPos, SOUND::BILSBOSS_FIRE, 50, 0);
  267.                         }
  268.                 }
  269.         }
  270.        
  271.         void handleKickingOnOneWaySlopes(jjPLAYER@ play) {
  272.                 for (uint i = 0; i < oneWays.length(); i++) {
  273.                         jjEventSet(oneWays[i].x, oneWays[i].y, AREA::ONEWAY);
  274.                 }
  275.                 oneWays.resize(0);
  276.                 int px = int(play.xPos), py = int(play.yPos);
  277.                 bool masked;
  278.                 for (int i = -11 + int(play.ySpeed); i <= 14; i++) {
  279.                         if (masked = jjMaskedHLine(px - 14, 28, py + i))
  280.                                 break;
  281.                 }
  282.                 if (!masked) {
  283.                         for (int i = 8; i <= 16; i += 8) {
  284.                                 for (int j = 12; j <= 20; j += 8) {
  285.                                         int x = (px + play.direction * j) >>> 5, y = (py + i) >>> 5;
  286.                                         if (x >= 0 && y >= 0 && x < jjLayerWidth[4] && y < jjLayerHeight[4] && jjEventGet(x, y) == AREA::ONEWAY) {
  287.                                                 vector2i point;
  288.                                                 jjEventSet(point.x = x, point.y = y, 0);
  289.                                                 oneWays.insertLast(point);
  290.                                         }
  291.                                 }
  292.                         }
  293.                 }
  294.         }
  295.        
  296.         void hideBackgroundLayers(jjPLAYER@ play) {
  297.                 array<jjLAYER@> layers = jjLayerOrderGet();
  298.                 if (play.cameraX >= 204*32 && play.cameraX <= 262*32 && play.cameraY >= 70*32) {
  299.                         for (int i = 12; i <= 21; i++) {
  300.                                 layers[i].hasTiles = false;
  301.                         }
  302.                 } else {
  303.                         for (int i = 12; i <= 21; i++) {
  304.                                 layers[i].hasTiles = true;
  305.                         }
  306.                 }
  307.         }
  308.        
  309.         void loadSamples() {
  310.                 jjSampleLoad(SOUND::WIND_WIND2A, "lavaflow.wav");
  311.                 jjSampleLoad(SOUND::BILSBOSS_THUNDER, "Rumble1.wav");
  312.                 jjSampleLoad(SOUND::BILSBOSS_FIRE, "Rumble3.wav");
  313.                 jjSampleLoad(SOUND::ORANGE_BOEMR, "expmine.wav");
  314.                 jjSampleLoad(SOUND::COMMON_WATER, "lavadrop.wav");
  315.                 jjSampleLoad(SOUND::COMMON_RINGGUN, "efatt1.wav");
  316.         }
  317.  
  318.         void setSkyProperties() {
  319.                 jjTexturedBGTexture = TEXTURE::MEDIVO;
  320.                 jjTexturedBGFadePositionY = 0.45;
  321.                 jjUseLayer8Speeds = true;
  322.         }
  323.        
  324.         void timedFlyCarrot(jjPLAYER@ play) {
  325.                 const uint flyCMaxTime = 700;
  326.                
  327.                 if (play.fly == FLIGHT::FLYCARROT && play.timerState == TIMER::STOPPED) play.timerStart(flyCMaxTime);
  328.                 if (play.fly == FLIGHT::NONE) play.timerStop();
  329.                 if (play.timerState == TIMER::STARTED && play.timerTime <= 3*70 && play.timerTime > 0 && play.timerTime % 70 == 0) jjSamplePriority(SOUND::COMMON_NOCOIN);
  330.                 if (play.timerTime == 0) play.fly = FLIGHT::NONE;
  331.                
  332.                 if (jjGameState == GAME::PAUSED) play.timerPause();
  333.                 else play.timerResume();
  334.         }
  335. }
  336.  
  337. jjANIMSET@ customSpringSprite;
  338. array<int> fastCustomSpringSpeeds(jjLocalPlayerCount);
  339. bool generateCustomSpringSprites(jjANIMSET@ anim, const array<uint> &in colors) {
  340.         int length = colors.length();
  341.         bool success = (@customSpringSprite = anim).allocate(array<uint>(length * 3, 5)) !is null;
  342.         if (success) {
  343.                 uint srcSet = jjAnimSets[ANIM::SPRING];
  344.                 for (int i = 0; i < length; i++) {
  345.                         uint color = colors[i];
  346.                         uint destAnimOffset = anim + i * 3;
  347.                         for (int j = 0; j < 3; j++) {
  348.                                 uint srcAnim = jjAnimations[srcSet + j];
  349.                                 uint destAnim = jjAnimations[destAnimOffset + j];
  350.                                 for (int k = 0; k < 5; k++) {
  351.                                         jjPIXELMAP image(jjAnimFrames[destAnim + k] = jjAnimFrames[srcAnim + k]);
  352.                                         int width = image.width;
  353.                                         int height = image.height;
  354.                                         for (int l = 0; l < height; l++) {
  355.                                                 for (int m = 0; m < width; m++) {
  356.                                                         int pixel = image[m, l];
  357.                                                         if (pixel >= 32 && pixel < 40)
  358.                                                                 image[m, l] = color + (pixel & 7);
  359.                                                 }
  360.                                         }
  361.                                         if (!image.save(jjAnimFrames[destAnim + k]))
  362.                                                 return false;
  363.                                 }
  364.                         }
  365.                 }
  366.         }
  367.         return success;
  368. }
  369.  
  370. void initializeCustomSpring(jjOBJ@ obj) {
  371.         int anim = obj.curAnim;
  372.         obj.behave(obj.behavior = BEHAVIOR::SPRING, false);
  373.         if (obj.curAnim != anim) {
  374.                 obj.curAnim = anim + 2;
  375.                 obj.determineCurFrame();
  376.         }
  377.         obj.draw();
  378. }
  379.  
  380. void turnIntoCustomSpring(jjOBJ@ obj, uint color, float power, bool horizontal) {
  381.         if (horizontal) {
  382.                 obj.xSpeed = power;
  383.                 obj.ySpeed = 0.f;
  384.         } else {
  385.                 obj.xSpeed = 0.f;
  386.                 obj.ySpeed = -power;
  387.                 if (obj.state == STATE::START && obj.creatorType == CREATOR::LEVEL) {
  388.                         int x = int(obj.xPos) >> 5;
  389.                         int y = int(obj.yPos) >> 5;
  390.                         if (jjParameterGet(x, y, 0, 1) != 0) {
  391.                                 jjParameterSet(x, y, 0, 1, 0);
  392.                                 obj.yPos -= 4.f;
  393.                                 obj.ySpeed = power;
  394.                         }
  395.                 }
  396.         }
  397.         obj.behavior = initializeCustomSpring;
  398.         obj.curAnim = customSpringSprite + color * 3 + (horizontal ? 1 : 0);
  399.         obj.energy = obj.frameID = obj.freeze = obj.justHit = obj.light = obj.points = 0;
  400.         obj.isBlastable = obj.isTarget = obj.scriptedCollisions = obj.triggersTNT = false;
  401.         obj.deactivates = obj.isFreezable = true;
  402.         obj.bulletHandling = HANDLING::IGNOREBULLET;
  403.         obj.playerHandling = HANDLING::SPECIAL;
  404.         obj.lightType = LIGHT::NORMAL;
  405.         obj.determineCurFrame();
  406. }
  407.  
  408. class CannotBeShotDown : jjBEHAVIORINTERFACE {
  409.         jjBEHAVIOR originalBehavior;
  410.         CannotBeShotDown(jjBEHAVIOR behavior) {
  411.                 originalBehavior = behavior;
  412.         }
  413.         void onBehave(jjOBJ@ obj) override {
  414.                 obj.behave(originalBehavior);
  415.                 if (obj.state == STATE::FLOATFALL)
  416.                         obj.state = STATE::FLOAT;
  417.                 if (obj.eventID == OBJECT::FULLENERGY)
  418.                         obj.xPos = obj.xOrg - 16;
  419.         }
  420.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
  421.                 obj.behavior = originalBehavior;
  422.                 if (bullet is null)
  423.                         player.objectHit(obj, force, obj.playerHandling);
  424.                 else
  425.                         bullet.objectHit(obj, obj.playerHandling);
  426.                 obj.behavior = CannotBeShotDown(obj.behavior);
  427.                 return true;
  428.         }
  429. }
  430.  
  431. class Meteor : jjBEHAVIORINTERFACE {
  432.         void onBehave(jjOBJ@ obj) {
  433.                 obj.behave(BEHAVIOR::BULLET, obj.state == STATE::EXPLODE? true:false);
  434.                 jjPLAYER@ creator = jjPlayers[obj.creatorID];
  435.                
  436.                 if (obj.state != STATE::EXPLODE) {
  437.                         if (obj.counter == 1 && creator.isLocal) {
  438.                                 jjSample(creator.xPos, creator.yPos, SOUND::ORANGE_BOEMR, 42, obj.eventID == OBJECT::BOUNCERBULLET? 22000 : 20000);
  439.                                 obj.var[2] = 0;
  440.                                
  441.                         }
  442.                         obj.age += obj.direction == 0? 10 : 10 * obj.direction;
  443.                        
  444.                         jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[22], obj.eventID == OBJECT::BOUNCERBULLET? 1:0, 0, -obj.age, 1, 1, obj.eventID == OBJECT::BOUNCERBULLET || obj.var[4] == 1? SPRITE::SINGLEHUE : SPRITE::NORMAL, 72);
  445.                        
  446.                         jjPARTICLE@ smoke = jjAddParticle(PARTICLE::SMOKE);
  447.                         if (smoke !is null) {
  448.                                 smoke.xPos = smoke.xPos;
  449.                                 smoke.yPos = smoke.yPos;
  450.                         }
  451.                        
  452.                         if (obj.eventID == OBJECT::BOUNCERBULLETPU && obj.var[4] == 0) {
  453.                                 jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[22], 0, 0, -obj.age, 1, 1, SPRITE::TRANSLUCENTSINGLEHUE, 40);
  454.                                 jjPARTICLE@ cinders = jjAddParticle(PARTICLE::FIRE);
  455.                                 if (cinders !is null) {
  456.                                         cinders.xPos = int(obj.xPos - 8) + jjRandom()%17;
  457.                                         cinders.yPos = int(obj.yPos - 8) + jjRandom()%17;
  458.                                 }
  459.                         }
  460.                        
  461.                         if (obj.yPos > jjWaterLevel) {
  462.                                 obj.var[4] = 1;
  463.                                 obj.xSpeed = obj.xSpeed * 0.875;
  464.                                 obj.ySpeed = obj.ySpeed * 0.875;
  465.                         }
  466.                
  467.                         switch (obj.direction) {
  468.                                 case 1: obj.xSpeed -= obj.eventID == OBJECT::BOUNCERBULLET? 0.1:0.15; obj.ySpeed += obj.eventID == OBJECT::BOUNCERBULLET? 0.15:0.2; break;
  469.                                 case -1: obj.xSpeed += obj.eventID == OBJECT::BOUNCERBULLET? 0.1:0.15; obj.ySpeed += obj.eventID == OBJECT::BOUNCERBULLET? 0.15:0.2; break;
  470.                         }
  471.                        
  472.                         if (obj.xSpeed == 0) obj.ySpeed += 0.4;
  473.                         if (obj.ySpeed > 8) obj.ySpeed = 8;
  474.                        
  475.                 } else {
  476.                         obj.age = 0;
  477.                         if (obj.var[2] == 0) {
  478.                                 jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BENZIN1, 0, 0);
  479.                                 obj.var[2] = 1;
  480.                                
  481.                                 for (int i = -1; i <= 1; i+= 2) {
  482.                                         Rock temp;
  483.                                                 jjOBJ@ rock = jjObjects[jjAddObject(OBJECT::SHARD, int(obj.xPos + (i * 12)), int(obj.yPos - 8), obj.creatorID, CREATOR::PLAYER, jjVOIDFUNCOBJ(temp.onBehave))];
  484.                                                 rock.determineCurAnim(obj.eventID == OBJECT::BOUNCERBULLETPU? ANIM::CUSTOM[22] : ANIM::FONT, obj.eventID == OBJECT::BOUNCERBULLETPU? 0:14);
  485.                                                 rock.playerHandling = HANDLING::PLAYERBULLET;
  486.                                                 rock.var[3] = 2;
  487.                                                 rock.var[4] = obj.var[4];
  488.                                                 rock.var[5] = obj.eventID == OBJECT::BOUNCERBULLETPU? 0:1;
  489.                                                 rock.var[6] = obj.eventID == OBJECT::BOUNCERBULLETPU? 8:0;
  490.                                                 rock.special = obj.eventID == OBJECT::BOUNCERBULLETPU? 40:72;
  491.                                                 rock.animSpeed = 2;
  492.                                                 rock.direction = i;
  493.                                                 rock.xSpeed = 6 * i;
  494.                                                 rock.ySpeed = -3;
  495.                                                 rock.state = STATE::FLY;
  496.                                                 rock.lightType = LIGHT::POINT;
  497.                                                 rock.light = 10;
  498.                                                 rock.counterEnd = jjObjectPresets[OBJECT::BOUNCERBULLET].counterEnd;
  499.                                                 rock.killAnim = jjObjectPresets[OBJECT::BOUNCERBULLET].killAnim;
  500.                                 }
  501.                         }
  502.                 }
  503.         }
  504. }
  505.  
  506. class Rock : jjBEHAVIORINTERFACE {
  507.         void onBehave(jjOBJ@ obj) {
  508.                 obj.behave(BEHAVIOR::BULLET, obj.state == STATE::EXPLODE? true:false);
  509.                
  510.                 if (obj.state == STATE::FLY) {
  511.                         obj.age += obj.direction == 0? 10 : 10 * obj.direction;
  512.                         jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[22], obj.var[5] == 0? 0:1, 0, -obj.age, 0.5, 0.5, SPRITE::SINGLEHUE, obj.special);
  513.                        
  514.                         switch (obj.direction) {
  515.                                 case 1: obj.xSpeed -= 0.05; obj.ySpeed += 0.1; break;
  516.                                 case -1: obj.xSpeed += 0.05; obj.ySpeed += 0.1; break;
  517.                         }
  518.                        
  519.                         if (obj.yPos > jjWaterLevel) {
  520.                                 obj.var[4] = 1;
  521.                                 obj.xSpeed = obj.xSpeed * 0.875;
  522.                                 obj.ySpeed = obj.ySpeed * 0.875;
  523.                         }
  524.                        
  525.                         jjPARTICLE@ smoke = jjAddParticle(PARTICLE::SMOKE);
  526.                         if (smoke !is null && obj.var[5] == 2) {
  527.                                 smoke.xPos = obj.xPos;
  528.                                 smoke.yPos = obj.yPos;
  529.                         }
  530.                        
  531.                 }
  532.                
  533.         }
  534. }
  535.  
  536. class SuperToaster : jjBEHAVIORINTERFACE {
  537.         void onBehave(jjOBJ@ obj) {
  538.                 obj.behave(BEHAVIOR::TOASTERBULLET);
  539.                
  540.                 if (obj.counter == 1) obj.xSpeed = 5 * obj.direction;
  541.                 if (obj.xSpeed != 0) obj.ySpeed += 0.085;
  542.                
  543.                 jjPARTICLE@ cinders = jjAddParticle(PARTICLE::FIRE);
  544.                 if (cinders !is null && obj.counter > 10) {
  545.                         cinders.xPos = int(obj.xPos - 8) + jjRandom()%17;
  546.                         cinders.yPos = int(obj.yPos - 8) + jjRandom()%17;
  547.                         cinders.fire.color = obj.eventID == OBJECT::TOASTERBULLETPU? 32:40;
  548.                         cinders.fire.colorStop = obj.eventID == OBJECT::TOASTERBULLETPU? 40:48;
  549.                         cinders.fire.colorDelta = 2;
  550.                 }
  551.         }
  552. }
  553.  
  554. class SuperFireball : jjBEHAVIORINTERFACE {
  555.         void onBehave(jjOBJ@ obj) {
  556.                 obj.behave(BEHAVIOR::BULLET, obj.state != STATE::FLY? true:false);
  557.                 obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
  558.                 if (obj.state == STATE::FLY) {
  559.                         jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::BILSBOSS, 3, jjGameTicks >> 2, obj.var[0], 1, 1, SPRITE::SINGLEHUE, obj.eventID == OBJECT::FIREBALLBULLETPU? 88:40);
  560.                 }
  561.         }
  562. }
  563.  
  564. bool LoadWeaponMega3() {
  565.         if (!SafeToReplaceWeapon(WEAPON::ICE))
  566.                 return false;
  567.        
  568.         jjWeapons[WEAPON::ICE].style = WEAPON::POPCORN;
  569.         jjWeapons[WEAPON::ICE].spread = SPREAD::TOASTER;
  570.         jjWeapons[WEAPON::ICE].multiplier = 6;
  571.         jjWeapons[WEAPON::ICE].gradualAim = true;
  572.        
  573.         Preset1.behavior = ApplyIceCloud;
  574.         Preset2.behavior = ApplyIceCloud;
  575.         Preset1.special = Preset1.determineCurAnim(AnimSet, 0);
  576.         Preset2.special = Preset2.determineCurAnim(AnimSet, 0);
  577.         Preset1.determineCurFrame(); Preset2.determineCurFrame();
  578.         Preset1.isBlastable = true; Preset2.isBlastable = true;
  579.         //Preset1.var[6] = Preset1.var[6] | 16; //"fireball"
  580.         //Preset2.var[6] = Preset2.var[6] | 16;
  581.         Preset1.counterEnd = 120; //lifetime
  582.         Preset2.counterEnd = 200;
  583.        
  584.         return true;
  585. }
  586. const bool WeaponMega3Loaded = LoadWeaponMega3();
  587.  
  588. void ApplyIceCloud(jjOBJ@ obj) { obj.behavior = IceCloud(obj); obj.behave(); }
  589. class IceCloud : WeaponMega {
  590.         IceCloud(jjOBJ@ objectOfAttachment) {
  591.                 @obj = @objectOfAttachment;
  592.                 obj.xSpeed += obj.var[7] / 65536.f;
  593.                 if (obj.creatorType == CREATOR::PLAYER)
  594.                         obj.ySpeed += int(jjPlayers[obj.creatorID].ySpeed) / 2;
  595.                 obj.state = STATE::FLY;
  596.         }
  597.         void onBehave(jjOBJ@) override {
  598.                 obj.xPos += obj.xSpeed *= 0.96;
  599.                 obj.yPos += obj.ySpeed *= 0.96;
  600.                 if (obj.frameID < 3 && ++obj.age & 15 == 15) {
  601.                         ++obj.frameID; ++obj.curFrame;
  602.                 }
  603.                 if (--obj.counterEnd == 0 || obj.state == STATE::EXPLODE) {
  604.                         int playerID;
  605.                         if (isPowerup() && (playerID = getNearestEnemy(256)) >= 0) {
  606.                                 obj.frameID = 0;
  607.                                 obj.killAnim = (obj.curAnim += 1) + 1;
  608.                                 obj.counterEnd = 100;
  609.                                 obj.freeze = 0;
  610.                                 const jjPLAYER@ target = jjPlayers[playerID];
  611.                                 obj.xSpeed = (target.xPos - obj.xPos) / 25;
  612.                                 obj.ySpeed = (target.yPos - obj.yPos) / 25;
  613.                                 obj.xAcc = obj.yAcc = obj.var[7] = 0;
  614.                                 obj.behavior = BEHAVIOR::BULLET;
  615.                         } else {
  616.                                 obj.counter = 0;
  617.                                 obj.frameID = 0;
  618.                                 obj.curAnim += 2;
  619.                                 obj.behavior = BEHAVIOR::EXPLOSION;
  620.                         }
  621.                         jjSample(obj.xPos, obj.yPos, SOUND::COMMON_ICECRUSH);
  622.                 } else if (jjGameTicks & 1 == 0) {
  623.                         jjPARTICLE@ part = jjAddParticle(PARTICLE::ICETRAIL);
  624.                         if (part !is null) {
  625.                                 part.yPos = obj.yPos;
  626.                                 part.xPos = obj.xPos + (jjRandom() & 31) - 15;
  627.                         }
  628.                 }
  629.         }
  630.         void onDraw(jjOBJ@) override {
  631.                 jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, 1, SPRITE::TRANSLUCENT);
  632.                 if (obj.frameID == 3 && isPowerup())
  633.                         jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, jjAnimations[obj.curAnim + 1], 0, SPRITE::TRANSLUCENTCOLOR, 15);
  634.         }
  635. }
  636.  
  637. Level level;
  638.  
  639. void onLevelLoad() {
  640.         level.createCustomObjects();
  641.         level.loadSamples();
  642.         level.setSkyProperties();
  643.        
  644.         array<jjLAYER@> layers = jjLayerOrderGet();
  645.         if (layers[6].hasTileMap) {
  646.                 level.darkenLayer(layers[6], array<uint8>(), function(color) {
  647.                         color.setHSL(color.getHue(), color.getSat(), color.getLight() * 7 / 10);
  648.                         return color;
  649.                 });
  650.         }
  651.        
  652.         if (layers[7].hasTileMap) {
  653.                 level.darkenLayer(layers[7], array<uint8>(), function(color) {
  654.                         color.setHSL(color.getHue(), color.getSat(), color.getLight() * 2 / 5);
  655.                         return color;
  656.                 });
  657.         }
  658.        
  659.         if (layers[9].hasTileMap) {
  660.                 level.darkenLayer(layers[9], array<uint8>(), function(color) {
  661.                         color.setHSL(color.getHue(), color.getSat(), color.getLight() * 3 / 5);
  662.                         color.red = color.red + 30;
  663.                         return color;
  664.                 });
  665.         }
  666. }
  667.  
  668. void onLevelReload() {
  669.         MLLE::Palette.apply();
  670. }
  671.  
  672. void onPlayer(jjPLAYER@ play) {
  673.         level.handleLevelBoundaries(play);
  674.         level.handleLevelEffects(play);
  675.         level.handleKickingOnOneWaySlopes(play);
  676.         if (!jjLowDetail) level.hideBackgroundLayers(play);
  677.         level.timedFlyCarrot(play);
  678.         weaponHook.processPlayer(play);
  679. }
  680.  
  681. void onPlayerInput(jjPLAYER@ play) {
  682.         weaponHook.processPlayerInput(play);
  683. }
  684.  
  685. void onPlayerTimerEnd(jjPLAYER@ play) {
  686.         play.fly = FLIGHT::NONE;
  687. }
  688.  
  689. void onMain() {
  690.         level.alignObjects();
  691.         level.ashFallout();
  692.         weaponHook.processMain();
  693. }
  694.  
  695. void onReceive(jjSTREAM &in packet, int clientID) {
  696.         weaponHook.processPacket(packet, clientID);
  697. }
  698.  
  699. bool onDrawPlayerTimer(jjPLAYER@ play, jjCANVAS@ canvas) {
  700.         level.drawFlyCarrotTimer(play, canvas);
  701.         return true;
  702. }
  703.  
  704. void onFunction0(jjPLAYER@ play) {
  705.         inside[play.localPlayerID] = false;
  706. }
  707.  
  708. void onFunction1(jjPLAYER@ play) {
  709.         inside[play.localPlayerID] = true;
  710. }