Downloads containing ab22btl10.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Anniversary Bash 22 levels Jazz2Online Multiple N/A Download file

File preview

  1. const bool MLLESetupSuccessful = MLLE::Setup(); ///@MLLE-Generated
  2. #include "MLLE-Include-1.5.asc" ///@MLLE-Generated
  3. #pragma require "ab22btl10-MLLE-Data-2.j2l" ///@MLLE-Generated
  4. #pragma require "ab22btl10-MLLE-Data-1.j2l" ///@MLLE-Generated
  5. #pragma require "ab22btl10.j2l" ///@MLLE-Generated
  6.  
  7. /*******************************
  8. A 2020 Mystic Legends Release!
  9. http://www.mysticlegends.org
  10. /******************************/
  11.  
  12. #pragma require "FTURROCK.wav"
  13. #pragma require "EXPSTD3.wav"
  14. #pragma require "redeemer_flight.wav"
  15.  
  16. #pragma require "SEenergyblast.asc"
  17. #include "SEenergyblast.asc"
  18.  
  19. jjANIMFRAME@ backgroundCastle;
  20.  
  21. jjTEXTAPPEARANCE AlienTalk = STRING::NORMAL;
  22.  
  23. bool controllingRedeemer, warning = false;
  24. int xPos = 0, yPos = 0, cameraX = 0, cameraY = 0, redeemerAngle = 0, CTFArrowTimer = 0;
  25. uint delay = 0;
  26.  
  27. se::DefaultWeaponHook weaponHook;
  28. funcdef jjPALCOLOR ColorFunction(jjPALCOLOR);
  29.  
  30. class Vine {
  31.         private uint x, y;
  32.         Vine(){}
  33.         Vine(uint xx, uint yy) { x = xx; y = yy; }
  34.         void setEvent(AREA::Area area) { jjEventSet(x, y, area); }
  35. }
  36. array<Vine> Vines;
  37. void SetVines(bool toVine) {
  38.         for (uint i = 0; i < Vines.length; ++i)
  39.                 Vines[i].setEvent(toVine ? AREA::VINE : AREA::ONEWAY);
  40. }
  41.  
  42. int redeemerColor(jjPLAYER@ creator) {
  43.         //switch(creator.team) {
  44.                 //case TEAM::BLUE: return 0;
  45.                 //case TEAM::RED: return 1;
  46.                 //case TEAM::GREEN: return 2;
  47.                 //case TEAM::YELLOW: return 3;
  48.         //}
  49.         return 0;
  50. }
  51.  
  52. bool gameIsActive() {
  53.         return jjGameState == GAME::STARTED || jjGameState == GAME::OVERTIME;
  54. }
  55.  
  56. bool CTFMode() {
  57.         return (jjGameMode == GAME::CTF && jjGameCustom == GAME::NOCUSTOM) || jjGameCustom == GAME::DCTF;
  58. }
  59.  
  60. bool otherMode() {
  61.         return jjGameMode != GAME::CTF || jjGameCustom == GAME::TB || jjGameCustom == GAME::TLRS || jjGameCustom == GAME::DOM;
  62. }
  63.  
  64. bool isDestructibleItem(jjOBJ@ target) {
  65.         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;
  66. }
  67.  
  68. void onLevelLoad() {
  69.         jjTexturedBGTexture = TEXTURE::DIAMONDUSBETA;
  70.         jjTexturedBGFadePositionY = 0.55;
  71.        
  72.         jjUseLayer8Speeds = true;
  73.        
  74.         se::energyBlast.loadAnims(jjAnimSets[ANIM::CUSTOM[0]]);
  75.         se::energyBlast.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BLOW});
  76.         se::energyBlast.setAsWeapon(3, weaponHook);    
  77.        
  78.         //redeemer stuff
  79.         jjObjectPresets[OBJECT::TNT].determineCurFrame();
  80.         jjObjectPresets[OBJECT::TNT].behavior = Redeemer();
  81.         jjObjectPresets[OBJECT::TNT].xSpeed = jjObjectPresets[OBJECT::BLASTERBULLET].xSpeed * 1.33;
  82.         jjObjectPresets[OBJECT::TNT].counterEnd = 255;
  83.         jjObjectPresets[OBJECT::TNT].killAnim = jjObjectPresets[OBJECT::SEEKERBULLET].killAnim;
  84.        
  85.         jjObjectPresets[OBJECT::TNTAMMO3].behavior = RedeemerPickup();
  86.         jjObjectPresets[OBJECT::TNTAMMO3].determineCurFrame();
  87.         jjObjectPresets[OBJECT::TNTAMMO3].scriptedCollisions = true;
  88.        
  89.         jjWeapons[WEAPON::TNT].maximum = 1;
  90.        
  91.         jjWeapons[WEAPON::ICE].maximum = 99;
  92.        
  93.         jjAnimSets[ANIM::SONCSHIP].load();
  94.         jjAnimSets[ANIM::VINE].load();
  95.         jjAnimations[jjAnimSets[ANIM::AMMO] + 59] = jjAnimations[jjAnimSets[ANIM::SONCSHIP] + 0];
  96.        
  97.         AlienTalk.align = STRING::CENTER;
  98.         AlienTalk.monospace = true;
  99.         AlienTalk.spacing = 8;
  100.         AlienTalk.xAmp = 0;
  101.         AlienTalk.yAmp = 1;
  102.        
  103.         for (int x = jjLayerWidth[4] - 1; x >= 0; --x) {
  104.                 for (int y = jjLayerHeight[4] - 1; y >= 0; --y) {
  105.                         if (jjEventGet(x, y) == AREA::VINE)
  106.                                 Vines.insertLast(Vine(x,y));
  107.                 }
  108.         }
  109.        
  110.         //generateColoredRedeemerSprites(jjAnimSets[ANIM::CUSTOM[0]], array<uint> = {32, 24, 16, 40});
  111.         generateRedeemerPickupSprite(jjAnimSets[ANIM::CUSTOM[1]], array<uint> = {0});
  112.        
  113.         jjSampleLoad(SOUND::P2_POEP, "FTURROCK.wav");
  114.         jjSampleLoad(SOUND::P2_PTOEI, "EXPSTD3.wav");
  115.         jjSampleLoad(SOUND::P2_SPLOUT, "redeemer_flight.wav");
  116. }
  117.  
  118. int elapsed = 0;
  119. int glowIndex = 0;
  120. array<uint8> glowColors = {1, 4, 5, 6};
  121.  
  122. const string ALIENTALK_1 = "(ayy lmao)";
  123. const string ALIENTALK_2 = "(seek the red flower)";
  124. const string ALIENTALK_3 = "(haha tractor beam goes bzz)";
  125. const string ALIENTALK_S = "(I want to go home...)";
  126.  
  127. void onDrawLayer3(jjPLAYER@ play, jjCANVAS@ layer) {
  128.         if (play.yPos >= 0) {
  129.                 int skill = jjParameterGet(uint16(play.xPos/32), uint16(play.yPos/32), -4, 2); 
  130.                 if (skill == 2) { //Hard
  131.                
  132.                         if (++elapsed % 14 == 0) {
  133.                                 if (glowIndex >= 3) {
  134.                                                 glowIndex = 0;
  135.                                 }
  136.                                 else {
  137.                                                 ++glowIndex;
  138.                                 }
  139.                                 //jjAlert("" + glowIndex);
  140.                         }
  141.                        
  142.                         layer.drawString(556,  224,  ALIENTALK_1, STRING::SMALL, AlienTalk, 0, SPRITE::NEONGLOW, glowColors[glowIndex]);
  143.                         layer.drawString(1936, 196,  ALIENTALK_2, STRING::SMALL, AlienTalk, 0, SPRITE::NEONGLOW, glowColors[glowIndex]);
  144.                         layer.drawString(3924, 260,  ALIENTALK_3, STRING::SMALL, AlienTalk, 0, SPRITE::NEONGLOW, glowColors[glowIndex]);
  145.                         layer.drawString(2354, 2208, ALIENTALK_S, STRING::SMALL, AlienTalk, 0, SPRITE::NEONGLOW, glowColors[glowIndex]);
  146.                 }
  147.                 else {
  148.                         elapsed = 0;
  149.                         glowIndex = 0;
  150.                 }
  151.         }      
  152. }
  153.  
  154. void onPlayer(jjPLAYER@ play) {
  155.                 weaponHook.processPlayer(play);
  156.                        
  157.                 //fix for getting stuck inside magnets, thanks SE                              
  158.                 const int x = int(play.xPos);
  159.                 const int y = int(play.yPos);
  160.                 const int left = x - 12;
  161.                 const int right = x + 12;
  162.                 const int top = y - (play.antiGrav ? 18 : 6);
  163.                 const int bottom = y + (play.antiGrav ? 6 : 18);
  164.                 const int middle = (top + bottom) >>> 1;
  165.                 const array<int> passThroughEvents = {AREA::HOOK, AREA::ONEWAY, AREA::VINE};
  166.                 int counter = 0;
  167.                 int direction = 0;
  168.                 int topmost = bottom;
  169.                 int bottommost = top;
  170.                 for (int i = top; i <= bottom; i++) {
  171.                     for (int j = left; j < right; j++) {
  172.                         if (jjMaskedPixel(j, i) && passThroughEvents.find(jjEventAtLastMaskedPixel) < 0) {
  173.                             counter++;
  174.                             direction += i < middle ? 1 : i > middle ? -1 : 0;
  175.                             if (i < topmost)
  176.                                 topmost = i;
  177.                             if (i > bottommost)
  178.                                 bottommost = i;
  179.                         }
  180.                     }
  181.                 }
  182.                 if (counter > 32) {
  183.                     if (direction > 0)
  184.                         play.yPos += bottommost - top;
  185.                     else if (direction < 0)
  186.                         play.yPos += topmost - bottom;
  187.                 }
  188.                
  189.                 if (controllingRedeemer) play.currWeapon = WEAPON::BLASTER;
  190. }
  191.  
  192. void onMain() {
  193.         weaponHook.processMain();
  194. }
  195.  
  196. void onPlayerInput(jjPLAYER@ play) {
  197.     weaponHook.processPlayerInput(play);
  198.    
  199.     //SetVines((play.currWeapon == WEAPON::ICE && play.keyFire));
  200. }
  201.  
  202. //redeemer
  203. class Redeemer : jjBEHAVIORINTERFACE {
  204.         void onBehave(jjOBJ@ obj) {
  205.                 //var[0] - angle
  206.                 //var[1] - angular speed
  207.                 //var[2] - has the redeemer exploded
  208.                 //special - value of jjGameTicks at the time the last packet was sent/received 
  209.                
  210.                 int angle;
  211.                 float speed = jjObjectPresets[OBJECT::TNT].xSpeed;
  212.                
  213.                 if (obj.creatorType != CREATOR::PLAYER)
  214.                         obj.delete();
  215.                 jjPLAYER@ creator = jjPlayers[obj.creatorID];
  216.                
  217.                 switch (obj.state) {
  218.                         case STATE::START:
  219.                                 obj.curAnim = jjObjectPresets[obj.eventID].curAnim;
  220.                                 jjSamplePriority(SOUND::P2_POEP);
  221.                                 obj.var[0] = int(atan2(-obj.ySpeed, obj.xSpeed) * (512.f * 0.318309886142228f));
  222.                                 obj.ySpeed = speed * -jjSin(obj.var[0]);
  223.                                 obj.xSpeed = speed * jjCos(obj.var[0]);
  224.                                 obj.direction = obj.xSpeed < 0.f ? -1 : 1;
  225.                                 obj.var[2] = 0;
  226.                                 if (creator.isLocal) controllingRedeemer = true;
  227.                                 obj.state = STATE::FLY;
  228.                         break;
  229.                                
  230.                         case STATE::FLY:
  231.                                 redeemerCamera(creator, obj);
  232.                                 jjDrawRotatedSprite(obj.xPos, obj.yPos, (creator.isLocal || jjGameMode != GAME::CTF)? ANIM::SONCSHIP : ANIM::SONCSHIP, (creator.isLocal || jjGameMode != GAME::CTF)? 0 : redeemerColor(creator), obj.curFrame, obj.var[0], 2, 2, SPRITE::NORMAL);
  233.                                 if (creator.isLocal) {
  234.                                         redeemerAngle = obj.var[0];
  235.                                         if (!jjLowDetail && (obj.counter % 131 == 36 || obj.counter == 1) && controllingRedeemer) jjSamplePriority(SOUND::P2_SPLOUT);
  236.                                         float dx = creator.xPos - obj.xPos, dy = creator.yPos - obj.yPos;
  237.                                                 if (dx * dx + dy * dy < 420 * 420) warning = true;
  238.                                                 else warning = false;
  239.                                         if (creator.health == 0) {
  240.                                                 creator.cameraUnfreeze(true);
  241.                                                 controllingRedeemer = false;
  242.                                         } else {
  243.                                                 if (controllingRedeemer) creator.xSpeed = 0;
  244.                                                 if (obj.counter >= 21) {
  245.                                                         if (controllingRedeemer) {
  246.                                                                 if (creator.keyRight || (obj.direction < 0 ? creator.keyUp : creator.keyDown))
  247.                                                                         obj.var[1] = -16;
  248.                                                                 else if (creator.keyLeft || (obj.direction < 0 ? creator.keyDown : creator.keyUp))
  249.                                                                         obj.var[1] = 16;
  250.                                                                 else
  251.                                                                         obj.var[1] = 0;
  252.                                                         }
  253.                                                         else obj.var[1] = 0;
  254.                                                 }
  255.                                                 if (obj.counter >= 127)
  256.                                                         obj.counter = 35;
  257.                                                 else if (obj.counter >= 35 && creator.keyFire && controllingRedeemer)
  258.                                                         obj.state = STATE::EXPLODE;
  259.                                         }
  260.                                         xPos = int(obj.xPos);
  261.                                         yPos = int(obj.yPos);
  262.                                 }
  263.                                 if (obj.yPos >= jjLayerHeight[4]*32) obj.state = STATE::EXPLODE;
  264.                                 obj.var[0] = obj.var[0] + obj.var[1];
  265.                                 obj.ySpeed = speed * -jjSin(obj.var[0]);
  266.                                 obj.xSpeed = speed * jjCos(obj.var[0]);
  267.                                 if (obj.counter % 3 == 0 && !jjLowDetail) spawnFireTrail(obj);
  268.                         break;
  269.                        
  270.                         case STATE::EXPLODE:
  271.                                 if (obj.var[2] == 0) {
  272.                                         RedeemerExplosion temp;
  273.                                         jjOBJ@ explosion = jjObjects[jjAddObject(OBJECT::BULLET, obj.xPos, obj.yPos, obj.creatorID, CREATOR::PLAYER, jjVOIDFUNCOBJ(temp.onBehave))];
  274.                                         jjSamplePriority(SOUND::P2_PTOEI);
  275.                                         obj.var[2] = 1;
  276.                                         explosion.var[2] = 1;
  277.                                 } else {
  278.                                         jjDrawResizedSprite(obj.xPos, obj.yPos, ANIM::AMMO, 5, obj.curFrame + 5, 8, 8, SPRITE::NORMAL, 0, 2, 2);
  279.                                 }
  280.                                 creator.cameraUnfreeze(true);
  281.                                 if (creator.isLocal) controllingRedeemer = false;
  282.                         break;
  283.                 }
  284.                
  285.                 int previousState = obj.state;
  286.                 obj.behave(BEHAVIOR::BULLET, false);
  287.                 if (!creator.isLocal) {
  288.                         if (obj.special + 128 > jjGameTicks)
  289.                                 obj.state = previousState;
  290.                 } else if (obj.special + 4 <= jjGameTicks) {
  291.                         jjSTREAM packet;
  292.                         packet.push(int8(obj.creatorID));
  293.                         packet.push(obj.state == STATE::EXPLODE);
  294.                         packet.push(obj.xPos);
  295.                         packet.push(obj.yPos);
  296.                         if (obj.state != STATE::EXPLODE) {
  297.                                 packet.push(int16(obj.var[0]));
  298.                                 packet.push(int16(obj.var[1]));
  299.                         }
  300.                         jjSendPacket(packet);
  301.                         obj.special = jjGameTicks;
  302.                 }
  303.         }
  304. }
  305.  
  306. void spawnFireTrail(jjOBJ@ obj) {
  307.         jjOBJ@ trail = jjObjects[jjAddObject(OBJECT::EXPLOSION, int(obj.xPos - jjCos(obj.var[0])), int(obj.yPos - jjSin(obj.var[0])))];
  308.         trail.determineCurAnim(ANIM::AMMO, 3);
  309.         trail.lightType = LIGHT::POINT;
  310.         trail.playerHandling = HANDLING::PARTICLE;
  311.         trail.bulletHandling = HANDLING::IGNOREBULLET;
  312.         trail.isBlastable = false;
  313. }
  314.  
  315. void redeemerCamera(jjPLAYER@ creator, jjOBJ@ obj) {
  316.         float dx = jjLayerWidth[4] - obj.xPos, dy = jjLayerHeight[4] - obj.yPos;
  317.        
  318.         if (jjLayerWidth[4] - dx <= 400) cameraX = 400;
  319.         else cameraX = int(obj.xPos);
  320.        
  321.         if (jjLayerHeight[4] - dy <= 400) cameraY = 400;
  322.         else cameraY = int(obj.yPos);
  323.        
  324.         if (controllingRedeemer) {
  325.                 creator.cameraFreeze(int(obj.xPos) >= 8528? 8528 : cameraX, int(obj.yPos) >= 4080? 4080 : cameraY, true, true);
  326.        
  327.                 for (int i = 0; i < 32; i++) {
  328.                         jjPLAYER@ play = jjPlayers[i];
  329.                         float reticleScale = jjSin(jjGameTicks*5);
  330.                         float reticleColor = jjSin(jjGameTicks*10)*2;
  331.                         float pdx = play.xPos - obj.xPos, pdy = play.yPos - obj.yPos;
  332.                         if ((pdx * pdx + pdy * pdy < 320 * 320) && (jjGameMode != GAME::CTF || jjFriendlyFire || play.team != creator.team) && !play.isLocal)
  333.                                 jjDrawResizedSprite(play.xPos, play.yPos, ANIM::SONCSHIP, 7, 0, reticleScale + 2, reticleScale + 2, SPRITE::SINGLECOLOR, int(reticleColor + 18), 1);
  334.                                                        
  335.                 }
  336.         }
  337. }
  338.  
  339. class RedeemerPickup : jjBEHAVIORINTERFACE {
  340.         void onBehave(jjOBJ@ obj) {
  341.                 obj.behave(BEHAVIOR::PICKUP, false);
  342.                 obj.direction = obj.xPos > 4464? -1:1;
  343.                 if (obj.isActive) jjDrawResizedSprite(int(obj.xPos) - (6 * obj.direction), int(obj.yPos) + jjSin(jjGameTicks*10)*6, ANIM::CUSTOM[1], 0, obj.curFrame, 2 * obj.direction, 2, ((obj.xPos < 4464 && jjLocalPlayers[0].team == TEAM::BLUE) || (obj.xPos > 4464 && jjLocalPlayers[0].team == TEAM::RED))? SPRITE::NORMAL : SPRITE::NORMAL);
  344.         }
  345.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
  346.                 if (play.ammo[WEAPON::TNT] < jjWeapons[WEAPON::TNT].maximum) {
  347.                         if ((obj.xPos < 4464 && play.team == TEAM::BLUE) || (obj.xPos > 4464 && play.team == TEAM::RED) || otherMode()) {
  348.                                 if (play.isLocal) {
  349.                                         play.ammo[WEAPON::TNT] = play.ammo[WEAPON::TNT] + 1;
  350.                                         play.currWeapon = WEAPON::TNT;
  351.                                         //jjSample(obj.xPos, obj.yPos, SOUND::COMMON_LOADSPAZ, 0, 0);
  352.                                         jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUPW1, 0, 0);
  353.                                         jjSample(obj.xPos, obj.yPos, SOUND::INTRO_IFEEL, 0, 0);
  354.                                         if (play.charCurr == CHAR::JAZZ) {
  355.                                                 jjSample(play.xPos, play.yPos, SOUND::JAZZSOUNDS_JUMMY, 0, 0);
  356.                                         }
  357.                                         if (play.charCurr == CHAR::SPAZ) {
  358.                                                 jjSample(play.xPos, play.yPos, SOUND::SPAZSOUNDS_HAPPY, 0, 0);
  359.                                         }
  360.                                         if (play.charCurr == CHAR::LORI) {
  361.                                                 jjSample(play.xPos, play.yPos, SOUND::LORISOUNDS_WEHOO, 0, 0);
  362.                                         }
  363.                                 }
  364.                                 obj.behavior = BEHAVIOR::EXPLOSION2;
  365.                                 obj.scriptedCollisions = false;
  366.                                 obj.frameID = 0;
  367.                         }
  368.                 }
  369.                 return true;
  370.         }
  371. }
  372.  
  373. class RedeemerExplosion : jjBEHAVIORINTERFACE {
  374.         void onBehave(jjOBJ@ obj) {
  375.                 //var[0] - obj.counter
  376.                 //var[2] - has the redeemer exploded
  377.                 //var[4] - blast radius
  378.                 //var[5] - damage
  379.                 //var[8] - has the player been hit by the explosion
  380.        
  381.                 obj.playerHandling = HANDLING::PARTICLE;
  382.                 obj.bulletHandling = HANDLING::IGNOREBULLET;
  383.                
  384.                 obj.lightType = obj.var[2] == 1? LIGHT::RING2 : LIGHT::NONE;
  385.                
  386.                 jjPLAYER@ creator = jjPlayers[obj.creatorID];
  387.                 jjPLAYER@ play = jjLocalPlayers[0];
  388.                
  389.                 if (obj.var[2] == 1) {
  390.                         obj.var[0] = obj.var[0] + 1;
  391.                         obj.light += 2;
  392.                         obj.var[4] = obj.light * 5;
  393.                        
  394.                         if (obj.var[4] >= 460) obj.var[5] = 1;
  395.                         else if (obj.var[4] >= 360 && obj.var[4] < 460) obj.var[5] = 2;
  396.                         else if (obj.var[4] < 360) obj.var[5] = 7;
  397.                        
  398.                         for (int i = 1; i < jjObjectCount; i++) {
  399.                                 jjOBJ@ target = jjObjects[i];
  400.                                 float dx = target.xPos - obj.xPos, dy = target.yPos - obj.yPos;
  401.                                 if (isDestructibleItem(target) && target.var[4] == 0) {
  402.                                         if (dx * dx + dy * dy < obj.var[4] * obj.var[4]) {
  403.                                                 if (target.eventID != OBJECT::TNT) creator.objectHit(target, -1, HANDLING::SPECIAL);
  404.                                                 else target.state = STATE::EXPLODE;
  405.                                                 target.var[4] = 1;
  406.                                         }
  407.                                         else target.var[4] = 0;
  408.                                 }
  409.                                 else if (target.behavior == BEHAVIOR::PICKUP && target.state == STATE::FLOAT) {
  410.                                         if (dx * dx + dy * dy < obj.var[4] * obj.var[4])
  411.                                                 target.state = STATE::FLOATFALL;
  412.                                 }
  413.                         }
  414.                        
  415.                         float pdx = play.xPos - obj.xPos, pdy = play.yPos - obj.yPos;
  416.                         if (pdx * pdx + pdy * pdy < 1600 * 1600) {
  417.                                 uint random = jjRandom();
  418.                                 int magnitude = (2 << (random & 3)) - 1;
  419.                                 int halfMagnitude = magnitude >> 1;
  420.                                
  421.                                 if ((jjGameTicks & 1 == 0 && !jjTriggers[19]) || (jjGameTicks & 1 == 0 && jjTriggers[19] && jjMaskedHLine(int(play.xPos) - 12, 24, int(play.yPos) + 21)) && !controllingRedeemer)
  422.                                         play.cameraFreeze(play.cameraX + (random & magnitude) - halfMagnitude, play.cameraY + (random >> 8 & magnitude) - halfMagnitude, false, true);
  423.                                 else
  424.                                         play.cameraUnfreeze();
  425.                         }
  426.                 }
  427.                
  428.                 if (jjIsServer && gameIsActive()) {
  429.                         for (int i = 0; i < 32; i++) {
  430.                                 jjPLAYER@ player = jjPlayers[i];
  431.                                 if (
  432.                                         player.isActive && player.isInGame && player.health > 0 &&
  433.                                                 (jjGameMode != GAME::CTF || jjFriendlyFire || player.team != creator.team || player is creator)
  434.                                 ) {
  435.                                         float dx = player.xPos - obj.xPos, dy = player.yPos - obj.yPos;
  436.                                         if (dx * dx + dy * dy < obj.var[4] * obj.var[4]) {
  437.                                                 if (obj.var[8] & 1 << i == 0) {
  438.                                                         player.hurt(obj.var[5], true, creator);
  439.                                                         obj.var[8] = obj.var[8] | 1 << i;
  440.                                                 }
  441.                                         }
  442.                                 }
  443.                         }
  444.                 }
  445.                
  446.                 if (obj.var[0] == 1) {
  447.                         jjSample(obj.xPos, obj.yPos, SOUND::BILSBOSS_FIRE, 0, 0);
  448.                         for (int i = -8; i <= 8; i+=8) {
  449.                                 for (int j = -8; j <= 8; j+=8) {
  450.                                         if (i != 0 || j != 0) {
  451.                                                 Fireworks temp;
  452.                                                 int id = jjAddObject(OBJECT::ELECTROBULLET, obj.xPos, obj.yPos, obj.creatorID, CREATOR::PLAYER, jjVOIDFUNCOBJ(temp.onBehave));
  453.                                                 if (id != 0) {
  454.                                                         jjOBJ@ flares = jjObjects[id];
  455.                                                         flares.xSpeed = j*2;
  456.                                                         flares.ySpeed = i*2;
  457.                                                 }
  458.                                         }
  459.                                 }
  460.                         }
  461.                 }
  462.                 else if (obj.var[0] == 70) {
  463.                         obj.var[0] = 0;
  464.                         obj.var[2] = 0;
  465.                         obj.var[4] = 0;
  466.                         if (!controllingRedeemer) play.cameraUnfreeze();
  467.                         obj.delete();
  468.                 }
  469.         }
  470. }
  471.  
  472. class Fireworks : jjBEHAVIORINTERFACE {
  473.         void onBehave(jjOBJ@ obj) {
  474.                 obj.behave(BEHAVIOR::ELECTROBULLET, false);
  475.                 obj.counterEnd = 210;
  476.                 if (obj.ySpeed < 10 && obj.xSpeed != 0) obj.ySpeed += 0.5;
  477.                 obj.playerHandling = HANDLING::PARTICLE;
  478.                 obj.bulletHandling = HANDLING::IGNOREBULLET;
  479.                 if (obj.state == STATE::FLY) obj.particlePixelExplosion(1);
  480.         }
  481. }
  482.  
  483. void onReceive(jjSTREAM &in packet, int clientID) {
  484.         int8 playerID;
  485.         bool explosion;
  486.         float xPos, yPos;
  487.         int16 angle, angleSpeed;
  488.         jjSTREAM packetBackup;
  489.         if (jjIsServer)
  490.                 packetBackup = packet;
  491.         if (packet.pop(playerID) && playerID >= 0 && playerID < 32 &&
  492.                 packet.pop(explosion) && packet.pop(xPos) && packet.pop(yPos) &&
  493.                 (explosion || packet.pop(angle) && packet.pop(angleSpeed))
  494.         ) {
  495.                 const jjPLAYER@ player = jjPlayers[playerID];
  496.                 if (!jjIsServer || player.isActive && player.isInGame && player.clientID == clientID ) {
  497.                         jjOBJ@ redeemer;
  498.                         for (int i = 0; i < jjObjectCount; i++) {
  499.                                 jjOBJ@ obj = jjObjects[i];
  500.                                 if (obj.isActive && obj.eventID == OBJECT::TNT && obj.creatorType == CREATOR::PLAYER && obj.creatorID == uint(playerID)) {
  501.                                         @redeemer = obj;
  502.                                         break;
  503.                                 }
  504.                         }
  505.                         if (redeemer is null && jjGameTicks < 140) {
  506.                                 int id = jjAddObject(OBJECT::TNT, xPos, yPos, playerID, CREATOR::PLAYER);
  507.                                 if (id > 0)
  508.                                         @redeemer = jjObjects[id];
  509.                         }
  510.                         if (redeemer !is null) {
  511.                                 if (jjIsServer)
  512.                                         jjSendPacket(packetBackup, -clientID);
  513.                                 if (explosion)
  514.                                         redeemer.state = STATE::EXPLODE;
  515.                                 redeemer.xPos = xPos;
  516.                                 redeemer.yPos = yPos;
  517.                                 redeemer.var[0] = angle;
  518.                                 redeemer.var[1] = angleSpeed;
  519.                                 redeemer.special = jjGameTicks;
  520.                         }
  521.                 }
  522.         }
  523.        
  524.         weaponHook.processPacket(packet, clientID);
  525. }
  526.  
  527. //void onPlayer(jjPLAYER@ play) {
  528.         //if (play.shieldTime > 15*70) play.shieldTime = 15*70;
  529.        
  530.         //play.lightType = LIGHT::NONE;
  531.         //jjEnforceLighting = LIGHT::COMPLETE;
  532.        
  533.         //if (controllingRedeemer) play.currWeapon = WEAPON::BLASTER;
  534.        
  535.         //if (play.fly == FLIGHT::AIRBOARD && play.timerState == TIMER::STOPPED) play.timerStart(20*70);
  536.         //if (play.fly == FLIGHT::NONE) play.timerStop();
  537.         //if (play.timerState == TIMER::STARTED && play.timerTime <= 3*70 && play.timerTime > 0 && play.timerTime % 70 == 0) jjSamplePriority(SOUND::COMMON_NOCOIN);
  538. //}
  539.  
  540. bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ canvas) {
  541.         if (controllingRedeemer) {
  542.                 canvas.drawString(
  543.                         jjSubscreenWidth - 480,
  544.                         jjSubscreenHeight - 450,
  545.                         "Redeemer!",
  546.                         STRING::MEDIUM,
  547.                         STRING::NORMAL
  548.                 );
  549.                 //canvas.drawString(
  550.                         //jjSubscreenWidth - 496,
  551.                         //jjSubscreenHeight - 422,
  552.                         //"Redeemer pos " + int(xPos / 32) + "," + int(yPos / 32),
  553.                         //STRING::SMALL,
  554.                         //STRING::NORMAL
  555.                 //);
  556.                 canvas.drawString(
  557.                         jjSubscreenWidth - 624,
  558.                         jjSubscreenHeight - 406,
  559.                         "§0|Use the |||movement keys |||||to rotate the missile",
  560.                         STRING::SMALL,
  561.                         STRING::NORMAL
  562.                 );
  563.                 canvas.drawString(
  564.                         jjSubscreenWidth - 625,
  565.                         jjSubscreenHeight - 390,
  566.                         "§0|Press |||FIRE |||||to detonate the missile in mid-air",
  567.                         STRING::SMALL,
  568.                         STRING::NORMAL
  569.                 );
  570.                 canvas.drawRectangle(
  571.                         jjSubscreenWidth - 750,
  572.                         jjSubscreenHeight - 240,
  573.                         140,
  574.                         140,
  575.                         87,
  576.                         SPRITE::TRANSLUCENT
  577.                 );
  578.                 canvas.drawString(
  579.                         jjSubscreenWidth - 708,
  580.                         jjSubscreenHeight - 108,
  581.                         "Radar",
  582.                         STRING::SMALL,
  583.                         STRING::PALSHIFT,
  584.                         16
  585.                 );
  586.                 canvas.drawRotatedSprite(
  587.                         jjSubscreenWidth - 680,
  588.                         jjSubscreenHeight - 170,
  589.                         ANIM::CUSTOM[1],
  590.                         0,
  591.                         jjGameTicks >> 2,
  592.                         redeemerAngle,
  593.                         1,
  594.                         1,
  595.                         SPRITE::SINGLEHUE,
  596.                         80
  597.                 );
  598.                
  599.                 for (int i = 0; i < 32; i++) {
  600.                         jjPLAYER@ player = jjPlayers[i];
  601.                        
  602.                         uint8 teamColor;
  603.                         switch (player.team) {
  604.                                 case TEAM::BLUE: teamColor = 34; break;
  605.                                 case TEAM::RED: teamColor = 24; break;
  606.                                 case TEAM::GREEN: teamColor = 18; break;
  607.                                 case TEAM::YELLOW: teamColor = 40; break;
  608.                                 default: teamColor = 24; break;
  609.                         }
  610.                        
  611.                         int radarOffsetX = int(xPos - player.xPos) / 35;
  612.                         int radarOffsetY = int(yPos - player.yPos) / 35;
  613.                        
  614.                         if (radarOffsetX < 70 && radarOffsetX > -63 && radarOffsetY < 70 && radarOffsetY > -63 && player.xPos > 0 && player.yPos > 0 && !play.isSpectating && !play.isOut && !play.isConnecting) {
  615.                                 if (player.flag != 0 && !player.isLocal) {
  616.                                         canvas.drawResizedSprite(
  617.                                                 ((jjSubscreenWidth - 678) - radarOffsetX),
  618.                                                 ((jjSubscreenHeight - 168) - radarOffsetY),
  619.                                                 ANIM::FLAG,
  620.                                                 3,
  621.                                                 jjGameTicks >> 2,
  622.                                                 radarOffsetX > 0? 0.4:-0.4,
  623.                                                 0.4,
  624.                                                 SPRITE::SINGLECOLOR,
  625.                                                 player.team == TEAM::BLUE? 24 : 34
  626.                                         );
  627.                                         canvas.drawRectangle(
  628.                                                 ((jjSubscreenWidth - 680) - radarOffsetX),
  629.                                                 ((jjSubscreenHeight - 170) - radarOffsetY),
  630.                                                 6,
  631.                                                 6,
  632.                                                 teamColor,
  633.                                                 SPRITE::NORMAL
  634.                                         );
  635.                                 }
  636.                                 else if (player.flag == 0) {
  637.                                         canvas.drawRectangle(
  638.                                                 ((jjSubscreenWidth - 680) - radarOffsetX),
  639.                                                 ((jjSubscreenHeight - 170) - radarOffsetY),
  640.                                                 player.isLocal? 8:6,
  641.                                                 player.isLocal? 8:6,
  642.                                                 player.isLocal? 64 : jjGameMode == GAME::CTF? teamColor : 24,
  643.                                                 SPRITE::NORMAL
  644.                                         );
  645.                                 }
  646.                         }
  647.                        
  648.                         for (int j = 1; j < jjObjectCount; j++) {
  649.                                 if (jjObjects[j].eventID == OBJECT::TNT) {
  650.                                        
  651.                                         uint8 redeemerColor;
  652.                                         switch (jjPlayers[jjObjects[j].creatorID].team) {
  653.                                                 case TEAM::BLUE: redeemerColor = 34; break;
  654.                                                 case TEAM::RED: redeemerColor = 24; break;
  655.                                                 case TEAM::GREEN: redeemerColor = 18; break;
  656.                                                 case TEAM::YELLOW: redeemerColor = 40; break;
  657.                                                 default: redeemerColor = 88; break;
  658.                                         }
  659.                                        
  660.                                         int radarMissileOffsetX = int(xPos - jjObjects[j].xPos) / 35;
  661.                                         int radarMissileOffsetY = int(yPos - jjObjects[j].yPos) / 35;
  662.                                        
  663.                                         if (!jjPlayers[jjObjects[j].creatorID].isLocal && radarMissileOffsetX < 70 && radarMissileOffsetX > -63 && radarMissileOffsetY < 70 && radarMissileOffsetY > -63) {
  664.                                                 canvas.drawRotatedSprite(
  665.                                                         ((jjSubscreenWidth - 680) - radarMissileOffsetX),
  666.                                                         ((jjSubscreenHeight - 170) - radarMissileOffsetY),
  667.                                                         ANIM::CUSTOM[1],
  668.                                                         0,
  669.                                                         jjGameTicks >> 2,
  670.                                                         jjObjects[j].var[0],
  671.                                                         0.5,
  672.                                                         0.5,
  673.                                                         SPRITE::SINGLECOLOR,
  674.                                                         jjGameMode == GAME::CTF? redeemerColor : 90
  675.                                                 );
  676.                                         }
  677.                                 }
  678.                         }
  679.                 }
  680.                
  681.                 if (warning) {
  682.                         canvas.drawString(
  683.                                 jjSubscreenWidth - 550,
  684.                                 jjSubscreenHeight - 374,
  685.                                 "||WARNING: YOU ARE IN RANGE!",
  686.                                 STRING::SMALL,
  687.                                 STRING::NORMAL
  688.                         );
  689.                 }
  690.                
  691.                 if (!jjLowDetail && jjGameTicks % 140 >= 7) {
  692.                         canvas.drawString(
  693.                                 jjSubscreenWidth - 132,
  694.                                 jjSubscreenHeight - 46,
  695.                                 "REC",
  696.                                 STRING::MEDIUM,
  697.                                 STRING::NORMAL
  698.                         );
  699.                         canvas.drawSprite(
  700.                                 jjSubscreenWidth - 146,
  701.                                 jjSubscreenHeight - 45,
  702.                                 ANIM::VINE,
  703.                                 0,
  704.                                 0,
  705.                                 0,
  706.                                 SPRITE::NORMAL
  707.                         );
  708.                 }
  709.         }
  710.         else if (!controllingRedeemer && play.currWeapon == WEAPON::TNT) {
  711.                 canvas.drawString(
  712.                         jjSubscreenWidth - 80,
  713.                         jjSubscreenHeight - 14,
  714.                         "x" + play.ammo[WEAPON::TNT],
  715.                         STRING::MEDIUM,
  716.                         STRING::NORMAL
  717.                 );
  718.                 canvas.drawResizedSprite(
  719.                         jjSubscreenWidth - 110,
  720.                         jjSubscreenHeight - 14,
  721.                         ANIM::CUSTOM[1],
  722.                         0,
  723.                         jjGameTicks >> 2,
  724.                         2,
  725.                         2,
  726.                         SPRITE::NORMAL
  727.                 );
  728.         }
  729.        
  730.         return weaponHook.drawAmmo(play, canvas);
  731. }
  732.  
  733. jjANIMSET@ redeemerPickupSprite;
  734. bool generateRedeemerPickupSprite(jjANIMSET@ anim, const array<uint> &in colors) {
  735.         int length = colors.length();
  736.         bool success = (@redeemerPickupSprite = anim).allocate(array<uint>(length, 8)) !is null;
  737.         if (success) {
  738.                 uint srcSet = jjAnimSets[ANIM::SONCSHIP];
  739.                 for (int i = 0; i < length; i++) {
  740.                         uint color = colors[i];
  741.                         uint destAnimOffset = anim + i;
  742.                         uint srcAnim = jjAnimations[srcSet + 0];
  743.                         uint destAnim = jjAnimations[destAnimOffset + 0];
  744.                         for (int k = 0; k < 8; k++) {
  745.                                 jjPIXELMAP image(jjAnimFrames[destAnim + k] = jjAnimFrames[srcAnim + k]);
  746.                                 int width = image.width;
  747.                                 int height = image.height;
  748.                                 for (int l = 0; l < height; l++) {
  749.                                         for (int m = 0; m < width; m++) {
  750.                                                 int pixel = image[m, l];
  751.                                                 if (pixel >= 40 && pixel < 48)
  752.                                                         image[m, l] = color;
  753.                                         }
  754.                                 }
  755.                         if (!image.save(jjAnimFrames[destAnim + k]))
  756.                                 return false;
  757.                         }
  758.                 }
  759.         }
  760.         return success;
  761. }