Downloads containing mo4a_2-4.j2as

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

File preview

const bool MLLESetupSuccessful = MLLE::Setup(array<MLLEWeaponApply@> = {null, null, DefaultWeapons::Blaster(), DefaultWeapons::Blaster(), WeaponVMega::Backfire::Weapon(), null, DefaultWeapons::Blaster(), null, ArcaneWeapons::MortarLauncher::Weapon()}); ///@MLLE-Generated
#include "MLLE-Include-1.5w.asc" ///@MLLE-Generated
#pragma require "mo4a_2-4.j2l" ///@MLLE-Generated
#include "ArcaneWeapon4.asc" ///@MLLE-Generated
#pragma require "ArcaneWeapon4.asc" ///@MLLE-Generated
#include "WeaponVMega5.asc" ///@MLLE-Generated
#pragma require "WeaponVMega5.asc" ///@MLLE-Generated
#include "MLLE-DefaultWeapons.asc" ///@MLLE-Generated
#pragma require "MLLE-DefaultWeapons.asc" ///@MLLE-Generated
bool boss = false;
#include "Jazz1Enemies v05.asc"
#include "Resize v11.asc"
#include "TrueColor v13.asc"
#include "HH18savegems.asc"
int torch = 0; 
bool torch11 = false; bool torch12 = false; bool torch13 = false; bool torch14 = false; bool torch15 = false; bool torch16 = false; bool torch17 = false; bool lever = false;
int SuperCopterOn = 0;


void onLevelLoad()  {

	gem::restorePlayerGems();


	jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::BANANA].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP pump(0, 33*32, 1*32, 1*32, 5);
		pump.save(frame);
	jjLevelName = ("@@@@@@@@@Sahara Desert");

	jjObjectPresets[OBJECT::SAVEPOST].behavior = CheckpointWrapper;
	jjObjectPresets[OBJECT::SAVEPOST].deactivates = false;

	jjObjectPresets[OBJECT::HAM].behavior = FakeFreezer();
	jjObjectPresets[OBJECT::HAM].scriptedCollisions = true;
	jjObjectPresets[OBJECT::HAM].determineCurAnim(ANIM::PICKUPS, 42);
	jjObjectPresets[OBJECT::HAM].determineCurFrame();

	jjObjectPresets[OBJECT::BIGROCK].deactivates = false;

	jjObjectPresets[OBJECT::SONICPLATFORM].scriptedCollisions = true;
	jjObjectPresets[OBJECT::SONICPLATFORM].behavior = SpikeBump();
	jjObjectPresets[OBJECT::SONICPLATFORM].deactivates = false;

	jjObjectPresets[OBJECT::BOLLPLATFORM].scriptedCollisions = true;
	jjObjectPresets[OBJECT::BOLLPLATFORM].behavior = PlatformV;
	jjObjectPresets[OBJECT::BOLLPLATFORM].deactivates = false;

	jjObjectPresets[OBJECT::DRAGON].behavior = BigDragon;
	jjObjectPresets[OBJECT::DRAGON].playerHandling = HANDLING::ENEMY;
	jjObjectPresets[OBJECT::DRAGON].bulletHandling = HANDLING::HURTBYBULLET;
	jjObjectPresets[OBJECT::DRAGON].energy = 5;
	jjObjectPresets[OBJECT::DRAGON].scriptedCollisions = true;

	jjObjectPresets[OBJECT::WITCH].behavior = Wizard;
	jjObjectPresets[OBJECT::WITCH].energy = 100;
	jjObjectPresets[OBJECT::WITCH].bulletHandling = HANDLING::HURTBYBULLET;
	jjObjectPresets[OBJECT::WITCH].state = STATE::ACTION;

	jjObjectPresets[OBJECT::BURGER].points = 0;
	jjObjectPresets[OBJECT::BURGER].scriptedCollisions = true;		
	jjObjectPresets[OBJECT::BURGER].behavior = WizardSpell;
	jjObjectPresets[OBJECT::BURGER].energy = 1;	
	jjObjectPresets[OBJECT::BURGER].state = STATE::ACTION;
	jjObjectPresets[OBJECT::BURGER].bulletHandling = HANDLING::IGNOREBULLET;

	jjObjectPresets[OBJECT::MILK].energy = 6;
	jjObjectPresets[OBJECT::MILK].behavior = SpittingBubba;
	jjObjectPresets[OBJECT::MILK].points = 1000;
	jjObjectPresets[OBJECT::MILK].xSpeed = 1;
	jjObjectPresets[OBJECT::MILK].state = STATE::WALK;
	jjObjectPresets[OBJECT::MILK].deactivates = false;
	jjObjectPresets[OBJECT::MILK].scriptedCollisions = true;
	jjObjectPresets[OBJECT::MILK].isTarget = true;
	jjObjectPresets[OBJECT::MILK].playerHandling = HANDLING::ENEMY;

	jjObjectPresets[OBJECT::LEMON].energy = 12;
	jjObjectPresets[OBJECT::LEMON].behavior = BubbaSpirit;
	jjObjectPresets[OBJECT::LEMON].points = 700;
	jjObjectPresets[OBJECT::LEMON].light = 15;
	jjObjectPresets[OBJECT::LEMON].lightType = LIGHT::RING2;
 	jjObjectPresets[OBJECT::LEMON].playerHandling = HANDLING::ENEMY;
	jjObjectPresets[OBJECT::LEMON].bulletHandling = HANDLING::IGNOREBULLET;
	jjObjectPresets[OBJECT::LEMON].isTarget = true;
	jjObjectPresets[OBJECT::LEMON].isBlastable = true;



	jjObjectPresets[OBJECT::ICECREAM].behavior = Key();
	jjObjectPresets[OBJECT::ICECREAM].scriptedCollisions = true;

	jjObjectPresets[OBJECT::PEAR].behavior = Head1();
	jjObjectPresets[OBJECT::PEAR].scriptedCollisions = true;

	jjObjectPresets[OBJECT::WEENIE].behavior = Head();
	jjObjectPresets[OBJECT::WEENIE].scriptedCollisions = true;

	jjObjectPresets[OBJECT::FASTFEET].behavior = HeadFlame();
	jjObjectPresets[OBJECT::FASTFEET].scriptedCollisions = true;

	jjObjectPresets[OBJECT::DONUT].behavior = AntiCarrot();
	jjObjectPresets[OBJECT::DONUT].scriptedCollisions = true;
	jjObjectPresets[OBJECT::DONUT].determineCurAnim(ANIM::PICKUPS,82);
	
	jjObjectPresets[OBJECT::SILVERCOIN].behavior = SuperCopter();
	jjObjectPresets[OBJECT::SILVERCOIN].scriptedCollisions = true;

	jjObjectPresets[OBJECT::LIME].behavior = Light;
	jjObjectPresets[OBJECT::LIME].scriptedCollisions = true;

	jjObjectPresets[OBJECT::MOTH].behavior = Treasure();
	jjObjectPresets[OBJECT::MOTH].scriptedCollisions = true;

	jjObjectPresets[OBJECT::FREEZEENEMIES].behavior = TimeFreezer();
	jjObjectPresets[OBJECT::FREEZEENEMIES].scriptedCollisions = true;
	Jazz1::MakeEnemy(OBJECT::CRAB, Jazz1::Enemies::Turtemple_ScorpWeenie).SetUsesJJ2StyleDeathAnimation(true);
	Jazz1::MakeEnemy(OBJECT::TUFTURT, Jazz1::Enemies::Turtemple_JeTurtle, true).SetUsesJJ2StyleDeathAnimation(true).SetBulletFireSound(SOUND::INTRO_SHOT1).SetBulletExplosionSound(SOUND::COMMON_GUNSM1);
	Jazz1::MakeEnemy(OBJECT::RAVEN, Jazz1::Enemies::Sluggion_Dragoon).SetUsesJJ2StyleDeathAnimation(true);
	Jazz1::MakeEnemy(OBJECT::DEMON, Jazz1::Enemies:: Battleships_ArmorDoofi).SetUsesJJ2StyleDeathAnimation(true);

}

