Downloads containing mo4a_2-3.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, SzmolWeaponPack::MeleeSword::Weapon(), 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-3-MLLE-Data-1.j2l" ///@MLLE-Generated
#pragma require "mo4a_2-3.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
#include "meleeSword.asc" ///@MLLE-Generated
#pragma require "meleeSword.asc" ///@MLLE-Generated
#include "Jazz1Enemies v05.asc"
#include "Resize v11.asc"
#include "TrueColor v13.asc"
int CountlessDoubleJumps = 0;


void onLevelLoad()  {
	jjSetWaterGradient(0, 10, 10, 0, 20, 20);
	jjSetWaterLevel(2020, true);
	jjWaterLighting = WATERLIGHT::GLOBAL;
	gem::restorePlayerGems();

	jjLevelName = ("@@@@@@@@@Castle");
	jjObjectPresets[OBJECT::SAVEPOST].behavior = CheckpointWrapper;
	jjObjectPresets[OBJECT::SAVEPOST].deactivates = false;

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

	jjObjectPresets[OBJECT::SILVERCOIN].behavior = PlatinCoin();
	jjObjectPresets[OBJECT::SILVERCOIN].scriptedCollisions = true;

	jjObjectPresets[OBJECT::MOTH].behavior = Magic;

	jjObjectPresets[OBJECT::FRUITPLATFORM].behavior = HeavyObjectHanging();

	jjObjectPresets[OBJECT::BIGROCK].behavior = HeavyObjectFallen;
	jjObjectPresets[OBJECT::BIGROCK].state = STATE::FALL;

	jjObjectPresets[OBJECT::FENCER].behavior = Thief();
	jjObjectPresets[OBJECT::FENCER].playerHandling = HANDLING::SPECIAL;
	jjObjectPresets[OBJECT::FENCER].scriptedCollisions = true;
	jjObjectPresets[OBJECT::FENCER].energy=1;

	jjObjectPresets[OBJECT::FATCHICK].bulletHandling = HANDLING::HURTBYBULLET;
	jjObjectPresets[OBJECT::FATCHICK].playerHandling = HANDLING::ENEMY;
	jjObjectPresets[OBJECT::FATCHICK].behavior = Thief2;
	jjObjectPresets[OBJECT::FATCHICK].scriptedCollisions = true;
	jjObjectPresets[OBJECT::FATCHICK].energy=2;

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

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

	jjObjectPresets[OBJECT::APPLE].behavior = Carpet();
	jjObjectPresets[OBJECT::APPLE].scriptedCollisions = true;

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

		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::GEMBARREL].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP vase(0, 6*32, 1*32, 1*32, 4);
		vase.save(frame);
}

class Carpet : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::PICKUP, true);
		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::APPLE].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP vase(0, 14*32, 2*32, 1*32, 4);
		vase.save(frame);
		++obj.counter; 
		obj.yPos = jjSin(obj.counter*15 + 5)*4 + obj.yOrg;
	}

}

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

		obj.behave(BEHAVIOR::FENCER, false);
			obj.determineCurAnim(ANIM::FENCER, 0);
			obj.determineCurFrame();
			jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 48);
	
	}
bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) { 
	if(play !is null && bullet is null)
		{obj.playerHandling = HANDLING::ENEMY;}
	else if(bullet !is null)
			{jjAddObject(OBJECT::FATCHICK, obj.xPos, obj.yPos-32);}
		
	if(force == -1 || force == 1)
		{obj.playerHandling = HANDLING::ENEMY;}

	return true;
	}

}


void Thief2(jjOBJ@ obj) {

			obj.putOnGround();
			obj.behave(BEHAVIOR::WALKINGENEMY, false);
		jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 48);
			obj.determineCurAnim(ANIM::FENCER, 0);
			obj.determineCurFrame();
			obj.xSpeed = 5*obj.direction;
			if (jjMaskedVLine(obj.xSpeed > 0 ? obj.xPos + 16 : obj.xPos - 16, obj.yPos, 1))
				{obj.direction = obj.xSpeed = -obj.xSpeed;}
		if(obj.justHit==0)
		{jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, 48);}
		else obj.draw();

}

