Downloads containing DiamUltEx.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Diamondus UltimateFeatured Download DoubleGJ Tileset conversion 9.7 Download file

File preview

const bool MLLESetupSuccessful = MLLE::Setup(); ///@MLLE-Generated
#include "MLLE-Include-1.6.asc" ///@MLLE-Generated
#pragma require "DiamUltEx-MLLE-Data-1.j2l" ///@MLLE-Generated
#pragma require "DiamUltEx.j2l" ///@MLLE-Generated
#pragma require "DD-Anims.j2a"
#include "DD-Order.asc"
#include "DD-Rank.asc"
#pragma require "DiamUlt-BNight.j2t"
#pragma require "DiamUlt-Candy.j2t"
#pragma require "waterfall-loop.wav"
#pragma require "night-loop.wav"
#pragma require "owl-loop1.wav"
#pragma require "owl-loop2.wav"
#pragma require "floppy-read.wav"
#pragma offer "DD-DiamFunk.xm"
#pragma offer "Biggyzoom - Diamondus (Reggae Remix).mp3"
#pragma offer "drgeno-boss2.mp3"

///@Event 67=Super Gem |+|Gem |Super |Gem |Color:2
///@Event 118=Turtlette|-|Enemy|Turt-|lette
///@Event 167=Amogus Pear|+|Food      |Sus|Pear
///@Event 168=Blueberry|+|Food      |Blue|Berry
///@Event 170=White Grapes|+|Food      |White|Grapes
///@Event 172=Floating Red Spring|+|Spring|Float|Spring|Velocity:6|Angle:3
///@Event 174=Firefly (stationary)|+|Scenery|Sit'n|F.Fly
///@Event 175=Raspberry|+|Food      |Rasp|Berry
///@Event 176=Bobbing Platform (beta)|+|Scenery|Bob|Beta
///@Event 177=Wild Berry|+|Food      |Wild|Berry
///@Event 179=Bobbing Platform (retail)|+|Scenery|Bob|Retail
///@Event 180=Firefly|+|Scenery|Fire|Fly|X Range:3|Y Range:3
///@Event 189=Invisible GemStomp |+|Gem |Gem |Stomp |Color:2
///@Event 204=Sparkle  |+|Scenery    |Sparkle |  |Adjust Y:5|Adjust X:-6

// not renaming Purple Gem since it's just a reskin (yes I know so is food but these are more convincing)

bool computerOn = false;
bool groovyMode = false;
bool bossFight = false;
int smeltIt = 0;
int countdownEOL = 0;
bool dialogOver = false;

const float maxScore = 110000;
const int bestTime = 420;
const int easyTimer = 0;
const int normalTimer = 0;
const int hardTimer = 84000;
const int turboTimer = 63000;

array<uint> fastFeetMode(4, 0);
bool noFast = true;

