Downloads containing mo4a_2-1.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Mystery of the Four... chandie Single player 6.6 Download file

File preview

  1. const bool MLLESetupSuccessful = MLLE::Setup(array<MLLEWeaponApply@> = {null, null, ArcaneWeapons::MortarLauncher::Weapon(), DefaultWeapons::Blaster(), WeaponVMega::Backfire::Weapon(), null, DefaultWeapons::Blaster(), null, ArcaneWeapons::MortarLauncher::Weapon()}); ///@MLLE-Generated
  2. #include "MLLE-Include-1.5w.asc" ///@MLLE-Generated
  3. #pragma require "mo4a_2-1.j2l" ///@MLLE-Generated
  4. #include "WeaponVMega5.asc" ///@MLLE-Generated
  5. #pragma require "WeaponVMega5.asc" ///@MLLE-Generated
  6. #include "MLLE-DefaultWeapons.asc" ///@MLLE-Generated
  7. #pragma require "MLLE-DefaultWeapons.asc" ///@MLLE-Generated
  8. #include "ArcaneWeapon4.asc" ///@MLLE-Generated
  9. #pragma require "ArcaneWeapon4.asc" ///@MLLE-Generated
  10. #include "TrueColor v13.asc"
  11. #include "Jazz1Enemies v05.asc"
  12. #include "Resize v11.asc"
  13. #include "HH18savegems.asc"
  14.  
  15. void onLevelLoad()  {
  16.         jjSetWaterLevel(2030, true);
  17.         jjWaterLighting = WATERLIGHT::GLOBAL;
  18.         gem::restorePlayerGems();
  19.         p.buttstomp = 121;
  20.         jjLevelName = ("@@@@@@@@@Central Area");
  21.         jjObjectPresets[OBJECT::SAVEPOST].behavior = CheckpointWrapper;
  22.         jjObjectPresets[OBJECT::SAVEPOST].deactivates = false;
  23.  
  24.         jjObjectPresets[OBJECT::SILVERCOIN].behavior = PlatinCoin();
  25.         jjObjectPresets[OBJECT::SILVERCOIN].scriptedCollisions = true;
  26.  
  27.         jjObjectPresets[OBJECT::WEENIE].behavior = Key();
  28.         jjObjectPresets[OBJECT::WEENIE].scriptedCollisions = true;
  29.  
  30.         jjObjectPresets[OBJECT::BANANA].behavior = Carpet();
  31.         jjObjectPresets[OBJECT::BANANA].scriptedCollisions = true;
  32.  
  33.         jjObjectPresets[OBJECT::CHICKENLEG].behavior = AntiCarrot();
  34.         jjObjectPresets[OBJECT::CHICKENLEG].scriptedCollisions = true;
  35.         jjObjectPresets[OBJECT::CHICKENLEG].determineCurAnim(ANIM::PICKUPS,82);
  36.        
  37.         jjObjectPresets[OBJECT::AIRBOARD].behavior = SuperCopter();
  38.         jjObjectPresets[OBJECT::AIRBOARD].scriptedCollisions = true;
  39.  
  40.         jjObjectPresets[OBJECT::ICEAMMO15].behavior = Mortallaunchergun();
  41.         jjObjectPresets[OBJECT::ICEAMMO15].scriptedCollisions = true;
  42.         jjObjectPresets[OBJECT::ICEAMMO15].playerHandling = HANDLING::SPECIAL;
  43.  
  44.         jjObjectPresets[OBJECT::GUN9AMMO3].deactivates = false;
  45.  
  46.         jjObjectPresets[OBJECT::MOTH].behavior = Magic;
  47.  
  48.         Jazz1::MakeEnemy(OBJECT::DRAGONFLY, Jazz1::Enemies::Jungrock_RedBuzzer).SetUsesJJ2StyleDeathAnimation(true);
  49.         Jazz1::MakeEnemy(OBJECT::LIZARD, Jazz1::Enemies::Pezrox_GreenSnake).SetUsesJJ2StyleDeathAnimation(true);
  50.         Jazz1::MakeEnemy(OBJECT::RAVEN, Jazz1::Enemies::Sluggion_Dragoon).SetUsesJJ2StyleDeathAnimation(true);
  51.         Jazz1::MakeEnemy(OBJECT::HATTER, Jazz1::Enemies::Turtemple_JeTurtle, true).SetUsesJJ2StyleDeathAnimation(true).SetBulletFireSound(SOUND::INTRO_SHOT1).SetBulletExplosionSound(SOUND::COMMON_GUNSM1);
  52.  
  53.         jjObjectPresets[OBJECT::EVA].behavior = TimeMachine;
  54.         jjObjectPresets[OBJECT::EVA].determineCurAnim(ANIM::FLAG, 1);
  55.         jjObjectPresets[OBJECT::EVA].putOnGround(false);
  56.         jjObjectPresets[OBJECT::EVA].scriptedCollisions = true;
  57.         jjANIMATION@ tmAnim = jjAnimations[jjObjectPresets[OBJECT::EVA].curAnim];
  58.         for (uint i = 0; i < tmAnim.frameCount; ++i)
  59.                 jjAnimFrames[tmAnim.firstFrame + i].coldSpotY = -44;
  60.         for (uint i = 0; i < tmAnim.frameCount; ++i)
  61.                 jjAnimFrames[tmAnim.firstFrame + i].hotSpotY = -64;
  62.         for (uint i = 0; i < tmAnim.frameCount; ++i)
  63.                 jjAnimFrames[tmAnim.firstFrame + i].hotSpotX = -54;
  64.  
  65.         jjObjectPresets[OBJECT::FLYCARROT].determineCurAnim(ANIM::PLUS_WARP, 0);
  66.         jjObjectPresets[OBJECT::FLYCARROT].behavior = Bonus;
  67.         jjObjectPresets[OBJECT::FLYCARROT].scriptedCollisions = true;
  68.         jjANIMATION@ BAnim = jjAnimations[jjObjectPresets[OBJECT::FLYCARROT].curAnim];
  69.         for (uint i = 0; i < BAnim.frameCount; ++i)
  70.                 jjAnimFrames[BAnim.firstFrame + i].hotSpotY = -85;
  71.         for (uint i = 0; i < BAnim.frameCount; ++i)
  72.                 jjAnimFrames[BAnim.firstFrame + i].hotSpotX = 20;
  73.  
  74.         jjObjectPresets[OBJECT::INVINCIBILITY].determineCurAnim(ANIM::PLUS_WARP, 1);
  75.         jjObjectPresets[OBJECT::INVINCIBILITY].behavior = Bonuseye;
  76.         jjObjectPresets[OBJECT::INVINCIBILITY].scriptedCollisions = true;
  77.         jjObjectPresets[OBJECT::INVINCIBILITY].bulletHandling = HANDLING::IGNOREBULLET;
  78.         jjObjectPresets[OBJECT::INVINCIBILITY].playerHandling = HANDLING::PLAYERBULLET;
  79.         jjANIMATION@ BeAnim = jjAnimations[jjObjectPresets[OBJECT::INVINCIBILITY].curAnim];
  80.  
  81.         for (uint i = 0; i < BeAnim.frameCount; ++i)
  82.                 jjAnimFrames[BeAnim.firstFrame + i].hotSpotY = 12;
  83.         for (uint i = 0; i < BeAnim.frameCount; ++i)
  84.                 jjAnimFrames[BeAnim.firstFrame + i].hotSpotX = 26;
  85.  
  86. }
  87.  
  88. void Bonuseye(jjOBJ@ obj){
  89.         obj.direction = -1;
  90.         obj.behave(BEHAVIOR::PICKUP, false);
  91.         obj.draw();
  92. }
  93. void Bonus(jjOBJ@ obj){
  94.         obj.putOnGround();
  95.         obj.direction = -1;
  96.         obj.behave(BEHAVIOR::PICKUP, false);
  97.         obj.draw();
  98. }
  99.  
  100. class Mortallaunchergun : jjBEHAVIORINTERFACE {
  101.  
  102.         void onBehave(jjOBJ@ obj) {
  103.                 if(p.ammo[WEAPON::GUN9] > 1)
  104.                 {obj.delete();}
  105.                 obj.behave(BEHAVIOR::MONITOR); 
  106.         }
  107.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
  108.                 if(bullet !is null && play !is null)
  109.                         {obj.behave(BEHAVIOR::EXPLOSION2);
  110.                         jjAddObject(OBJECT::GUN9AMMO3, 78*32, 30*32);
  111.                         jjAddObject(OBJECT::GUN9AMMO3, 79*32, 30*32);
  112.                         jjAddObject(OBJECT::GUN9AMMO3, 70*32, 40*32);
  113.                         jjAddObject(OBJECT::GUN9AMMO3, 76*32, 40*32);                  
  114.                         jjAddObject(OBJECT::GUN9AMMO3, 82*32, 40*32);
  115.                         jjAddObject(OBJECT::GUN9AMMO3, 88*32, 40*32);
  116.                         jjAddObject(OBJECT::GUN9AMMO3, 185*32, 10*32);
  117.                         jjAddObject(OBJECT::GUN9AMMO3, 184*32, 10*32);
  118.                         jjAddObject(OBJECT::GUN9AMMO3, 183*32, 10*32);
  119.                         jjAddObject(OBJECT::GUN9AMMO3, 185*32, 11*32);                 
  120.                         jjAddObject(OBJECT::GUN9AMMO3, 184*32, 11*32);
  121.                         jjAddObject(OBJECT::GUN9AMMO3, 183*32, 11*32);
  122.                         jjSample(p.xPos, p.yPos, SOUND::COMMON_HARP1, 1000);}
  123.                 return true;
  124.         }
  125.        
  126. }
  127.  
  128. class PlatinCoin : jjBEHAVIORINTERFACE {
  129.  
  130.         void onBehave(jjOBJ@ obj) {
  131.                 if(p.coins >= 1)
  132.                 {obj.delete();}
  133.                 obj.behave(BEHAVIOR::PICKUP, false);
  134.                 ++obj.counter;
  135.                 obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
  136.                 jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -8);
  137. }
  138.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
  139.                 p.coins += 1;
  140.                 obj.behavior = BEHAVIOR::EXPLOSION2;
  141.                 jjSample(obj.xPos, obj.yPos, SOUND::COMMON_COIN, 1000);
  142.  
  143.                 return true;
  144.         }
  145. }
  146.  
  147. void Magic(jjOBJ@ obj) {
  148.         obj.behave(BEHAVIOR::MOTH,false);
  149.         if(jjTriggers[8] == true && p.xPos<12*32){
  150.                 jjPARTICLE@ particle = jjAddParticle(PARTICLE::FLOWER);
  151.                 particle.xPos = obj.xPos;
  152.                 particle.yPos = obj.yPos;
  153.         }
  154. }
  155.  
  156. void onFunction0(jjPLAYER@ p) {
  157.         p.cameraFreeze(105*32, 10*32, true, false);
  158.         jjEnabledASFunctions[0] = false;
  159.         control = false;}
  160.  
  161. void onFunction1(jjPLAYER@ p) {
  162.         p.showText("@@@@@@@@@@@@@@@@@@@@@@@@@Castle Road", STRING::MEDIUM);
  163.         jjEnabledASFunctions[1] = false;}
  164.  
  165. void onFunction2(jjPLAYER@ p) {
  166.         p.showText("@@@@@@@@@@@@@@@@@@@@@@@@@Sahara Desert", STRING::MEDIUM);
  167.         jjEnabledASFunctions[2] = false;}
  168.  
  169. void onFunction3(jjPLAYER@ p) {
  170. jjNxt("mo4a_2-4_save", false, true);
  171.                 gem::saveGemData();}
  172.  
  173. bool textdisplayed = false;
  174.  
  175. void onFunction4(jjPLAYER@ p) {
  176.         if(jjTriggers[1]==false && textdisplayed == false) {
  177.         p.showText("@@@@@Locked.");}
  178.         textdisplayed = true;
  179. }
  180.  
  181. bool control = true;
  182.  
  183. void onFunction5(jjPLAYER@ p) {
  184.         keypicked = false;
  185. }
  186.  
  187. void onFunction6(jjPLAYER@ p) {
  188.         p.cameraFreeze(208*32, 16*32, true, false);
  189.         jjEnabledASFunctions[6] = false;
  190.         control = false;}
  191.  
  192.  
  193. class Carpet : jjBEHAVIORINTERFACE {
  194.  
  195.         void onBehave(jjOBJ@ obj) {
  196.                 obj.behave(BEHAVIOR::PICKUP);
  197.                 jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::BANANA].curAnim];
  198.                 anim.frameCount = 1;
  199.                 jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
  200.                 jjPIXELMAP carpet(0, 1*32, 2*32, 1*32, 4);
  201.                 carpet.save(frame);
  202. }
  203.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
  204.                 if(p.coins < 1)
  205.                 {play.testForCoins(1);}
  206.                 if(p.coins >= 1)
  207.                 {jjNxt("mo4a_2-2_save", false, true);
  208.                 gem::saveGemData();}
  209.  
  210.                 return true;
  211.         }
  212. }
  213.  
  214.  
  215. void TimeMachine(jjOBJ@ obj){
  216.         obj.behave(BEHAVIOR::EVA, false);
  217.                 jjDrawResizedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, 1, 1, SPRITE::PALSHIFT, 8);
  218.  
  219. }
  220.  
  221. class AntiCarrot: jjBEHAVIORINTERFACE {
  222.  
  223.         void onBehave(jjOBJ@ obj) {
  224.                 obj.determineCurFrame();
  225.                 obj.behave(BEHAVIOR::PICKUP, false);
  226.                 ++obj.counter;
  227.                 obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
  228.                 jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -24);
  229.         }
  230.  
  231.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ p, int force) {
  232.                 p.health = 1;
  233.                 p.blink = 245; 
  234.                 jjSample(obj.xPos, obj.yPos, SOUND::COMMON_EAT1, 1000);
  235.                 obj.frameID = 0;
  236.                 obj.behavior = BEHAVIOR::EXPLOSION2;
  237.  
  238.                 return true;
  239.         }
  240. }
  241.  
  242.  
  243. bool buyammo = false, startrush = false, readytorush = false;
  244.  
  245. void onPlayer(jjPLAYER@ p) {
  246.                 if(control==false)
  247.                 {p.keyLeft = false;
  248.                 p.keyRight = false;
  249.                 p.keyDown = false;}
  250.  
  251.                 if(p.idle > 100)
  252.                 {p.cameraUnfreeze(true);
  253.                 control=true;}
  254.                 else if ((p.idle > 5 && (p.keyLeft || p.keyRight || p.keyJump || p.keyFire)) || (p.curAnim - jjAnimSets[p.setID].firstAnim == RABBIT::LEDGEWIGGLE))
  255.                 {p.cameraUnfreeze(true);
  256.                 control=true;}
  257.  
  258.         gem::trackPlayerGems(p);
  259.         gem::upgradeHealth(p);
  260.  
  261.         if(p.food == 100 && jjKey[0x52] == false && startrush == false)
  262.                 {p.showText("@@@@@@@@@@@@@@@@Press 'R' when you need to use Sugar Rush!", STRING::MEDIUM);
  263.                 p.startSugarRush(0);
  264.                 startrush = true;
  265.                 readytorush = true;}
  266.  
  267.         if(readytorush == true)
  268.                 {p.food = 100;}
  269.  
  270.         for (int i = 1; i < jjObjectCount; i++) {
  271.         jjOBJ@ o = jjObjects[i];
  272.                 if (o.isActive && o.eventID == OBJECT::SILVERCOIN && p.coins >= 1) {
  273.                 o.state = STATE::KILL;
  274.                 }
  275.  
  276.         }
  277.  
  278.         if(p.food == 100 && jjKey[0x52])
  279.                 {p.startSugarRush(1400);
  280.                 p.food = 0;
  281.                 readytorush = false;
  282.                 startrush = false;
  283.         }
  284.  
  285.         p.ammo[WEAPON::ICE] = 0;
  286.         if(p.xPos<11*32 && p.yPos>45*32 && p.coins < 3)
  287.                 {p.testForCoins(3);}
  288.         if(p.coins >= 3)
  289.                 {jjTriggers[8] = true;}
  290.         if(p.ammo[WEAPON::GUN9] < 1 && p.xPos>65*32 && p.xPos<67*32 && p.yPos<43*32 && p.yPos>39*32 && jjKey[0x50] && p.gems[GEM::RED]<50 && buyammo == false)
  291.                 {p.testForGems(50, GEM::RED);}
  292.         if(p.ammo[WEAPON::GUN9] < 1 && p.xPos>65*32 && p.xPos<67*32 && p.yPos<43*32 && p.yPos>39*32 && jjKey[0x50] && p.gems[GEM::RED]>=50 && buyammo == false)
  293.                 {p.testForGems(50, GEM::RED);
  294.         jjTriggers[2]=true;
  295.         buyammo = true;}
  296.         if(p.ammo[WEAPON::GUN9] >= 1 && p.xPos>65*32 && p.xPos<67*32 && p.yPos<43*32 && p.yPos>39*32 && jjKey[0x50] && buyammo == false)
  297.                 {p.showText("@@You already have the weapon.");}
  298.         p.lightType = LIGHT::NONE;
  299.  
  300.         if(SuperCopterOn > jjGameTicks)
  301.                 {jjCharacters[CHAR::JAZZ].helicopterYSpeed= 0;}
  302.         if(SuperCopterOn < jjGameTicks)
  303.                 {jjCharacters[CHAR::JAZZ].helicopterYSpeed= 1;}
  304. }
  305.  
  306. int SuperCopterOn = 0;
  307.  
  308. class SuperCopter : jjBEHAVIORINTERFACE {
  309.         void onBehave(jjOBJ@ obj) {
  310.                 obj.behave(BEHAVIOR::PICKUP, false);
  311.                 obj.determineCurAnim(ANIM::PICKUPS, 33);
  312.                 ++obj.counter;
  313.                 obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
  314.                 jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -8);
  315.  
  316. }
  317.  
  318.         bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ play, int force) {
  319.                 play.timerStart(360);
  320.                 p.morphTo(CHAR::JAZZ);
  321.                 SuperCopterOn= jjGameTicks + 6 * 61;
  322.                 obj.behavior = BEHAVIOR::EXPLOSION2;
  323.                 obj.frameID = 0;
  324.                 jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUP1, 6000);
  325.  
  326.                 return true;
  327.         }
  328.  
  329. }
  330.  
  331. void onMain() {
  332. gem::deleteCollectedGems();
  333. if(jjKey[9] && jjKey[0x51]) {
  334. p.morphTo(CHAR::JAZZ, false);
  335. }
  336. if(jjKey[9] && jjKey[0x57]) {
  337. p.morphTo(CHAR::SPAZ, false);
  338. }
  339. if(jjKey[9] && jjKey[0x45]) {
  340. p.morphTo(CHAR::LORI, false);
  341. }
  342. }
  343.  
  344. bool keypicked = false;
  345.  
  346. class Key : jjBEHAVIORINTERFACE {
  347.  
  348.         void onBehave(jjOBJ@ obj) {
  349.                 if(jjTriggers[1]==true)
  350.                         {obj.delete();}
  351.                 obj.behave(BEHAVIOR::PICKUP, false);
  352.                 jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::WEENIE].curAnim];
  353.                 anim.frameCount = 1; //The Bee enemy's animation has several frames, but the tileset only has material for one. Editing jjANIMATION::frameCount to 1 will ensure that the animation never extends beyond the one frame we're providing.
  354.                 jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
  355.                 jjPIXELMAP pump(0, 0*32, 1*32, 1*32, 4);
  356.                 pump.save(frame);
  357.                 ++obj.counter;
  358.                 obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
  359.                 jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NORMAL);
  360. }
  361.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) { //"bullet" will always be null, because this is a PICKUP; "force" doesn't usually matter, because in normal JJ2 you can collect pickups regardless of whether you're using a special attack at the time.
  362.                 jjTriggers[1]=true;
  363.                 obj.behavior = BEHAVIOR::EXPLOSION2;
  364.                 keypicked = true;
  365.                 control = false;
  366.                 p.cameraFreeze(50*32,52*32,true,false);
  367.                 jjSample(obj.xPos, obj.yPos, SOUND::MENUSOUNDS_TYPEENTER, 1000);
  368.  
  369.                 return true;
  370.         }
  371. }
  372.  
  373.  
  374. bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) {
  375.     canvas.drawSprite(20, 585, ANIM::PICKUPS, 84, jjGameTicks>>2, -1, SPRITE::PALSHIFT, -8);
  376.     canvas.drawString(30, 585, formatInt(player.coins%4, "1") + "/3", STRING::SMALL, STRING::NORMAL);
  377. if(keypicked == true && jjTriggers[1] == true)
  378.     {canvas.drawSprite(110, 585, ANIM::PICKUPS, 91, jjGameTicks>>2, -1, SPRITE::NORMAL);}
  379.     return false;
  380. }
  381.  
  382. bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas) {return true;}
  383.  
  384. void onLevelReload()  {
  385.         MLLE::Palette.apply();
  386.         jjSetWaterLevel(2030, true);
  387.         jjWaterLighting = WATERLIGHT::GLOBAL;
  388.         gem::restorePlayerGems();
  389.         jjLocalPlayers[0].lives++;
  390.         buyammo == false;
  391.         jjTriggers[2] = false;
  392.         for (uint i = 0; i < 32; ++i)
  393.                 jjTriggers[i] = SavedTriggers[i];
  394. }
  395.  
  396. array<bool> SavedTriggers(32, false);
  397. //Extendable Checkpoints by VioletCLM
  398. void CheckpointWrapper(jjOBJ@ obj) {
  399.   if (obj.state == STATE::STOP) { //don't do anything anymore
  400.     jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 8);
  401.   } else if (obj.state == STATE::DEACTIVATE) { //due to death
  402.     obj.deactivate();
  403.   } else {
  404.     obj.behave(BEHAVIOR::CHECKPOINT);
  405.         jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 8);
  406.     if (obj.state == STATE::DONE) { //triggered by the player hitting it
  407.       obj.state = STATE::STOP;
  408.       //save the current state of some properties
  409.       for (uint i = 0; i < 32; ++i)
  410.         SavedTriggers[i] = jjTriggers[i];
  411.  
  412.       //OPTIONAL: this loop makes checkpoints reusable, so only the most recent checkpoint you touched is ever active
  413.       for (int i = jjObjectCount; --i > 0;) {
  414.         jjOBJ@ obj2 = jjObjects[i];
  415.         if (obj2.eventID == OBJECT::CHECKPOINT && i != obj.objectID && obj2.isActive) {
  416.           obj2.state = STATE::SLEEP;
  417.           obj2.var[0] = 0;
  418.         }
  419.       }
  420.     }
  421.   }
  422. }
  423.  
  424. jjTEXTAPPEARANCE SignTextAppearance = STRING::NORMAL;
  425. class Sign {
  426.         private int xPos, yPos; //These pixel-based positions will be generated from tile-based positions in the constructor by multiplying by 32
  427.         private string text;
  428.         private uint widthOfText;
  429.         Sign(){} //AngelScript requires any class that appears in any array to have an explicit default constructor, even if it's never called
  430.         Sign(int xTile, int yTile, const string &in t) {
  431.                 xPos = xTile * 32; //Since this is a constant operation, it could strictly be performed in the draw method instead of the constructor, but this way involves fewer multiplication instructions
  432.                 yPos = yTile * 32; //
  433.                 text = t;
  434.                 SignTextAppearance.newline = STRING::SPECIALSIGN; //Causes the drawString method to interpret instances of the \n character as signals to drop down to a new line, similar to the special effect of the @ character in the STRING::SPIN appearance.
  435.                 SignTextAppearance.spacing = -2; //int jjTEXTAPPEARANCE::spacing is new in 5.2, and this particular value is equivalent to prefixing the string with "ยง2". Make sure to check out bool jjTEXTAPPEARANCE::monospace too, though it didn't end up getting used in this level.
  436.                 widthOfText = jjGetStringWidth(text, STRING::SMALL, SignTextAppearance); //Used for determining how large of a dark rectangle should be drawn behind the text. A matching heightOfText value could of course be generated by counting the number of newline characters--for example, "heightOfText = text.split("\n").length * 20;"--but here the rectangles are constant height instead to limit the temptation to ramble on and on.
  437.         }
  438.         void draw(jjCANVAS@ layer, uint8 textIntensity) const { //Because this method will be called from an onDraw method, it's important to have a jjCANVAS@ passed among the arguments.
  439.                 layer.drawRectangle(xPos, yPos - 16, widthOfText + 8, 55, 0, SPRITE::TRANSLUCENT);
  440.                 layer.drawString(xPos, yPos, text, STRING::SMALL, SignTextAppearance, 0, SPRITE::BLEND_HARDLIGHT, textIntensity);
  441.         }
  442. }
  443. const array<Sign> Signs = {
  444.         Sign(102, 59, "Find the second Time Freezer\nand come back."),
  445.         Sign(92, 58, "This city is ruled by the Sultan.\nHis castle is in the East beyond the desert."),
  446.         Sign(57, 61, "A piece of advice: Don't eat everything\nyou see when you time travel."),
  447.         Sign(20, 50, "A magical cave, full of goodies\nlies beneath the West side of the desert."),
  448.         Sign(150, 38, "Have you seen my husband?\nHis name is Ali Babba."),
  449.         Sign(183, 25, "They say Aladdin, who lives up there got\na magic lamp which grants your wishes."),
  450.         Sign(181, 21, "The Sultan took my lamp.\nI'm never gonna see it again."),
  451.         Sign(146, 54, "The castle was robbed by the 40 Thieves.\nThey're still there, looking for something."),
  452.         Sign(169, 61, "We have the water supply\nthrough the canals."),
  453.         Sign(209, 57, "Don't you go further, son. You'd die\nof thrist in the desert."),
  454.         Sign(70, 41, "Press P if you'd like to\nbuy Mortal Launcher for 50 Gems."),
  455. };
  456.  
  457. void onDrawLayer3(jjPLAYER@, jjCANVAS@ layer) {
  458.         if(jjKey[0x54]){
  459.         const uint8 textIntensity = 200 + int(jjSin(jjGameTicks * 16) * 50);
  460.         for (uint signID = 0; signID < Signs.length; ++signID)
  461.                 Signs[signID].draw(layer, textIntensity);
  462. }
  463. }
  464.  
  465. void onDrawLayer2(jjPLAYER@, jjCANVAS@ layer) {
  466.         if(jjKey[0x54] && (p.yPos <21*32)){
  467.         const uint8 textIntensity = 200 + int(jjSin(jjGameTicks * 16) * 50);
  468.         for (uint signID = 0; signID < Signs.length; ++signID)
  469.                 Signs[signID].draw(layer, textIntensity);
  470. }
  471. }
  472. bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
  473.         return MLLE::WeaponHook.drawAmmo(player, canvas);
  474. }
  475.