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