class Treasure : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::MOTH, false);
	}
	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) { 
		obj.causesRicochet = true;
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_HIBELL, 1000);
		jjPARTICLE@ particle = jjAddParticle(PARTICLE::FLOWER);
		particle.ySpeed = 0;
		particle.flower.petals = 2;
		particle.flower.size = 40;
		particle.flower.color = 15;
		particle.flower.angularSpeed = 64;
		particle.flower.angle = 50;
		particle.xPos = obj.xPos;
		particle.yPos = obj.yPos;
		return true;
	}
}


void PlatformV (jjOBJ@ obj) {

	switch (obj.state) {
		case STATE::START:
		if(obj.xPos < 32*32)
			{obj.direction = obj.ySpeed = 6;}
		if(obj.xPos > 32*32 && obj.xPos < 43*32)
			{obj.direction = obj.ySpeed = 2;}
		if(obj.xPos > 42*32)
			{obj.direction = obj.ySpeed = 4;}
			obj.determineCurAnim(ANIM::SONICPLAT, 0);   
			obj.determineCurFrame();
			obj.state = STATE::FLY;
			obj.beSolid();
		case STATE::FLY:
			if(p.keyUp == true && lever == true && p.yPos > 32*32 && p.xPos > 43*32)
			{obj.yPos = obj.yPos - obj.ySpeed;}
			if(p.keyDown == true && lever == true && p.yPos > 32*32 && p.xPos > 43*32)
			{obj.yPos = obj.yPos + obj.ySpeed;}
			obj.beSolid();
			obj.deactivates = false;
			if (jjMaskedVLine(obj.xSpeed > 0 ? obj.xPos + 16 : obj.xPos - 16, obj.yPos-50, 1)) 
				{obj.direction = obj.ySpeed = -obj.ySpeed;}
			obj.draw();
			break;

	}
}