int spring = 0;
class SpikeBump : jjBEHAVIORINTERFACE {

void onBehave(jjOBJ@ obj) {
	switch (obj.state) {
		case STATE::START:

			obj.determineCurFrame();
			obj.direction = obj.xSpeed = 2;
			obj.playerHandling = HANDLING::SPECIAL;
			obj.beSolid();
			obj.state = STATE::FLY;

		case STATE::FLY:
			obj.yPos = jjSin(obj.counter*3 + 5)*2 + obj.yOrg;
			obj.beSolid();
			obj.deactivates = false;
			if (jjMaskedVLine(obj.xSpeed > 0 ? obj.xPos + 16 : obj.xPos - 16, obj.yPos, 1)) {
				obj.direction = obj.xSpeed = -obj.xSpeed;
			}

			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); 
			jjDrawResizedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, 1, 1, SPRITE::PALSHIFT, -8);
			obj.determineCurFrame();}
			else {jjDrawResizedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, 1, 1, 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))
			{obj.behave(BEHAVIOR::PLATFORM, false);
			obj.determineCurAnim(ANIM::BOLLPLAT, 0); 
			jjDrawResizedSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, 2, 1, SPRITE::PALSHIFT, -24);
			obj.determineCurFrame();
			obj.frameID = obj.counter/5;
			obj.beSolid();
			spring = jjGameTicks + 1*61;
			obj.determineCurFrame();

			jjSample(obj.xPos, obj.yPos, SOUND::PINBALL_BELL, 1000);}
	if(play !is null && force == 0)
			{play.hurt();
			obj.determineCurAnim(ANIM::SPIKEBOLL, 0);   
			obj.determineCurFrame();
			jjSample(obj.xPos, obj.yPos, SOUND::COMMON_METALHIT, 1000);}

	if(play is null && force > -2) {
			obj.determineCurAnim(ANIM::BOLLPLAT, 0);   
			obj.determineCurFrame();}
		return true;
}

}

class HeavyObjectHanging : jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {

			jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::FRUITPLATFORM].curAnim];
			anim.frameCount = 1; 
			jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
			jjPIXELMAP rope(0, 7*32, 2*32, 4*32, 4);
			rope.save(frame);
			frame.hotSpotX = -30;
			obj.behave(BEHAVIOR::PLATFORM);
			if(obj.xPos > p.xPos+64 || obj.xPos < p.xPos -64)
			{obj.scriptedCollisions = false;}
			else 			obj.scriptedCollisions = true;

	}


	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) { 
	if(play !is null && bullet !is null && bullet.var[3]==WEAPON::ICE)
		{obj.delete();
		jjAddObject(OBJECT::BIGROCK, 162*32, 51*32);}

	else if(p !is null && bullet !is null)
		{obj.scriptedCollisions = false;
		p.showText("@@Clever! But maybe something sharper...");}
		return true;
	}
}


void onLevelReload() {
	gem::restorePlayerGems();
	jjLocalPlayers[0].lives++;
	jjSetWaterGradient(0, 10, 10, 0, 20, 20);
	jjSetWaterLevel(2020, true);
	jjWaterLighting = WATERLIGHT::GLOBAL;
	p.jumpStrength = -10;
  	for (uint i = 0; i < 32; ++i)
	  	jjTriggers[i] = SavedTriggers[i];
}


void HeavyObjectFallen(jjOBJ@ obj) {

	obj.behave(BEHAVIOR::BIGOBJECT);
			jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::BIGROCK].curAnim];
			anim.frameCount = 1; 
			jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
			jjPIXELMAP rope(0, 11*32, 4*32, 2*32, 4);
			rope.save(frame);

	if(obj.yPos >= 55*32)
	{jjTriggers[0]=true;
	jjAddObject(OBJECT::ELECTROBULLET, 162*32, 56*32);
	obj.behavior = BEHAVIOR::EXPLOSION2;
	obj.counter = 0;
		if(obj.behavior == BEHAVIOR::EXPLOSION2 && obj.counter > 10)
		{obj.delete();}
	}
}

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); 
}
}

