Downloads containing ab21btl21.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Anniversary Bash 21 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 "ab21btl21.j2l"
  4. #pragma require "Aztec2.j2t"
  5. #pragma require "Heaven.j2t"
  6.  
  7. /*******************************
  8. A 2019 Mystic Legends Release!
  9. http://www.mysticlegends.org
  10. /******************************/
  11.  
  12. #pragma require "SEenergyblast.asc"
  13. #include "SEenergyblast.asc"
  14.  
  15. #pragma require "Nail.j2a"
  16. #pragma require "ROCKET1I.wav"
  17. #pragma require "SPIKE2.wav"
  18.  
  19. se::DefaultWeaponHook weaponHook;
  20. funcdef jjPALCOLOR ColorFunction(jjPALCOLOR);
  21.  
  22. const array<int> FoodAnims = {26, 89, 1, 71, 11, 74, 73, 12, 2, 48, 16, 21, 50, 13};
  23.  
  24. array<jjLAYER@> ClonedRainLayers;
  25.  
  26. void onLevelLoad() {
  27.  
  28.                 se::energyBlast.loadAnims(jjAnimSets[ANIM::CUSTOM[0]]);
  29.                 se::energyBlast.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BLOW});
  30.                 se::energyBlast.setAsWeapon(8, weaponHook);            
  31.                
  32.                 NailgunPrepStuff(); //goto 308
  33.                 jjWeapons[WEAPON::RF].comesFromGunCrates = false;      
  34.                
  35.                 jjObjectPresets[OBJECT::BOUNCERPOWERUP].direction = SPRITE::FLIPH;
  36.                 jjObjectPresets[OBJECT::RFPOWERUP].direction = SPRITE::FLIPNONE;
  37.                                
  38.                 jjObjectPresets[OBJECT::SWINGINGVINE].lightType = LIGHT::BRIGHT;
  39.                 jjObjectPresets[OBJECT::SWINGINGVINE].light = 8;
  40.                
  41.                 jjObjectPresets[OBJECT::BRIDGE].behavior = MyBridge;
  42.  
  43.                 jjLayers[4].generateSettableTileArea();
  44.  
  45.                 for (uint i = 0; i < FoodAnims.length; i++) {
  46.                         jjANIMFRAME@ frame = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PICKUPS].firstAnim + FoodAnims[i]].firstFrame];
  47.                         jjPIXELMAP(32+i*32, 0, 32, 32, 4).save(frame);
  48.                         frame.hotSpotX = -frame.width/2;
  49.                         frame.hotSpotY = -frame.height + 14;
  50.                         jjTileSet(4, 1+i, 0, 0);
  51.                 }
  52.                
  53.                 jjANIMFRAME@ grapeFrame = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PICKUPS].firstAnim + 38].firstFrame];
  54.                 jjPIXELMAP(32, 32, 32, 64, 4).save(grapeFrame);
  55.                 grapeFrame.hotSpotX = -grapeFrame.width/2;
  56.                 grapeFrame.hotSpotY = -grapeFrame.height;
  57.                 jjTileSet(4, 1, 1, 0);
  58.                 jjTileSet(4, 1, 2, 0);
  59.                
  60.                 //sorry, I tried to do this in a loop but it didn't work
  61.                 jjObjectPresets[OBJECT::CARROT].lightType =
  62.                 jjObjectPresets[OBJECT::FASTFIRE].lightType =
  63.                 jjObjectPresets[OBJECT::BOUNCERAMMO3].lightType =
  64.                 jjObjectPresets[OBJECT::ICEAMMO3].lightType =
  65.                 jjObjectPresets[OBJECT::SEEKERAMMO3].lightType =
  66.                 jjObjectPresets[OBJECT::TOASTERAMMO3].lightType =
  67.                 jjObjectPresets[OBJECT::GUN8AMMO3].lightType =
  68.                 jjObjectPresets[OBJECT::GUN9AMMO3].lightType =
  69.                 jjObjectPresets[OBJECT::SILVERCOIN].lightType =
  70.                 jjObjectPresets[OBJECT::SHARD].lightType = LIGHT::POINT;
  71.                                
  72.                 //jjObjectPresets[OBJECT::SOFTDRINK].determineCurAnim(ANIM::PLUS_COMMON, 7);
  73.                
  74.                 for (int i = 1; i < 255; i++) {
  75.                         if (jjObjectPresets[i].playerHandling == HANDLING::PICKUP) {
  76.                                 jjObjectPresets[i].behavior = CannotBeShotDown(jjObjectPresets[i].behavior);
  77.                         }
  78.                 }              
  79.                
  80.         jjANIMFRAME@ bridgeFrame = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::BRIDGE].firstAnim + 5].firstFrame];
  81.         jjPIXELMAP(33, 96, 16, 16, 4).save(bridgeFrame);
  82.                 bridgeFrame.hotSpotX = -bridgeFrame.width/2;
  83.                 bridgeFrame.hotSpotY = -bridgeFrame.height + 8;
  84.         jjTileSet(4, 1, 3, 0);
  85.        
  86.         jjANIMFRAME@ woodBridgeFrame = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::BRIDGE].firstAnim + 6].firstFrame];
  87.         jjPIXELMAP(42, 148, 14, 21, 4).save(woodBridgeFrame);
  88.                 woodBridgeFrame.hotSpotX = -woodBridgeFrame.width/2;
  89.                 woodBridgeFrame.hotSpotY = -woodBridgeFrame.height + 16;
  90.         jjTileSet(4, 1, 4, 0);
  91.                 jjTileSet(4, 1, 5, 0);
  92.                
  93.                 /*jjPIXELMAP rain(1,1);        
  94.                 jjANIMATION@ anim = jjAnimations[jjAnimSets[ANIM::COMMON].firstAnim + 2];
  95.                 for (uint frameID = 0; frameID < anim.frameCount; ++frameID) {
  96.                         jjANIMFRAME@ blank = jjAnimFrames[anim.firstFrame + frameID];
  97.                         rain.save(blank);
  98.                         blank.hotSpotX = -blank.width/2;
  99.                         blank.hotSpotY = -blank.height;
  100.                 }*/
  101.                
  102.                 ClonedRainLayers = jjLayersFromLevel("mlfingers.j2l", array<uint> = {1, 1, 1, 1, 1, 1});
  103.                 for (uint i = 0; i < ClonedRainLayers.length; i++) {
  104.                         ClonedRainLayers[i].spriteMode = SPRITE::BLEND_NORMAL;
  105.                         ClonedRainLayers[i].spriteParam = 24;
  106.                         ClonedRainLayers[i].xOffset = ClonedRainLayers[i].yOffset = jjRandom()%112;
  107.                 }              
  108.                 array<jjLAYER@> ClonedBigClouds = jjLayersFromLevel("mlfingers.j2l", array<uint> = {6, 6});            
  109.                 array<jjLAYER@> ClonedMountains = jjLayersFromLevel("mlfingers.j2l", array<uint> = {7});
  110.                
  111.                 ClonedBigClouds[0].xOffset = 112;
  112.                 ClonedBigClouds[0].yOffset = 96;
  113.                 ClonedBigClouds[0].xSpeed = ClonedBigClouds[0].ySpeed = 0.325f;        
  114.                 //ClonedBigClouds[0].spriteMode = SPRITE::TRANSLUCENTTILE;
  115.                
  116.                 ClonedBigClouds[1].xOffset = 32;
  117.                 ClonedBigClouds[1].yOffset = -4000;
  118.                 ClonedBigClouds[1].xSpeed = ClonedBigClouds[1].ySpeed = 1.25f;         
  119.                 //ClonedBigClouds[1].spriteMode = SPRITE::TRANSLUCENTTILE;
  120.                
  121.                 ClonedMountains[0].xSpeed = ClonedMountains[0].ySpeed = 0.15f;
  122.                 ClonedMountains[0].xOffset = 1500;
  123.                 ClonedMountains[0].yOffset = 16;
  124.                
  125.                 jjLayerOrderSet(array<jjLAYER@> = {
  126.                                         ClonedBigClouds[1],
  127.                                 jjLayers[1],
  128.                                         ClonedRainLayers[0],
  129.                                         ClonedRainLayers[1],
  130.                                         ClonedRainLayers[2],
  131.                                         ClonedRainLayers[3],
  132.                                         ClonedRainLayers[4],
  133.                                         ClonedRainLayers[5],           
  134.                                 jjLayers[3],
  135.                                 jjLayers[4],
  136.                                 jjLayers[5],
  137.                                 jjLayers[2],
  138.                                 jjLayers[6],
  139.                                         ClonedBigClouds[0],
  140.                                 jjLayers[7],
  141.                                         ClonedMountains[0],
  142.                                 jjLayers[8]
  143.                         }
  144.                 );
  145.                
  146.                 jjUseLayer8Speeds = true;
  147.                
  148.                 jjCharacters[CHAR::BIRD].canRun = true;
  149.                
  150.                 //jjSnowingType = SNOWING::RAIN;
  151. }
  152.  
  153. const float TOPS00 = 3*32;
  154. const float TOPS01 = 9*32;
  155. const float TOPS02 = 15*32;
  156.  
  157. const float FLOOR0 = 20*32;
  158. const float FLOOR1 = 36*32;
  159. const float FLOOR2 = 53*32;
  160. const float FLOOR3 = 70*32;
  161. const float FLOOR4 = 81*32;
  162. const float FLOOR5 = 97*32;
  163. const int LEVELHEIGHT = 3840;
  164.  
  165. const array<int> ColumnsToLock = {7, 33, 42, 69, 76, 102};
  166.  
  167. const int SIXTYSECONDS = 45*70;
  168. const int GODHEAD = 777*70;
  169.  
  170. void onPlayer(jjPLAYER@ play) {
  171.                
  172.                 weaponHook.processPlayer(play);
  173.        
  174.                 for (uint i = 0; i < ClonedRainLayers.length; i++) {           
  175.                                 if (play.yPos < 40*32) {
  176.                                         jjLayers[1].hasTiles = ClonedRainLayers[i].hasTiles = false;
  177.                                 }
  178.                                 else {
  179.                                         jjLayers[1].hasTiles = ClonedRainLayers[i].hasTiles = true;
  180.                                         jjLayers[1].spriteParam = ClonedRainLayers[i].spriteParam = int(30 * (play.yPos / LEVELHEIGHT));
  181.                                 }
  182.                 }
  183.                
  184.                 if (play.shieldType == SHIELD::LASER) {
  185.                                 for (int x = 0; x < 6; x++) {
  186.                                         for (int y = 30; y < 118; y++) {
  187.                                                 jjTileSet(4, ColumnsToLock[x], y, 1981);       
  188.                                         }
  189.                                 }
  190.                                
  191.                                 play.shieldTime = GODHEAD;
  192.                                 play.currWeapon = WEAPON::BLASTER;
  193.                 }
  194.                 else {                 
  195.                                 for (int x = 0; x < 6; x++) {
  196.                                         for (int y = 30; y < 118; y++) {
  197.                                                 jjTileSet(4, ColumnsToLock[x], y, 0);  
  198.                                         }
  199.                                 }
  200.                                
  201.                                 play.shieldTime = 0;
  202.                 }
  203.                
  204.                 if (!play.isSpectating) {
  205.                         if (play.yPos > FLOOR5) play.lighting = 72;
  206.                         else if (play.yPos > FLOOR4 && play.yPos < FLOOR5) play.lighting = 75;
  207.                         else if (play.yPos > FLOOR3 && play.yPos < FLOOR4) play.lighting = 79;
  208.                         else if (play.yPos > FLOOR2 && play.yPos < FLOOR3) play.lighting = 82;
  209.                         else if (play.yPos > FLOOR1 && play.yPos < FLOOR2) play.lighting = 89;
  210.                         else if (play.yPos > FLOOR0 && play.yPos < FLOOR1) play.lighting = 100;
  211.                        
  212.                         else if (play.yPos > TOPS02 && play.yPos < FLOOR0) play.lighting = 110;
  213.                         else if (play.yPos > TOPS01 && play.yPos < TOPS02) play.lighting = 118;
  214.                         else if (play.yPos > TOPS00 && play.yPos < TOPS01) play.lighting = 124;
  215.                         else if (play.yPos < TOPS00) play.lighting = 140;
  216.                 }
  217.                
  218.                 if (play.charCurr == CHAR::LORI) {
  219.                         jjAlert("Sorry, not this time!");
  220.                         play.morphTo(CHAR::JAZZ);
  221.                 }
  222.  
  223.                 /*if (play.charCurr == CHAR::BIRD2) {
  224.                         if (play.xSpeed > 0) {
  225.                                 play.xPos += 0.5f;
  226.                         }
  227.                         else if (play.xSpeed < 0) {
  228.                                 play.xPos -= 0.5f;
  229.                         }
  230.                        
  231.                         if (play.ySpeed > 0) {
  232.                                 play.yPos += 0.75f;
  233.                         }
  234.                         else if (play.ySpeed < 0) {
  235.                                 play.yPos -= 0.75f;
  236.                         }
  237.                 }*/
  238.                 if (play.timerState == TIMER::STARTED && play.timerTime <= 3*70 && play.timerTime > 0 && play.timerTime % 70 == 0) {
  239.                         jjSamplePriority(SOUND::COMMON_NOCOIN);
  240.                 }
  241.                
  242.                 play.noFire = play.invisibility;
  243. }
  244.  
  245. bool onDrawPlayerTimer(jjPLAYER@ play, jjCANVAS@ canvas) {
  246.         canvas.drawString(
  247.                         jjSubscreenWidth - 75,
  248.                 jjSubscreenHeight - 284,
  249.                 "" + (play.timerTime > 0? (play.timerTime + 70) / 70 : 0),
  250.                 STRING::LARGE,
  251.                 STRING::PALSHIFT,
  252.                 play.timerTime > 3*70?
  253.                 0 :
  254.                 jjGameTicks % 28 > 14?
  255.                 216 :
  256.                 232
  257.                 );
  258.                
  259.                 canvas.drawSprite(
  260.                         jjSubscreenWidth - 92,
  261.                         jjSubscreenHeight - 280,
  262.                         ANIM::BIRD,
  263.                         6,
  264.                         jjGameTicks / 6 % 8,
  265.                         0,
  266.                         SPRITE::PLAYER
  267.                 );
  268.         return true;
  269. }
  270.  
  271. void onPlayerTimerEnd(jjPLAYER@ play) {
  272.         play.morphTo(play.charOrig);
  273. }
  274.  
  275. void onFunction0(jjPLAYER@ play) {
  276.         play.showText("@@§0#You found Pandora's Box!");
  277. }
  278.  
  279. void onFunction1(jjPLAYER@ play) {
  280.         play.showText("@@§0Pandora's Box is only accessed from below...");
  281. }
  282.  
  283. void onFunction10(jjPLAYER@ play) {
  284.                 if (play.noclipMode && play.charCurr != CHAR::BIRD2) {
  285.                         play.noclipMode = false;
  286.                         play.morphTo(CHAR::BIRD2);
  287.                         jjSample(play.xPos, play.yPos, SOUND::COMMON_BUBBLGN1);
  288.                         play.timerStart(SIXTYSECONDS);
  289.                         play.showText("@@§0#Dare to fly where eagles soar!");
  290.                 }
  291. }
  292.  
  293. void onFunction100(jjPLAYER@ play) {
  294.         if (play.charCurr == CHAR::BIRD2) {
  295.                 play.timerTime = 0;
  296.                 play.morphTo(play.charOrig);
  297.         }
  298.         jjSample(play.xPos, play.yPos, SOUND::INTRO_BOEM2);
  299.         jjSample(play.xPos, play.yPos, SOUND::INTRO_IFEEL);
  300.         //jjSamplePriority(SOUND::DEVILDEVAN_WHISTLEDESCENDING2);
  301.         play.ballTime = 70;
  302.         play.xSpeed = 0;
  303.         play.ySpeed = 10;
  304.         play.blink = 99999;
  305.         play.shieldType = SHIELD::LASER;
  306.         play.shieldTime = GODHEAD;
  307. }
  308.  
  309. class CannotBeShotDown : jjBEHAVIORINTERFACE {
  310.         jjBEHAVIOR originalBehavior;
  311.         CannotBeShotDown(jjBEHAVIOR behavior) {
  312.                 originalBehavior = behavior;
  313.         }
  314.         void onBehave(jjOBJ@ obj) override {
  315.                 obj.behave(originalBehavior);
  316.                 if (obj.state == STATE::FLOATFALL)
  317.                         obj.state = STATE::FLOAT;
  318.                 if (obj.eventID == OBJECT::FULLENERGY)
  319.                         obj.xPos = obj.xOrg - 16;
  320.         }
  321.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
  322.                 obj.behavior = originalBehavior;
  323.                 if (bullet is null)
  324.                         player.objectHit(obj, force, obj.playerHandling);
  325.                 else
  326.                         bullet.objectHit(obj, obj.playerHandling);
  327.                 obj.behavior = CannotBeShotDown(obj.behavior);
  328.                 return true;
  329.         }
  330. }
  331.  
  332. void onMain() {
  333.         weaponHook.processMain();
  334. }
  335.  
  336. void onReceive(jjSTREAM &in packet, int clientID) {
  337.     weaponHook.processPacket(packet, clientID);
  338. }
  339.  
  340. bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ canvas) {
  341.     return weaponHook.drawAmmo(play, canvas);
  342. }
  343.  
  344. void onPlayerInput(jjPLAYER@ play) {
  345.     weaponHook.processPlayerInput(play);
  346.    
  347.     if (play.shieldType == SHIELD::LASER) {
  348.         play.keyDown = play.keyJump = false;
  349.         if (play.ballTime > 0) {
  350.                 play.keyLeft = play.keyRight = false;
  351.         }
  352.     }
  353. }
  354.  
  355. //nailgun stuff begins here
  356.  
  357. bool gameIsActive() {
  358.         return jjGameState == GAME::STARTED || jjGameState == GAME::OVERTIME;
  359. }
  360.  
  361. void NailgunPrepStuff() {
  362.         jjAnimSets[ANIM::CUSTOM[25]].load(0, "Nail.j2a");
  363.        
  364.         jjAnimations[jjAnimSets[ANIM::AMMO] + 49] = jjAnimations[jjAnimSets[ANIM::CUSTOM[25]] + 4];
  365.         jjAnimations[jjAnimSets[ANIM::AMMO] + 48] = jjAnimations[jjAnimSets[ANIM::CUSTOM[25]] + 5];
  366.        
  367.         //jjSampleLoad(SOUND::P2_CRUNCH, "f_ar3.wav");
  368.         jjSampleLoad(SOUND::P2_CRUNCH, "ROCKET1I.wav");
  369.         jjSampleLoad(SOUND::P2_FART, "SPIKE2.wav");    
  370.        
  371.         jjObjectPresets[OBJECT::RFBULLET].behavior = jjObjectPresets[OBJECT::RFBULLETPU].behavior = Nailgun();
  372.         jjObjectPresets[OBJECT::RFBULLET].var[6] = 16;
  373.         jjObjectPresets[OBJECT::RFBULLET].counterEnd = 60;
  374.         jjObjectPresets[OBJECT::RFBULLET].killAnim = jjObjectPresets[OBJECT::BLASTERBULLET].killAnim;
  375.         jjObjectPresets[OBJECT::RFBULLET].special = jjObjectPresets[OBJECT::RFBULLET].determineCurAnim(ANIM::CUSTOM[25], 0);
  376.         jjObjectPresets[OBJECT::RFBULLETPU].var[6] = 8 + 16;
  377.         jjObjectPresets[OBJECT::RFBULLETPU].counterEnd = 55;
  378.         jjObjectPresets[OBJECT::RFBULLETPU].killAnim = jjObjectPresets[OBJECT::BLASTERBULLET].killAnim;
  379.         jjObjectPresets[OBJECT::RFBULLETPU].special = jjObjectPresets[OBJECT::RFBULLETPU].determineCurAnim(ANIM::CUSTOM[25], 1);
  380.         jjObjectPresets[OBJECT::RFBULLET].lightType = jjObjectPresets[OBJECT::RFBULLETPU].lightType = LIGHT::POINT;
  381.        
  382.         jjObjectPresets[OBJECT::RFAMMO3].lightType = LIGHT::POINT;
  383.        
  384.         jjObjectPresets[OBJECT::RFAMMO15].determineCurAnim(ANIM::CUSTOM[25], 2);
  385.         jjObjectPresets[OBJECT::RFAMMO15].determineCurFrame();
  386.        
  387.         jjObjectPresets[OBJECT::RFPOWERUP].determineCurAnim(ANIM::CUSTOM[25], 3);
  388.         jjObjectPresets[OBJECT::RFPOWERUP].determineCurFrame();
  389.        
  390.         jjWeapons[WEAPON::RF].spread = SPREAD::NORMAL;
  391.         jjWeapons[WEAPON::RF].style = WEAPON::NORMAL;
  392.         jjWeapons[WEAPON::RF].defaultSample = false;
  393.        
  394.         jjANIMATION@ anim = jjAnimations[jjAnimSets[ANIM::AMMO] + 71];
  395.         for (uint i = 0; i < anim.frameCount; ++i) {
  396.                 jjANIMFRAME@ frame = jjAnimFrames[anim + i];
  397.                 jjPIXELMAP sprite(frame);
  398.                 for (uint x = 0; x < sprite.width; ++x)
  399.                         for (uint y = 0; y < sprite.height; ++y)
  400.                         if (sprite[x,y] != 0) sprite[x,y] = 0;
  401.                 sprite.save(frame);
  402.         }
  403. }
  404.  
  405. class Nailgun : jjBEHAVIORINTERFACE {
  406.         void onBehave(jjOBJ@ obj) {
  407.                 obj.behave(obj.state == STATE::EXPLODE? BEHAVIOR::BULLET : BEHAVIOR::RFBULLET, obj.state == STATE::EXPLODE? true:false);
  408.                 jjPLAYER@ creator = jjPlayers[obj.creatorID];
  409.                
  410.                 obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
  411.                
  412.                 obj.xAcc = (obj.eventID == OBJECT::RFBULLETPU? 0.4:0.35) * obj.direction;
  413.                 if (obj.ySpeed < 0 && obj.direction == 0 && obj.xSpeed == 0) obj.yAcc = -0.5;
  414.                
  415.                
  416.                 if (obj.state != STATE::EXPLODE) {
  417.                         if (obj.counter == 1 && creator.isLocal) {
  418.                                 //jjSample(creator.xPos, creator.yPos, SOUND::P2_CRUNCH, 48, obj.eventID == OBJECT::RFBULLETPU? 19000:17500);
  419.                                 jjSample(creator.xPos, creator.yPos, obj.eventID == OBJECT::RFBULLETPU? SOUND::P2_FART : SOUND::P2_CRUNCH, 48);
  420.                                 obj.var[2] = 0;
  421.                                 obj.playerHandling = HANDLING::PLAYERBULLET;
  422.                         }
  423.                        
  424.                         jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::CUSTOM[25], obj.eventID == OBJECT::RFBULLETPU? 1:0, 0, obj.var[0], 1, 1, SPRITE::NORMAL);
  425.                        
  426.                         float dx = jjLocalPlayers[0].xPos - obj.xPos, dy = jjLocalPlayers[0].yPos - obj.yPos;
  427.                         if ((dx * dx + dy * dy < 64 * 24) && !creator.isLocal && jjLocalPlayers[0].blink == 0 && (jjLocalPlayers[0].team != creator.team || jjFriendlyFire || jjGameMode != GAME::CTF) && gameIsActive()) {
  428.                                 jjLocalPlayers[0].xPos = obj.xPos - (24 * obj.direction);
  429.                                 jjLocalPlayers[0].ySpeed = obj.ySpeed;
  430.                         }
  431.                        
  432.                         if (jjMaskedPixel(int(obj.xPos + obj.xSpeed + obj.var[7] / 65536.f), int(obj.yPos))) {
  433.                                 obj.xSpeed = 0;
  434.                                 obj.var[7] = 0;
  435.                                 obj.playerHandling = HANDLING::PARTICLE;
  436.                                 obj.bePlatform(obj.xPos, obj.yPos, 32, 8);
  437.                                 if (obj.var[2] == 0) {
  438.                                         jjSample(obj.xPos, obj.yPos, SOUND::COMMON_METALHIT, 0, 0);
  439.                                         obj.counter = 1;
  440.                                         if (obj.eventID == OBJECT::RFBULLETPU) obj.counterEnd = 90;
  441.                                         obj.var[2] = 1;
  442.                                 }
  443.                         }
  444.                         else if (jjMaskedPixel(int(obj.xPos), int(obj.yPos + obj.ySpeed))) {
  445.                                 obj.ySpeed = 0;
  446.                                 obj.playerHandling = HANDLING::PARTICLE;
  447.                                 if (obj.var[2] == 0) {
  448.                                         jjSample(obj.xPos, obj.yPos, SOUND::COMMON_METALHIT, 0, 0);
  449.                                         obj.counter = 1;
  450.                                         if (obj.eventID == OBJECT::RFBULLETPU) obj.counterEnd = 90;
  451.                                         obj.var[2] = 1;
  452.                                 }
  453.                         }
  454.                 } else {
  455.                         obj.clearPlatform();
  456.                         obj.var[2] = 0;
  457.                         obj.counterEnd = obj.eventID == OBJECT::RFBULLETPU? 55:60;
  458.                 }
  459.         }
  460. }
  461.  
  462. //violet's witchcraft bridges
  463.  
  464. enum BridgeVariables { PhysicalWidth, MaximumSagDistance, VisualWidth, FirstObjectIDOfPlatformForSplitscreenPlayers, Angle = FirstObjectIDOfPlatformForSplitscreenPlayers + 3 };
  465. void MyBridge(jjOBJ@ obj) {
  466. //first, check collision with bridge
  467.  
  468.         if (obj.state==STATE::START) {
  469.                 obj.state=STATE::STILL;
  470.  
  471.                 const uint xTile = uint(obj.xOrg) >> 5, yTile = uint(obj.yOrg) >> 5;
  472.                 obj.var[BridgeVariables::PhysicalWidth] = 32 * jjParameterGet(xTile,yTile, 0,4);
  473.                 obj.curAnim = jjAnimSets[ANIM::BRIDGE].firstAnim + (jjParameterGet(xTile,yTile, 4,3) % 7); //"Type" parameter... % 7 because there are only seven bridge types for some reason.
  474.  
  475.                 int toughness = jjParameterGet(xTile,yTile, 7,4);
  476.                 if (toughness == 0) toughness = 4; //default toughness of 4, to avoid dividing by zero
  477.                 obj.var[BridgeVariables::MaximumSagDistance] = obj.var[BridgeVariables::PhysicalWidth] / toughness;
  478.                
  479.                 //int heightInTiles = jjParameterGet(xTile,yTile, 11,-5);
  480.                 int heightInTiles = jjParameterGet(xTile, yTile-1, 0, -8);
  481.                 obj.var[BridgeVariables::Angle] = int(atan2(heightInTiles, obj.var[BridgeVariables::PhysicalWidth] / 32) * 162.974662f);
  482.                 obj.xAcc = jjCos(obj.var[BridgeVariables::Angle]);
  483.                 obj.yAcc = jjSin(obj.var[BridgeVariables::Angle]);
  484.                
  485.                 { //determine how wide the bridge is, in drawn pixels (will always be >= how wide it is in mask pixels)
  486.                         int frameID = 0;
  487.                         int bridge_len = 0;
  488.                         const int numberOfFramesUsedByAnimation = jjAnimations[obj.curAnim].frameCount;
  489.                         const uint firstBridgeFrameID = jjAnimations[obj.curAnim].firstFrame;
  490.                         while (true) {
  491.                                 if ((bridge_len += jjAnimFrames[firstBridgeFrameID + frameID].width) >= obj.var[BridgeVariables::PhysicalWidth])
  492.                                         break;
  493.                                        
  494.                                 if (++frameID >= numberOfFramesUsedByAnimation)
  495.                                         frameID = 0;
  496.                         }
  497.                         obj.var[BridgeVariables::VisualWidth] = bridge_len;
  498.                 }
  499.  
  500.                 obj.xOrg -= 16; //start at left edge of tile, not center
  501.                 obj.yOrg -= 6; //worth noting that bridges are never deactivated, so we don't need to worry about where this gets moved to at all
  502.                
  503.                 for (int i = 1; i < jjLocalPlayerCount; ++i) { //this portion has no native JJ2 counterpart, because the API for platforms is still pretty limited
  504.                         const int platformObjectID = jjAddObject(OBJECT::BRIDGE, 0,0, obj.objectID,CREATOR::OBJECT, BEHAVIOR::BEES);
  505.                         jjOBJ@ platform = jjObjects[platformObjectID];
  506.                         platform.deactivates = false;
  507.                         platform.curFrame = jjAnimations[obj.curAnim].firstFrame;
  508.                         obj.var[BridgeVariables::FirstObjectIDOfPlatformForSplitscreenPlayers - 1 + i] = platformObjectID;
  509.                 }
  510.         }
  511.        
  512.         obj.clearPlatform();
  513.         for (int i = 1; i < jjLocalPlayerCount; ++i)
  514.                 jjObjects[obj.var[BridgeVariables::FirstObjectIDOfPlatformForSplitscreenPlayers - 1 + i]].clearPlatform();
  515.  
  516.         array<int> pressXPosition;
  517.         array<jjPLAYER@> pressPlayer;
  518.         for (int playerID = 0; playerID < 32; ++playerID) {
  519.                 jjPLAYER@ play = jjPlayers[playerID];
  520.                 if (play.isActive && play.shieldType != SHIELD::LASER && jjObjects[play.platform].eventID != OBJECT::BURGER) { //all active players are valid, even if isLocal is false
  521.                         const int tx = int(play.xPos-obj.xOrg);
  522.                         const int ty = int(play.yPos-obj.yOrg - obj.yAcc / obj.xAcc * tx);
  523.  
  524.                         if ((tx >= 0) && (tx <= obj.var[BridgeVariables::PhysicalWidth]) && //player is within bridge area (horizontal)
  525.                                 (ty > -32) && (ty < obj.var[BridgeVariables::MaximumSagDistance]) && //(and vertical) //-32 was -24
  526.                                 (play.ySpeed > -1.f)) //not jumping, using a spring, etc.
  527.                         {
  528.                                 pressXPosition.insertLast(tx);
  529.                                 pressPlayer.insertLast(play);
  530.                         }
  531.                 }
  532.         }
  533.        
  534.         float max, amp, leftamp, rightamp;
  535.         int     leftmostPressedX, rightmostPressedX;
  536.  
  537.         if (pressPlayer.length != 0) {
  538.                 if (pressPlayer.length > 1) {
  539.                         leftmostPressedX=12312312;
  540.                         rightmostPressedX=0;
  541.                         uint t = 0;
  542.                         do {
  543.                                 const int pressedX = pressXPosition[t];
  544.                                 if (pressedX < leftmostPressedX)
  545.                                         leftmostPressedX = pressedX;
  546.                                 if (pressedX > rightmostPressedX)
  547.                                         rightmostPressedX = pressedX;
  548.                         } while (++t < pressPlayer.length);
  549.  
  550.                         leftamp =  obj.var[BridgeVariables::MaximumSagDistance]*jjSin((512* leftmostPressedX)/obj.var[BridgeVariables::PhysicalWidth]);
  551.                         rightamp = obj.var[BridgeVariables::MaximumSagDistance]*jjSin((512*rightmostPressedX)/obj.var[BridgeVariables::PhysicalWidth]);
  552.                 }
  553.                
  554.                 uint t = 0;
  555.                 uint numberOfLocalPlayersNeedingPlatforms = 0;
  556.                 do {
  557.                         const auto pressedPosition = pressXPosition[t];
  558.                         if (pressPlayer.length == 1)
  559.                                 max = obj.var[BridgeVariables::MaximumSagDistance] * jjSin((512 * pressedPosition) / obj.var[BridgeVariables::PhysicalWidth]); //same formula as side amps above, but for single player bridges
  560.                         else if ((pressedPosition>leftmostPressedX) && (pressedPosition<rightmostPressedX))
  561.                                 max = leftamp+(rightamp-leftamp)*(pressedPosition-leftmostPressedX)/(rightmostPressedX-leftmostPressedX);
  562.                         else
  563.                                 max = obj.var[BridgeVariables::MaximumSagDistance]*jjSin((512 * pressedPosition)/obj.var[BridgeVariables::PhysicalWidth]);
  564.  
  565.                         jjPLAYER@ play = pressPlayer[t];
  566.                         play.yPos = obj.yOrg + obj.yAcc / obj.xAcc * pressedPosition + max - 24;
  567.                         if (play.isLocal) {
  568.                                 jjOBJ@ platform = (numberOfLocalPlayersNeedingPlatforms == 0) ? obj : jjObjects[obj.var[BridgeVariables::FirstObjectIDOfPlatformForSplitscreenPlayers - 1 + numberOfLocalPlayersNeedingPlatforms]];
  569.                                 platform.bePlatform(
  570.                                         platform.xPos = play.xPos,
  571.                                         platform.yPos = play.yPos + 24
  572.                                 );
  573.                                 //platform.draw();
  574.                                 if (play.buttstomp < 120)
  575.                                         play.buttstomp = 120;
  576.                                 numberOfLocalPlayersNeedingPlatforms += 1;
  577.                         }
  578.                 } while (++t < pressPlayer.length);
  579.         }
  580.  
  581.         //draw
  582.         float bridge_len_x = 0, bridge_len_y = 0;
  583.         int frameID = 0;
  584.         const int numberOfFramesUsedByAnimation = jjAnimations[obj.curAnim].frameCount;
  585.         while (true) {  //cooba - change specifically for mlfingers.j2l conditions
  586.                 obj.curFrame = jjAnimations[obj.curAnim].firstFrame + frameID;
  587.                 const jjANIMFRAME@ frame = jjAnimFrames[obj.curFrame];
  588.                
  589.                 float plankOffset = 0; //"straight bridge, or terugveren"
  590.                 if (pressPlayer.length == 1) {
  591.                         const auto pressedPosition = pressXPosition[0];
  592.                         plankOffset = ((bridge_len_x<pressedPosition) ?
  593.                                 (max*jjSin(int(256*bridge_len_x)/pressedPosition)) : //left
  594.                                 (max*jjCos(int(256*(bridge_len_x-pressedPosition))/(obj.var[BridgeVariables::VisualWidth]-pressedPosition) ))
  595.                         );
  596.                 } else if (pressPlayer.length > 1) {
  597.                         if (bridge_len_x < leftmostPressedX)
  598.                                 plankOffset = (leftamp*jjSin(int(256*bridge_len_x)/leftmostPressedX));
  599.                         else if (bridge_len_x > rightmostPressedX)
  600.                                 plankOffset = (rightamp*jjCos(int(256*(bridge_len_x-rightmostPressedX))/(obj.var[BridgeVariables::VisualWidth]-rightmostPressedX) ));
  601.                         else
  602.                                 plankOffset = leftamp+(rightamp-leftamp)*(bridge_len_x-leftmostPressedX)/(rightmostPressedX-leftmostPressedX);
  603.                 }
  604.                 jjDrawRotatedSpriteFromCurFrame(
  605.                         obj.xOrg + bridge_len_x - frame.hotSpotX,
  606.                         obj.yOrg + bridge_len_y + plankOffset,
  607.                         obj.curFrame,
  608.                         -obj.var[BridgeVariables::Angle],
  609.                         1,
  610.                         1,
  611.                         jjLocalPlayers[0].shieldType == SHIELD::LASER? SPRITE::TRANSLUCENTPALSHIFT : SPRITE::NORMAL,
  612.                         96
  613.                 );
  614.  
  615.                 if (int(bridge_len_x += obj.xAcc * frame.width) >= obj.var[BridgeVariables::PhysicalWidth])
  616.                         break;
  617.                 bridge_len_y += obj.yAcc * frame.width;
  618.                        
  619.                 if (++frameID >= numberOfFramesUsedByAnimation)
  620.                         frameID = 0;
  621.         }
  622. }