void onLevelLoad() { 	
	initiateRanking();
	initFade();
	initiateDialogue();
	
	jjAnimSets[ANIM::ROBOT].load();
	jjAnimSets[ANIM::CUSTOM[37]].load(37, "DD-Anims.j2a");
	
	jjLayers[8].xSpeed = 0.02;
	jjLayers[8].ySpeed = 0.02;
	jjLayers[8].xAutoSpeed = 0.07;
	jjLayers[8].xSpeedModel = LAYERSPEEDMODEL::NORMAL;
	jjLayers[8].ySpeedModel = LAYERSPEEDMODEL::NORMAL;
	
	jjSampleLoad(SOUND::SCIENCE_PLOPKAOS, "waterfall-loop.wav");
	jjSampleLoad(SOUND::DOG_WAF1, "night-loop.wav");
	jjSampleLoad(SOUND::DOG_AGRESSIV, "owl-loop1.wav");
	jjSampleLoad(SOUND::DOG_SNIF1, "owl-loop2.wav");
	jjSampleLoad(SOUND::DOG_WAF2, "floppy-read.wav");
	
	jjAnimSets[ANIM::CUSTOM[8]].load(9, "DD-Anims.j2a");
	jjObjectPresets[OBJECT::PSYCHPOLE].behavior = sparkle;
	jjObjectPresets[OBJECT::PSYCHPOLE].determineCurAnim(ANIM::CUSTOM[8], 0);
	jjAnimSets[ANIM::CUSTOM[2]].load(10, "DD-Anims.j2a");
	jjObjectPresets[OBJECT::JUNGLEPOLE].determineCurAnim(ANIM::CUSTOM[2], 0);
	
	jjAnimSets[ANIM::CUSTOM[3]].load(6, "DD-Anims.j2a");
	jjObjectPresets[OBJECT::HELMUT].determineCurAnim(ANIM::CUSTOM[3], 0);
	jjObjectPresets[OBJECT::HELMUT].points = 50;
	jjObjectPresets[OBJECT::HELMUT].energy = 1;
	jjObjectPresets[OBJECT::HELMUT].xSpeed = 0.5;
	jjObjectPresets[OBJECT::HELMUT].behavior = turtlette();
	
	jjAnimSets[ANIM::CUSTOM[4]].load(11, "DD-Anims.j2a");
	jjObjectPresets[OBJECT::PURPLEGEM].behavior = floppy();
	jjObjectPresets[OBJECT::PURPLEGEM].determineCurAnim(ANIM::CUSTOM[4], 0);
	jjObjectPresets[OBJECT::STANDMONKEY].behavior = computer();
	jjObjectPresets[OBJECT::STANDMONKEY].determineCurAnim(ANIM::CUSTOM[4], 1);
	jjObjectPresets[OBJECT::STANDMONKEY].bulletHandling = HANDLING::IGNOREBULLET;
	jjObjectPresets[OBJECT::STANDMONKEY].playerHandling = HANDLING::SPECIAL;
	jjAnimSets[ANIM::CUSTOM[5]].load(5, "DD-Anims.j2a");
	jjObjectPresets[OBJECT::EVA].behavior = evaPlus();

	jjAnimSets[ANIM::CUSTOM[7]].load(12, "DD-Anims.j2a");
	jjObjectPresets[OBJECT::WEENIE].behavior = firefly;	
	jjObjectPresets[OBJECT::WEENIE].determineCurAnim(ANIM::CUSTOM[7], 0);
	jjObjectPresets[OBJECT::WEENIE].playerHandling = HANDLING::PARTICLE;
	jjObjectPresets[OBJECT::BURGER].behavior = fireflySit;
	jjObjectPresets[OBJECT::BURGER].determineCurAnim(ANIM::CUSTOM[7], 0);
	jjObjectPresets[OBJECT::BURGER].playerHandling = HANDLING::PARTICLE;
	
	jjAnimSets[ANIM::CUSTOM[6]].load(3, "DD-Anims.j2a");
	jjAnimSets[ANIM::CUSTOM[9]].load(17, "DD-Anims.j2a");
	jjObjectPresets[OBJECT::CAKE].determineCurAnim(ANIM::CUSTOM[9], 2);
	jjObjectPresets[OBJECT::PIZZA].determineCurAnim(ANIM::CUSTOM[6], 9);
	jjObjectPresets[OBJECT::CHICKENLEG].determineCurAnim(ANIM::CUSTOM[6], 10);
	jjObjectPresets[OBJECT::CHIPS].determineCurAnim(ANIM::CUSTOM[6], 11);
	jjObjectPresets[OBJECT::DONUT].determineCurAnim(ANIM::CUSTOM[6], 12);
	
	jjObjectPresets[OBJECT::COKE].behavior = bubbaMod;
	jjObjectPresets[OBJECT::COKE].energy = 100;
	jjObjectPresets[OBJECT::COKE].points = 1000;
	jjObjectPresets[OBJECT::COKE].bulletHandling = HANDLING::HURTBYBULLET;
	jjObjectPresets[OBJECT::COKE].playerHandling = HANDLING::ENEMY;
	jjObjectPresets[OBJECT::PEPSI].behavior = bubbaMod;
	jjObjectPresets[OBJECT::PEPSI].energy = 100;
	jjObjectPresets[OBJECT::PEPSI].points = 1000;
	jjObjectPresets[OBJECT::PEPSI].bulletHandling = HANDLING::HURTBYBULLET;
	jjObjectPresets[OBJECT::PEPSI].playerHandling = HANDLING::ENEMY;
	
	const jjOBJ@ spring = jjObjectPresets[OBJECT::REDSPRING];
	jjOBJ@ preset = jjObjectPresets[OBJECT::CHOCBAR];
	preset.behavior = floatingSpring;
	preset.curAnim = spring.curAnim;
	preset.objType = spring.objType;
	preset.noHit = spring.noHit;
	preset.ySpeed = spring.ySpeed;
	preset.deactivates = false;
	
	jjPIXELMAP bob1(0, 16, 64, 80, 4);
	jjANIMFRAME@ retailplat = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::BOLLPLAT].firstAnim].firstFrame];
	bob1.save(retailplat);
	retailplat.hotSpotX = -18;
	retailplat.hotSpotY = -20;
	
	jjObjectPresets[OBJECT::TACO].determineCurAnim(ANIM::BOLLPLAT, 0);
	jjObjectPresets[OBJECT::TACO].bulletHandling = HANDLING::IGNOREBULLET;
	jjObjectPresets[OBJECT::TACO].playerHandling = HANDLING::SPECIAL;
	
	jjPIXELMAP bob2(64, 0, 64, 32, 4);
	jjANIMFRAME@ betaplat = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::SONICPLAT].firstAnim].firstFrame];
	bob2.save(betaplat);
	betaplat.hotSpotX = -12;
	betaplat.hotSpotY = -20;
	
	jjObjectPresets[OBJECT::FRIES].determineCurAnim(ANIM::SONICPLAT, 0);
	jjObjectPresets[OBJECT::FRIES].bulletHandling = HANDLING::IGNOREBULLET;
	jjObjectPresets[OBJECT::FRIES].playerHandling = HANDLING::SPECIAL;
	
	jjObjectPresets[OBJECT::THING].behavior = multiBossHealthHandler;
	jjObjectPresets[OBJECT::THING].energy = 100;
	
	int frogLife = jjAddObject(OBJECT::EXTRALIFE, 314*32+20, 53*32-8); // slightly displaced so frog tongue can reach it
	jjObjects[frogLife].lightType = LIGHT::LASER; // illuminate surroundings (garage edition)
	jjObjects[frogLife].light = 10;
	jjObjects[frogLife].deactivates = false; // otherwise the game seems to forget the item exists...
}