int killWitch = 0;
class RedPotion : 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, -40);
}

	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) { 

		play.jumpStrength = -10;
		jjCharacters[CHAR::JAZZ].groundJump=GROUND::JAZZ;
		jjCharacters[CHAR::SPAZ].groundJump=GROUND::SPAZ;
		jjCharacters[CHAR::LORI].groundJump=GROUND::LORI;
		jjSample(obj.xPos, obj.yPos, SOUND::WITCH_MAGIC, 3000);
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_DRINKSPAZZ2, 1000);
		obj.frameID = 0;
		killWitch = 1;
		obj.behavior = BEHAVIOR::EXPLOSION2;


		return true; 
	}
}

class CountlessJumps : 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, 16);

}

	bool onObjectHit(jjOBJ@ obj, jjOBJ@, jjPLAYER@ play, int force) {
		play.timerStart(1500);
		p.morphTo(CHAR::SPAZ);
		CountlessDoubleJumps = jjGameTicks + 25 * 61;
		obj.behavior = BEHAVIOR::EXPLOSION2;
		obj.frameID = 0;
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_PICKUP1, 6000);

		return true;
	}

}


bool textdisplayed = false, rubtextdisplayed = false, swimtext = false, lockdisplay = false;

void onFunction0(jjPLAYER@ p) {
	if(jjTriggers[4]==false && lockdisplay == false)
	{p.showText("@@Locked.");
	lockdisplay = true;}
	}

void onFunction1(jjPLAYER@ p) {
	if(jjTriggers[17]==false && textdisplayed == false)
	{p.showText("@@Place all 4 coloured stones to the@alcoves above to unlock the gate.");
	textdisplayed = true;}
	}


void Magic(jjOBJ@ obj) {
	obj.behave(BEHAVIOR::MOTH,false);
		jjPARTICLE@ particle = jjAddParticle(PARTICLE::SPARK);
		particle.xPos = obj.xPos;
		particle.yPos = obj.yPos;
}


class Lamp : jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::PICKUP);
		obj.lightType = LIGHT::LASER;
		obj.light = 10;
		obj.deactivates = false;
		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::WEENIE].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP lamp(0, 5*32, 2*32, 1*32, 4);
		lamp.save(frame);
		frame.hotSpotY = -17;
}
	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) { 
		if(jjTriggers[13]==false)
			{jjAddObject(OBJECT::MOTH, obj.xPos, obj.yPos);
			if(rubtextdisplayed == false)
				{p.showText("@@@@@@@@@@@Press UP to rub.");
				rubtextdisplayed = true;}
				if(p.keyUp==true)
					{p.warpToID(0);
					jjSample(obj.xPos, obj.yPos, SOUND::COMMON_HARP1, 1000);
					}
			}
		if (jjTriggers[13]==true && swimtext == false)
			{p.showText("@@I really feel like I can swim.");
			swimtext = true;}
		return true; 
	}
}


bool keylock = false;

class Key: jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		if(jjTriggers[4] == true)
			{obj.delete();}
		obj.behave(BEHAVIOR::PICKUP, false);
		obj.determineCurAnim(ANIM::MENU, 5);
		++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@ bullet, jjPLAYER@ player, int force) { 
		jjTriggers[4] = true;
		obj.behavior = BEHAVIOR::EXPLOSION2;
		p.cameraFreeze(231*32, 54*32, true, true);
		keylock= true;
		control = false;
		jjSample(obj.xPos, obj.yPos, SOUND::MENUSOUNDS_TYPEENTER, 1000);

		return true; 
	}
}


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

