Downloads containing ab23btl19.j2as

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