void onLevelBegin() {
	setTimer();
}

void onLevelReload() {
	if (groovyMode) { getFunky(jjLocalPlayers[1]); }
	else { jjMusicLoad("DD-DiamFunk.xm"); }
	
	const jjOBJ@ spring = jjObjectPresets[OBJECT::REDSPRING];
	jjOBJ@ preset = jjObjectPresets[OBJECT::CHOCBAR];
	preset.behavior = floatingSpring;
	preset.curAnim = spring.curAnim;
	preset.objType = spring.objType;
	preset.noHit = spring.noHit;
	preset.ySpeed = spring.ySpeed;
	preset.deactivates = false;
	
	bossFight = false;
	
	int frogLife = jjAddObject(OBJECT::EXTRALIFE, 314*32+20, 53*32-8); // respawn on SP player death like other objects
	jjObjects[frogLife].lightType = LIGHT::LASER;
	jjObjects[frogLife].light = 10;
	jjObjects[frogLife].deactivates = false;
	
	scoreSeconds = storeScoreSeconds;
}

bool onDrawScore(jjPLAYER@ player, jjCANVAS@ canvas) {
	if (fastFeetMode[player.playerID] > 210 || (fastFeetMode[player.playerID] > 0 && jjGameTicks % 2 == 0)) canvas.drawString((jjSubscreenWidth / 2) - (jjGetStringWidth("GOTTA GO FAST 00", STRING::MEDIUM, STRING::BOUNCE) / 2), 50, "GOTTA GO FAST " + uint(fastFeetMode[player.playerID] / 70), STRING::MEDIUM, STRING::BOUNCE, 16);
	if (computerOn) {
		canvas.drawSprite((jjResolutionWidth / 2) - 16, jjResolutionHeight - (jjResolutionHeight / 32), ANIM::CUSTOM[4], 0, (jjGameTicks/5) & 15);
		canvas.drawString(jjResolutionWidth / 2, jjResolutionHeight - (jjResolutionHeight / 32), "x" + player.gems[GEM::PURPLE], STRING::MEDIUM);
	}
	if (CurrentPopup !is null) {
		CurrentPopup.Draw(canvas);
		return !CurrentPopup.DrawHUD();
	}
	if (levelOver) {
		drawFade(player, canvas);
		if (rankLine < 6) rankingDisplay(player, canvas);
	}
	if (rankLine >= 6) return true;
	else return false;
}

bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
	if (rankLine >= 6) return true;
	else return CurrentPopup !is null && !CurrentPopup.DrawHUD();
}

bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) {
	if (rankLine >= 6) return true;
	else return CurrentPopup !is null && !CurrentPopup.DrawHUD();
}

bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas) { 
	if (jjDifficulty == 0 && CurrentPopup is null) {
		return true;
	}
	if (rankLine >= 6) return true;
    else return CurrentPopup !is null && !CurrentPopup.DrawHUD();
}
bool onDrawPlayerTimer(jjPLAYER@ player, jjCANVAS@ canvas) { return CurrentPopup !is null && !CurrentPopup.DrawHUD(); }

void onPlayerDraw(jjPLAYERDRAW& draw) {
	jjPLAYER@ play = draw.player;
	if (isFading) {
		draw.sprite = false;
		return;
	}
}