void onPlayer(jjPLAYER@ p) {
	
	if(control==false)
		{p.keyLeft = false;
		p.keyRight = false;
		p.keyDown = false;}

	if(p.xPos < 240*32) {
		if(p.idle > 100)
		{p.cameraUnfreeze(true);
		control=true;}
		else if ((p.idle > 5 && (p.keyLeft || p.keyRight || p.keyJump || p.keyFire)) || (p.curAnim - jjAnimSets[p.setID].firstAnim == RABBIT::LEDGEWIGGLE))
		{p.cameraUnfreeze(true);
		control=true;}
	}

	if(coin==false && jjTriggers[5] == true && jjTriggers[7] == true && jjTriggers[8] == true && jjTriggers[15] == true)
			{p.cameraFreeze(107*32, 58*32,true, false);
			p.showText("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Coin unlocked.");
			coin = true;}

	gem::trackPlayerGems(p);
	gem::upgradeHealth(p);
	p.lightType = LIGHT::NONE;

		jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::BURGER].curAnim];
		anim.frameCount = 1;  
		jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
		jjPIXELMAP stone(0, 13*32, 1*32, 1*32, 4);
		stone.save(frame);
		frame.hotSpotY = -17;

	for (int i = 1; i < jjObjectCount; i++) {
	jjOBJ@ o = jjObjects[i];
		if (o.isActive && o.eventID == OBJECT::SILVERCOIN && p.coins >= 3) {
		o.state = STATE::KILL;
		}

	}


	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;
	}

	if(p.xPos > 17*32 && p.xPos <20*32 && p.yPos > 58*32){
		if(p.coins < 3)
		p.testForCoins(3);
		else { 
		jjNxt(false, true);
		gem::saveGemData();}
	}

	exit = 0;
	if(jjTriggers[5] == true)
		{exit += 1;}
	if(jjTriggers[7] == true)
		{exit += 1;}
	if(jjTriggers[8] == true)
		{exit += 1;}
	if(jjTriggers[15] == true)
		{exit += 1;}

	if(p.xPos < 158*32 && p.xPos > 155*32 && p.yPos > 42*32 && p.yPos <44*32 && jjTriggers[5] == false)
	{jjTriggers[5] = true;
	exit += 1;
	jjSample(p.xPos, p.yPos, SOUND::COMMON_PICKUP1, 1000);}

	if(p.xPos < 164 *32 && p.xPos > 161*32 && p.yPos > 60*32 && p.yPos <62*32 && jjTriggers[7] == false)
	{jjTriggers[7] = true;
	exit += 1;
	jjSample(p.xPos, p.yPos, SOUND::COMMON_PICKUP1, 1000);}

	if(p.xPos < 236 *32 && p.xPos > 233*32 && p.yPos > 13*32 && p.yPos <15*32 && jjTriggers[8] == false)
	{jjTriggers[8] = true;
	exit += 1;
	jjSample(p.xPos, p.yPos, SOUND::COMMON_PICKUP1, 1000);}

	if(p.xPos < 64 *32 && p.xPos > 61*32 && p.yPos > 4*32 && p.yPos <6*32 && jjTriggers[15] == false)
	{jjTriggers[15] = true;
	exit += 1;
	jjSample(p.xPos, p.yPos, SOUND::COMMON_PICKUP1, 1000);}

	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(jjTriggers[5]==true && jjTriggers[7]==true && jjTriggers[8]==true && jjTriggers[15]==true)
{jjTriggers[17]=true;}

p.invisibility = false;


if(p.keyFire && p.currWeapon == WEAPON::ICE)
{p.invisibility = true;
jjDrawSprite(p.xPos, p.yPos, p.setID, RABBIT::QUIT, p.curFrame, p.direction, SPRITE::PLAYER);
}

if(p.xPos > 256*32){
	jjTriggers[13]=true;
	p.idle = 100;
	p.cameraFreeze(261*32, 52*32, true, true);
	p.lighting = 1;
	p.noFire = true;
	if(p.keyJump || p.keyFire)
		{p.warpToID(5);}
}

if(p.coins == 0)
{p.coins += 2;}
	MLLE::WeaponHook.processPlayer(p);
if(p.jumpStrength==-2){
p.keyUp = false;
}


if (CountlessDoubleJumps > jjGameTicks && p.keyJump) {
	p.doubleJumpCount = 0;}
if (p.health == 0){
	CountlessDoubleJumps  = 0;
}



if (p.yPos > jjWaterLevel && jjTriggers[13]==false) {
    p.health = 0;
  }
 
}

void onFunction2(jjPLAYER@ play) {
	p.cameraUnfreeze();
	p.noFire = false;}

void onFunction3(jjPLAYER@ play) {
	CountlessDoubleJumps  = 0;
	play.timerStop();}

void onFunction4(jjPLAYER@ play) {
if(jjTriggers[13]==false)
{p.showText("@@Learn how to swim first.");}
}

void onFunction6(jjPLAYER@ play) {
keylock = false;}

						

class PlatinCoin : jjBEHAVIORINTERFACE {

