Downloads containing primpXmas.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Jingle JumbleFeatured Download Primpy Single player 9.3 Download file

File preview

  1. const bool MLLESetupSuccessful = MLLE::Setup(); ///@MLLE-Generated
  2. #include "MLLE-Include-1.6.asc" ///@MLLE-Generated
  3. #pragma require "primpXmas-MLLE-Data-2.j2l" ///@MLLE-Generated
  4. #pragma require "primpXmas-MLLE-Data-1.j2l" ///@MLLE-Generated
  5. #pragma require "Hellfire.j2t" ///@MLLE-Generated
  6. #pragma require "primpXmas.j2l" ///@MLLE-Generated
  7. #pragma require "SExmas.j2a"
  8. #pragma require "xmasBoss.pal"
  9. #include "PickupTracker.asc"
  10. #include "HH17Enemies.asc"
  11.  
  12. const float PI = 3.141592f;
  13. uint fallLoopCount, teleCooldown, firstRemainingGiftID, secondRemainingGiftID, thirdRemainingGiftID;
  14. string plrCharacterStr;
  15. bool bossActivatedOnce, isBossActive, cutscene, blasterPoweredUp, noTeleArea;
  16. float bossPalOpacity;
  17. jjPAL bossPalette;
  18. array<jjLAYER@> layers, bossLayers;
  19. array<bool> SavedTriggers(32, false);
  20.  
  21. class Collectible {
  22.         int x, y;
  23.         bool found = false;
  24.         Collectible(){}
  25.         Collectible(int newX, int newY, bool newFound) {
  26.                 x = newX;
  27.                 y = newY;
  28.                 found = newFound;
  29.         }
  30. }
  31. array<Collectible> collectibleData;
  32.  
  33. array<string> fallLoopMessages = {
  34.                 "#|||~I can't wait to meet Santa...",
  35.                 "...",
  36.                 "#|||~Santa sure lives deep underground...",
  37.                 "#|||~Wait... underground? Oh no...",
  38.                 "#|||~This isn't Santa... it's Satan!",
  39.                 "#||||~[???]@@Sure is! Name's Bilsy!",
  40.                 "#||||~[Bilsy]@@Thanks for bringing Santa's lost gifts@right to me!",
  41.                 "#|||~You're not stealing these presents@on my watch!"
  42. };
  43.  
  44. array<string> postBossMessages = {
  45.                 "#||||~[Bilsy]@@Hold it! This fight was fun but@you're misunderstanding the situation.",
  46.                 "#||||~[Bilsy]@@I was assigned to@wait for you to recover the gifts@and deliver them to Santa.",
  47.                 "#|||~Santa employs demons to aid him in his work?",
  48.                 "#||||~[Bilsy]@@How else do you think he could manage to@give gifts to everyone on every planet?",
  49.                 "#||||~[Bilsy]@@Also, notice the hat and cape I'm wearing?@He makes us wear these silly work uniforms...",
  50.                 "#|||~When you put it that way, it makes@more sense... Sorry for earlier.",
  51.                 "#||||~[Bilsy]@@No biggie.@Anyhoo, thanks for gathering the lost gifts.",
  52.                 "#||||~[Bilsy]@@Toodles! And happy holidays!",
  53. };
  54.  
  55. array<string> getNPCMessages(float x, float y)
  56. {
  57.         if (x == 4527 && y == 3471) return {
  58.                 "Hi there, " + plrCharacterStr + "!@",
  59.                 "Thank you for agreeing to help Santa with@"
  60.                 "finding his lost gifts.@",
  61.                 "When you find at least " + PickupTracker::minAmount + " gifts,@"
  62.                 "the hole to your left will open.@",
  63.                 "Jump in it and deliver the gifts.@",
  64.                 "Good luck!"
  65.                 };
  66.         if (x == 335 && y == 1039) return {
  67.                 "Do you think Santa is hot?@",
  68.                 "Just kidding... Hahaha..."};
  69.         if (x == 2607 && y == 2063) return {
  70.                 "Santa? Really? He isn't real.@",
  71.                 "Science will bring my presents."};
  72.         if (x == 5295 && y == 3119) return {
  73.                 "The roundy, floaty, glowy gifts are Santa's.@",
  74.                 "The gifts that look like this one are for you!"};
  75.         if (x == 3119 && y == 5231) return {
  76.                 "Brrr... It's awfully cold in this cave...@",
  77.                 "Icicles have started growing in a place@"
  78.                 "where no rabbit should have icicles..."};
  79.         if (x == 7151 && y == 5583) return {
  80.                 "When you eat tons of sweets,@"
  81.                 "you become super strong.@",
  82.                 "When I eat tons of sweets,@"
  83.                 "I get a tummy ache.@",
  84.                 "Life is so unfair."};
  85.         if (x == 7951 && y == 719) return {
  86.                 "I just ate some frozen chicken with my@reindeer girlfriend. Yum." };
  87.         if (x == 2991 && y == 687) return { "Pepperoni secret." };
  88.         return { "" };
  89. }
  90.  
  91. float getPickupY(const jjOBJ@ obj) {
  92.         bool floating = obj.state == STATE::FLOAT || obj.behavior != BEHAVIOR::PICKUP;
  93.         int arg = (((obj.objectID << 3) + jjGameTicks) << (floating && obj.yPos > jjWaterLevel ? 1 : 4)) + (floating ? int(obj.xPos) << 4 : 0);
  94.         return obj.yPos + jjSin(arg) * 0.5f;
  95. }
  96.  
  97. float getAngle(int x1, int x2, int y1, int y2) {
  98.         return atan2(y2 - y1, x2 - x1);
  99. }
  100.  
  101. void drawArrow(jjPLAYER@ player, Collectible collectible, uint8 color) {
  102.        
  103.         float angle = getAngle(int(player.xPos), collectible.x * 32 + 15, int(player.yPos), collectible.y * 32 + 15);
  104.         jjDrawRotatedSpriteFromCurFrame(
  105.                                                 player.xPos + cos(angle) * 32,
  106.                                                 player.yPos + sin(angle) * 32,
  107.                                                 jjAnimations[jjAnimSets[ANIM::FLAG]], int(-(angle / (2 * PI)) * 1024 - 55), 1, 1, SPRITE::SINGLEHUE, color, -1);
  108. }
  109.  
  110. void applyBossPalette() {      
  111.         if (bossPalOpacity < 1.f && cutscene) {
  112.                 jjPalette.reset();
  113.                 jjPalette.copyFrom(1, 254, 1, bossPalette, bossPalOpacity);
  114.                 jjPalette.apply();
  115.                 if (!bossActivatedOnce) {
  116.                         if (jjGameTicks % 20 == 0)
  117.                                 bossPalOpacity += 0.01f;
  118.                 }
  119.                 else {
  120.                         if (jjGameTicks % 2 == 0)
  121.                                 bossPalOpacity += 0.01f;
  122.                 }
  123.         }
  124. }
  125.  
  126. void applyBossLight(jjPLAYER@ player) {
  127.         if (player.lighting > 10 && cutscene) {
  128.                 if (!bossActivatedOnce) {
  129.                         if (jjGameTicks % 70 == 0)
  130.                                 player.lighting = player.lighting - 1;
  131.                 }
  132.                 else {
  133.                         if (jjGameTicks % 10 == 0)
  134.                                 player.lighting = player.lighting - 1;
  135.                 }
  136.         }
  137. }
  138.  
  139. string getPlrCharacterStr() { return jjPlayers[0].charCurr == CHAR::JAZZ ? "Jazz" : (jjPlayers[0].charCurr == CHAR::SPAZ ? "Spaz" : (jjPlayers[0].charCurr == CHAR::LORI ? "Lori" : "little critter")); }
  140.  
  141. void CheckpointWrapper(jjOBJ@ obj) {
  142.         if (obj.state == STATE::STOP) {
  143.                 jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame);
  144.         } else if (obj.state == STATE::DEACTIVATE) {
  145.                 obj.deactivate();
  146.         } else {
  147.                 obj.behave(BEHAVIOR::CHECKPOINT);
  148.                 if (obj.state == STATE::DONE) {
  149.                         obj.state = STATE::STOP;
  150.                 for (uint i = 0; i < 32; ++i)
  151.                         SavedTriggers[i] = jjTriggers[i];
  152.                 for (int i = jjObjectCount; --i > 0;) {
  153.                         jjOBJ@ obj2 = jjObjects[i];
  154.         if (obj2.eventID == OBJECT::CHECKPOINT && i != obj.objectID && obj2.isActive) {
  155.           obj2.state = STATE::SLEEP;
  156.           obj2.var[0] = 0;
  157.         }
  158.       }
  159.     }
  160.   }
  161. }
  162.  
  163. void findRemainingGifts() {
  164.         uint8 amount = 0;
  165.         for (uint i = 0; i < collectibleData.length(); ++i) {
  166.                 if (collectibleData[i].found == false) {
  167.                         if (amount == 0)
  168.                                 firstRemainingGiftID = i;
  169.                         else if (amount == 1)
  170.                                 secondRemainingGiftID = i;
  171.                         else
  172.                                 thirdRemainingGiftID = i;
  173.                         amount++;
  174.                 }
  175.                 if (amount == 3)
  176.                         break;
  177.         }
  178. }
  179.  
  180. void markCollectibleAsFound(int xOrg, int yOrg) {
  181.         for (uint i = 0; i < collectibleData.length(); ++i) {
  182.                 if (collectibleData[i].x == xOrg && collectibleData[i].y == yOrg) {
  183.                         collectibleData[i].found = true;
  184.                         return;
  185.                 }
  186.         }
  187. }
  188.  
  189. void processHellbats() {
  190.         for (uint i = 0; i < 5; i++) {
  191.                 jjANIMATION@ animBat = jjAnimations[jjAnimSets[ANIM::BAT] + i];
  192.                 for (uint j = 0; j < animBat.frameCount; j++) {
  193.                         jjANIMFRAME@ frame = jjAnimFrames[animBat + j];
  194.                         jjPIXELMAP sprite(frame);
  195.                         for (uint x = 0; x < sprite.width; ++x) {
  196.                                 for (uint y = 0; y < sprite.height; ++y) {
  197.                                         if (sprite[x,y] >= 88 - 57 && sprite[x,y] <= 94 - 57) sprite[x,y] -= 8;
  198.                                 }
  199.                         }
  200.                         sprite.save(frame);
  201.                 }
  202.         }
  203. }
  204.  
  205. void processIcebats() {
  206.         for (uint i = 0; i < 5; i++) {
  207.                 jjANIMATION@ animBat = jjAnimations[jjAnimSets[ANIM::BAT] + i];
  208.                 for (uint j = 0; j < animBat.frameCount; j++) {
  209.                         jjANIMFRAME@ frame = jjAnimFrames[animBat + j];
  210.                         jjPIXELMAP sprite(frame);
  211.                         for (uint x = 0; x < sprite.width; ++x) {
  212.                                 for (uint y = 0; y < sprite.height; ++y) {
  213.                                         if (sprite[x,y] >= 88 - 65 && sprite[x,y] <= 94 - 65) sprite[x,y] += 8;
  214.                                 }
  215.                         }
  216.                         sprite.save(frame);
  217.                 }
  218.         }
  219. }
  220.  
  221. void GiftPickup() {
  222.         jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::LEMON].curAnim];
  223.         anim.frameCount = 1;
  224.        
  225.         jjAnimSets[ANIM::CUSTOM[1]].load(2, "SExmas.j2a");
  226.        
  227.         jjObjectPresets[OBJECT::LEMON].determineCurAnim(ANIM::CUSTOM[1], 0);
  228.         jjObjectPresets[OBJECT::LEMON].points = 1000;
  229.         jjObjectPresets[OBJECT::LEMON].scriptedCollisions = true;
  230.         jjObjectPresets[OBJECT::LEMON].behavior = CustomPickup();
  231. }
  232.  
  233. class CustomPickup : jjBEHAVIORINTERFACE {
  234.         void onBehave(jjOBJ@ obj) {
  235.                 obj.behave(BEHAVIOR::PICKUP, false);
  236.                 if(obj.state == STATE::FLOATFALL)
  237.                         obj.state = STATE::FLOAT;
  238.                 obj.yPos = getPickupY(obj);
  239.                 if (obj.var[0] == 0)
  240.                         obj.var[0] = 1 + jjRandom() % 3;
  241.         }
  242.         bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ player, int) {
  243.                 obj.behavior = BEHAVIOR::EXPLOSION2;
  244.                 jjSample(obj.xPos, obj.yPos, SOUND::COMMON_HIBELL, 63);
  245.                 player.gems[GEM::RED] = player.gems[GEM::RED] + 1;
  246.                 jjEventSet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0);
  247.                 markCollectibleAsFound(int((obj.xOrg - 15) / 32), int((obj.yOrg - 15) / 32));
  248.                 return true;
  249.         }
  250.         void onDraw(jjOBJ@ obj) {
  251.                 jjDrawSpriteFromCurFrame(obj.xPos + 2, obj.yPos + 2, obj.curFrame, obj.direction, SPRITE::SHADOW, 0, 5);
  252.                 jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame + obj.var[0] - 1, obj.direction, SPRITE::NORMAL);
  253.         }
  254. }
  255.  
  256. class NPC : jjBEHAVIORINTERFACE {
  257.         bool debounce = true;
  258.         float lastXPos = -1.f, lastYPos = -1.f;
  259.        
  260.         void onBehave(jjOBJ@ obj) {
  261.                 int drawParam = ((int(obj.xPos) + int(obj.yPos)) % 5) * 8 + 16;
  262.                 jjDrawSprite((obj.direction == -1) ? (obj.xPos + 15) : (obj.xPos - 15), obj.yPos, ANIM::PLUS_WARP, 0, jjGameTicks >> 3, obj.direction, SPRITE::SINGLEHUE, drawParam);
  263.                 jjDrawSprite((obj.direction == -1) ? (obj.xPos + 15) : (obj.xPos - 15), obj.yPos, ANIM::PLUS_WARP, 1, jjGameTicks >> 3, obj.direction, SPRITE::NORMAL);
  264.                
  265.                 int playerID_direction = obj.findNearestPlayer(100000);
  266.                 if (playerID_direction >= 0)
  267.                 {
  268.                         if (obj.xPos > jjPlayers[playerID_direction].xPos)
  269.                                 obj.direction = -1;
  270.                         else obj.direction = 1;
  271.                 }
  272.                
  273.                 // NPCs should be at least 2 tiles away from one another, otherwise expect your ears to bleed.
  274.                 int playerID_collision = obj.findNearestPlayer(2000);
  275.                 if (playerID_collision >= 0)
  276.                 {
  277.                         jjPLAYER@ player = jjPlayers[playerID_direction];
  278.                         if (obj.var[0] == 0 || (debounce == true && (obj.xPos != lastXPos || obj.yPos != lastYPos)))
  279.                         {
  280.                                 int sound = jjGameTicks % 3;
  281.                                 switch (sound) {
  282.                                         case 0:
  283.                                                 jjSample(obj.xPos, obj.yPos, SOUND::SPAZSOUNDS_HAHAHA, 0);
  284.                                                 break;
  285.                                         case 1:
  286.                                                 jjSample(obj.xPos, obj.yPos, SOUND::SPAZSOUNDS_HAHAHA2, 0);
  287.                                                 break;
  288.                                         case 2:
  289.                                                 jjSample(obj.xPos, obj.yPos, SOUND::SPAZSOUNDS_HIHI, 0);
  290.                                                 break;
  291.                                 }
  292.                                 array<string> messages = getNPCMessages(obj.xPos, obj.yPos);
  293.                                 string msg = "@@@@[Rabbit]@@";
  294.                                
  295.                                 for (uint i = 0; i < messages.length(); ++i) {
  296.                                         msg = msg + messages[i] + "@";
  297.                                         //player.showText("@", STRING::MEDIUM);
  298.                                 }
  299.                                
  300.                                 player.showText(msg, STRING::MEDIUM);
  301.                                 obj.var[0] = 450;
  302.                                 debounce = true;
  303.                                 lastXPos = obj.xPos;
  304.                                 lastYPos = obj.yPos;
  305.                         }
  306.                 }
  307.                
  308.                 if (obj.var[0] > 0)
  309.                         obj.var[0] = obj.var[0] - 1;
  310.                 if (obj.var[0] == 0 && debounce == true && obj.xPos != lastXPos && obj.yPos != lastYPos) {
  311.                         debounce = false;
  312.                 }
  313.         }
  314. }
  315.  
  316.  class CustomBilsy: jjBEHAVIORINTERFACE {
  317.         void onBehave(jjOBJ@ obj) {
  318.                 if (obj.state != STATE::EXTRA) {
  319.                         obj.behave(BEHAVIOR::BILSY);
  320.                 }
  321.                 else
  322.                 {
  323.                         if (uint(obj.var[0]) < (postBossMessages.length() - 1) * 400) {
  324.                                 if (obj.var[0] % 400 == 0)
  325.                                         jjLocalPlayers[0].showText("@@@@" + postBossMessages[obj.var[0] / 400], STRING::MEDIUM);
  326.                                 obj.var[0] = obj.var[0] + 1;
  327.                                
  328.                                 jjDrawSprite(obj.xPos, obj.yPos, ANIM::XBILSY, 4, jjGameTicks >> 3, (obj.xPos > jjPlayers[0].xPos) ? -1 : 1, SPRITE::NORMAL);
  329.                         }
  330.                         else if (obj.var[1] <= 16 * 2) {
  331.                                 jjDrawSprite(obj.xPos, obj.yPos, ANIM::XBILSY, 2, obj.var[1] / 2, jjLocalPlayers[0].direction, SPRITE::NORMAL);
  332.                                 obj.var[1] = obj.var[1] + 1;
  333.                         }
  334.                         else {
  335.                                 jjNxt();
  336.                                 obj.state = STATE::KILL;
  337.                         }
  338.                 }
  339.     }
  340.        
  341.         bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
  342.                 if (obj.state != STATE::EXTRA && obj.state != STATE::KILL) {
  343.                         obj.scriptedCollisions = false;
  344.                         if (bullet is null)
  345.                                 player.objectHit(obj, force, HANDLING::SPECIAL);
  346.                         else
  347.                                 bullet.objectHit(obj, HANDLING::ENEMY);
  348.                         obj.scriptedCollisions = true;
  349.                        
  350.                         if (obj.energy <= 5) {
  351.                                 obj.energy = 5;
  352.                                 obj.state = STATE::EXTRA;
  353.                                 player.boss = -1;
  354.                                 player.invincibility = -50000;
  355.                         }
  356.                 }
  357.                 return true;
  358.         }
  359. }
  360.  
  361. void onLevelLoad() {
  362.         layers = jjLayerOrderGet();
  363.         bossLayers = layers;
  364.         layers.removeAt(3);
  365.         for (int i = 0; i < 5; ++i) {
  366.                 bossLayers.insertAt(7, bossLayers[bossLayers.length() - 1]);
  367.                 bossLayers.removeLast();
  368.         }
  369.         bossLayers.removeRange(bossLayers.length() - 9, 9);
  370.         jjLayerOrderSet(layers);
  371.        
  372.         fallLoopCount = 0;
  373.         bossActivatedOnce = false;
  374.         isBossActive = false;
  375.         cutscene = false;
  376.         noTeleArea = false;
  377.         blasterPoweredUp = false;
  378.         teleCooldown = 150;
  379.         bossPalette.load("xmasBoss.pal");
  380.         bossPalOpacity = 0.f;
  381.        
  382.         plrCharacterStr = getPlrCharacterStr();
  383.        
  384.         for (int x = 0; x < jjLayerWidth[4]; ++x) {
  385.                 for (int y = jjLayerHeight[4] - 1; y >= 0; --y) {
  386.                         uint8 eventID = jjEventGet(x, y);
  387.                         if (eventID == OBJECT::LEMON) {
  388.                                 collectibleData.insertLast(Collectible(x, y, false));
  389.                         }
  390.                 }
  391.         }
  392.                
  393.         jjAnimSets[ANIM::PLUS_WARP].load();
  394.         jjAnimSets[ANIM::BUBBA].load();
  395.         uint src = jjAnimSets[ANIM::CUSTOM[255]].load(0, "SExmas.j2a");
  396.         uint dest = jjAnimSets[ANIM::PICKUPS];
  397.         for (int i = 0; i < 95; i++) {
  398.                 const jjANIMATION@ anim = jjAnimations[src + i];
  399.                 if (anim.frameCount != 0)
  400.                         jjAnimations[dest + i] = anim;
  401.         }
  402.        
  403.         HH17::setEnemy(OBJECT::BAT);
  404.         HH17::setEnemy(OBJECT::DRAGON);
  405.         HH17::setEnemy(OBJECT::MONKEY);
  406.        
  407.         jjObjectPresets[OBJECT::STRAWBERRY].behavior = NPC();
  408.         jjObjectPresets[OBJECT::STRAWBERRY].playerHandling = HANDLING::PARTICLE;
  409.         jjObjectPresets[OBJECT::STRAWBERRY].bulletHandling = HANDLING::DESTROYBULLET;
  410.         jjObjectPresets[OBJECT::STRAWBERRY].scriptedCollisions = true;
  411.        
  412.         jjObjectPresets[OBJECT::XMASBILSY].behavior = CustomBilsy();
  413.         jjObjectPresets[OBJECT::XMASBILSY].deactivates = false;
  414.         jjObjectPresets[OBJECT::XMASBILSY].scriptedCollisions = true;
  415.        
  416.         jjObjectPresets[OBJECT::SAVEPOST].behavior = CheckpointWrapper;
  417.         jjObjectPresets[OBJECT::SAVEPOST].deactivates = false;
  418.        
  419.         GiftPickup();
  420.         PickupTracker::restorePlayerPickups();
  421.        
  422.         jjPIXELMAP rockImage(0,0, 96,96, 5);
  423.         jjANIMFRAME@ rockFrame = jjAnimFrames[jjObjectPresets[OBJECT::ROTATINGROCK].curFrame];
  424.         rockImage.save(rockFrame);
  425.         rockFrame.hotSpotY -= 8;
  426.        
  427.         uint giftAnimID = jjAnimSets[ANIM::CUSTOM[0]].allocate(array<uint> = {3,1,1,1,1, 3,1,1,1,1, 3,1,1,1,1});
  428.         for (uint color = 0; color < 3; ++color, ++giftAnimID) {
  429.                 const uint y = (3 + color) * 32;
  430.                 for (uint state = 0; state < 3; ++state) {
  431.                         jjANIMFRAME@ boxFrame = jjAnimFrames[jjAnimations[giftAnimID] + state];
  432.                         jjPIXELMAP(state * 64 + 13, y, 48,32, 5).save(boxFrame);
  433.                         boxFrame.hotSpotX = -24;
  434.                         boxFrame.hotSpotY = 0;
  435.                 }
  436.                 for (uint shard = 0; shard < 4; ++shard) {
  437.                         jjANIMFRAME@ shardFrame = jjAnimFrames[jjAnimations[++giftAnimID]];
  438.                         jjPIXELMAP((6 + shard) * 32, y, 32,32, 5).save(shardFrame);
  439.                         shardFrame.hotSpotX = shardFrame.hotSpotY = -16;
  440.                 }
  441.         }
  442.        
  443.         jjObjectPresets[OBJECT::GUNCRATE].behavior =
  444.         jjObjectPresets[OBJECT::CARROTCRATE].behavior =
  445.         jjObjectPresets[OBJECT::ONEUPCRATE].behavior =
  446.         jjObjectPresets[OBJECT::BOMBCRATE].behavior =
  447.         jjObjectPresets[OBJECT::SPRINGCRATE].behavior =
  448.         jjObjectPresets[OBJECT::GEMCRATE].behavior =
  449.         jjObjectPresets[OBJECT::BOUNCERAMMO15].behavior =
  450.         jjObjectPresets[OBJECT::ICEAMMO15].behavior =
  451.         jjObjectPresets[OBJECT::SEEKERAMMO15].behavior =
  452.         jjObjectPresets[OBJECT::RFAMMO15].behavior =
  453.         jjObjectPresets[OBJECT::TOASTERAMMO15].behavior =
  454.                 Gift;
  455.                
  456.         jjObjectPresets[OBJECT::DESTRUCTSCENERY].behavior = Lamp;
  457. }
  458.  
  459. void onMain() {
  460.         HH17::handleEnemyProjectiles();
  461.         PickupTracker::deleteGemDrops();
  462.        
  463.         if (PickupTracker::foundAllMax && !blasterPoweredUp) {
  464.                 jjLocalPlayers[0].powerup[WEAPON::BLASTER] = true;
  465.                 blasterPoweredUp = true;
  466.         }
  467. }
  468.  
  469. void onPlayer(jjPLAYER@ player)
  470. {
  471.         if (PickupTracker::pickupsCollected == PickupTracker::maxAmount - 3 && firstRemainingGiftID == 0 && secondRemainingGiftID == 0 && thirdRemainingGiftID == 0) {
  472.                 findRemainingGifts();
  473.         }
  474.         if (!cutscene && !isBossActive && PickupTracker::pickupsCollected >= PickupTracker::maxAmount - 3 && firstRemainingGiftID != secondRemainingGiftID && firstRemainingGiftID != thirdRemainingGiftID) {
  475.                 if (collectibleData[firstRemainingGiftID].found == false)
  476.                         drawArrow(player, collectibleData[firstRemainingGiftID], 16);
  477.                 if (collectibleData[secondRemainingGiftID].found == false)
  478.                         drawArrow(player, collectibleData[secondRemainingGiftID], 24);
  479.                 if (collectibleData[thirdRemainingGiftID].found == false)
  480.                         drawArrow(player, collectibleData[thirdRemainingGiftID], 32);
  481.         }
  482.        
  483.         if (isBossActive && player.boss > -1 && player.buttstomp < 121 && jjDifficultyOrig > 0)
  484.                 jjDifficulty = 3;
  485.         else jjDifficulty = jjDifficultyOrig;
  486.        
  487.         if (isBossActive && player.boss > -1 && jjDifficultyOrig > 0 && player.invincibility < -30)
  488.                 player.invincibility = -30;
  489.  
  490.         if (cutscene)
  491.         {
  492.                 player.keyLeft = player.keyRight = player.keyUp = player.keyDown = player.keyFire = player.keyJump = player.keyRun = false;
  493.                 player.idle = 0;
  494.                 player.xSpeed = 0;
  495.         }
  496.         PickupTracker::trackPlayerPickups(player);
  497.         PickupTracker::onFoundAllPickups(player, PickupTracker::FoundAllReward::Unlock);
  498.        
  499.         if (teleCooldown > 0 && PickupTracker::foundAllMin)
  500.                 teleCooldown--;
  501.         if (jjKey[84] && teleCooldown == 0 && !cutscene && !isBossActive && !noTeleArea) // Pressed T
  502.         {      
  503.                 player.warpToID(3);
  504.                 teleCooldown = 150;
  505.         }
  506.        
  507.         applyBossPalette();
  508.         applyBossLight(player);
  509. }      
  510.  
  511. void onLevelReload()
  512. {
  513.         jjLayerOrderSet(layers);
  514.         jjDifficulty = jjDifficultyOrig;
  515.         cutscene = false;
  516.         noTeleArea = false;
  517.         isBossActive = false;
  518.         blasterPoweredUp = false;
  519.         fallLoopCount = 0;
  520.         teleCooldown = 150;
  521.         bossPalOpacity = 0.f;
  522.        
  523.         for (uint i = 0; i < 32; ++i)
  524.                 jjTriggers[i] = SavedTriggers[i];
  525.                
  526.         PickupTracker::restorePlayerPickups();
  527.         jjLocalPlayers[0].lives++;
  528.         jjMusicLoad("kaze_icelevel.ogg");
  529.         if (PickupTracker::foundAllMin)
  530.                 jjTriggers[11] = true;
  531.                
  532.         plrCharacterStr = getPlrCharacterStr();
  533.  
  534.         HH17::processEnemyColors();
  535.         processIcebats();
  536. }
  537.  
  538. bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas)  { return true; }
  539.  
  540. bool onDrawScore(jjPLAYER@ player, jjCANVAS@ canvas) {
  541.         PickupTracker::drawCounter(player, canvas, "gifts");
  542.         if (PickupTracker::foundAllMin && !cutscene && !isBossActive && !noTeleArea)
  543.                 canvas.drawString(20, jjResolutionHeight - 20, "|(Press 'T' to teleport to the exit)", STRING::SMALL, STRING::NORMAL);
  544.                
  545.         return false;
  546. }
  547.  
  548. void onFunction0(jjPLAYER@ player) {
  549.         cutscene = true;
  550.         jjLayerOrderSet(bossLayers);
  551.         jjMusicStop();
  552.         if (!bossActivatedOnce) {                      
  553.                 if (fallLoopCount < 5 * fallLoopMessages.length())
  554.                 {
  555.                         player.warpToID(0, true);                      
  556.                         if (fallLoopCount % 5 == 0) {
  557.                                 player.showText( "@@@@@" + fallLoopMessages[uint(fallLoopCount / 5)], STRING::MEDIUM);
  558.                         }
  559.                         fallLoopCount++;
  560.                 }
  561.         }
  562.         else
  563.         {
  564.                 if (fallLoopCount == 1)
  565.                         player.showText( "@@@@@" + "#|||~I'm gonna kick you in the@deviled eggs this time!", STRING::MEDIUM);
  566.                 if (fallLoopCount < 5)
  567.                 {
  568.                         player.warpToID(0, true);
  569.                         fallLoopCount++;
  570.                 }
  571.         }
  572. }
  573.  
  574. void onFunction1(jjPLAYER@ player) {
  575.         processHellbats();
  576.         player.activateBoss();
  577.         bossActivatedOnce = true;
  578.         cutscene = false;
  579.         isBossActive = true;
  580.         jjMusicLoad("kaze_boss.ogg", false, true);
  581.         player.limitXScroll(115, 25);
  582. }
  583.  
  584. void onFunction2(jjPLAYER@ player) {
  585.         if (jjDifficulty >= 2)
  586.                 player.hurt();
  587.         if (jjTriggers[12] == false)
  588.                 player.warpToID(1);
  589.         else player.warpToID(2);
  590. }
  591.  
  592. void onFunction3(jjPLAYER@ player) {
  593.         noTeleArea = true;
  594. }
  595.  
  596. void onFunction4(jjPLAYER@ player) {
  597.         noTeleArea = false;
  598. }
  599.  
  600. bool onCheat(string &in cheat) {
  601.         jjPLAYER@ Player = jjLocalPlayers[0];
  602.         if ((cheat == "jjk" || cheat == "jjkill") && Player.health <= 0) { ; }
  603.         else if (cheat == "jjgems") {
  604.                 jjLocalPlayers[0].gems[GEM::RED] = jjLocalPlayers[0].gems[GEM::RED] + 5;
  605.         }
  606.         else if (cheat == "jjmorph") {
  607.                 jjLocalPlayers[0].morph(false, false);
  608.                 plrCharacterStr = getPlrCharacterStr();
  609.         }
  610.         else return false;
  611.         jjAlert(cheat, false, STRING::MEDIUM);
  612.         return true;
  613. }
  614.  
  615. [SOLID]
  616. void Gift(jjOBJ@ obj) {
  617.         if (obj.state == STATE::START) {
  618.                 obj.determineCurAnim(ANIM::CUSTOM[0], (jjRandom() % 3) * 5);
  619.                 obj.frameID = 0;
  620.                 obj.determineCurFrame();
  621.                 obj.behave(BEHAVIOR::CRATE, false);
  622.         } else if (obj.state == STATE::DONE) {
  623.                 //obj.beSolid();
  624.                 obj.draw();
  625.         } else if (obj.state == STATE::ACTION) {
  626.                 obj.behave(BEHAVIOR::CRATE, false);
  627.                 if (jjGameConnection == GAME::LOCAL) {
  628.                         obj.state = STATE::DONE;
  629.                         obj.creatorType = CREATOR::OBJECT;
  630.                         obj.behavior = Gift;
  631.                         obj.playerHandling = HANDLING::SPECIALDONE;
  632.                         obj.bulletHandling = HANDLING::IGNOREBULLET;
  633.                         obj.curFrame = jjAnimations[obj.curAnim] + 2;
  634.                         obj.justHit = 0;
  635.                         obj.draw();
  636.                         uint shardID = 0;
  637.                         for (uint objectID = jjObjectCount; --objectID != 0;) {
  638.                                 jjOBJ@ shard = jjObjects[objectID];
  639.                                 if (shard.eventID == OBJECT::SHARD && shard.isActive && shard.xOrg == obj.xPos && shard.yOrg == obj.yPos)
  640.                                         shard.curAnim = obj.curAnim + 1 + (shardID++ & 3);
  641.                         }
  642.                 } else {
  643.                         obj.delete();
  644.                 }
  645.         } else {
  646.                 obj.behave(BEHAVIOR::CRATE);
  647.                 jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos - 32, obj.curFrame + 1, 1);
  648.         }
  649. }
  650.  
  651. void Lamp(jjOBJ@ obj) {
  652.         if (obj.state == STATE::START) {
  653.                 obj.behave(BEHAVIOR::DESTRUCTSCENERY, false);
  654.                 if ((jjTileGet(4, uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5) & TILE::RAWRANGE) == 361) {
  655.                         obj.lightType = LIGHT::NORMAL;
  656.                         obj.light = 11;
  657.                 }
  658.         } else {
  659.                 obj.behave(BEHAVIOR::DESTRUCTSCENERY, false);
  660.                 if (obj.state == STATE::DONE) {
  661.                         obj.lightType = LIGHT::NONE;
  662.                         obj.behavior = BEHAVIOR::DESTRUCTSCENERY;
  663.                 }
  664.         }
  665. }