void onPlayer(jjPLAYER@ play) {
	dialogueInterface(play);
	rankingInterface(play);
	if (fastFeetMode[play.playerID] > 0) {
			if (play.xAcc > 0) {
				play.xAcc = play.xAcc + 1;
				play.xSpeed = play.xSpeed + 2;
			}
			if (play.xAcc < 0) {
				play.xAcc = play.xAcc - 1;
				play.xSpeed = play.xSpeed - 2;
			}
			play.keyRun = true;
		fastFeetMode[play.playerID]--;
	} else if (jjGetModTempo() != 108) jjSetModTempo(108);
}

void onMain() {
	updateGems();
	if (dialogOver) countdownEOL++;
	if (countdownEOL == 140) {
		jjLocalPlayers[smeltIt].activateBoss(false);
		endLevel(jjLocalPlayers[smeltIt]);
	}
	
	if (jjDifficulty == 0) {
		oneUpsIntoBlueGems();
	}
	if ((jjGameTicks % 70) == 0 && !levelOver && CurrentPopup is null) {
		scoreSeconds++;
	}	
	rankingSetup();
	if (levelOver) updateFade();
	
	for (int i = 0; i <= jjLocalPlayerCount; i++) {
		if (fastFeetMode[i] != 0) {
			noFast = false;
			break;
		} else noFast = true;
	}
}

void updateGems() {
	for (int i=1; i < jjObjectCount; i++) {
		if (jjObjects[i].isActive) {
			if (jjObjects[i].eventID == OBJECT::SUPERGEM) {
				jjObjects[i].var[0] = jjParameterGet(int(jjObjects[i].xOrg / 32), int(jjObjects[i].yOrg / 32), 0, 2) + 1;
			}
			if (jjObjects[i].eventID == OBJECT::FLICKERGEM) {
				if (jjEventGet(int(jjObjects[i].xOrg / 32), int(jjObjects[i].yOrg / 32)) == OBJECT::SUPERGEM) {
					jjObjects[i].var[0] = jjParameterGet(int(jjObjects[i].xOrg / 32), int(jjObjects[i].yOrg / 32), 0, 2) + 1;
				}
				else if (jjEventGet(int(jjObjects[i].xOrg / 32), int(jjObjects[i].yOrg / 32 + 1)) == OBJECT::GEMSTOMP) {
					jjObjects[i].var[0] = jjParameterGet(int(jjObjects[i].xOrg / 32), int(jjObjects[i].yOrg / 32 + 1), 0, 2) + 1;
				}
				if (jjObjects[i].var[0] == 2 || jjObjects[i].var[0] == 3) {
					jjObjects[i].points=500*(jjObjects[i].var[0]-1);
				}
			}
		}
	}
}

void floatingSpring(jjOBJ@ obj) {
	if (obj.state == STATE::DEACTIVATE) {
		obj.eventID = OBJECT::CHOCBAR;
		obj.deactivate();
		return;
	}
	float xSpeed = obj.xSpeed;
	float ySpeed = obj.ySpeed;
	int8 direction = obj.direction;
	if (obj.state == STATE::START) {
		obj.behave(BEHAVIOR::BUTTERFLY, false);
		obj.eventID = OBJECT::REDSPRING;
		obj.xPos = obj.xOrg;
		obj.yPos = obj.yOrg;
		obj.state = STATE::SLEEP;
	} else {
		obj.xSpeed = fpFromIEEE(uint(obj.var[8]));
		obj.ySpeed = fpFromIEEE(uint(obj.var[9]));
		obj.direction = obj.var[10];
	}
	obj.pathMovement();
	obj.var[3] = int(obj.xOrg * 0x10000);
	obj.var[4] = int(obj.yOrg * 0x10000);
	obj.var[8] = fpToIEEE(obj.xSpeed);
	obj.var[9] = fpToIEEE(obj.ySpeed);
	obj.var[10] = obj.direction;
	obj.xSpeed = xSpeed;
	obj.ySpeed = ySpeed;
	obj.direction = direction;
	float xPos = obj.xPos;
	float yPos = obj.yPos;
	obj.behave(BEHAVIOR::SPRING);
	obj.xPos = xPos;
	obj.yPos = yPos;
	jjPARTICLE@ particle = jjAddParticle(PARTICLE::FIRE);
	if (particle !is null) {
		particle.xPos = obj.xPos;
		particle.yPos = obj.yPos + 9;
		particle.ySpeed = 0.1;
		particle.fire.size = jjRandom()&3;
	}
}