int spring = 0;
bool spike = false;
class SpikeBump : jjBEHAVIORINTERFACE {

void onBehave(jjOBJ@ obj) {

	switch (obj.state) {
		case STATE::START:
			obj.determineCurFrame();
			obj.state = STATE::FLY;


		case STATE::FLY:
			obj.playerHandling = HANDLING::SPECIAL;
			obj.xPos = obj.xPos + obj.xSpeed;
			obj.deactivates = false;
			if(p.xPos > 128*32 && obj.xPos > 128*32 && obj.xPos < 178*32 && obj.yPos > 43*32)
			{obj.xSpeed = 0.5;}
			if((p.xPos > 128*32 && obj.xPos > p.xPos + 612) || obj.xPos > 196*32)
			{obj.delete();}
			
			if(obj.xPos > p.xPos + 64 || obj.xPos < p.xPos - 64 || obj.yPos > p.yPos + 64 || obj.yPos < p.yPos - 64)
			{obj.determineCurAnim(ANIM::BOLLPLAT, 0); 
			jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -8);
			obj.determineCurFrame();}
			else {jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -24);}
			break;

		
	}
}

	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) { 
		if(bullet is null && play !is null && (force == -1 || force == 1))
			{spring = jjGameTicks + 1*61;
			obj.determineCurAnim(ANIM::BOLLPLAT, 0); 
			jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -24);
			obj.determineCurFrame();
			p.buttstomp = 121;
			jjSample(obj.xPos, obj.yPos, SOUND::PINBALL_BELL, 1000);}
		if(force == 0 && spring < jjGameTicks)
			{play.hurt();
			obj.determineCurAnim(ANIM::SPIKEBOLL, 0);   
			obj.determineCurFrame();
			if(spike == false)
			{jjSample(obj.xPos, obj.yPos, SOUND::COMMON_METALHIT, 1000);}
			spike = true;}
		return true;
		}

}




bool timedoortext = false;

class SuperCopter : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {

obj.behave(BEHAVIOR::PICKUP, false);
obj.determineCurAnim(ANIM::PICKUPS, 33);
++obj.counter; 
		obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;

		jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -8);

}

	bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ play, int force) {
		play.timerStart(1500);
		p.morphTo(CHAR::JAZZ);
		p.cameraFreeze(53*32, 24*32, true, false);
		jjTriggers[7]= true;
		SuperCopterOn= jjGameTicks + 25 * 61;
		if(timedoortext == false)
			{p.showText("@@A timed door. Better move my ears fast.");}
		timedoortext =true;
		obj.behavior = BEHAVIOR::EXPLOSION2;
		obj.frameID = 0;
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUP1, 6000);

		return true;
	}

}

	
void onMain() {
gem::deleteCollectedGems();
if(jjKey[9] && jjKey[0x51]) {
p.morphTo(CHAR::JAZZ, false); 
}
if(jjKey[9] && jjKey[0x57]) {
p.morphTo(CHAR::SPAZ, false); 
}
if(jjKey[9] && jjKey[0x45]) {
p.morphTo(CHAR::LORI, false); 
}
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::ROTATINGROCK].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP pump(0, 20*32, 3*32, 3*32, 5);
		pump.save(frame);
}


bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) {
	if(keylock == true && jjTriggers[3]==true)
		{canvas.drawSprite(25, 585, ANIM::PICKUPS,43, jjGameTicks>>2, -1, SPRITE::NORMAL);}
	if(Dragonactivated == true && personaltorch == false)
		{canvas.drawSprite(20, 585, ANIM::PICKUPS,74, jjGameTicks>>2, -1, SPRITE::NORMAL);}
		//{canvas.drawResizedSprite(20, 585, ANIM::FACES,3, 4,0.7, 0.7, SPRITE::PALSHIFT, 16);}
	if(personaltorch == true)
		{canvas.drawSprite(20, 585, ANIM::AMMO,13, jjGameTicks>>2, -1, SPRITE::NORMAL);}
    return false;
}

bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas) {return true;}

bool startrush = false, readytorush = false, control = true;