	void onBehave(jjOBJ@ obj) {
		if(p.coins >= 3)
		{obj.delete();}
		obj.behave(BEHAVIOR::PICKUP, false);
		++obj.counter;
		obj.deactivates = false;
		if(obj.xPos > 108*32)
		{obj.xPos = obj.xPos - 8;} 
		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@ bullet, jjPLAYER@ player, int force) {
		p.coins += 1; 
		obj.behavior = BEHAVIOR::EXPLOSION2;
		jjSample(obj.xPos, obj.yPos, SOUND::COMMON_COIN, 1000);

		return true;
	}
}


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

int exit = 0;

bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) {
if(p.xPos < 256*32){
    canvas.drawString(30, 585, formatInt(exit%5, "1") + "/4", STRING::SMALL, STRING::NORMAL);
    canvas.drawSprite(20, 585, ANIM::PICKUPS, 11, jjGameTicks>>2, -1, SPRITE::NORMAL);
	if(keylock == true && jjTriggers[4]==true)
		{canvas.drawSprite(90, 580, ANIM::MENU,5, jjGameTicks>>2, -1, SPRITE::PALSHIFT, 8);}
    return false;}
	else return true;
}

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

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(58, 55, "The 40 Thieves killed the Sultan.\nThey're still here, looking for something."),
	Sign(92, 51, "The Sultan is murdered, but his crown's\nstill lingering in the throne room."),
	Sign(250, 56, "YOU: Hey what's going on?\nGENIE: Grand your three wishes,\nI shall make them come true!\nYOU: Hmm...I want Devan Shell captured.\nGENIE: No Devan Shell exist in this world.\nYOU: B-but...\nGEENIE: Grant your second wish."),
	Sign(260, 56, "YOU:Then I'd like to locate the second Time Freezer.\nIt does exist in this timeline, right?\nGENIE: Look for it in the Magical Cave.\nYOU: Hey! Won't you bring it here?\nGENIE:You said locate, stranger. Grand your last wish!\nYOU:Oh well. At least you could teach me how to swim.\n\nHit |||||FIRE |to learn how to swim."),
	Sign(202, 12, "Thieves are looking for the magic lamp.\nThankfully I am good at hiding stuff."),
};

void onDrawLayer1(jjPLAYER@, jjCANVAS@ layer) { 
	if(jjKey[0x54] || p.xPos > 256*32){
	const uint8 textIntensity = 200 + int(jjSin(jjGameTicks * 16) * 50); 
	for (uint signID = 0; signID < Signs.length; ++signID) 
		Signs[signID].draw(layer, textIntensity);
}
}


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;
        }
      }
    }
  }
}


//HH18.savegems.asc 
// Had to copy the contents in here so that I could return DrawScore true during the cutscene.

namespace gem {
	int gemsCollected, nextHealth, currAmount;
	
	int maxHealth() {
		return ((jjMaxHealth+1) - (jjDifficulty < 3? 5:3));
	}
	
	array<int> gemTotals(4);
	bool restoreGems;
	bool draw = true;

	void upgradeHealth(jjPLAYER@ play) { //onPlayer
		switch (maxHealth()) {
			case 1: currAmount = 100; break;
			case 2: currAmount = 275; break;
			case 3: currAmount = 450; break;
			case 4: currAmount = 625; break;
			case 5: currAmount = 800; break;
		}
	
		if (gemsCollected >= currAmount && nextHealth != maxHealth() && maxHealth() < 6) {
			jjChat("/smhealth " + (jjMaxHealth + 1));
			for (int i = 0; i < 8; ++i) {
				jjAlert("");
			}
			nextHealth = jjMaxHealth;
			if (jjGameTicks > 7) {
				jjSample(play.xPos, play.yPos, SOUND::COMMON_HARP1, 0, 0);
				jjAlert("||||By the power of gems, your maximum health is increased!", false, STRING::MEDIUM);
				if (maxHealth() == 6) jjAlert("|||Congratulations, your health is maximised!", false, STRING::MEDIUM);
			}
		}
	}
	