class turtlette : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::WALKINGENEMY);
		obj.scriptedCollisions = true;
		obj.playerHandling = HANDLING::SPECIAL;
	}
	bool onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ player, int force) {
		if (bullet !is null) {
			if (bullet.var[3] == 1) { obj.grantPickup(player, 5); }
				else { obj.grantPickup(player, 10); }
			obj.justHit = 20;
			obj.state = STATE::KILL; // surprisingly, freezing still works
			player.score += 50;
			jjPARTICLE@ particle = jjAddParticle(PARTICLE::STRING);
				particle.string.text = "50";
				particle.xPos = obj.xPos;
				particle.yPos = obj.yPos;
				particle.xSpeed = -0.7;
				particle.ySpeed = -1.5;
			bullet.state = STATE::EXPLODE;
			if (bullet.var[6] == 2) {
				obj.particlePixelExplosion(1);
				jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BURN);
				}
				else { obj.particlePixelExplosion(0); }
		}
		else if (player !is null && force != 0) {
			obj.state = STATE::KILL;
			player.score += 50;
			jjPARTICLE@ particle = jjAddParticle(PARTICLE::STRING);
				particle.string.text = "50";
				particle.xPos = obj.xPos;
				particle.yPos = obj.yPos;
				particle.xSpeed = -0.7;
				particle.ySpeed = -1.5;
			obj.particlePixelExplosion(2);
			jjSample(obj.xPos, obj.yPos, SOUND::COMMON_SMASH);
		}
		return true;
	}
}

void firefly(jjOBJ@ obj) {
    obj.var[6] = jjParameterGet(int(obj.xOrg / 32), int(obj.yOrg / 32), 0, 3);
    obj.var[7] = jjParameterGet(int(obj.xOrg / 32), int(obj.yOrg / 32), 3, 3);
    obj.counter += 1 + (jjRandom() & 3);
    int arg = obj.counter / ((obj.var[6] + 1) + (obj.var[7] + 1) / 2);
    obj.xPos = obj.xOrg + jjSin(arg * 4) * 32 * (obj.var[6] + 1);
    obj.yPos = obj.yOrg + jjCos(arg * 2) * 24 * (obj.var[7] + 1);
    if (arg & 255 < 128 ^^ obj.direction < 0) {
        jjSample(obj.xPos, obj.yPos, SOUND::COMMON_FOEW1, 10, (obj.direction < 0 ? 30300 : 30000) + (jjRandom() & 0x7FF));
        obj.direction = obj.direction < 0 ? 1 : -1;
    }
    obj.frameID = obj.counter / 6 % jjAnimations[obj.curAnim].frameCount;
    obj.determineCurFrame();
    obj.draw();
    obj.lightType = LIGHT::NORMAL;
    obj.light = 9 + jjRandom() % 6;
}

void fireflySit(jjOBJ@ obj) {
	obj.behave(BEHAVIOR::MOTH);
	obj.lightType = LIGHT::NORMAL;
	obj.light = (9 + jjRandom()%6);
	obj.determineCurAnim(ANIM::CUSTOM[7], 0);
}

class floppy : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		obj.eventID = 66; 
		obj.behave(BEHAVIOR::PICKUP);
		obj.points = 50;
		obj.var[0] = 0;
	}
}

class computer : jjBEHAVIORINTERFACE {
	int txtCD = 0;
	int sampCD = 0;
	void onBehave(jjOBJ@ obj) {
		obj.lightType = LIGHT::FLICKER;
		obj.light = 10;
		if (sampCD > 0) { sampCD--; }
		obj.isBlastable = obj.isFreezable = obj.isTarget = obj.triggersTNT = false;
		switch (obj.state) {
			case STATE::START:
				obj.state = STATE::IDLE;
			case STATE::IDLE:
				computerOn = false;
				obj.frameID = (jjGameTicks/5) & 3;
				obj.determineCurFrame();
				txtCD = 0;
				if (obj.findNearestPlayer(128) >= 0) { obj.state = STATE::WAKE; }
				break;
			case STATE::WAKE:
				computerOn = true;
				obj.frameID = (jjGameTicks/5) & 3;
				obj.determineCurFrame();
				if (txtCD == 0) {
					jjLocalPlayers[obj.findNearestPlayer(128)].showText("@@@Insert 100 disks@to alter your experience!", STRING::MEDIUM);
					txtCD = 2000;
				}
				else if (txtCD > 0) { txtCD--; }
				if (jjKey[0x54]) { //T
					if (jjLocalPlayers[obj.findNearestPlayer(128)].gems[GEM::PURPLE] >= 100) {
						if (sampCD == 0) { jjSamplePriority(SOUND::DOG_WAF2); }
						jjLocalPlayers[obj.findNearestPlayer(128)].showText("@@@@#GROOVY MODE", STRING::LARGE);
						getFunky(jjLocalPlayers[obj.findNearestPlayer(128)]);
						jjLocalPlayers[obj.findNearestPlayer(128)].gems[GEM::PURPLE] = jjLocalPlayers[obj.findNearestPlayer(128)].gems[GEM::PURPLE] - 100;
					}
					else if (sampCD == 0) { jjSamplePriority(SOUND::COMMON_NOCOIN); }
					sampCD = 50;
				}
				if (obj.findNearestPlayer(128) < 0) { obj.state = STATE::IDLE; }
				break;
			case STATE::DEACTIVATE:
				obj.deactivate();
				break;
		}
	}
	void onDraw(jjOBJ@ obj) {
		obj.draw();
		if (obj.state == STATE::WAKE) { 
			jjDrawSprite(obj.xPos - 64, obj.yPos - 48, ANIM::CUSTOM[5], 0, (jjGameTicks/12) & 1);
		}
	}
}