void onPlayer(jjPLAYER@ p){

	if(p.lives <2)
	{p.lives += 1;}

	jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::COKE].curAnim];
	anim.frameCount = 1;
	jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
	jjPIXELMAP water(0, 46*32, 1*32, 1*32, 5);
	water.save(frame);
	frame.hotSpotX = -frame.width/2;

		if(control==false)
		{p.keyLeft = false;
		p.keyRight = false;
		p.keyDown = false;}

		if(p.idle > 100 && lever == false)
		{p.cameraUnfreeze(true);
		control=true;}
		else if (p.idle > 5 && (p.keyLeft || p.keyRight || p.keyJump || p.keyFire))
		{p.cameraUnfreeze(true);
		control=true;
		spike = false;}


	gem::trackPlayerGems(p);
	gem::upgradeHealth(p);
	if(p.coins == 0)
	{p.coins +=3;}

	if(p.food == 100 && jjKey[0x52] == false && startrush == false)
		{p.showText("@@@@@@@@@@@@@@@@Press 'R' when you need to use Sugar Rush!", STRING::MEDIUM);
		p.startSugarRush(0);
		startrush = true;
		readytorush = true;}

	if(readytorush == true)
		{p.food = 100;}

	if(p.food == 100 && jjKey[0x52])
		{p.startSugarRush(1400);
		p.food = 0;
		readytorush = false;
		startrush = false;
	}

	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ o = jjObjects[i];
		if (o.isActive && o.eventID == OBJECT::SEEKERAMMO3 && p.ammo[WEAPON::SEEKER] < 1) {
			o.state = STATE::KILL;}
	}
	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ o = jjObjects[i];
		if (o.isActive && o.eventID == OBJECT::RFAMMO3 && p.ammo[WEAPON::RF] < 1) {
			o.state = STATE::KILL;}
	}
	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ o = jjObjects[i];
		if (o.isActive && o.eventID == OBJECT::TNTAMMO3 && p.ammo[WEAPON::TNT] < 1) {
			o.state = STATE::KILL;}
	}
	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ o = jjObjects[i];
		if (o.isActive && o.eventID == OBJECT::GUN9AMMO3 && p.ammo[WEAPON::GUN9] < 1) {
			o.state = STATE::KILL;}
	}
	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ o = jjObjects[i];
		if (o.isActive && o.eventID == OBJECT::SEEKERPOWERUP && p.ammo[WEAPON::SEEKER] < 1) {
			o.state = STATE::KILL;}
	}
	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ o = jjObjects[i];
		if (o.isActive && o.eventID == OBJECT::RFPOWERUP && p.ammo[WEAPON::RF] < 1) {
			o.state = STATE::KILL;}
	}
	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ o = jjObjects[i];
		if (o.isActive && o.eventID == OBJECT::TNTPOWERUP && p.ammo[WEAPON::TNT] < 1) {
			o.state = STATE::KILL;}
	}
	for (int i = 1; i < jjObjectCount; i++) {
		jjOBJ@ o = jjObjects[i];
		if (o.isActive && o.eventID == OBJECT::GUN9POWERUP && p.ammo[WEAPON::GUN9] < 1) {
			o.state = STATE::KILL;}
	}

if(spring > jjGameTicks)
{p.ySpeed = -10;}
	if (torch > jjGameTicks) {
	p.lightType = LIGHT::FLICKER;}
	if (torch < jjGameTicks || torch==0) {
	p.lightType = LIGHT::NONE;}

	if(SuperCopterOn > jjGameTicks)
	{jjTriggers[7]= true;
	jjCharacters[CHAR::JAZZ].helicopterYSpeed= 0;}

	if(SuperCopterOn < jjGameTicks)
	{jjTriggers[7]= false;
	jjCharacters[CHAR::JAZZ].helicopterYSpeed= 1;}


		if (p.keyUp && p.xPos> 225*32 && p.xPos< 227*32 && p.yPos >33*32 && p.yPos < 36*32 && jjTriggers[11]==false){ 
		jjTriggers[11]= true;
		jjAddObject(OBJECT::LIME, 226*32, 34*32);}

		if (p.keyUp && p.xPos> 237*32 && p.xPos< 240*32 && p.yPos >33*32 && p.yPos < 36*32 && jjTriggers[12]==false){  
		jjTriggers[12]= true;
		jjAddObject(OBJECT::LIME, 238*32, 34*32);}

		if (p.keyUp && p.xPos> 225*32 && p.xPos< 227*32 && p.yPos >27*32 && p.yPos < 30*32 && jjTriggers[13]==false){  
		jjTriggers[13]= true;
		jjAddObject(OBJECT::LIME, 226*32, 28*32);}

		if (p.keyUp && p.xPos> 233*32 && p.xPos< 236*32 && p.yPos >27*32 && p.yPos < 30*32 && jjTriggers[14]==false){  
		jjTriggers[14]= true; 
		jjAddObject(OBJECT::LIME, 234*32, 28*32);}

		if (p.keyUp && p.xPos> 248*32 && p.xPos< 251*32 && p.yPos >27*32 && p.yPos < 30*32 && jjTriggers[15]==false){  
		jjTriggers[15]= true;
		jjAddObject(OBJECT::LIME, 249*32, 28*32);}

		if (p.keyUp && p.xPos> 242*32 && p.xPos< 245*32 && p.yPos >27*32 && p.yPos < 30*32 && jjTriggers[16]==false){  
		jjTriggers[16]= true; 
		jjAddObject(OBJECT::LIME, 243*32, 28*32);}

		if (p.keyUp && p.xPos> 237*32 && p.xPos< 240*32 && p.yPos >27*32 && p.yPos < 30*32 && jjTriggers[17]==false){  
		jjTriggers[17]= true; 
		jjAddObject(OBJECT::LIME, 238*32, 28*32);}


if(jjTriggers[17] == true && jjTriggers[16] == true && jjTriggers[15] == true && jjTriggers[14] == true && jjTriggers[13] == true && jjTriggers[12] == true && jjTriggers[11] == true){
		jjTriggers[18]= true;


		}
	if(p.yPos >39*32) {
		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::WEENIE].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP pump(0, 2*32, 1*32, 1*32, 5);
		pump.save(frame);
		frame.hotSpotX = -18;
	}



}

void onlevelReload(){
	gem::restorePlayerGems();
	jjLocalPlayers[0].lives++;
  	for (uint i = 0; i < 32; ++i)
	  	jjTriggers[i] = SavedTriggers[i];
}

void onFunction1(jjPLAYER@ p) {
		jjTriggers[1] = true;
		jjTriggerRock(0);}

void onFunction2(jjPLAYER@ p) {
		p.showText("@@OPEN SESAME!");
		jjTriggers[2] = true;}

