Downloads containing ab24ctf12.j2as

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