class evaPlus : jjBEHAVIORINTERFACE {
	void onBehave(jjOBJ@ obj) {
		obj.behave(BEHAVIOR::EVA);
		if (obj.state == STATE::STILL && jjLocalPlayers[obj.findNearestPlayer(1024)].charCurr != CHAR::FROG) { obj.state = STATE::WAKE; }
		if (obj.state == STATE::WAKE) {
			if (jjKey[0x54]) { evaSpeaks(jjLocalPlayers[obj.findNearestPlayer(1024)]); }
			else if (obj.findNearestPlayer(1024) < 0) { obj.state = STATE::STILL; }			
		}
	}
	void onDraw(jjOBJ@ obj) {
		obj.draw();
		if (obj.state == STATE::WAKE) { 
			jjDrawSprite(obj.xPos - 40, obj.yPos - 48, ANIM::CUSTOM[5], 0, (jjGameTicks/12) & 1);
		}
	}
}
	
void apply(jjPAL pal = jjPalette) {
	jjSetFadeColors(
		pal.color[206].red,
		pal.color[206].green,
		pal.color[206].blue
	);
	pal.apply();
}

void sparkle(jjOBJ@ obj) {
	obj.behave(BEHAVIOR::POLE);
	obj.frameID = (jjGameTicks/10) & 7;
	obj.determineCurFrame();
	obj.bulletHandling = HANDLING::IGNOREBULLET;
	obj.playerHandling = HANDLING::SPECIAL; // whatever doesn't interact at all
	obj.isBlastable = obj.isFreezable = obj.isTarget = obj.triggersTNT = false;
}

void getFunky(jjPLAYER@ p) {
	jjPAL candyPal;
	candyPal.load("DiamUlt-Candy.j2t");
	apply(candyPal);
	jjMusicLoad("Biggyzoom - Diamondus (Reggae Remix).mp3");
	groovyMode = true;
}

void stopFunky(jjPLAYER@ p) { // I could probably merge the two functions to be elegant and shorten the code but who gives a shit
	apply(jjBackupPalette);
	jjMusicLoad("DD-DiamFunk.xm");
	groovyMode = false;
}

bool onCheat(string &in cheat) { // made for testing but do go off
	if (cheat == "jjgroovy") {
			if (!groovyMode) { getFunky(jjLocalPlayers[1]); }
			else { stopFunky(jjLocalPlayers[1]); }
			jjAlert("jjgroovy", size: STRING::MEDIUM);
			return true;
	}
	if (cheat == "jjfast") {
		fastFeetMode[0] = 1400; // can only cheat in SP mode anyway
		jjSetModTempo(144);
		jjAlert("jjfast", size: STRING::MEDIUM);
		return true;
	}
	if (levelOver || CurrentPopup !is null) return true;
	else return false;
}

void onFunction0(jjPLAYER@ p) {
	p.showText("@@@@#D I A M O N G U S", STRING::LARGE);
}

void onFunction1(jjPLAYER@ p) {
	p.lighting = 60;
	if (!bossFight) {
		p.boss = jjAddObject(OBJECT::THING, 429*32, 69*32);
		jjMusicLoad("drgeno-boss2.mp3");
		bossFight = true;
		smeltIt = p.localPlayerID;
	}
}

void multiBossHealthHandler(jjOBJ@ obj) {
	int energy = 0;
	bool active = false;
	for (int i = 0; i < 2; i++) {
		if (obj.var[i] != 0) {
			active = true;
			if (jjObjects[obj.var[i]].behavior != BEHAVIOR::INACTIVE)
				energy += jjObjects[obj.var[i]].energy;
			else
				obj.var[i] = 0;
		}
	}
	if (active)
		obj.energy = (energy + 1) / 2;
	if (obj.counter++ < 20) {
	if (obj.counter == 5) { 
			int bossOne = jjAddObject(OBJECT::COKE, 422*32-16, 64*32-16);
			int bossTwo = jjAddObject(OBJECT::PEPSI, 433*32-16, 64*32-16);
			obj.var[0] = bossOne;
			obj.var[1] = bossTwo;
			jjLocalPlayers[smeltIt].activateBoss();
			}
	} else if (obj.energy <= 0) {
		if (bossFight) { endDialog(jjLocalPlayers[smeltIt]); }
		obj.delete();
	}
}