void onFunction3(jjPLAYER@ p) {
		p.showText("@@Now I have a torch!");
		jjSwitchTrigger(20);
		p.boss=jjAddObject(OBJECT::WEENIE, 54*32, 24*32);}

bool windtext = false;

void onFunction4(jjPLAYER@ p) {
	if(windtext == false){
		p.showText("@@I can cross the other side by copter@ears. But it's way too windy.");
		windtext = true;}
}

void onFunction5(jjPLAYER@ p) {
	p.showText("@@@@@@@@@@@@@@@@@@@@@@@@@40 Thieves' Cave", STRING::MEDIUM);
	jjMusicLoad("mo4a_The Lava Stream (Reprise 2).ogg");	
	jjEnabledASFunctions[5] = false;}

void onFunction6(jjPLAYER@ p) {
lever = true;
p.cameraFreeze(36*32, 11*32, true, false);
}

void onFunction7(jjPLAYER@ p) {
	jjPAL resPal;
	resPal.load("Arabian Cave.j2t");
	resPal.apply();
}

bool textdisappear = false, torchidea = false, torchfail = false;
void onFunction8(jjPLAYER@ p) {
	jjLayerOrderSet(array<jjLAYER@> = {jjLayers[2], jjLayers[3], jjLayers[4], jjLayers[5], jjLayers[6], jjLayers[7], jjLayers[8], jjLayers[1]});
	textdisappear = true;
}

void onFunction9(jjPLAYER@ p) {
	if(headburn == false)
	{p.showText("@@Oh god...@Is this Ali Babba's head?");
	jjEnabledASFunctions[9] = false;}
}

void onFunction10(jjPLAYER@ p) {
	if(personaltorch == false)
	{p.showText("@@It's too dark.@I can't see anything.");
	torchidea = true;
	p.lighting = 1;}
	if(personaltorch == true)
	p.warpToID(4, true);
}

void onFunction11(jjPLAYER@ p) {
	if(torchidea == true)
	{p.showText("@@Hey! Let's use Ali Babba's head@as a torch. But how@should I light it?");
	torchfail = true;
	torchidea = false;}
}

void onFunction12(jjPLAYER@ p) {
	if(torchfail == true && personaltorch == false)
	{p.showText("@@Nope. Need a stronger fire.");
	torchfail = false;}
}

void onFunction13(jjPLAYER@ p) {
	keylock = false; }

void onFunction14(jjPLAYER@ p) {
		if(personaltorch == false)
		{p.showText("@@Hmm... A strong fire source...");}
}

bool sesame = false;
void onFunction15(jjPLAYER@ p) {
		if(jjTriggers[7] == false && sesame == false)
		{p.showText("@@OPEN SESAME...@Well, nice try...");
		sesame = true;}
}

class TimeFreezer : jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::PICKUP);
		obj.lightType = LIGHT::LASER;
		obj.light = 100;
	}
	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ p, int force) {
		obj.behavior = BEHAVIOR::EXPLOSION2;
		jjNxt();
		gem::saveGemData();

		return true;
	}
}
class Head1 : jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {
		if(Dragonactivated == true)
			{obj.delete();}
		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::PEAR].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP pump(0, 2*32, 1*32, 1*32, 5);
		pump.save(frame);
		frame.hotSpotX = -18;
		obj.behave(BEHAVIOR::PICKUP);
	obj.bulletHandling = HANDLING::IGNOREBULLET;
	obj.playerHandling = HANDLING::SPECIAL;

}
	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ per, int force) { 
		Dragonactivated = true;
		p.showText("@@This head could be useful at something.");
		obj.behavior = BEHAVIOR::EXPLOSION2;
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_SPLAT2, 1000);
		return true; 
	}
}

bool personaltorch = false;

class Head : jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::PICKUP);
	obj.bulletHandling = HANDLING::IGNOREBULLET;
	obj.playerHandling = HANDLING::SPECIAL;
		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::WEENIE].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP pump(0, 2*32, 1*32, 1*32, 5);
		pump.save(frame);
		frame.hotSpotX = -18;
}
	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ per, int force) { 
	if(p.idle >1) {
		torch = jjGameTicks + 60*61;
		personaltorch = true;
		p.showText("@@Now I can visit the last room!");
		obj.behavior = BEHAVIOR::EXPLOSION2;
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_SPLAT2, 1000); }
		return true;
	}
}


class HeadFlame : jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::PICKUP);

	obj.playerHandling = HANDLING::SPECIAL;
	obj.determineCurAnim(ANIM::AMMO, 55);
	obj.bulletHandling = HANDLING::IGNOREBULLET;
	obj.lightType = LIGHT::FLICKER;

if (torch > jjGameTicks) {
		obj.behavior = BEHAVIOR::EXPLOSION2;

	}
}}


bool keylock = false;

class Key : jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::PICKUP);
		if(jjTriggers[3] == true)
		{obj.delete();}
		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::ICECREAM].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP pump(0, 1*32, 1*32, 1*32, 5);
		pump.save(frame);
		frame.hotSpotY = -17;
}
	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ per, int force) { 
		jjTriggers[3] = true;
		keylock= true;
		obj.behavior = BEHAVIOR::EXPLOSION2;
		p.cameraFreeze(121*32, 34*32, true, false);
		control = false;
		jjSample(obj.xPos, obj.yPos, SOUND::MENUSOUNDS_TYPEENTER, 1000);

		return true; 
	}
}