	void trackPlayerGems(jjPLAYER@ play) { //onPlayer
		if (!restoreGems) {
			gemTotals[0] = play.gems[GEM::RED];
			gemTotals[1] = play.gems[GEM::GREEN] * 5;
			gemTotals[2] = play.gems[GEM::BLUE] * 10;
			gemTotals[3] = play.gems[GEM::PURPLE] * 20;
			gemsCollected = gemTotals[0] + gemTotals[1] + gemTotals[2] + gemTotals[3];
		} else {
			play.gems[GEM::RED] = jjGameTicks > 1? gemTotals[0] : play.lives;
			play.gems[GEM::GREEN] = gemTotals[1] / 5;
			play.gems[GEM::BLUE] = gemTotals[2] / 10;
			play.gems[GEM::PURPLE] = gemTotals[3] / 20;
			restoreGems = false;
		}
	}
	
	void restorePlayerGems() { //onLevelLoad and onLevelReload
		restoreGems = true;
	}
	
	void saveGemData() { //this needs to go in an AS function that also acts as the level exit
		jjLocalPlayers[0].lives = gemsCollected;
	}
	
	void deleteCollectedGems() {
		for (int i = 1; i < jjObjectCount; i++) {
			jjOBJ@ obj = jjObjects[i];
			int playerID = obj.findNearestPlayer(200000);
			jjPLAYER@ play = jjPlayers[playerID];
			
			if (playerID > -1 && 
			(obj.eventID == OBJECT::REDGEM ||
			obj.eventID == OBJECT::GREENGEM ||
			obj.eventID == OBJECT::BLUEGEM ||
			obj.eventID == OBJECT::PURPLEGEM ||
			obj.eventID == OBJECT::RECTREDGEM ||
			obj.eventID == OBJECT::RECTGREENGEM ||
			obj.eventID == OBJECT::RECTBLUEGEM)) {
				if (obj.creatorType == CREATOR::LEVEL) {
					if (play.doesCollide(obj, true)) {
						jjEventSet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0);
					}
				} else {
					if (obj.creatorID == 0 && obj.state != STATE::FLOATFALL) {
						obj.playerHandling = HANDLING::PARTICLE;
						obj.delete();
					}
					
				}
			}
			
			if (obj.eventID == OBJECT::GEMBARREL || obj.eventID == OBJECT::GEMCRATE) {
				if (obj.state == STATE::EXPLODE) jjEventSet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0);
			}
			
			if (obj.eventID == OBJECT::GEMRING) {
				if (obj.state == STATE::HIT) jjEventSet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0);
			}
			
			if (obj.eventID == OBJECT::SUPERGEM) {
				if (obj.state == STATE::ACTION) jjEventSet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0);
			}
			
			if (obj.eventID == OBJECT::BOMBCRATE || obj.eventID == OBJECT::ONEUPCRATE) {
				if (obj.state == STATE::FALL && (obj.var[0] == OBJECT::REDGEM ||
				obj.var[0] == OBJECT::GREENGEM ||
				obj.var[0] == OBJECT::BLUEGEM ||
				obj.var[0] == OBJECT::PURPLEGEM ||
				obj.var[0] == OBJECT::RECTREDGEM ||
				obj.var[0] == OBJECT::RECTGREENGEM ||
				obj.var[0] == OBJECT::RECTBLUEGEM)) {
					jjEventSet(uint(obj.xOrg) >> 5, uint(obj.yOrg) >> 5, 0);
				}
			}
		}
	}
}

bool onCheat(string &in cheat) {
	if (cheat == "jjnxt" || cheat == "jjnext") {
		gem::saveGemData();
		jjNxt(true, true);
	} else if (cheat == "jjgems") {
		jjLocalPlayers[0].gems[GEM::RED] = jjLocalPlayers[0].gems[GEM::RED] + 100;
	} else
		return false;
	jjAlert(cheat, false, STRING::MEDIUM);
	return true;
}

bool onDrawScore(jjPLAYER@ play, jjCANVAS@ canvas) {

	if (gem::draw && p.xPos < 256*32) {
		canvas.drawSprite(20, 42, ANIM::PICKUPS, 22, jjGameTicks>>2, 0, SPRITE::GEM, 0);
		canvas.drawString(36, 42, "x " + gem::gemsCollected, STRING::MEDIUM, STRING::NORMAL);
		if (gem::maxHealth() < 6) {
			canvas.drawString(8, 70, "|" + gem::currAmount + " |||||for upgrade", STRING::SMALL, STRING::NORMAL);
		} else {
			canvas.drawString(8, 70, "||||Max!", STRING::SMALL, STRING::NORMAL);
		}
	
	return false;}
	else return true;
}