void bubbaMod(jjOBJ@ obj) {
	array<int> bosses(32);
	for (int i = 0; i < 32; i++) {
		bosses[i] = jjPlayers[i].boss;
	}
	obj.behave(BEHAVIOR::BUBBA);
	obj.isBlastable = obj.isFreezable = obj.isTarget = obj.triggersTNT = true;
	for (int i = 0; i < 32; i++) {
		jjPlayers[i].boss = bosses[i];
	}
}

void evaSpeaks(jjPLAYER@ p) {
	@CurrentPopup = Conversation(array<Screen@> = {
		Screen(top: Line("to be honest, i just really like kissing frogs.", right: Eva, direction: 1, color: 32)),
		Screen(top: Line("what can i say? they're CUTE! you should try it sometime.", right: Eva, direction: 1, color: 32)),
	});
}

void endDialog(jjPLAYER@ p) {
	@CurrentPopup = Conversation(array<Screen@> = {
			Screen(top: Line("this is the end of the example level! hope you had fun, and that you'll enjoy using the DIAMONDUS ULTIMATE tileset yourself!", left: Bubba, direction: -1, color: 24)),
			Screen(
				top: Line(left: Bubba),
				bottom: Line("wait a minute, why did we just fight TWO of you?!", right: Jazz, direction: 1)
			),
			Screen(
				top: Line("hoho! if you're indeed curious, look out for DEMON DASH episode 1: STRAIGHT OUTTA RETIREMENT!", left: Bubba, direction: -1, color: 24),
				bottom: Line(right: Jazz),
				finish: function() {
				bossFight = false;
				dialogOver = true;
				}
			),
		});
}