bool headburn = false, Dragonactivated = false;

void BigDragon(jjOBJ@ enemy) {

	if(enemy.energy <5)
	{enemy.energy += 10;}

	if(p.xPos >25*32 && p.xPos <30*32 && p.yPos >32*32 && p.yPos <39*32) {
		//enemy.delete();
		if(Dragonactivated == true && headburn == false) {
		jjAddObject(OBJECT::FASTFEET, 846, 38*32);
		jjAddObject(OBJECT::WEENIE, 840, 38*32);
		p.showText("@@Let's try this...");
		headburn = true;}
	}

	enemy.behave(BEHAVIOR::DRAGON, false);
	
	
	if (enemy.justHit == 0) {
		jjDrawResizedSpriteFromCurFrame(enemy.xPos, enemy.yPos, enemy.curFrame, -2, 2, SPRITE::PALSHIFT, -8);}
		else jjDrawResizedSpriteFromCurFrame(enemy.xPos, enemy.yPos, enemy.curFrame, -2, 2, SPRITE::BRIGHTNESS, 255);
}

class AntiCarrot: jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {
		obj.determineCurFrame();
	obj.behave(BEHAVIOR::PICKUP, false);
		++obj.counter; 
		obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
		jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -24);
}

	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ p, int force) { 
		p.health = 1;
		p.blink = 245;	
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_EAT1, 1000);
		obj.frameID = 0;
		obj.behavior = BEHAVIOR::EXPLOSION2;


		return true; 
	}
}
bool final = false;



class FakeFreezer : jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {
		obj.determineCurFrame();
	obj.behave(BEHAVIOR::PICKUP, false);
		++obj.counter; 
		obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
	if(final==false)
		{obj.draw();}
	else
		jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, -16);

}

	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) { 
	if(final == false){
	for (int i = 1; i < jjObjectCount; i++) { 
	jjOBJ@ o = jjObjects[i]; 	jjOBJ@ ob = jjObjects[i];
	if (o.isActive && o.eventID == OBJECT::MILK || ob.isActive && ob.eventID == OBJECT::LEMON) {
		o.state = STATE::KILL;}
	}
		p.showText("@@Uh oh... This is fake!");
		obj.frameID = 0;
		p.activateBoss();
		final=true;
		{p.boss=jjAddObject(OBJECT::WITCH, 236*32, 27*32);}
		jjMusicLoad("mo4a_Doc's Cave.ogg");
		jjOBJ@ boss = jjObjects[p.boss];
		}
		return true; 

	}
}


