Downloads containing xlmskywardJB.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Skyward ShowdownFeatured Download PurpleJazz Capture the flag 9.1 Download file

File preview

  1. #pragma require "FTURROCK.wav"
  2. #pragma require "EXPSTD3.wav"
  3. #pragma require "redeemer_flight.wav"
  4. #pragma require "wind1.wav"
  5. #pragma require "SHIPHUMS.wav"
  6. #pragma require "xlmskywardex.j2l"
  7. #pragma require "xlmskywardex2.j2l"
  8.  
  9. bool gameIsActive() {
  10.         return jjGameState == GAME::STARTED || jjGameState == GAME::OVERTIME;
  11. }
  12.  
  13. bool CTFMode() {
  14.         return (jjGameMode == GAME::CTF && jjGameCustom == GAME::NOCUSTOM) || jjGameCustom == GAME::DCTF;
  15. }
  16.  
  17. bool otherMode() {
  18.         return jjGameMode != GAME::CTF || jjGameCustom == GAME::TB || jjGameCustom == GAME::TLRS || jjGameCustom == GAME::DOM;
  19. }
  20.  
  21. bool muteAmbientWind() {
  22.         return (jjLocalPlayers[0].xPos < 22*32 && jjLocalPlayers[0].yPos < 46*32) || (jjLocalPlayers[0].xPos > 258*32 && jjLocalPlayers[0].yPos < 46*32);
  23. }
  24.  
  25. bool isWindSound(jjOBJ@ sound) {
  26.         return sound.xOrg >= 277*32;
  27. }
  28.  
  29. bool isShipSound(jjOBJ@ sound) {
  30.         return sound.xOrg <= 2*32;
  31. }
  32.  
  33. bool isDestructibleItem(jjOBJ@ target) {
  34.         return target.eventID == OBJECT::TNT || target.eventID == OBJECT::BOUNCERPOWERUP || target.eventID == OBJECT::RFPOWERUP || target.eventID == OBJECT::TOASTERPOWERUP || target.eventID == OBJECT::GUN8POWERUP || target.eventID == OBJECT::LIGHTNINGSHIELD;
  35. }
  36.  
  37. const array<uint16> invisibleTiles = {
  38.         75,
  39.         102, 103,
  40.         112, 113, 116, 117, 118, 119,
  41.         122, 123, 126, 127, 128, 129,
  42.         132, 133,
  43.         142, 143,
  44.         152, 153
  45. };
  46.  
  47. bool controllingRedeemer, warning = false;
  48. int xPos = 0, yPos = 0, cameraX = 0, cameraY = 0, redeemerAngle = 0, CTFArrowTimer = 0;
  49. uint delay = 0;
  50.  
  51. int redeemerColor(jjPLAYER@ creator) {
  52.         switch(creator.team) {
  53.                 case TEAM::BLUE: return 0;
  54.                 case TEAM::RED: return 1;
  55.                 case TEAM::GREEN: return 2;
  56.                 case TEAM::YELLOW: return 3;
  57.         }
  58.         return 0;
  59. }
  60.  
  61. uint8 getTeamColor(TEAM::Color team) {
  62.         switch (team) {
  63.                 case TEAM::BLUE: return 32;
  64.                 case TEAM::RED: return 24;
  65.         }
  66.         return 32;
  67. }
  68.  
  69. const array<TEAM::Color> teams = {TEAM::BLUE, TEAM::RED, TEAM::GREEN, TEAM::YELLOW};
  70. const float PI = 3.1415927f;
  71.  
  72. void onLevelLoad() {
  73.         jjSampleLoad(SOUND::P2_POEP, "FTURROCK.wav");
  74.         jjSampleLoad(SOUND::P2_PTOEI, "EXPSTD3.wav");
  75.         jjSampleLoad(SOUND::P2_SPLOUT, "redeemer_flight.wav");
  76.         jjSampleLoad(SOUND::WIND_WIND2A, "wind1.wav");
  77.         jjSampleLoad(SOUND::SCIENCE_PLOPKAOS, "SHIPHUMS.wav");
  78.  
  79.         jjAnimSets[ANIM::SONCSHIP].load();
  80.         jjAnimSets[ANIM::VINE].load();
  81.         jjAnimations[jjAnimSets[ANIM::AMMO] + 59] = jjAnimations[jjAnimSets[ANIM::SONCSHIP] + 0];
  82.        
  83.         jjTexturedBGFadePositionY = 0.1;
  84.         jjUseLayer8Speeds = true;
  85.        
  86.         jjObjectPresets[OBJECT::BLASTERPOWERUP].behavior =
  87.         jjObjectPresets[OBJECT::RFPOWERUP].behavior = OscillatingMonitor();
  88.        
  89.         jjObjectPresets[OBJECT::AMBIENTSOUND].behavior = AmbientSound();
  90.        
  91.         jjObjectPresets[OBJECT::CTFBASE].behavior = JailBase();
  92.        
  93.         jjObjectPresets[OBJECT::TNT].determineCurFrame();
  94.         jjObjectPresets[OBJECT::TNT].behavior = Redeemer();
  95.         jjObjectPresets[OBJECT::TNT].xSpeed = jjObjectPresets[OBJECT::BLASTERBULLET].xSpeed * 1.33;
  96.         jjObjectPresets[OBJECT::TNT].counterEnd = 255;
  97.         jjObjectPresets[OBJECT::TNT].killAnim = jjObjectPresets[OBJECT::SEEKERBULLET].killAnim;
  98.        
  99.         jjObjectPresets[OBJECT::TNTAMMO3].behavior = RedeemerPickup();
  100.         jjObjectPresets[OBJECT::TNTAMMO3].determineCurFrame();
  101.         jjObjectPresets[OBJECT::TNTAMMO3].scriptedCollisions = true;
  102.        
  103.         jjWeapons[WEAPON::TNT].maximum = 1;
  104.         jjWeapons[WEAPON::GUN8].comesFromGunCrates = true;
  105.        
  106.         jjLayerXOffset[6] = 128;
  107.        
  108.         array<jjLAYER@> extraLayers = jjLayersFromLevel("xlmskywardex.j2l", array<uint> = {1,2,3,5,6,7}, 0);
  109.         array<jjLAYER@> extraLayers2 = jjLayersFromLevel("xlmskywardex2.j2l", array<uint> = {1,2,3,4,5,6,7}, 0);
  110.         jjLayerOrderSet(array<jjLAYER@> = {extraLayers[0], extraLayers[1], extraLayers2[4], extraLayers2[5], extraLayers2[6], jjLayers[3], jjLayers[1], jjLayers[4], extraLayers2[0], extraLayers2[1], extraLayers2[2], extraLayers2[3], jjLayers[2], jjLayers[5], extraLayers[2], jjLayers[6], jjLayers[7], extraLayers[3], extraLayers[4], extraLayers[5], jjLayers[8]});
  111.        
  112.         extraLayers[1].spriteMode = SPRITE::TRANSLUCENTCOLOR;
  113.         extraLayers[1].spriteParam = 86;
  114.        
  115.         extraLayers[2].xOffset = 100;
  116.         extraLayers[2].yOffset = 360;
  117.         extraLayers[3].xOffset = 80;
  118.         extraLayers[3].yOffset = 120;
  119.         extraLayers[4].xOffset = 160;
  120.         extraLayers[4].yOffset = 140;
  121.         extraLayers[5].xOffset = 320;
  122.         extraLayers[5].yOffset = 160;
  123.        
  124.         extraLayers2[4].xOffset = 200;
  125.         extraLayers2[4].yOffset = -1700;
  126.         extraLayers2[5].xOffset = 300;
  127.         extraLayers2[5].yOffset = -1600;
  128.         extraLayers2[6].xOffset = 400;
  129.         extraLayers2[6].yOffset = -1500;
  130.        
  131.         for (uint16 i = 0; i < invisibleTiles.length(); i++) {
  132.                 jjTileType[invisibleTiles[i]] = 3; //invisible
  133.         }
  134.         jjTileType[1176] = 5;
  135.        
  136.         generateColoredRedeemerSprites(jjAnimSets[ANIM::CUSTOM[0]], array<uint> = {32, 24, 16, 40});
  137.         generateRedeemerPickupSprite(jjAnimSets[ANIM::CUSTOM[1]], array<uint> = {0});
  138. }
  139.  
  140. jjANIMSET@ coloredRedeemerSprite;
  141. bool generateColoredRedeemerSprites(jjANIMSET@ anim, const array<uint> &in colors) {
  142.         int length = colors.length();
  143.         bool success = (@coloredRedeemerSprite = anim).allocate(array<uint>(length * 4, 8)) !is null;
  144.         if (success) {
  145.                 uint srcSet = jjAnimSets[ANIM::SONCSHIP];
  146.                 for (int i = 0; i < length; i++) {
  147.                         uint color = colors[i];
  148.                         uint destAnimOffset = anim + i;
  149.                         for (int j = 0; j < 4; j++) {
  150.                                 uint srcAnim = jjAnimations[srcSet + 0];
  151.                                 uint destAnim = jjAnimations[destAnimOffset + j];
  152.                                 for (int k = 0; k < 8; k++) {
  153.                                         jjPIXELMAP image(jjAnimFrames[destAnim + k] = jjAnimFrames[srcAnim + k]);
  154.                                         int width = image.width;
  155.                                         int height = image.height;
  156.                                         for (int l = 0; l < height; l++) {
  157.                                                 for (int m = 0; m < width; m++) {
  158.                                                         int pixel = image[m, l];
  159.                                                         if (pixel >= 88 && pixel < 96)
  160.                                                                 image[m, l] = color + (pixel & 7);
  161.                                                 }
  162.                                         }
  163.                                         if (!image.save(jjAnimFrames[destAnim + k]))
  164.                                                 return false;
  165.                                 }
  166.                         }
  167.                 }
  168.         }
  169.         return success;
  170. }
  171.  
  172. jjANIMSET@ redeemerPickupSprite;
  173. bool generateRedeemerPickupSprite(jjANIMSET@ anim, const array<uint> &in colors) {
  174.         int length = colors.length();
  175.         bool success = (@redeemerPickupSprite = anim).allocate(array<uint>(length, 8)) !is null;
  176.         if (success) {
  177.                 uint srcSet = jjAnimSets[ANIM::SONCSHIP];
  178.                 for (int i = 0; i < length; i++) {
  179.                         uint color = colors[i];
  180.                         uint destAnimOffset = anim + i;
  181.                         uint srcAnim = jjAnimations[srcSet + 0];
  182.                         uint destAnim = jjAnimations[destAnimOffset + 0];
  183.                         for (int k = 0; k < 8; k++) {
  184.                                 jjPIXELMAP image(jjAnimFrames[destAnim + k] = jjAnimFrames[srcAnim + k]);
  185.                                 int width = image.width;
  186.                                 int height = image.height;
  187.                                 for (int l = 0; l < height; l++) {
  188.                                         for (int m = 0; m < width; m++) {
  189.                                                 int pixel = image[m, l];
  190.                                                 if (pixel >= 40 && pixel < 48)
  191.                                                         image[m, l] = color;
  192.                                         }
  193.                                 }
  194.                         if (!image.save(jjAnimFrames[destAnim + k]))
  195.                                 return false;
  196.                         }
  197.                 }
  198.         }
  199.         return success;
  200. }
  201.  
  202. class OscillatingMonitor : jjBEHAVIORINTERFACE {
  203.         void onBehave(jjOBJ@ obj) {
  204.                 obj.behave(BEHAVIOR::MONITOR);
  205.                 obj.xPos = obj.xOrg - 4;
  206.                 obj.yPos = (obj.yOrg + 2) - jjLayerYOffset[2];
  207.                 obj.direction = -1;
  208.         }
  209. }
  210.  
  211. class AmbientSound : jjBEHAVIORINTERFACE {
  212.         void onBehave(jjOBJ@ sound) {
  213.                 sound.behave(jjLowDetail && jjGameTicks >= 2? BEHAVIOR::INACTIVE : BEHAVIOR::AMBIENTSOUND, false);
  214.                 if (jjLocalPlayers[0].health > 0) delay++;
  215.                 else delay = 0;
  216.                
  217.                 if (jjTriggers[19] && isWindSound(sound) && delay >= 35) {
  218.                         loopSound(sound);
  219.                 }
  220.                 if (!jjTriggers[19] && isShipSound(sound) && delay >= 35) {
  221.                         loopSound(sound);
  222.                 }
  223.        
  224.                 if ((muteAmbientWind() && isWindSound(sound)) || jjLocalPlayers[0].health == 0) {
  225.                         jjTriggers[19] = false;
  226.                         sound.xPos = sound.xOrg;
  227.                         sound.yPos = sound.yOrg;
  228.                 }
  229.         }
  230. }
  231.  
  232. void loopSound(jjOBJ@ sound) {
  233.         sound.xPos = jjLocalPlayers[0].xPos;
  234.         sound.yPos = jjLocalPlayers[0].yPos;
  235. }
  236.  
  237. class JailBase : jjBEHAVIORINTERFACE {
  238.         void onBehave(jjOBJ@ obj) {
  239.                 obj.behave(BEHAVIOR::FLAG, false);
  240.         }
  241. }
  242.  
  243. class Redeemer : jjBEHAVIORINTERFACE {
  244.         void onBehave(jjOBJ@ obj) {
  245.                 //var[0] - angle
  246.                 //var[1] - angular speed
  247.                 //var[2] - has the redeemer exploded
  248.                 //special - value of jjGameTicks at the time the last packet was sent/received 
  249.                
  250.                 int angle;
  251.                 float speed = jjObjectPresets[OBJECT::TNT].xSpeed;
  252.                
  253.                 if (obj.creatorType != CREATOR::PLAYER)
  254.                         obj.delete();
  255.                 jjPLAYER@ creator = jjPlayers[obj.creatorID];
  256.                
  257.                 switch (obj.state) {
  258.                         case STATE::START:
  259.                                 obj.curAnim = jjObjectPresets[obj.eventID].curAnim;
  260.                                 jjSamplePriority(SOUND::P2_POEP);
  261.                                 obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
  262.                                 obj.ySpeed = speed * -jjSin(obj.var[0]);
  263.                                 obj.xSpeed = speed * jjCos(obj.var[0]);
  264.                                 obj.direction = obj.xSpeed < 0.f ? -1 : 1;
  265.                                 obj.var[2] = 0;
  266.                                 if (creator.isLocal) controllingRedeemer = true;
  267.                                 obj.state = STATE::FLY;
  268.                         break;
  269.                                
  270.                         case STATE::FLY:
  271.                                 redeemerCamera(creator, obj);
  272.                                 jjDrawRotatedSprite(obj.xPos, obj.yPos, (creator.isLocal || jjGameMode != GAME::CTF)? ANIM::SONCSHIP : ANIM::CUSTOM[0], (creator.isLocal || jjGameMode != GAME::CTF)? 0 : redeemerColor(creator), obj.curFrame, obj.var[0], 2, 2, SPRITE::NORMAL);
  273.                                 if (creator.isLocal) {
  274.                                         redeemerAngle = obj.var[0];
  275.                                         if (!jjLowDetail && (obj.counter % 131 == 36 || obj.counter == 1) && controllingRedeemer) jjSamplePriority(SOUND::P2_SPLOUT);
  276.                                         float dx = creator.xPos - obj.xPos, dy = creator.yPos - obj.yPos;
  277.                                                 if (dx * dx + dy * dy < 420 * 420) warning = true;
  278.                                                 else warning = false;
  279.                                         if (creator.health == 0) {
  280.                                                 creator.cameraUnfreeze(true);
  281.                                                 controllingRedeemer = false;
  282.                                         } else {
  283.                                                 if (controllingRedeemer) creator.xSpeed = 0;
  284.                                                 if (obj.counter >= 21) {
  285.                                                         if (controllingRedeemer) {
  286.                                                                 if (creator.keyRight || (obj.direction < 0 ? creator.keyUp : creator.keyDown))
  287.                                                                         obj.var[1] = -16;
  288.                                                                 else if (creator.keyLeft || (obj.direction < 0 ? creator.keyDown : creator.keyUp))
  289.                                                                         obj.var[1] = 16;
  290.                                                                 else
  291.                                                                         obj.var[1] = 0;
  292.                                                         }
  293.                                                         else obj.var[1] = 0;
  294.                                                 }
  295.                                                 if (obj.counter >= 127)
  296.                                                         obj.counter = 35;
  297.                                                 else if (obj.counter >= 35 && creator.keyFire && controllingRedeemer)
  298.                                                         obj.state = STATE::EXPLODE;
  299.                                         }
  300.                                         xPos = int(obj.xPos);
  301.                                         yPos = int(obj.yPos);
  302.                                 }
  303.                                 if (obj.yPos >= jjLayerHeight[4]*32) obj.state = STATE::EXPLODE;
  304.                                 obj.var[0] = obj.var[0] + obj.var[1];
  305.                                 obj.ySpeed = speed * -jjSin(obj.var[0]);
  306.                                 obj.xSpeed = speed * jjCos(obj.var[0]);
  307.                                 if (obj.counter % 3 == 0 && !jjLowDetail) spawnFireTrail(obj);
  308.                         break;
  309.                        
  310.                         case STATE::EXPLODE:
  311.                                 if (obj.var[2] == 0) {
  312.                                         RedeemerExplosion temp;
  313.                                         jjOBJ@ explosion = jjObjects[jjAddObject(OBJECT::BULLET, obj.xPos, obj.yPos, obj.creatorID, CREATOR::PLAYER, jjVOIDFUNCOBJ(temp.onBehave))];
  314.                                         jjSamplePriority(SOUND::P2_PTOEI);
  315.                                         obj.var[2] = 1;
  316.                                         explosion.var[2] = 1;
  317.                                 } else {
  318.                                         jjDrawResizedSprite(obj.xPos, obj.yPos, ANIM::AMMO, 5, obj.curFrame + 5, 8, 8, SPRITE::NORMAL, 0, 2, 2);
  319.                                 }
  320.                                 creator.cameraUnfreeze(true);
  321.                                 if (creator.isLocal) controllingRedeemer = false;
  322.                         break;
  323.                 }
  324.                
  325.                 int previousState = obj.state;
  326.                 obj.behave(BEHAVIOR::BULLET, false);
  327.                 if (!creator.isLocal) {
  328.                         if (obj.special + 128 > jjGameTicks)
  329.                                 obj.state = previousState;
  330.                 } else if (obj.special + 4 <= jjGameTicks) {
  331.                         jjSTREAM packet;
  332.                         packet.push(int8(obj.creatorID));
  333.                         packet.push(obj.state == STATE::EXPLODE);
  334.                         packet.push(obj.xPos);
  335.                         packet.push(obj.yPos);
  336.                         if (obj.state != STATE::EXPLODE) {
  337.                                 packet.push(int16(obj.var[0]));
  338.                                 packet.push(int16(obj.var[1]));
  339.                         }
  340.                         jjSendPacket(packet);
  341.                         obj.special = jjGameTicks;
  342.                 }
  343.         }
  344. }
  345.  
  346. void spawnFireTrail(jjOBJ@ obj) {
  347.         jjOBJ@ trail = jjObjects[jjAddObject(OBJECT::EXPLOSION, int(obj.xPos - jjCos(obj.var[0])), int(obj.yPos - jjSin(obj.var[0])))];
  348.         trail.determineCurAnim(ANIM::AMMO, 3);
  349.         trail.lightType = LIGHT::POINT;
  350.         trail.playerHandling = HANDLING::PARTICLE;
  351.         trail.bulletHandling = HANDLING::IGNOREBULLET;
  352.         trail.isBlastable = false;
  353. }
  354.  
  355. void redeemerCamera(jjPLAYER@ creator, jjOBJ@ obj) {
  356.         float dx = jjLayerWidth[4] - obj.xPos, dy = jjLayerHeight[4] - obj.yPos;
  357.        
  358.         if (jjLayerWidth[4] - dx <= 400) cameraX = 400;
  359.         else cameraX = int(obj.xPos);
  360.        
  361.         if (jjLayerHeight[4] - dy <= 400) cameraY = 400;
  362.         else cameraY = int(obj.yPos);
  363.        
  364.         if (controllingRedeemer) {
  365.                 creator.cameraFreeze(int(obj.xPos) >= 8528? 8528 : cameraX, int(obj.yPos) >= 4080? 4080 : cameraY, true, true);
  366.        
  367.                 for (int i = 0; i < 32; i++) {
  368.                         jjPLAYER@ play = jjPlayers[i];
  369.                         float reticleScale = jjSin(jjGameTicks*5);
  370.                         float reticleColor = jjSin(jjGameTicks*10)*2;
  371.                         float pdx = play.xPos - obj.xPos, pdy = play.yPos - obj.yPos;
  372.                         if ((pdx * pdx + pdy * pdy < 320 * 320) && (jjGameMode != GAME::CTF || jjFriendlyFire || play.team != creator.team) && !play.isLocal)
  373.                                 jjDrawResizedSprite(play.xPos, play.yPos, ANIM::SONCSHIP, 7, 0, reticleScale + 2, reticleScale + 2, SPRITE::SINGLECOLOR, int(reticleColor + 18), 1);
  374.                                                        
  375.                 }
  376.         }
  377. }
  378.  
  379. class RedeemerPickup : jjBEHAVIORINTERFACE {
  380.         void onBehave(jjOBJ@ obj) {
  381.                 obj.behave(BEHAVIOR::PICKUP, false);
  382.                 obj.direction = obj.xPos > 4464? -1:1;
  383.                 if (obj.isActive) jjDrawResizedSprite(int(obj.xPos) - (6 * obj.direction), int(obj.yPos) + jjSin(jjGameTicks*10)*6, ANIM::CUSTOM[1], 0, obj.curFrame, 2 * obj.direction, 2, ((obj.xPos < 4464 && jjLocalPlayers[0].team == TEAM::BLUE) || (obj.xPos > 4464 && jjLocalPlayers[0].team == TEAM::RED))? SPRITE::NORMAL : SPRITE::TRANSLUCENTSINGLEHUE, jjLocalPlayers[0].team == TEAM::BLUE? 24:32);
  384.         }
  385.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
  386.                 if (play.ammo[WEAPON::TNT] < jjWeapons[WEAPON::TNT].maximum) {
  387.                         if ((obj.xPos < 4464 && play.team == TEAM::BLUE) || (obj.xPos > 4464 && play.team == TEAM::RED) || otherMode()) {
  388.                                 if (play.isLocal) {
  389.                                         play.ammo[WEAPON::TNT] = play.ammo[WEAPON::TNT] + 1;
  390.                                         if (jjAutoWeaponChange) play.currWeapon = WEAPON::TNT;
  391.                                         jjSample(obj.xPos, obj.yPos, SOUND::COMMON_LOADSPAZ, 0, 0);
  392.                                 }
  393.                                 obj.behavior = BEHAVIOR::EXPLOSION2;
  394.                                 obj.scriptedCollisions = false;
  395.                                 obj.frameID = 0;
  396.                         }
  397.                 }
  398.                 return true;
  399.         }
  400. }
  401.  
  402. class RedeemerExplosion : jjBEHAVIORINTERFACE {
  403.         void onBehave(jjOBJ@ obj) {
  404.                 //var[0] - obj.counter
  405.                 //var[2] - has the redeemer exploded
  406.                 //var[4] - blast radius
  407.                 //var[5] - damage
  408.                 //var[8] - has the player been hit by the explosion
  409.        
  410.                 obj.playerHandling = HANDLING::PARTICLE;
  411.                 obj.bulletHandling = HANDLING::IGNOREBULLET;
  412.                
  413.                 obj.lightType = obj.var[2] == 1? LIGHT::RING2 : LIGHT::NONE;
  414.                
  415.                 jjPLAYER@ creator = jjPlayers[obj.creatorID];
  416.                 jjPLAYER@ play = jjLocalPlayers[0];
  417.                
  418.                 if (obj.var[2] == 1) {
  419.                         obj.var[0] = obj.var[0] + 1;
  420.                         obj.light += 2;
  421.                         obj.var[4] = obj.light * 5;
  422.                        
  423.                         if (obj.var[4] >= 460) obj.var[5] = 1;
  424.                         else if (obj.var[4] >= 360 && obj.var[4] < 460) obj.var[5] = 2;
  425.                         else if (obj.var[4] < 360) obj.var[5] = 3;
  426.                        
  427.                         for (int i = 1; i < jjObjectCount; i++) {
  428.                                 jjOBJ@ target = jjObjects[i];
  429.                                 float dx = target.xPos - obj.xPos, dy = target.yPos - obj.yPos;
  430.                                 if (isDestructibleItem(target) && target.var[4] == 0) {
  431.                                         if (dx * dx + dy * dy < obj.var[4] * obj.var[4]) {
  432.                                                 if (target.eventID != OBJECT::TNT) creator.objectHit(target, -1, HANDLING::SPECIAL);
  433.                                                 else target.state = STATE::EXPLODE;
  434.                                                 target.var[4] = 1;
  435.                                         }
  436.                                         else target.var[4] = 0;
  437.                                 }
  438.                                 else if (target.behavior == BEHAVIOR::PICKUP && target.state == STATE::FLOAT) {
  439.                                         if (dx * dx + dy * dy < obj.var[4] * obj.var[4])
  440.                                                 target.state = STATE::FLOATFALL;
  441.                                 }
  442.                         }
  443.                        
  444.                         float pdx = play.xPos - obj.xPos, pdy = play.yPos - obj.yPos;
  445.                         if (pdx * pdx + pdy * pdy < 1600 * 1600) {
  446.                                 uint random = jjRandom();
  447.                                 int magnitude = (2 << (random & 3)) - 1;
  448.                                 int halfMagnitude = magnitude >> 1;
  449.                                
  450.                                 if ((jjGameTicks & 1 == 0 && !jjTriggers[19]) || (jjGameTicks & 1 == 0 && jjTriggers[19] && jjMaskedHLine(int(play.xPos) - 12, 24, int(play.yPos) + 21)) && !controllingRedeemer)
  451.                                         play.cameraFreeze(play.cameraX + (random & magnitude) - halfMagnitude, play.cameraY + (random >> 8 & magnitude) - halfMagnitude, false, true);
  452.                                 else
  453.                                         play.cameraUnfreeze();
  454.                         }
  455.                 }
  456.                
  457.                 if (jjIsServer && gameIsActive()) {
  458.                         for (int i = 0; i < 32; i++) {
  459.                                 jjPLAYER@ player = jjPlayers[i];
  460.                                 if (
  461.                                         player.isActive && player.isInGame && player.health > 0 && !player.isJailed &&
  462.                                                 (jjGameMode != GAME::CTF || jjFriendlyFire || player.team != creator.team || player is creator)
  463.                                 ) {
  464.                                         float dx = player.xPos - obj.xPos, dy = player.yPos - obj.yPos;
  465.                                         if (dx * dx + dy * dy < obj.var[4] * obj.var[4]) {
  466.                                                 if (obj.var[8] & 1 << i == 0) {
  467.                                                         player.hurt(obj.var[5], true, creator);
  468.                                                         obj.var[8] = obj.var[8] | 1 << i;
  469.                                                 }
  470.                                         }
  471.                                 }
  472.                         }
  473.                 }
  474.                
  475.                 if (obj.var[0] == 1) {
  476.                         jjSample(obj.xPos, obj.yPos, SOUND::BILSBOSS_FIRE, 0, 0);
  477.                         for (int i = -8; i <= 8; i+=8) {
  478.                                 for (int j = -8; j <= 8; j+=8) {
  479.                                         if (i != 0 || j != 0) {
  480.                                                 Fireworks temp;
  481.                                                 int id = jjAddObject(OBJECT::ELECTROBULLET, obj.xPos, obj.yPos, obj.creatorID, CREATOR::PLAYER, jjVOIDFUNCOBJ(temp.onBehave));
  482.                                                 if (id != 0) {
  483.                                                         jjOBJ@ flares = jjObjects[id];
  484.                                                         flares.xSpeed = j*2;
  485.                                                         flares.ySpeed = i*2;
  486.                                                 }
  487.                                         }
  488.                                 }
  489.                         }
  490.                 }
  491.                 else if (obj.var[0] == 70) {
  492.                         obj.var[0] = 0;
  493.                         obj.var[2] = 0;
  494.                         obj.var[4] = 0;
  495.                         if (!controllingRedeemer) play.cameraUnfreeze();
  496.                         obj.delete();
  497.                 }
  498.         }
  499. }
  500.  
  501. class Fireworks : jjBEHAVIORINTERFACE {
  502.         void onBehave(jjOBJ@ obj) {
  503.                 obj.behave(BEHAVIOR::ELECTROBULLET, false);
  504.                 obj.counterEnd = 210;
  505.                 if (obj.ySpeed < 10 && obj.xSpeed != 0) obj.ySpeed += 0.5;
  506.                 obj.playerHandling = HANDLING::PARTICLE;
  507.                 obj.bulletHandling = HANDLING::IGNOREBULLET;
  508.                 if (obj.state == STATE::FLY) obj.particlePixelExplosion(1);
  509.         }
  510. }
  511.  
  512. void onReceive(jjSTREAM &in packet, int clientID) {
  513.         int8 playerID;
  514.         bool explosion;
  515.         float xPos, yPos;
  516.         int16 angle, angleSpeed;
  517.         jjSTREAM packetBackup;
  518.         if (jjIsServer)
  519.                 packetBackup = packet;
  520.         if (packet.pop(playerID) && playerID >= 0 && playerID < 32 &&
  521.                 packet.pop(explosion) && packet.pop(xPos) && packet.pop(yPos) &&
  522.                 (explosion || packet.pop(angle) && packet.pop(angleSpeed))
  523.         ) {
  524.                 const jjPLAYER@ player = jjPlayers[playerID];
  525.                 if (!jjIsServer || player.isActive && player.isInGame && player.clientID == clientID ) {
  526.                         jjOBJ@ redeemer;
  527.                         for (int i = 0; i < jjObjectCount; i++) {
  528.                                 jjOBJ@ obj = jjObjects[i];
  529.                                 if (obj.isActive && obj.eventID == OBJECT::TNT && obj.creatorType == CREATOR::PLAYER && obj.creatorID == uint(playerID)) {
  530.                                         @redeemer = obj;
  531.                                         break;
  532.                                 }
  533.                         }
  534.                         if (redeemer is null && jjGameTicks < 140) {
  535.                                 int id = jjAddObject(OBJECT::TNT, xPos, yPos, playerID, CREATOR::PLAYER);
  536.                                 if (id > 0)
  537.                                         @redeemer = jjObjects[id];
  538.                         }
  539.                         if (redeemer !is null) {
  540.                                 if (jjIsServer)
  541.                                         jjSendPacket(packetBackup, -clientID);
  542.                                 if (explosion)
  543.                                         redeemer.state = STATE::EXPLODE;
  544.                                 redeemer.xPos = xPos;
  545.                                 redeemer.yPos = yPos;
  546.                                 redeemer.var[0] = angle;
  547.                                 redeemer.var[1] = angleSpeed;
  548.                                 redeemer.special = jjGameTicks;
  549.                         }
  550.                 }
  551.         }
  552. }
  553.  
  554. void onPlayer(jjPLAYER@ play) {
  555.         play.lightType = LIGHT::NONE;
  556.         jjEnforceLighting = LIGHT::COMPLETE;
  557.        
  558.         if (controllingRedeemer) play.currWeapon = WEAPON::BLASTER;
  559.        
  560.         if (play.fly == FLIGHT::AIRBOARD && play.timerState == TIMER::STOPPED) play.timerStart(20*70);
  561.         if (play.fly == FLIGHT::NONE) play.timerStop();
  562.         if (play.timerState == TIMER::STARTED && play.timerTime <= 3*70 && play.timerTime > 0 && play.timerTime % 70 == 0) jjSamplePriority(SOUND::COMMON_NOCOIN);
  563. }
  564.  
  565. void onPlayerTimerEnd(jjPLAYER@ play) { play.fly = FLIGHT::NONE; }
  566.  
  567. void onMain() {
  568.         if (!jjLowDetail) {
  569.                 jjLayerYOffset[1] = jjCos(jjGameTicks*8)*4;
  570.                 jjLayerYOffset[2] = jjCos(jjGameTicks*8)*4;
  571.         } else {
  572.                 jjLayerYOffset[1] =
  573.                 jjLayerYOffset[2] = 0;
  574.         }
  575.        
  576.         array<jjLAYER@> layers = jjLayerOrderGet();
  577.         layers[0].hasTiles = layers[1].hasTiles = controllingRedeemer;
  578.         layers[8].xOffset = jjSin(jjGameTicks*48)*8;
  579.         layers[9].xOffset = -jjSin(jjGameTicks*48)*8;
  580.         layers[10].yOffset = jjCos(jjGameTicks*48)*8;
  581.         layers[11].yOffset = -jjCos(jjGameTicks*48)*8;
  582.        
  583.         if (controllingRedeemer && CTFMode()) {
  584.                 if (CTFArrowTimer > jjGameTicks + 280) CTFArrowTimer = jjGameTicks;
  585.                 if (CTFArrowTimer < jjGameTicks) {
  586.                         if (CTFArrowTimer + 64 >= jjGameTicks) {
  587.                                 for (int i = 0; i < 32; i++) {
  588.                                         jjPLAYER@ target = jjPlayers[i];
  589.                                         if (target.flag != 0 && target.team != jjLocalPlayers[0].team) {
  590.                                                 int angle = int(atan2(target.yPos - yPos, target.xPos - xPos) * (512 / PI));
  591.                                                 const float scale = 64.f / (112.f - jjSin((jjGameTicks - CTFArrowTimer) << 3) * 64.f);
  592.                                                 jjDrawRotatedSprite(xPos + 32 * jjCos(angle), yPos + 32 * jjSin(angle), ANIM::FLAG, 0, 0, 970 - angle, scale, scale, SPRITE::PALSHIFT, getTeamColor(target.team) - 32, 1);
  593.                                         }
  594.                                 }
  595.                         } else {
  596.                                 CTFArrowTimer = jjGameTicks + 210;
  597.                         }
  598.                 }
  599.         }
  600. }
  601.  
  602. bool onDrawPlayerTimer(jjPLAYER@ play, jjCANVAS@ canvas) {
  603.         if (play.fly == FLIGHT::AIRBOARD) {
  604.         canvas.drawString(
  605.                         jjSubscreenWidth - 75,
  606.                 jjSubscreenHeight - 284,
  607.                 "" + (play.timerTime > 0? (play.timerTime + 70) / 70 : 0),
  608.                 STRING::LARGE,
  609.                 STRING::PALSHIFT,
  610.                 play.timerTime > 3*70?
  611.                 24 :
  612.                 jjGameTicks % 28 > 14?
  613.                 -40 :
  614.                 -24
  615.                 );
  616.                
  617.                 canvas.drawSprite(
  618.                         jjSubscreenWidth - 92,
  619.                         jjSubscreenHeight - 280,
  620.                         ANIM::PICKUPS,
  621.                         36,
  622.                         jjGameTicks / 6 % 8
  623.                 );
  624.         }
  625.         return true;
  626. }
  627.  
  628. bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ canvas) {
  629.         if (controllingRedeemer) {
  630.                 canvas.drawString(
  631.                         jjSubscreenWidth - 480,
  632.                         jjSubscreenHeight - 450,
  633.                         "Redeemer!",
  634.                         STRING::MEDIUM,
  635.                         STRING::NORMAL
  636.                 );
  637.                 canvas.drawString(
  638.                         jjSubscreenWidth - 496,
  639.                         jjSubscreenHeight - 422,
  640.                         "Redeemer pos " + int(xPos / 32) + "," + int(yPos / 32),
  641.                         STRING::SMALL,
  642.                         STRING::NORMAL
  643.                 );
  644.                 canvas.drawString(
  645.                         jjSubscreenWidth - 624,
  646.                         jjSubscreenHeight - 406,
  647.                         "|Use the |||movement keys |||||to rotate the missile",
  648.                         STRING::SMALL,
  649.                         STRING::NORMAL
  650.                 );
  651.                 canvas.drawString(
  652.                         jjSubscreenWidth - 625,
  653.                         jjSubscreenHeight - 390,
  654.                         "|Press |||FIRE |||||to detonate the missile in mid-air",
  655.                         STRING::SMALL,
  656.                         STRING::NORMAL
  657.                 );
  658.                 canvas.drawRectangle(
  659.                         jjSubscreenWidth - 750,
  660.                         jjSubscreenHeight - 240,
  661.                         140,
  662.                         140,
  663.                         87,
  664.                         SPRITE::TRANSLUCENT
  665.                 );
  666.                 canvas.drawString(
  667.                         jjSubscreenWidth - 708,
  668.                         jjSubscreenHeight - 108,
  669.                         "Radar",
  670.                         STRING::SMALL,
  671.                         STRING::PALSHIFT,
  672.                         16
  673.                 );
  674.                 canvas.drawRotatedSprite(
  675.                         jjSubscreenWidth - 680,
  676.                         jjSubscreenHeight - 170,
  677.                         ANIM::CUSTOM[1],
  678.                         0,
  679.                         jjGameTicks >> 2,
  680.                         redeemerAngle,
  681.                         1,
  682.                         1,
  683.                         SPRITE::SINGLEHUE,
  684.                         80
  685.                 );
  686.                
  687.                 for (int i = 0; i < 32; i++) {
  688.                         jjPLAYER@ player = jjPlayers[i];
  689.                        
  690.                         uint8 teamColor;
  691.                         switch (player.team) {
  692.                                 case TEAM::BLUE: teamColor = 34; break;
  693.                                 case TEAM::RED: teamColor = 24; break;
  694.                                 case TEAM::GREEN: teamColor = 18; break;
  695.                                 case TEAM::YELLOW: teamColor = 40; break;
  696.                                 default: teamColor = 24; break;
  697.                         }
  698.                        
  699.                         int radarOffsetX = int(xPos - player.xPos) / 35;
  700.                         int radarOffsetY = int(yPos - player.yPos) / 35;
  701.                        
  702.                         if (radarOffsetX < 70 && radarOffsetX > -63 && radarOffsetY < 70 && radarOffsetY > -63 && player.xPos > 0 && player.yPos > 0 && !play.isSpectating && !play.isOut && !play.isConnecting) {
  703.                                 if (player.flag != 0 && !player.isLocal) {
  704.                                         canvas.drawResizedSprite(
  705.                                                 ((jjSubscreenWidth - 678) - radarOffsetX),
  706.                                                 ((jjSubscreenHeight - 168) - radarOffsetY),
  707.                                                 ANIM::FLAG,
  708.                                                 3,
  709.                                                 jjGameTicks >> 2,
  710.                                                 radarOffsetX > 0? 0.4:-0.4,
  711.                                                 0.4,
  712.                                                 SPRITE::SINGLECOLOR,
  713.                                                 player.team == TEAM::BLUE? 24 : 34
  714.                                         );
  715.                                         canvas.drawRectangle(
  716.                                                 ((jjSubscreenWidth - 680) - radarOffsetX),
  717.                                                 ((jjSubscreenHeight - 170) - radarOffsetY),
  718.                                                 6,
  719.                                                 6,
  720.                                                 teamColor,
  721.                                                 SPRITE::NORMAL
  722.                                         );
  723.                                 }
  724.                                 else if (player.flag == 0) {
  725.                                         canvas.drawRectangle(
  726.                                                 ((jjSubscreenWidth - 680) - radarOffsetX),
  727.                                                 ((jjSubscreenHeight - 170) - radarOffsetY),
  728.                                                 player.isLocal? 8:6,
  729.                                                 player.isLocal? 8:6,
  730.                                                 player.isLocal? 64 : jjGameMode == GAME::CTF? teamColor : 24,
  731.                                                 SPRITE::NORMAL
  732.                                         );
  733.                                 }
  734.                         }
  735.                        
  736.                         for (int j = 1; j < jjObjectCount; j++) {
  737.                                 if (jjObjects[j].eventID == OBJECT::TNT) {
  738.                                        
  739.                                         uint8 redeemerColor;
  740.                                         switch (jjPlayers[jjObjects[j].creatorID].team) {
  741.                                                 case TEAM::BLUE: redeemerColor = 34; break;
  742.                                                 case TEAM::RED: redeemerColor = 24; break;
  743.                                                 case TEAM::GREEN: redeemerColor = 18; break;
  744.                                                 case TEAM::YELLOW: redeemerColor = 40; break;
  745.                                                 default: redeemerColor = 88; break;
  746.                                         }
  747.                                        
  748.                                         int radarMissileOffsetX = int(xPos - jjObjects[j].xPos) / 35;
  749.                                         int radarMissileOffsetY = int(yPos - jjObjects[j].yPos) / 35;
  750.                                        
  751.                                         if (!jjPlayers[jjObjects[j].creatorID].isLocal && radarMissileOffsetX < 70 && radarMissileOffsetX > -63 && radarMissileOffsetY < 70 && radarMissileOffsetY > -63) {
  752.                                                 canvas.drawRotatedSprite(
  753.                                                         ((jjSubscreenWidth - 680) - radarMissileOffsetX),
  754.                                                         ((jjSubscreenHeight - 170) - radarMissileOffsetY),
  755.                                                         ANIM::CUSTOM[1],
  756.                                                         0,
  757.                                                         jjGameTicks >> 2,
  758.                                                         jjObjects[j].var[0],
  759.                                                         0.5,
  760.                                                         0.5,
  761.                                                         SPRITE::SINGLECOLOR,
  762.                                                         jjGameMode == GAME::CTF? redeemerColor : 90
  763.                                                 );
  764.                                         }
  765.                                 }
  766.                         }
  767.                 }
  768.                
  769.                 if (warning) {
  770.                         canvas.drawString(
  771.                                 jjSubscreenWidth - 550,
  772.                                 jjSubscreenHeight - 374,
  773.                                 "||WARNING: YOU ARE IN RANGE!",
  774.                                 STRING::SMALL,
  775.                                 STRING::NORMAL
  776.                         );
  777.                 }
  778.                
  779.                 if (!jjLowDetail && jjGameTicks % 140 >= 7) {
  780.                         canvas.drawString(
  781.                                 jjSubscreenWidth - 132,
  782.                                 jjSubscreenHeight - 46,
  783.                                 "REC",
  784.                                 STRING::MEDIUM,
  785.                                 STRING::NORMAL
  786.                         );
  787.                         canvas.drawSprite(
  788.                                 jjSubscreenWidth - 146,
  789.                                 jjSubscreenHeight - 45,
  790.                                 ANIM::VINE,
  791.                                 0,
  792.                                 0,
  793.                                 0,
  794.                                 SPRITE::NORMAL
  795.                         );
  796.                 }
  797.         }
  798.         else if (!controllingRedeemer && play.currWeapon == WEAPON::TNT) {
  799.                 canvas.drawString(
  800.                         jjSubscreenWidth - 80,
  801.                         jjSubscreenHeight - 14,
  802.                         "x" + play.ammo[WEAPON::TNT],
  803.                         STRING::MEDIUM,
  804.                         STRING::NORMAL
  805.                 );
  806.                 canvas.drawResizedSprite(
  807.                         jjSubscreenWidth - 110,
  808.                         jjSubscreenHeight - 14,
  809.                         ANIM::CUSTOM[1],
  810.                         0,
  811.                         jjGameTicks >> 2,
  812.                         2,
  813.                         2,
  814.                         SPRITE::NORMAL
  815.                 );
  816.         }
  817.        
  818.         return controllingRedeemer || play.currWeapon == WEAPON::TNT;
  819. }
  820.  
  821. void onFunction0(jjPLAYER@ play) {
  822.         play.showText("@@@@Skyward Showdown@Created by PurpleJazz of XLM (2009-2017)@Tileset by BlurredD@np: Kevin Riepl - Skyscraper [2:01]");
  823. }