void onHelp(array<jjHELPPAGE@>& pages) {
	@pages[3] = (jjHELPPAGE(
		{
			jjHELPPARAGRAPH(
				"Blocks",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::CENTER
			),
			jjHELPPARAGRAPH(
				"Blocks frequently stand between you and a bountiful harvest of goodies and secrets. Fortunately, blocks are made to be smashed. The symbol (or lack thereof) on the face of each block indicates what you need to do to destroy it, and proceed to the riches beyond.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT
			),
			jjHELPPARAGRAPH(
				"Blast'em Blocks",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::LEFT
			),
			jjHELPPARAGRAPH(
				"Use your weapons to blast these blocks to smithereens. Different weapons are better suited to destroying blocks in certain locations, so if you can't seem to blast a block away with one weapon, try using another in your arsenal.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PLUS_SCENERY].firstAnim + 4].firstFrame + 10],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"Countdown Blocks",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::LEFT
			),
			jjHELPPARAGRAPH(
				"Countdown Blocks are Blast'em Blocks with an attitude. These toughies don't crack easily. You will need to blast them several times (just how many times is indicated by the numeral on each block) to make them fall to pieces.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PLUS_SCENERY].firstAnim + 4].firstFrame + 9],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"Weapon Blocks",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::LEFT
			),
			jjHELPPARAGRAPH(
				"These blocks can only be destroyed with the particular weapon pictured on their sides. For this reason, it is a good idea to try to save at least a few rounds of ammo in each of the weapons you possess in case you need them to blast through a Weapon Block and access the treasure behind.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PLUS_SCENERY].firstAnim + 4].firstFrame + 15],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"Speed Blocks",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::LEFT
			),
			jjHELPPARAGRAPH(
				"These plain-faced blocks can only be smashed by running through them at full speed, or by using special physical attacks.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PLUS_SCENERY].firstAnim + 4].firstFrame],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"(Note that in Demon Dash, Speed Blocks always have this unique embossing instead. Blocks without any symbol are reserved for special cases, not destructible by any of your conventionally available means.)",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PLUS_SCENERY].firstAnim + 4].firstFrame + 3],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"Switch Blocks",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::LEFT
			),
			jjHELPPARAGRAPH(
				"Switch blocks can be dealt with by finding and breaking the Switch Crates that influence them. Sometimes, you may also obtain a key or other pass that'll open these for you - the blocks are typically color-coded in such a case.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PLUS_SCENERY].firstAnim + 4].firstFrame + 1],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"Smash the right Switch Crates to remove solid Switch Blocks or to materialize ghost Switch Blocks.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PLUS_SCENERY].firstAnim + 4].firstFrame + 2],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"The Switch Crates that activate particular Switch Blocks may be a considerable distance from the blocks themselves. They're made of solid metal, so you can only destroy them with a buttstomp, special move, or TNT.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PICKUPS].firstAnim + 52].firstFrame],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"Butt-Stomp Blocks",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::LEFT
			),
			jjHELPPARAGRAPH(
				"There's nothing (literally) like a good old fashioned butt-stomping to smash these blocks to oblivion. Remember, jump, then push the down button in mid-air to execute the butt-stomp move. Physical attacks can also destroy these blocks.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PLUS_SCENERY].firstAnim + 4].firstFrame + 4],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"Jazz Tip",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::LEFT
			),
			jjHELPPARAGRAPH(
				"If you happen to have any TNT on you, the world is your oyster! Its explosive blast can easily break almost any block. The only ones it can't destroy are Switch Blocks, Lori Blocks and special plain-faced blocks.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimations[jjAnimSets[ANIM::AMMO].firstAnim + 59],
				position: HELP::FLOATLEFT
			)
		},
		"event object"
	));
	@pages[10] = (jjHELPPAGE(
		{ //beginning of array of jjHELPPARAGRAPH instances
			jjHELPPARAGRAPH(
				"Turtlettes",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::CENTER
			),
			jjHELPPARAGRAPH(
				"Tiny turtles that pose no immediate threat to the Jackrabbits. They wander around looking for something to eat. Blast 'em anyways for some extra points and maybe a bonus item! (If you're worried about having kids on your conscience, don't fret - they're all clones.)",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimations[jjAnimSets[ANIM::CUSTOM[3]].firstAnim],
				position: HELP::FLOATRIGHT
			)
		}, //end of array
		"enemy object event" //some tags for other script modules to potentially look at
	));
	pages.removeAt(14);
	pages.removeRange(11, 2);
	pages.insertAt(7, jjHELPPAGE(
		{
			jjHELPPARAGRAPH(
				"Level Ranking",
				textSize: STRING::MEDIUM,
				textAlignment: STRING::CENTER
			),
			jjHELPPARAGRAPH(
				"Jazz Jackrabbit 2: Demon Dash introduces a new mechanic intended to keep you coming back to the levels to keep getting better at them: it awards you ranks at the end of a level! When you complete a regular level (not a save room, not a secret level), you'll see a revamped summary screen that'll evaluate how well you did, using a special end-level score tally that's separate from your usual accumulation of points.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::CUSTOM[37]].firstAnim].firstFrame],
				position: HELP::FLOATLEFT
			),
			jjHELPPARAGRAPH(
				"The ranks you may be given are, from best to worst: S, A, B, C, D, E. Each level has a set score you need to collect on the summary screen to get an S rank. For this level you're playing right now, the score you need for an S rank is " + formatInt(int(maxScore * 1.5)) + ". Lower ranks are always the same fraction of this number.",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT
			),
			jjHELPPARAGRAPH(
				"Level Score: Simply how many points you collected in the level, just as you normally do. Pay attention that this is NOT your overall score that you see on your usual HUD - only the points you collected in this particular level count!",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PICKUPS].firstAnim + 37].firstFrame],
				position: HELP::RIGHT
			),
			jjHELPPARAGRAPH(
				"Time Bonus: How quickly you completed the level. You can check your time whenever you activate a checkpoint marker. Every Demon Dash level has a predetermined optimal completion time, which is usually pretty tight! You'll have to carefully balance between going for speed and picking up those precious points to be awarded that sweet, sweet S rank. For this level, you'll get the maximum amount of Time Bonus points if you finish it in " + formatInt(int(bestTime / 60)) + ":" + formatInt(bestTime % 60, '0', 2) + ".",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PICKUPS].firstAnim + 42].firstFrame],
				position: HELP::RIGHT
			),
			jjHELPPARAGRAPH(
				"Hit Penalty: The more harm you throw yourself at, the more level points you'll lose! Each time you take a hit, you lose 1000 points. If you're super-careful and manage to complete the entire level without taking damage even once, you'll get a whopping 50000 points bonus, which is sure to increase your rank by a grade or two!",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::ROBOT].firstAnim].firstFrame],
				position: HELP::RIGHT
			),
			jjHELPPARAGRAPH(
				"Gems: Have you heard that the gem total summed up at the end of a JJ2 level was always intended to grant you extra lives? Well, now in Demon Dash, it does! You'll receive a \"1 up\" for every 300 units you collected in a level (refer to the help paragraph on gems to see how much each of them is worth).",
				textSize: STRING::SMALL,
				textAlignment: STRING::LEFT,
				image: jjAnimFrames[jjAnimations[jjAnimSets[ANIM::PICKUPS].firstAnim].firstFrame],
				position: HELP::RIGHT
			)
		},
		"gamemode sp"
	));
}