void Wizard(jjOBJ@ boss) {
		
	if (boss.energy==0) { 
		boss.state=STATE::KILL;
		boss.delete();
		boss.counter==0;
		boss.xSpeed = 3*p.direction;
		boss.counter += 1; 
		boss.frameID = boss.counter/56;
		jjAddObject(OBJECT::FREEZEENEMIES, boss.xPos, boss.yPos);
		jjDrawSpriteFromCurFrame(boss.xPos, boss.yPos, boss.curFrame, boss.direction, SPRITE::NORMAL);
		++boss.counter;
	}
	

	if (boss.xPos < 147*32 || boss.xPos > 153*32)
	{boss.xPos = boss.xPos - 1;}
	if (boss.yPos > 27*32)
	{boss.yPos = boss.yPos - 1;}	
	else {boss.direction==1;}

	switch (boss.state) {
		case STATE::ACTION:
		boss.lightType = LIGHT::FLICKER;
		boss.yPos = jjSin(boss.counter*20 + 55)*4 + boss.yOrg;
		boss.xPos = boss.xSpeed +boss.xPos;
	if (boss.xPos < 230*32)
		{boss.xSpeed = 10;}

	if (boss.xPos > 252*32)
	{boss.xSpeed = -10;}
			
		++boss.counter;
		if (boss.findNearestPlayer(300*300) > -1) 

		{boss.yPos = jjCos(boss.counter/2)*2 + boss.yPos;
		boss.xPos = 4 + boss.xPos;}

		boss.determineCurFrame();
		boss.frameID = boss.counter/30;
		boss.counter += 1; 
		boss.draw();
			if (++boss.counter > 100&&boss.findNearestPlayer(300*300) > -1) 
			switch (jjRandom() & 2) 
			{case 0:
			boss.state = STATE::ATTACK;
			break;
			case 1:
			boss.state = STATE::ACTION;
			break;}

			break;
	 case STATE::ATTACK:	
	 boss.direction = (p.xPos < boss.xPos) ? -1 : 1;
	if (boss.xPos < 220*32 || boss.xPos < 222*32 || boss.xPos > 242*32)
	{boss.xPos = boss.xPos - 1;}
		boss.yPos = jjSin(boss.counter*20 + 55)*4 + boss.yOrg;
	 	if (boss.counter >= 1200) {
			int spell = OBJECT::BURGER;
			jjSample(boss.xPos, boss.yPos, SOUND::WITCH_MAGIC);
			jjOBJ@ obj = jjObjects[boss.fireBullet(OBJECT::BURGER)];
			obj.killAnim = obj.determineCurAnim(ANIM::AMMO, 4, false);
			obj.determineCurAnim(ANIM::WITCH,3);
			obj.determineCurFrame();	
			obj.yPos = boss.yPos+22;
			obj.xPos = boss.xPos+32*(boss.direction);
		}
		boss.frameID = boss.counter/53;
		boss.counter += 6; 
		if (boss.justHit == 0)
		jjDrawSpriteFromCurFrame(boss.xPos, boss.yPos, boss.curFrame, boss.direction, SPRITE::PALSHIFT, -8);
		else jjDrawSpriteFromCurFrame(boss.xPos, boss.yPos, boss.curFrame, boss.direction, SPRITE::SINGLECOLOR,15);

	if (++boss.counter > 1206) 
	{boss.xAcc= boss.yAcc =0;
	boss.state = STATE::ACTION;
	boss.counter =0;}
	break;
	case STATE::KILL:
	break;	
	}
	if (boss.state == STATE::ACTION) {
		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::WITCH].curAnim];
		anim.frameCount = 1;
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP wizard2(0, 50*32, 2*32, 2*32, 5);
		wizard2.save(frame);
	}

	else if (boss.state == STATE::ATTACK) {
		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::WITCH].curAnim];
		anim.frameCount = 1;
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP wizard(0, 48*32, 2*32, 2*32, 5);
		wizard.save(frame);
	}

	if (boss.justHit == 0)
		jjDrawSpriteFromCurFrame(boss.xPos, boss.yPos, boss.curFrame, boss.direction, SPRITE::NORMAL);
		else jjDrawSpriteFromCurFrame(boss.xPos, boss.yPos, boss.curFrame, boss.direction, SPRITE::SINGLECOLOR,15);			
}
	

					
void WizardSpell(jjOBJ@ enemy) {
		jjPLAYER@ play = jjLocalPlayers[0];
		
		if (enemy.xPos > play.xPos)
			enemy.xPos = enemy.xPos - 3; 
		else if (enemy.xPos < play.xPos) 
			enemy.xPos = enemy.xPos + 3;
		if (enemy.yPos > play.yPos)
			enemy.yPos = enemy.yPos - 3; 
		else if (enemy.yPos < play.yPos) 
			enemy.yPos = enemy.yPos + 3;
		enemy.determineCurAnim(ANIM::WITCH,3);
		enemy.determineCurFrame();
		enemy.frameID = enemy.counter/8;
		++enemy.counter;
		enemy.counter += 1; 
		 if (enemy.counter >200*jjDifficulty/2+400)
		{enemy.delete();
		  int explosionID = jjAddObject(OBJECT::BLASTERBULLET, enemy.xPos, enemy.yPos, enemy.creator, CREATOR::OBJECT);
		jjObjects[explosionID].determineCurAnim(ANIM::AMMO, 4, true);
		jjObjects[explosionID].state = STATE::EXPLODE;
		}
		jjDrawSpriteFromCurFrame(enemy.xPos, enemy.yPos, enemy.curFrame, enemy.direction, SPRITE::PALSHIFT, 8);}
	


	
void onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
	if (obj.eventID == OBJECT::BURGER) {
	p.hurt();
	obj.behavior = BEHAVIOR::EXPLOSION2;
		
	}
}



// Credit: from Stone Abbys by Bloody_Body
	jjOBJ@ spawnedObject;
