Downloads containing ab20ctf17.j2as

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