Downloads containing SwitchTestV.j2as

Downloads
Name Author Game Mode Rating
JJ2+ Only: Mighty Switch Test!Featured Download Violet CLM Test 8.4 Download file

File preview

  1. #pragma offer "SUCCESSF.WAV"
  2. #pragma offer "TC_TRANS.WAV"
  3.  
  4. array<int> SwitchesPerLevel;
  5. array<CHAR::Char> CharactersPerLevel;
  6.  
  7. array<bool> TriggerColorsOld(3, true);
  8.  
  9. class Point {
  10.         float x; float y;
  11.         Point(){}
  12.         Point(int xx, int yy) {
  13.                 x = xx * 32.f + 16;
  14.                 y = yy * 32.f + 16;
  15.         }
  16. }
  17. array<Point> TargetsPerLevel;
  18.  
  19. void onLevelLoad() {
  20.         jjUseLayer8Speeds = true;
  21.        
  22.         jjObjectPresets[OBJECT::ICEBULLET].behavior = Switch;
  23.         jjWeapons[WEAPON::ICE].defaultSample = false;
  24.         jjWeapons[WEAPON::BLASTER].infinite = false;
  25.         jjWeapons[WEAPON::BLASTER].replenishes = false;
  26.        
  27.         jjObjectPresets[OBJECT::MORPH].behavior = InfiniteMonitor;
  28.         jjObjectPresets[OBJECT::SPARK].behavior = Electricity;
  29.         jjObjectPresets[OBJECT::SPARK].lightType = LIGHT::POINT2;
  30.         jjObjectPresets[OBJECT::SPARK].playerHandling = HANDLING::PARTICLE;
  31.        
  32.         jjObjectPresets[OBJECT::BURGER].determineCurAnim(ANIM::TWEEDLE, 7);
  33.         jjObjectPresets[OBJECT::BURGER].playerHandling = HANDLING::SPECIAL;
  34.         jjObjectPresets[OBJECT::BURGER].scriptedCollisions = true;
  35.         jjObjectPresets[OBJECT::BURGER].energy = 5;
  36.         jjObjectPresets[OBJECT::BURGER].behavior = Tweedle;
  37.         jjObjectPresets[OBJECT::BURGER].lightType = LIGHT::NORMAL;
  38.         jjObjectPresets[OBJECT::BURGER].light = 17;
  39.         jjObjectPresets[OBJECT::BURGER].direction = -1;
  40.        
  41.         jjObjectPresets[OBJECT::APPLE].behavior = MovingTarget;
  42.         jjObjectPresets[OBJECT::APPLE].deactivates = false;
  43.         jjObjectPresets[OBJECT::APPLE].playerHandling = HANDLING::PARTICLE;
  44.         jjObjectPresets[OBJECT::APPLE].lightType = LIGHT::BRIGHT;
  45.         jjObjectPresets[OBJECT::APPLE].light = 14;
  46.        
  47.         jjObjectPresets[OBJECT::FLICKERGEM].var[2] = 17;
  48.         jjObjectPresets[OBJECT::FLICKERGEM].playerHandling = HANDLING::DELAYEDPICKUP;
  49.         jjObjectPresets[OBJECT::FLICKERGEM].points = 0;
  50.        
  51.         jjSampleLoad(SOUND::COMMON_HARP1, "SUCCESSF.WAV");
  52.         jjSampleLoad(SOUND::COMMON_NOCOIN, "TC_TRANS.WAV");
  53.        
  54.         jjAnimSets[ANIM::FLARE].load();
  55.        
  56.         jjGenerateSettableTileArea(5, 0, 0, jjLayerWidth[5], jjLayerHeight[5]);
  57.        
  58.         for (int x = 0; jjEventGet(x, 0) != 0; ++x) {
  59.                 const uint16 tileID = jjTileGet(4, x, 0);
  60.                 if (tileID == 50) CharactersPerLevel.insertLast(CHAR::SPAZ);
  61.                 else if (tileID == 60) CharactersPerLevel.insertLast(CHAR::JAZZ);
  62.                 else if (tileID == 40) CharactersPerLevel.insertLast(jjIsTSF ? CHAR::LORI : CHAR::JAZZ); //I guess
  63.                 else CharactersPerLevel.insertLast(CHAR::FROG); //placeholder
  64.                 SwitchesPerLevel.insertLast(jjParameterGet(x, 0, 0, -8));
  65.                 LaserBlockArraysPerLevel.insertLast(array<LaserBlock>());
  66.         }
  67.         TargetsPerLevel.resize(LaserBlockArraysPerLevel.length + 1);
  68.        
  69.         for (int x = LayerWidth - 1; x >= 0; --x)
  70.                 for (int y = LayerHeight - 1; y >= 0; --y) {
  71.                         const uint8 eventID = jjEventGet(x, y);
  72.                         if (eventID == OBJECT::APPLE) {
  73.                                 SwitchBlocks.insertLast(SwitchBlock(x, y));
  74.                                 jjEventSet(x, y, 0);
  75.                         } else if (eventID == OBJECT::BANANA) {
  76.                                 LaserBlockArraysPerLevel[jjParameterGet(x, y, 0, 5)].insertLast(LaserBlock(x, y));
  77.                                 jjEventSet(x, y, 0);
  78.                         } else if (eventID == AREA::WARPTARGET) {
  79.                                 const uint8 warpID = jjParameterGet(x, y, 0, 8);
  80.                                 if (warpID >= 200) {
  81.                                         TargetsPerLevel[warpID - 200] = Point(x, y);
  82.                                 }
  83.                         }
  84.                         if (jjTileGet(4, x, y) == 17 | TILE::ANIMATED) { //warp
  85.                                 jjTileSet(4, x, y, 0);
  86.                                 jjTileSet(5, x, y, 17 | TILE::ANIMATED);
  87.                         }
  88.                 }
  89.        
  90.         int tileSourceID = 260;
  91.         jjANIMATION@ animation = jjAnimations[jjAnimSets[ANIM::CUSTOM[0]].allocate(array<uint> = {12})];
  92.         int curFrame = animation.firstFrame;
  93.         for (uint frameID = 0; frameID < animation.frameCount; ) {
  94.                 jjPIXELMAP fullTile(tileSourceID); tileSourceID += 10;
  95.                 jjPIXELMAP quarterTile(16, 16);
  96.                 for (uint x = 0; x < quarterTile.width; ++x)
  97.                         for (uint y = 0; y < quarterTile.height; ++y)
  98.                                 quarterTile[x,y] = fullTile[x,y];
  99.                 for (int repetitionCount = (frameID == 0 || frameID == 6) ? 4 : 1; repetitionCount > 0; --repetitionCount) {
  100.                         jjANIMFRAME@ frame = jjAnimFrames[curFrame++];
  101.                         quarterTile.save(frame);
  102.                         frame.hotSpotX = -8; frame.hotSpotY = -4;
  103.                         ++frameID;
  104.                 }
  105.         }
  106.         jjAnimations[jjAnimSets[ANIM::AMMO] + 29] = animation; //ice
  107.         //jjAnimations[jjAnimSets[ANIM::PICKUPS] + 29] = animation; //jazz gun
  108.         //jjAnimations[jjAnimSets[ANIM::PICKUPS] + 30] = animation; //spaz gun
  109.         //if (jjIsTSF)
  110.         //      jjAnimations[jjAnimSets[ANIM::PLUS_AMMO] + 5] = animation; //lori gun
  111.  
  112.         /*if (jjObjectCount > 1) { //Load Game
  113.                 WarpID = jjLocalPlayers[0].score - 1;
  114.                 for (int i = jjObjectCount - 1; i >= 1; --i)
  115.                         jjObjects[i].behavior = jjObjectPresets[jjObjects[i].eventID].behavior;
  116.         }*/
  117.        
  118.         jjAddObject(OBJECT::APPLE, 0, 0); //target
  119. }
  120. void onLevelBegin() {
  121.         jjWeapons[WEAPON::ICE].allowed = true;
  122.         jjWeapons[WEAPON::ICE].allowedPowerup = true;
  123.        
  124.         jjPLAYER@ play = jjLocalPlayers[0];
  125.         play.spriteMode = SPRITE::INVISIBLE;
  126.         play.lightType = LIGHT::NONE;
  127.         play.ammo[WEAPON::BLASTER] = 0;
  128.        
  129.         onFunction0(play, 0); //play.score);
  130.        
  131.         if (jjLocalPlayerCount > 1)
  132.                 jjAlert("|This level is not designed for splitscreeners!");
  133. }
  134. int QuakeLayer4 = 0;
  135. void onMain() {
  136.         for (int i = 0; i < 32; ++i) {
  137.                 jjPLAYER@ play = jjPlayers[i];
  138.                 if (play.isInGame && (play.blink == 0 || ((jjRenderFrame >> 2) & 1) == 1)) {
  139.                         if (play.isLocal && crispyFried)
  140.                                 continue;
  141.                         else if (play.isLocal && suckerOn) {
  142.                                 jjANIMATION@ BallAnim = jjAnimations[jjAnimSets[play.setID] + RABBIT::ROLLING];
  143.                                 jjDrawSpriteFromCurFrame(play.xOrg, play.yOrg, BallAnim.firstFrame + ((jjGameTicks >> 2) % BallAnim.frameCount), play.direction, SPRITE::PLAYER, i, 5);
  144.                         } else if (play.isLocal && knockedIntoScreen != 0) {
  145.                                 jjANIMATION@ FallAnim = jjAnimations[jjAnimSets[play.setID] + RABBIT::FALL];
  146.                                 knockedIntoScreen += 0.2;
  147.                                 float scale = knockedIntoScreen;
  148.                                 if (scale > 3.0f)
  149.                                         scale = 3.0f;
  150.                                 //else
  151.                                         //play.cameraFreeze(play.cameraX + (jjRandom() % 7) - 3, play.cameraY + (jjRandom() % 7) - 3, false, true);
  152.                                 jjDrawResizedSprite(play.xOrg, play.yOrg, ANIM::AMMO, 5, int(scale * 2), scale, scale, SPRITE::SINGLEHUE, 210, 1);
  153.                                 jjDrawRotatedSpriteFromCurFrame(play.xOrg, play.yOrg + knockedIntoScreen * 2, FallAnim.firstFrame + ((jjGameTicks >> 3) % FallAnim.frameCount), int(knockedIntoScreen * 4 * play.direction), scale, scale, SPRITE::PLAYER, i, 1);
  154.                         } else
  155.                                 jjDrawSpriteFromCurFrame(play.xPos, play.yPos, play.curFrame, play.direction, SPRITE::PLAYER, i, 5);
  156.                         //jjDrawTile(int(play.xPos / 32) * 32, int(play.yPos / 32) * 32, 51);
  157.                         //jjDrawPixel(play.xPos, play.yPos, 255);
  158.                         //jjDrawString(play.xPos, play.yPos - 50, "" + (int(play.xPos) & 31));
  159.                         //jjDrawString(play.xPos, play.yPos - 30, "" + (int(play.yPos) & 31));
  160.                 }
  161.         }
  162.         if (QuakeLayer4 > 0) {
  163.                 if (--QuakeLayer4 == 0) {
  164.                         jjLayerXOffset[4] = 0;
  165.                         jjLayerYOffset[4] = 0;
  166.                 } else {
  167.                         jjLayerXOffset[4] = (jjRandom() & 7) - 3.5;
  168.                         jjLayerYOffset[4] = (jjRandom() & 7) - 3.5;
  169.                 }
  170.         }
  171.         { //update all special blocks
  172.                 const bool atLeastOneColorChanged =
  173.                         TriggerColorsOld[0] != jjTriggers[0] ||
  174.                         TriggerColorsOld[1] != jjTriggers[1] ||
  175.                         TriggerColorsOld[2] != jjTriggers[2];
  176.                 const bool updateTubeDirections = (jjGameTicks % 70) == 69; //once a second
  177.                 if (atLeastOneColorChanged)
  178.                         for (int i = SwitchBlocks.length - 1; i >= 0; --i) {
  179.                                 SwitchBlocks[i].switchTile();
  180.                         }
  181.                 if (updateTubeDirections)
  182.                         for (int i = SwitchBlocks.length - 1; i >= 0; --i) {
  183.                                 SwitchBlock@ block = SwitchBlocks[i];
  184.                                 if (updateTubeDirections && block.TubeBlock)
  185.                                         block.changeDirection();
  186.                         }
  187.                 for (int i = LaserBlockArraysPerLevel.length - 1; i >= 0; --i) {
  188.                         array<LaserBlock>@ lasers = LaserBlockArraysPerLevel[i];
  189.                         for (int j = lasers.length - 1; j >= 0; --j) {
  190.                                 if (i == WarpID) {
  191.                                         if (updateTubeDirections || atLeastOneColorChanged)
  192.                                                 lasers[j].updatePath();
  193.                                         lasers[j].draw();
  194.                                 } else
  195.                                         lasers[j].dead();
  196.                         }
  197.                 }
  198.                 if (atLeastOneColorChanged)
  199.                         for (int i = 0; i < 3; ++i)
  200.                                 TriggerColorsOld[i] = jjTriggers[i];
  201.         }
  202. }
  203.  
  204. bool suckerOn = false;
  205. float suckerSpeedX = 0;
  206. float suckerSpeedY = 0;
  207. int lastSuckTile = 0;
  208. void suckPlayer(jjPLAYER@ play, int xSpeed, int ySpeed) {
  209.         if (lastSuckTile != play.currTile) {
  210.                 lastSuckTile = play.currTile;
  211.                 suckerSpeedX = xSpeed * SuckerSpeedSpeed;
  212.                 suckerSpeedY = ySpeed * SuckerSpeedSpeed;
  213.                 play.xPos = play.xOrg = int(play.xPos / 32) * 32 + 15;
  214.                 play.yPos = play.yOrg = int(play.yPos / 32) * 32 + 15;
  215.                 suckerOn = true;
  216.         }
  217. }
  218. void unsuckPlayer(jjPLAYER@ play) {
  219.         suckerOn = false;
  220.         lastSuckTile = 0;
  221.         play.xSpeed = play.xAcc = play.ySpeed = play.yAcc = 0;
  222. }
  223. void onBelt(jjPLAYER@ play, int dir) {
  224.         if (play.keyJump) {
  225.                 play.xSpeed = 0;
  226.         } else {
  227.                 play.xSpeed = dir * 2;
  228.                 play.direction = dir;
  229.         }
  230.         play.keyLeft = play.keyRight = false;
  231. }
  232. int getCurrTileValue(int x, int y) {
  233.         return (x >> 5) + (y >> 5 << 16);
  234. }
  235. bool maskedPixel(int x, int y) {
  236.         x += int(suckerSpeedX * 4) - 2;
  237.         y += int(suckerSpeedY * 4) + 4;
  238.         return getCurrTileValue(x, y) != lastSuckTile && jjEventGet(x / 32, y / 32) != AREA::ONEWAY && jjMaskedPixel(x, y);
  239. }
  240. int warpInsideTile(int xTile, int yTile) {
  241.         const uint16 tileID = jjTileGet(4, xTile, yTile);
  242.         if (tileID == 40 || tileID == 50 || tileID == 60) //special block came into solidity
  243.                 return 1;
  244.         else if (tileID == 10 && jjEventGet(xTile, yTile) != AREA::ONEWAY) //wallclimbing
  245.                 return 2;
  246.         else if (tileID == (4 | TILE::ANIMATED)) //tube block
  247.                 return -1;
  248.         return 0;
  249. }
  250. int warpInsidePixel(float x, float y) {
  251.         return warpInsideTile(int(x) / 32, int(y) / 32);
  252. }
  253. const float SuckerSpeedSpeed = 4.f;
  254. uint16 floorTileID = 0;
  255. uint SpendFramesCheckingIfPlayerIsStuck = 0;
  256. float knockedIntoScreen = 0.f;
  257. bool crispyFried = false;
  258. bool warping = false;
  259. void onPlayer(jjPLAYER@ play) {
  260.         if (!jjLowDetail) {
  261.                 uint rand = jjRandom();
  262.                 if ((rand & 3) == 1) {
  263.                         rand >>= 2;
  264.                         const uint xOffset = rand % jjResolutionWidth;
  265.                         rand >> 10;
  266.                         const uint yOffset = rand % jjResolutionHeight;
  267.                         rand >>= 9;
  268.                         const uint xTile = uint(play.cameraX + xOffset) / 32;
  269.                         const uint yTile = uint(play.cameraY + yOffset) / 32;
  270.                         if (jjTileGet(4, xTile, yTile) == 10) { //normal wall
  271.                                 jjAddObject(OBJECT::SPARK, xTile * 32 + 16, yTile * 32 + 16);
  272.                         }
  273.                 }
  274.         }
  275.        
  276.         if (!play.isInGame || play.xPos < 0 || play.yPos < 0) //spectating
  277.                 return;
  278.         play.currWeapon = WEAPON::ICE;
  279.         floorTileID = 0;
  280.         if (attackingWildly) {
  281.                 play.keyDown = play.ySpeed >= 0;
  282.                 play.direction = -1;
  283.                 play.keyUp = play.keyLeft = play.keyRight = play.keyFire = play.keySelect = play.keyJump = play.keyRun = false;
  284.         } else if (Endgame) {
  285.                 play.keyFire = false;
  286.                 const int timeTillFire = jjGameTicks % 210; //every third second
  287.                 if (timeTillFire == 209)
  288.                         play.fireBullet(WEAPON::ICE, false, false);
  289.                 else if (timeTillFire == 209 - 35 || timeTillFire == 209 - 70 || timeTillFire == 209 - 105)
  290.                         //jjSample(play.xPos, play.yPos, SOUND::COMMON_COIN);
  291.                         jjSample(play.xPos, play.yPos, SOUND::COMMON_BELL_FIRE2);
  292.                 if (timeTillFire >= 209 - 105) {
  293.                         const int frameID = ((timeTillFire + 1) % 35) / 2;
  294.                         if (frameID < 6)
  295.                                 jjDrawSprite(play.xPos, play.yPos, ANIM::FLARE, 0, frameID, 0, SPRITE::TRANSLUCENTCOLOR, 15, 1);
  296.                 }
  297.         }
  298.         if (warping && play.warpID == 0) {
  299.                 if (crispyFried || knockedIntoScreen != 0)
  300.                         play.blink = 70;
  301.                 knockedIntoScreen = 0;
  302.                 crispyFried = false;
  303.                 warping = false;
  304.                 play.cameraUnfreeze();
  305.                
  306.                 jjTriggers[0] = jjTriggers[1] = jjTriggers[2] = false;
  307.                
  308.                 array<LaserBlock>@ lasers = LaserBlockArraysPerLevel[WarpID];
  309.                         for (int i = lasers.length - 1; i >= 0; --i)
  310.                                 lasers[i].countdownToDestruction = 0; //restore to life
  311.         }
  312.         if (SpendFramesCheckingIfPlayerIsStuck > 0) {
  313.                 --SpendFramesCheckingIfPlayerIsStuck;
  314.                 if (!warping && warpInsidePixel(play.xPos, play.yPos) == 0) {
  315.                         const int truncatedX = int(play.xPos) & 31;
  316.                         if (truncatedX < 12) {
  317.                                 const int shouldWarp = warpInsidePixel(play.xPos - 32, play.yPos);
  318.                                 if (shouldWarp >= 1)
  319.                                         play.xPos += (12 - truncatedX); //extract
  320.                                 else if (shouldWarp == -1)
  321.                                         play.xPos -= 32; //squeeze into tube
  322.                         } else if (truncatedX > 20) {
  323.                                 const int shouldWarp = warpInsidePixel(play.xPos + 32, play.yPos);
  324.                                 if (shouldWarp >= 1)
  325.                                         play.xPos -= (truncatedX - 20);
  326.                                 else if (shouldWarp == -1)
  327.                                         play.xPos += 32;
  328.                         }
  329.                         const int truncatedY = int(play.yPos) & 31;
  330.                         if (truncatedY > 12) {
  331.                                 int shouldWarp = warpInsidePixel(play.xPos, play.yPos + 32);
  332.                                 if (shouldWarp == 0) {
  333.                                         if (truncatedX < 12)
  334.                                                 shouldWarp = warpInsidePixel(play.xPos - 32, play.yPos + 32);
  335.                                         else if (truncatedX > 20)
  336.                                                 shouldWarp = warpInsidePixel(play.xPos + 32, play.yPos + 32);
  337.                                 }
  338.                                 if (shouldWarp >= 1)
  339.                                         play.yPos -= (truncatedY - 12);
  340.                                 else if (shouldWarp == -1)
  341.                                         play.yPos += 32;
  342.                         } /*else if (truncatedY < 4 || truncatedY ) {
  343.                                 if (jjMaskedPixel(int(play.xPos), int(play.yPos - 32)))
  344.                                         play.yPos += (4 - truncatedY);
  345.                         } */
  346.                 }
  347.         }
  348.         if (suckerOn) {
  349.                 for (int i = 0; i < 2; ++i)
  350.                         if (suckerSpeedX != 0) {
  351.                                 if (maskedPixel(int(play.xOrg), int(play.yOrg))) {
  352.                                         unsuckPlayer(play);
  353.                                         break;
  354.                                 } else {
  355.                                         play.xPos = play.xOrg += suckerSpeedX;
  356.                                         play.yPos = play.yOrg;
  357.                                         play.ySpeed = 0; //testing to make spectating look better
  358.                                 }
  359.                         } else if (suckerSpeedY != 0) {
  360.                                 if (maskedPixel(int(play.xOrg), int(play.yOrg))) {
  361.                                         unsuckPlayer(play);
  362.                                         break;
  363.                                 } else {
  364.                                         play.xPos = play.xOrg;
  365.                                         play.yPos = play.yOrg += suckerSpeedY;
  366.                                 }
  367.                         } else { //waiting for feedback
  368.                                 if (play.keyRight)
  369.                                         suckerSpeedX = SuckerSpeedSpeed;
  370.                                 else if (play.keyLeft)
  371.                                         suckerSpeedX = -SuckerSpeedSpeed;
  372.                                 else if (play.keyDown)
  373.                                         suckerSpeedY = SuckerSpeedSpeed;
  374.                                 else if (play.keyUp)
  375.                                         suckerSpeedY = -SuckerSpeedSpeed;
  376.                                 else {
  377.                                         play.xPos = play.xOrg;
  378.                                         play.yPos = play.yOrg;
  379.                                         play.xSpeed = play.xAcc = play.ySpeed = play.yAcc = 0;
  380.                                         suckerOn = false; lastSuckTile = 0;
  381.                                 }
  382.                                 const int distance = jjGameTicks & 15;
  383.                                 const int xTile = int(play.xPos / 32) * 32;
  384.                                 const int yTile = int(play.yPos / 32) * 32;
  385.                                 jjDrawTile(xTile + 32 + distance, yTile, BigArrowTileIDs[0] + 2);
  386.                                 jjDrawTile(xTile - 32 - distance, yTile, BigArrowTileIDs[2] + 2);
  387.                                 jjDrawTile(xTile, yTile + 32 + distance, BigArrowTileIDs[1] + 2);
  388.                                 jjDrawTile(xTile, yTile - 32 - distance, BigArrowTileIDs[3] + 2);
  389.                                 break;
  390.                         }
  391.         } else {
  392.                 if (play.warpID == 0 && (play.ySpeed == 0 || warpInsidePixel(play.xPos, play.yPos - 32) != 0)) { //probably standing
  393.                         const int floorTileY = int(play.yPos / 32) + 1;
  394.                         int floorTileX = int(play.xPos / 32);
  395.                         bool onTileCorner = false;
  396.                         if (!jjMaskedPixel(floorTileX * 32, floorTileY * 32)) {
  397.                                 const int playTruncatedX = int(play.xPos) & 31;
  398.                                 if (playTruncatedX < 12) --floorTileX;
  399.                                 else if (playTruncatedX > 18) ++floorTileX;
  400.                                 onTileCorner = true;
  401.                         }
  402.                         //jjDrawTile(floorTileX * 32, floorTileY * 32, 51);
  403.                         floorTileID = jjTileGet(4, floorTileX, floorTileY);
  404.                        
  405.                         if (floorTileID == 26 | TILE::ANIMATED) {
  406.                                 onBelt(play, -1);
  407.                         } else if (floorTileID == 26 | TILE::ANIMATED | TILE::HFLIPPED) {
  408.                                 onBelt(play, 1);
  409.                         } else if (floorTileID == 50 || floorTileID == 60) { //red, green specials
  410.                                 if (onTileCorner)
  411.                                         floorTileID = 0; //must be standing full on for one of these tiles
  412.                                 else
  413.                                         jjDrawTile(floorTileX * 32, floorTileY * 32, 231);
  414.                         }
  415.                 }
  416.         }
  417.         if (play.warpID == 0) {
  418.                 play.xOrg = play.xPos;
  419.                 play.yOrg = play.yPos;
  420.                 const int xTile = int(play.xPos / 32);
  421.                 const int yTile = int(play.yPos / 32);
  422.                
  423.                 array<LaserBlock>@ lasers = LaserBlockArraysPerLevel[WarpID];
  424.                 for (int i = lasers.length - 1; i >= 0; --i) {
  425.                         if (lasers[i].tileIsInPath(xTile, yTile)) {
  426.                                 crispyFried = true;
  427.                                 jjObjects[0].xPos = play.xPos;
  428.                                 jjObjects[0].yPos = play.yPos;
  429.                                 jjObjects[0].curFrame = play.curFrame;
  430.                                 jjObjects[0].direction = play.direction;
  431.                                 jjObjects[0].particlePixelExplosion(1);
  432.                                 play.cameraFreeze(play.cameraX, play.cameraY, false, true);
  433.                                 jjSample(play.xPos, play.yPos, SOUND::COMMON_BURN);
  434.                                 jjSample(play.xPos, play.yPos, SOUND::COMMON_ELECTRIC1);
  435.                                 onFunction1(play);
  436.                                 return;
  437.                         }
  438.                 }
  439.                 const int shouldWarp = warpInsideTile(xTile, yTile);
  440.                 if (shouldWarp >= 1) {
  441.                         if (shouldWarp == 1 && play.fly == 0) {
  442.                                 jjSample(play.xPos, play.yPos, SOUND::COMMON_SMASH);
  443.                                 jjSample(play.xPos, play.yPos, SOUND::SPAZSOUNDS_AUTSCH1);
  444.                                 knockedIntoScreen = 1.0;
  445.                                 play.cameraFreeze(play.cameraX, play.cameraY, false, true);
  446.                         }
  447.                         onFunction1(play);
  448.                 } else if (shouldWarp == -1) {
  449.                         const uint16 backTileID = jjTileGet(5, xTile, yTile);
  450.                         if (backTileID == BigArrowTileIDs[0]) {
  451.                                 suckPlayer(play, 1, 0);
  452.                         } else if (backTileID == BigArrowTileIDs[1]) {
  453.                                 suckPlayer(play, 0, 1);
  454.                         } else if (backTileID == BigArrowTileIDs[2]) {
  455.                                 suckPlayer(play, -1, 0);
  456.                         } else if (backTileID == BigArrowTileIDs[3]) {
  457.                                 suckPlayer(play, 0, -1);
  458.                         } else {
  459.                                 suckPlayer(play, 0, 0);
  460.                         }
  461.                 }
  462.         }
  463. }
  464. void Switch(jjOBJ@ obj) {
  465.         if (jjPlayers[obj.creator].isLocal) {
  466.                 jjTriggers[0] = !jjTriggers[0];
  467.                 if (floorTileID != 50) //red
  468.                         jjTriggers[1] = !jjTriggers[1];
  469.                 if (floorTileID != 60) //green
  470.                         jjTriggers[2] = !jjTriggers[2];
  471.                 QuakeLayer4 = 10;
  472.                 jjSamplePriority(SOUND::COMMON_CANSPS);
  473.         }
  474.         obj.delete();
  475.         SpendFramesCheckingIfPlayerIsStuck = 2;
  476. }
  477.  
  478. bool Successful = false;
  479. int WarpID = -1;
  480. void onFunction0(jjPLAYER@ play, int8 newWarpID) {
  481.         if (WarpID + 1 == newWarpID) {
  482.                 Successful = true;
  483.                 const bool wasEndgame = Endgame;
  484.                 Endgame = SwitchesPerLevel[newWarpID] < 0;
  485.                 jjTriggers[ENDGAMETRIGGERID] = Endgame;
  486.                 WarpID = newWarpID;
  487.                 play.score = newWarpID + 1; //in case if playing in SP
  488.                 if (!Endgame) {
  489.                         if (WarpID > 0)
  490.                                 jjSamplePriority(SOUND::COMMON_HARP1);
  491.                         if (wasEndgame) {
  492.                                 jjLayerHasTiles[1] = true;
  493.                                 jjPalette.reset();
  494.                                 jjPalette.apply();
  495.                         }
  496.                 } else {
  497.                         if (!wasEndgame) {
  498.                                 jjLayerHasTiles[1] = false;
  499.                                 jjSamplePriority(SOUND::COMMON_NOCOIN);
  500.                                 for (int i = 151; i <= 159; ++i)
  501.                                         jjPalette.color[i].swizzle(COLOR::BLUE, COLOR::BLUE, COLOR::RED);
  502.                                 for (int i = 176; i <= 208; ++i)
  503.                                         jjPalette.color[i].swizzle(COLOR::BLUE, COLOR::GREEN, COLOR::RED);
  504.                                 jjPalette.apply();
  505.                         } else
  506.                                 jjSamplePriority(SOUND::COMMON_HARP1);
  507.                 }
  508.                 const int maxSwitches = int(abs(SwitchesPerLevel[newWarpID]));
  509.                 jjWeapons[WEAPON::ICE].maximum = maxSwitches;
  510.                 jjWeapons[WEAPON::ICE].infinite = maxSwitches >= 99;
  511.                 play.ammo[WEAPON::ICE] = jjWeapons[WEAPON::ICE].maximum; //double sure?
  512.                 if (!Endgame)
  513.                         play.showText("@@@@@@@@@@@@@@#" + (CharactersPerLevel[newWarpID] == CHAR::JAZZ ? "|||" : (CharactersPerLevel[newWarpID] == CHAR::FROG ? "~" : "||||")) +"~  Incident " + formatInt(newWarpID + 1, "0", 2) + "!@@" + ((maxSwitches >= 99) ? "Unlimited" : formatInt(maxSwitches, "d")) + " switches", STRING::MEDIUM);
  514.                 onFunction1(play);
  515.         }
  516. }
  517. void onFunction1(jjPLAYER@ play) {
  518.         attackingWildly = false;
  519.         //if (!warping) {
  520.         {
  521.                 unsuckPlayer(play);
  522.                 play.warpToID(WarpID);
  523.                 warping = true;
  524.                 play.ammo[WEAPON::ICE] = jjWeapons[WEAPON::ICE].maximum;
  525.                 const CHAR::Char newChar = CharactersPerLevel[WarpID];
  526.                 if (play.charCurr != newChar && newChar != CHAR::FROG)
  527.                         play.morphTo(newChar, true);
  528.         }
  529.                
  530. }
  531.  
  532. bool Endgame = false;
  533. const uint8 ENDGAMETRIGGERID = 21;
  534. const array<uint16> BigArrowTileIDs = {0 | TILE::ANIMATED, 1 | TILE::ANIMATED, 0 | TILE::ANIMATED | TILE::HFLIPPED, 1 | TILE::ANIMATED | TILE::VFLIPPED};
  535. class SwitchBlock {
  536.         bool TubeBlock = false;
  537.         bool EndgameOnly = false;
  538.         uint triggerID = 0;
  539.         bool triggerWasOn = false;
  540.         uint16 offTileID, onTileID;
  541.         uint currentDirection;
  542.         uint legalDirections;
  543.         uint xTile, yTile;
  544.         SwitchBlock(){}
  545.         SwitchBlock(uint x, uint y) {
  546.                 xTile = x; yTile = y;
  547.                 const uint16 animatedTileID = jjTileGet(4, xTile, yTile);
  548.                 switch (animatedTileID ^ TILE::ANIMATED) {
  549.                         case 18:
  550.                                 offTileID = 40;
  551.                                 onTileID = 41;
  552.                                 break;
  553.                         case 19:
  554.                                 offTileID = 41;
  555.                                 onTileID = 40;
  556.                                 break;
  557.                         case 20:
  558.                                 offTileID = 50;
  559.                                 onTileID = 51;
  560.                                 triggerID += 1;
  561.                                 break;
  562.                         case 21:
  563.                                 offTileID = 51;
  564.                                 onTileID = 50;
  565.                                 triggerID += 1;
  566.                                 break;
  567.                         case 22:
  568.                                 offTileID = 60;
  569.                                 onTileID = 61;
  570.                                 triggerID += 2;
  571.                                 break;
  572.                         case 23:
  573.                                 offTileID = 61;
  574.                                 onTileID = 60;
  575.                                 triggerID += 2;
  576.                                 break;
  577.                         case 24:
  578.                                 offTileID = (4 | TILE::ANIMATED);
  579.                                 onTileID = 81;
  580.                                 TubeBlock = true;
  581.                                 break;
  582.                         case 25:
  583.                                 offTileID = 81;
  584.                                 onTileID = (4 | TILE::ANIMATED);
  585.                                 TubeBlock = true;
  586.                                 break;
  587.                         case 26:
  588.                                 offTileID = 26 | TILE::ANIMATED;
  589.                                 onTileID = 26 | TILE::ANIMATED | TILE::HFLIPPED;
  590.                                 break;
  591.                         case 26 | TILE::HFLIPPED:
  592.                                 offTileID = 26 | TILE::ANIMATED | TILE::HFLIPPED;
  593.                                 onTileID = 26 | TILE::ANIMATED;
  594.                                 break;
  595.                         case 28:
  596.                         case 29:
  597.                         case 30: { //mirrors
  598.                                 const int color = ((animatedTileID & TILE::RAWRANGE) - 28);
  599.                                 triggerID += color;
  600.                                 offTileID = 271 + color * 10;
  601.                                 onTileID = offTileID | TILE::HFLIPPED;
  602.                                 break; }
  603.                         case 28 | TILE::HFLIPPED:
  604.                         case 29 | TILE::HFLIPPED:
  605.                         case 30 | TILE::HFLIPPED: { //flipped mirrors
  606.                                 const int color = ((animatedTileID & TILE::RAWRANGE) - 28);
  607.                                 triggerID += color;
  608.                                 onTileID = 271 + color * 10;
  609.                                 offTileID = onTileID | TILE::HFLIPPED;
  610.                                 break; }
  611.                         default:
  612.                                 jjDebug("invalid trigger tile!");
  613.                 }
  614.                 if (TubeBlock) {
  615.                         legalDirections = jjParameterGet(xTile, yTile, 0, 4);
  616.                         currentDirection = jjParameterGet(xTile, yTile, 4, 2);
  617.                 }
  618.                 EndgameOnly = jjParameterGet(xTile, yTile, 7, 1) == 1;
  619.                 if (jjParameterGet(xTile, yTile, 6, 1) == 1) { //move downwards one tile, to allow placing blocks on top of warps
  620.                         jjTileSet(4, xTile, yTile, 0);
  621.                         yTile += 1;
  622.                 }
  623.         }
  624.         void switchTile() {
  625.                 const bool triggerOn = jjTriggers[triggerID];
  626.                 if (triggerOn != TriggerColorsOld[triggerID])
  627.                         jjTileSet(4, xTile,yTile, (!EndgameOnly || Endgame) ? (triggerOn ? onTileID : offTileID) : 0);
  628.         }
  629.         void changeDirection() {
  630.                 if ((!EndgameOnly || Endgame) && legalDirections != 0) { //level-set direction, not player-set
  631.                         int newDirection = currentDirection;
  632.                         for (int i = 0; i < 3; ++i) {
  633.                                 newDirection = (newDirection + 1) & 3;
  634.                                 if ((legalDirections & (1 << newDirection)) != 0) {
  635.                                         currentDirection = newDirection;
  636.                                         break;
  637.                                 }
  638.                         }
  639.                         jjTileSet(5, xTile,yTile, BigArrowTileIDs[currentDirection]);
  640.                 }
  641.         }
  642. }
  643. array<SwitchBlock> SwitchBlocks;
  644. class TileCoordinates {
  645.         uint16 xTile, yTile;
  646.         float xPos, yPos;
  647.         uint16 tileID;
  648.         TileCoordinates(){}
  649.         TileCoordinates(uint x, uint y, uint oldDir, uint newDir) {
  650.                 xPos = (xTile = x) * 32.f; yPos = (yTile = y) * 32.f;
  651.                 if (oldDir == newDir) {
  652.                         if ((oldDir & 1) == 0)
  653.                                 tileID = 32 | TILE::ANIMATED; //horizontal
  654.                         else
  655.                                 tileID = 31 | TILE::ANIMATED; //vertical
  656.                 } else switch(oldDir | (newDir << 2)) { //corner
  657.                         case 12:
  658.                         case 9:
  659.                                 tileID = 33 | TILE::ANIMATED;
  660.                                 break;
  661.                         case 1:
  662.                         case 14:
  663.                                 tileID = 33 | TILE::ANIMATED | TILE::HFLIPPED;
  664.                                 break;
  665.                         case 4:
  666.                         case 11:
  667.                                 tileID = 33 | TILE::ANIMATED | TILE::VFLIPPED;
  668.                                 break;
  669.                         case 3:
  670.                         case 6:
  671.                                 tileID = 33 | TILE::ANIMATED | TILE::HFLIPPED | TILE::VFLIPPED;
  672.                                 break;
  673.                 }
  674.         }
  675. }
  676. const uint LayerWidth = jjLayerWidth[4];
  677. const uint LayerHeight = jjLayerHeight[4];
  678. class LaserBlock {
  679.         uint8 currentDirection;
  680.         uint8 countdownToDestruction = 0;
  681.         int xTile, yTile;
  682.         array<TileCoordinates> path(0);
  683.         LaserBlock(){}
  684.         LaserBlock(uint x, uint y) {
  685.                 xTile = x; yTile = y;
  686.                 const uint16 tileID = jjTileGet(4, xTile, yTile);
  687.                 switch (tileID) {
  688.                         case 301:
  689.                                 currentDirection = 3; //up
  690.                                 break;
  691.                         case 301 | TILE::VFLIPPED:
  692.                                 currentDirection = 1; //down
  693.                                 break;
  694.                         case 311:
  695.                                 currentDirection = 0; //right
  696.                                 break;
  697.                         case 311 | TILE::HFLIPPED:
  698.                                 currentDirection = 2; //left
  699.                                 break;
  700.                         default:
  701.                                 jjDebug("invalid laser tile!");
  702.                 }
  703.         }
  704.         void updatePath() {
  705.                 if (countdownToDestruction >= 2)
  706.                         return;
  707.                 path.resize(0);
  708.                 uint pathDirection = currentDirection;
  709.                 uint newDirection = pathDirection;
  710.                 int newTileX = xTile;
  711.                 int newTileY = yTile;
  712.                 while (true) {
  713.                         switch (pathDirection) {
  714.                                 case 0: //right
  715.                                         newTileX += 1;
  716.                                         break;
  717.                                 case 1: //down
  718.                                         newTileY += 1;
  719.                                         break;
  720.                                 case 2: //left
  721.                                         newTileX -= 1;
  722.                                         break;
  723.                                 case 3: //break
  724.                                         newTileY -= 1;
  725.                         }
  726.                         while (newTileX < 0) newTileX += LayerWidth;
  727.                         while (newTileY < 0) newTileY += LayerHeight;
  728.                         const uint16 tileID = jjTileGet(4, newTileX %= LayerWidth, newTileY %= LayerHeight);
  729.                         //if (tileID != 0)
  730.                         if (tileID == 40 || tileID == 50 || tileID == 60 || tileID == (26 | TILE::ANIMATED) || tileID == (26 | TILE::ANIMATED | TILE::HFLIPPED) || (tileID == 10 && jjEventGet(newTileX, newTileY) != AREA::ONEWAY)) //wall
  731.                                 break;
  732.                         else if (tileID == 301 || tileID == (301 | TILE::VFLIPPED) || tileID == 311 || tileID == (311 | TILE::HFLIPPED)) { //hit another laser!
  733.                                 array<LaserBlock>@ lasers = LaserBlockArraysPerLevel[WarpID];
  734.                                 for (int i = lasers.length - 1; i >= 0; --i) {
  735.                                         LaserBlock@ laser = lasers[i];
  736.                                         if (laser.xTile == newTileX && laser.yTile == newTileY) { //found the right one
  737.                                                 if (laser.countdownToDestruction == 0)
  738.                                                         laser.countdownToDestruction = 1;
  739.                                                 break;
  740.                                         }
  741.                                 } //if none are found, oh well, that's weird but keep going
  742.                                 break;
  743.                         } else if (tileID == 4 | TILE::ANIMATED) { //sucker tube
  744.                                 const uint16 arrowTileID = jjTileGet(5, newTileX, newTileY);
  745.                                 for (int i = 0; i < 4; ++i)
  746.                                         if (arrowTileID == BigArrowTileIDs[i]) {
  747.                                                 newDirection = i;
  748.                                                 break;
  749.                                         }
  750.                                 if (((newDirection + 2) & 3) == pathDirection) //reversed
  751.                                         break;
  752.                         } else if (tileID == 261 || tileID == 271 || tileID == 281 || tileID == 291) { //mirror
  753.                                 newDirection ^= 1;
  754.                         } else if (tileID == (261 | TILE::HFLIPPED) || tileID == (271 | TILE::HFLIPPED) || tileID == (281 | TILE::HFLIPPED) || tileID == (291 | TILE::HFLIPPED)) { //mirror 2
  755.                                 newDirection = 3 - pathDirection;
  756.                         }
  757.                         path.insertLast(TileCoordinates(newTileX, newTileY, pathDirection, newDirection));
  758.                         pathDirection = newDirection;
  759.                 }
  760.         }
  761.         void dead() {
  762.                 jjPARTICLE@ fire = jjAddParticle(((jjRandom() & 1) == 1) ? PARTICLE::SMOKE : PARTICLE::SPARK);
  763.                 if (fire !is null) {
  764.                         fire.xPos = xTile * 32 + (jjRandom() & 31);
  765.                         fire.yPos = yTile * 32 + (jjRandom() & 31);
  766.                 }
  767.         }
  768.         void draw() {
  769.                 if (countdownToDestruction == 1) //just got hit, but stay alive
  770.                         countdownToDestruction = 2;
  771.                 else if (countdownToDestruction == 2) { //dead
  772.                         dead();
  773.                 } else {
  774.                         const uint8 glowColor = 40 + (jjRenderFrame & 3);
  775.                         const uint8 glowIntensity = uint8(abs(jjSin(jjRenderFrame << 4) * 64));
  776.                         jjDrawRectangle(xTile * 32, yTile * 32, 32, 32, glowColor, SPRITE::BLEND_NORMAL, glowIntensity);
  777.                         for (uint i = 0; i < path.length; ++i) {
  778.                                 jjDrawRectangle(path[i].xPos, path[i].yPos, 32, 32, glowColor, SPRITE::BLEND_NORMAL, glowIntensity);
  779.                                 jjDrawTile(path[i].xPos, path[i].yPos, path[i].tileID);
  780.                         }
  781.                 }
  782.         }
  783.         bool tileIsInPath(uint x, uint y) {
  784.                 if (countdownToDestruction >= 2)
  785.                         return false;
  786.                 for (uint i = 0; i < path.length; ++i)
  787.                         if (x == path[i].xTile && y == path[i].yTile)
  788.                                 return true;
  789.                 return false;
  790.         }
  791. }
  792. array<array<LaserBlock>> LaserBlockArraysPerLevel;
  793.  
  794. bool onDrawLives(jjPLAYER@ play, jjCANVAS@ screen) {
  795.         return true;
  796. }
  797. bool onDrawHealth(jjPLAYER@ play, jjCANVAS@ screen) {
  798.         return true;
  799. }
  800. bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ screen) {
  801.         //if (SwitchesPerLevel[WarpID] < 99)
  802.         //      screen.drawString(20, jjResolutionHeight - 50, "" + SwitchesPerLevel[WarpID], STRING::LARGE);
  803.         const CHAR::Char intendedChar = CharactersPerLevel[WarpID];
  804.         const int frameID = jjRenderFrame >> 3;
  805.         if (jjIsTSF && (intendedChar == CHAR::LORI || intendedChar == CHAR::FROG))
  806.                 screen.drawSprite(50, jjResolutionHeight, ANIM::FACES, 4, frameID, 0, SPRITE::PLAYER, play.playerID);
  807.         if (intendedChar == CHAR::SPAZ || intendedChar == CHAR::FROG)
  808.                 screen.drawSprite(30, jjResolutionHeight, ANIM::FACES, (jjIsTSF) ? 5 : 4, frameID, 0, SPRITE::PLAYER, play.playerID);
  809.         if (intendedChar == CHAR::JAZZ || intendedChar == CHAR::FROG)
  810.                 screen.drawSprite(10, jjResolutionHeight, ANIM::FACES, 3, frameID, 0, SPRITE::PLAYER, play.playerID);
  811.         return Endgame;
  812. }
  813.  
  814. void InfiniteMonitor(jjOBJ@ obj) {
  815.         if (obj.state == STATE::KILL) { //destroyed
  816.                 obj.state = STATE::START; //restart
  817.                 obj.xPos = obj.xOrg;
  818.                 obj.yPos = obj.yOrg;
  819.                 obj.objType = jjObjectPresets[obj.eventID].objType;
  820.                 obj.energy = jjObjectPresets[obj.eventID].energy;
  821.         }
  822.         obj.behave(BEHAVIOR::MONITOR);
  823. }
  824. void Electricity(jjOBJ@ obj) {
  825.         if (obj.state == STATE::DEACTIVATE || jjLowDetail) {
  826.                 obj.delete(); //don't bother deactivating
  827.                 return;
  828.         } else if (obj.state == STATE::START) {
  829.                 obj.state = STATE::FLY;
  830.                 switch (jjRandom() & 3) {
  831.                         case 0:
  832.                                 obj.xSpeed = 2;
  833.                                 obj.ySpeed = 0;
  834.                                 break;
  835.                         case 1:
  836.                                 obj.xSpeed = 0;
  837.                                 obj.ySpeed = 2;
  838.                                 break;
  839.                         case 2:
  840.                                 obj.xSpeed = -2;
  841.                                 obj.ySpeed = 0;
  842.                                 break;
  843.                         case 3:
  844.                                 obj.xSpeed = 0;
  845.                                 obj.ySpeed = -2;
  846.                                 break;
  847.                 }
  848.         }
  849.         if (!jjMaskedPixel(int(obj.xPos+= obj.xSpeed), int(obj.yPos+= obj.ySpeed))) { //outside the wall
  850.                 obj.delete();
  851.                 uint rand = jjRandom();
  852.                 for (int i = 0; i < 7; ++i) {
  853.                         const int angle = (rand & 31) << 5;
  854.                         rand >>= 5;
  855.                         jjPARTICLE@ spark = jjAddParticle(PARTICLE::SPARK);
  856.                         if (spark !is null) {
  857.                                 spark.xPos = obj.xPos;
  858.                                 spark.yPos = obj.yPos;
  859.                                 spark.xSpeed = jjSin(angle) * 2.f;
  860.                                 spark.ySpeed = jjCos(angle) * 2.f;
  861.                                 if (!Endgame) {
  862.                                         spark.spark.color -= 8; spark.spark.colorStop -= 8; //blue
  863.                                 }
  864.                         }
  865.                 }
  866.         } else if ((int(obj.xPos) & 31) == 16 && (int(obj.yPos) & 31) == 16) {
  867.                 const uint rand = jjRandom();
  868.                 if ((rand & 1) == 1) { //turn
  869.                         if (obj.xSpeed != 0) {
  870.                                 obj.xSpeed = 0;
  871.                                 obj.ySpeed = ((rand & 2) == 2) ? 2 : -2;
  872.                         } else {
  873.                                 obj.ySpeed = 0;
  874.                                 obj.xSpeed = ((rand & 2) == 2) ? 2 : -2;
  875.                         }
  876.                 }
  877.         }
  878.         //else
  879.                
  880. }
  881.  
  882. void Tweedle(jjOBJ@ obj) {
  883.         if (obj.state == STATE::DEACTIVATE)
  884.                 obj.deactivate();
  885.         else if (obj.state == STATE::DONE) {
  886.                 obj.state = STATE::FALL;
  887.                 obj.determineCurAnim(ANIM::TWEEDLE, 5);
  888.                 obj.ySpeed = -7;
  889.                 obj.yAcc = 0.3;
  890.         } else if (obj.state == STATE::FALL) {
  891.                 obj.xPos -= 2;
  892.                 if ((obj.yPos += (obj.ySpeed += obj.yAcc)) > obj.yOrg + 5*32) {
  893.                         obj.state = STATE::EXPLODE;
  894.                         obj.counterEnd = 0;
  895.                 }
  896.         } else if (obj.state == STATE::EXPLODE) {
  897.                 if (obj.counterEnd++ < 240) {
  898.                         QuakeLayer4 = 10;
  899.                         obj.xPos += jjLayerXOffset[4];
  900.                         obj.yPos += jjLayerYOffset[4];
  901.                         if ((obj.counterEnd & 15) == 0) {
  902.                                 obj.justHit = 8;
  903.                                 obj.particlePixelExplosion(1);
  904.                                 jjSamplePriority(SOUND::COMMON_ELECTRIC1);
  905.                         }
  906.                 } else {
  907.                         obj.state = STATE::START;
  908.                         obj.xPos = obj.xOrg;
  909.                         obj.yPos = obj.yOrg;
  910.                         obj.energy = jjObjectPresets[obj.eventID].energy;
  911.                         obj.curAnim = jjObjectPresets[obj.eventID].curAnim;
  912.                         attackingWildly = false;
  913.                         Endgame = false;
  914.                         jjTriggers[ENDGAMETRIGGERID] = false;
  915.                         WarpID = 0;
  916.                         jjLocalPlayers[0].score = 1;
  917.                         jjLocalPlayers[0].showText("#|||||~@@@CONGRATULATIONS!", STRING::LARGE);
  918.                         jjLayerHasTiles[1] = true;
  919.                         jjPalette.reset();
  920.                         jjPalette.apply();
  921.                         jjSamplePriority(SOUND::COMMON_EXPL_TNT);
  922.                 }
  923.         } else if (WarpID == 0) {
  924.                 return; //don't delete; wait until can be deactivated
  925.         }
  926.         obj.frameID = jjGameTicks >> 2;
  927.         obj.determineCurFrame();
  928.         obj.draw();
  929. }
  930.  
  931. bool attackingWildly;
  932. void onFunction2(jjPLAYER@ play) {
  933.         attackingWildly = true;
  934. }
  935. void onObjectHit(jjOBJ@ object, jjOBJ@ bullet, jjPLAYER@ player, int force) {
  936.         if (bullet is null && force == 1 && WarpID != 0) {
  937.                 player.buttstomp = 121;
  938.                 player.ySpeed = -10;
  939.                 player.yAcc = 0;
  940.                 object.justHit = 6;
  941.                 if (--object.energy <= 0) {
  942.                         object.state = STATE::DONE;
  943.                 }
  944.         }
  945. }
  946.  
  947. void MovingTarget(jjOBJ@ obj) { //only an object because it has a lighttype
  948.         if (Successful) {
  949.                 Successful = false;
  950.                 for (int i = 0; i < 11; ++i) {
  951.                         jjOBJ@ reward = jjObjects[jjAddObject(OBJECT::FLICKERGEM, obj.xPos, obj.yPos, obj.objectID)];
  952.                         reward.xSpeed = ((jjRandom() & 15) - 7.5f) / 2.f;
  953.                         reward.ySpeed = -1.1 - ((jjRandom() & 7) / 2.f);
  954.                         reward.var[0] = (jjRandom() & 3) + 1;
  955.                 }
  956.         }
  957.         uint targetID = WarpID + 1;
  958.         if (targetID >= TargetsPerLevel.length)
  959.                 targetID = TargetsPerLevel.length - 1;
  960.         obj.xPos += (TargetsPerLevel[targetID].x - obj.xPos) / 128;
  961.         obj.yPos += (TargetsPerLevel[targetID].y - obj.yPos) / 128;
  962.         const float scale = 4.5f + jjSin(jjGameTicks << 4) * 2;
  963.         jjDrawRotatedSprite(obj.xPos, obj.yPos, ANIM::PLUS_RETICLES, 1, 0, jjGameTicks << 2, scale, scale, SPRITE::SINGLECOLOR, 47 - (jjRenderFrame & 31), 1);
  964. }
  965.  
  966.  
  967.  
  968.  
  969.  
  970.  
  971.  
  972.  
  973.  
  974.  
  975.  
  976.  
  977.  
  978.  
  979.  
  980.  
  981.  
  982.  
  983.  
  984.  
  985.  
  986.  
  987.  
  988.  
  989.  
  990.  
  991.  
  992.  
  993.  
  994.  
  995.  
  996.  
  997.  
  998.  
  999.  
  1000.  
  1001.  
  1002.  
  1003.  
  1004.  
  1005.  
  1006.  
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015.  
  1016.  
  1017.  
  1018.  
  1019.  
  1020.  
  1021.  
  1022.  
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036.  
  1037. //go away you silly cheater
  1038. bool onLocalChat(string &in stringReceived, CHAT::Type chatType) {
  1039.         array<string> regexResults;
  1040.         if (jjRegexMatch(stringReceived, "SKIPTO (\\d+)", regexResults, false)) {
  1041.                 int newWarpID = parseInt(regexResults[1]) - 1;
  1042.                 if (newWarpID >= 0 && newWarpID < int(SwitchesPerLevel.length)) {
  1043.                         WarpID = newWarpID - 1; //force function to accept value
  1044.                         onFunction0(jjLocalPlayers[0], newWarpID);
  1045.                 } else
  1046.                         jjAlert("|Invalid Incident!");
  1047.                 return true;
  1048.         }
  1049.         return false;
  1050. }