void SpittingBubba(jjOBJ@ enemy) {
					if ( enemy.energy == 0)
					enemy.state = STATE::KILL;
	switch (enemy.state) {
		case STATE::WALK:
		enemy.behave(BEHAVIOR::WALKINGENEMY);
		enemy.determineCurAnim(ANIM::BUBBA, 5);	
										
			 if (enemy.findNearestPlayer(64*800) > -1 && ++enemy.counter > 36) enemy.state = STATE::IDLE;
				if (enemy.energy == 0)
					enemy.state = STATE::KILL;
			break;
			case STATE::IDLE:
			enemy.frameID = enemy.counter/5;
			enemy.determineCurFrame();
			
			switch (jjRandom() & 3) {
				
				case 0:  
				case 1:
				
					enemy.state = STATE::ACTION;
					enemy.determineCurAnim(ANIM::BUBBA, 0);
					enemy.counter = 0;
					break;
					
				case 2:
				
					enemy.state = STATE::WALK;
					enemy.determineCurAnim(ANIM::BUBBA, 5);
					enemy.counter = 0;
					
					break;
					
					}
			break;
			
			
		case STATE::ACTION:
		if (++enemy.counter < 36) {
			enemy.frameID = enemy.counter/5;
			enemy.determineCurFrame();
			enemy.direction = (jjLocalPlayers[0].xPos < enemy.xPos) ? -1 : 1;
				   if (enemy.justHit == 0)
			if (enemy.counter == 25 ) {
			//if difficulty is easy Bubba spits once per every "state::action", if normal- twice, it hard or turbo- three times.
		jjOBJ@ bullet = jjObjects[enemy.fireBullet(OBJECT::FIRESHIELDBULLET)];
				bullet.determineCurAnim(ANIM::BUBBA, 4);
				bullet.killAnim = bullet.determineCurAnim(ANIM::AMMO, 3, false);
				bullet.playerHandling = HANDLING::ENEMYBULLET;
				bullet.state = STATE::FLY;
				bullet.xPos = enemy.xPos;
				bullet.yPos = bullet.yPos - 16; 
				
				bullet.animSpeed = 2;
				jjSample(enemy.xPos, enemy.yPos, SOUND::BUBBA_SNEEZE2);
				
				
				
			}
		} else {
			enemy.frameID = enemy.counter = 0;
			enemy.determineCurAnim(ANIM::BUBBA, 5);
			enemy.state = STATE::IDLE;
		}
		break;
	
			
		case STATE::FREEZE:
			if (enemy.freeze > 0) {
				enemy.draw();
				enemy.freeze -= 4;
			}
			if (enemy.freeze < 4) {
				enemy.unfreeze(0);
				enemy.state = enemy.oldState;
			}
			break; 
	
			
		case STATE::KILL:
			
			enemy.particlePixelExplosion(2);
			@spawnedObject = jjObjects[jjAddObject(OBJECT::LEMON, enemy.xPos, enemy.yPos)];
			spawnedObject.determineCurAnim(ANIM::BUBBA, 1);
			jjSample(enemy.xPos, enemy.yPos, SOUND::RAPIER_GOSTRIP);
			enemy.delete();
			break;
			}
		enemy.draw();
		
		
	}

		void BubbaSpirit(jjOBJ@ enemy) {
		enemy.determineCurAnim(ANIM::BUBBA, 1);
		enemy.behave(BEHAVIOR::BEE);
		}

void Light(jjOBJ@ obj) {

		obj.behave(BEHAVIOR::PICKUP, false);
		obj.determineCurAnim(ANIM::PICKUPS, 2);
		obj.lightType = LIGHT::FLICKER; 
}

array<bool> SavedTriggers(32, false);
//Extendable Checkpoints by VioletCLM
void CheckpointWrapper(jjOBJ@ obj) {
  if (obj.state == STATE::STOP) { //don't do anything anymore
    jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 8);
  } else if (obj.state == STATE::DEACTIVATE) { //due to death
    obj.deactivate();
  } else {
    obj.behave(BEHAVIOR::CHECKPOINT);
	jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 8);
    if (obj.state == STATE::DONE) { //triggered by the player hitting it
      obj.state = STATE::STOP;
      //save the current state of some properties
      for (uint i = 0; i < 32; ++i)
        SavedTriggers[i] = jjTriggers[i];

      //OPTIONAL: this loop makes checkpoints reusable, so only the most recent checkpoint you touched is ever active
      for (int i = jjObjectCount; --i > 0;) {
        jjOBJ@ obj2 = jjObjects[i];
        if (obj2.eventID == OBJECT::CHECKPOINT && i != obj.objectID && obj2.isActive) {
          obj2.state = STATE::SLEEP;
          obj2.var[0] = 0;
        }
      }
    }
  }
}


bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
	return MLLE::WeaponHook.drawAmmo(player, canvas);
}


jjTEXTAPPEARANCE SignTextAppearance = STRING::NORMAL;
class Sign {
	private int xPos, yPos; //These pixel-based positions will be generated from tile-based positions in the constructor by multiplying by 32
	private string text;
	private uint widthOfText;
	Sign(){} //AngelScript requires any class that appears in any array to have an explicit default constructor, even if it's never called
	Sign(int xTile, int yTile, const string &in t) {
		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
		yPos = yTile * 32; //
		text = t;
		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.
		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.
		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.
	}
	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.
		layer.drawRectangle(xPos, yPos - 16, widthOfText + 8, 55, 0, SPRITE::TRANSLUCENT);
		layer.drawString(xPos, yPos, text, STRING::SMALL, SignTextAppearance, 0, SPRITE::BLEND_HARDLIGHT, textIntensity);
	}
}
const array<Sign> Signs = { 
	Sign(249, 12, "The sun is about to set.\nIt's not safe to linger around."),
	Sign(198, 9, "A sandstorm is coming lad!\nBetter head back to the city."),
	Sign(237, 25, "Turtles destroyed our totems.\nWrath of the gods is coming!"),
	Sign(164, 61, "I'm the Emperor Jazztezuma II.\nWhat you are looking for is beneath the Temple of Sun."),
	Sign(161, 13, "Collect all the food in these lands\nwithout dying and sugar rush will happen."),
	Sign(18, 61, "It is rumoured that a Frog Spirit was wandering\naround the Sacred Woods to prtoect our women from turtles."),
	Sign(166, 48, "Press P if you'd like to\ntrade this ammo for 1 00 Red Gems."),
};

void onDrawLayer3(jjPLAYER@, jjCANVAS@ layer) { 
	if(jjKey[0x54] && textdisappear == false){
	const uint8 textIntensity = 200 + int(jjSin(jjGameTicks * 16) * 50); 
	for (uint signID = 0; signID < Signs.length; ++signID) 
		Signs[signID].draw(layer, textIntensity);
}
}