Downloads containing DiamUltEx.j2as

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Diamondus UltimateFeatured Download DoubleGJ Tileset conversion 10 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"
#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 require "children-yay.wav"
#pragma require "party-horn.wav"
#pragma offer "DD-DiamFunk.xm"
#pragma offer "Biggyzoom - Diamondus (Reggae Remix).mp3"
#pragma offer "Gore.it"

///@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;

bool levelOver, fanfarePlayed, smallScreen = false;
int levelSeconds, levelMinutes, storeSeconds, storeMinutes, scoreSeconds, storeScoreSeconds, timerMsgCD;
float timeDifference, leftMargin, leftIndent, topMargin, bigLine, smallLine = 0;
array<int> startingScore(5, 0);
array<int> timeBonus(5, 0);
array<int> hitPenalty(5, -1000); // take into account start of level blink

const float maxScore = 110000; // greatest REALISTICALLY OBTAINABLE score to obtain in the level (do not calculate, playtest)
const int bestTime = 420; // best REALISTICALLY OBTAINABLE level completion time in seconds (don't just blast thru the level with jjinv/jjgod)

void onLevelLoad() { 	
	OrderTextAppearance.pipe = STRING::DISPLAYSIGN;
	OrderTextAppearance.spacing -= 3;
	uint8 i;
	for (i = 0; i < 256; ++i)
		if (jjAnimSets[ANIM::CUSTOM[i]] == 0) {
			@OrderFontAnim = jjAnimations[jjAnimSets[ANIM::CUSTOM[i++]].load(0, "DD-Anims.j2a")];
			break;
		}
	for (; i < 256; ++i)
		if (jjAnimSets[ANIM::CUSTOM[i]] == 0) {
			jjAnimSets[OrderPortraitSet = ANIM::CUSTOM[i]].load(1, "DD-Anims.j2a");
			break;
		}
		
	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");
	jjObjectPresets[OBJECT::CAKE].determineCurAnim(ANIM::CUSTOM[6], 8);
	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...
	
	for (int i = 0; i < (jjLocalPlayerCount + 1); i++) {
		if (jjDifficulty > 1) {
			if (jjDifficulty == 2) { jjLocalPlayers[i].timerStart(84000, false); }
			else { jjLocalPlayers[i].timerStart(63000, false); }
			jjLocalPlayers[i].timerPersists = true;
		}
	}
	
	jjSampleLoad(SOUND::INTRO_BOEM1, "children-yay.wav");
	jjSampleLoad(SOUND::INTRO_BOEM2, "party-horn.wav");
	jjObjectPresets[OBJECT::SAVEPOST].behavior = savePost;
	for (int i = 0; i < (jjLocalPlayerCount + 1); i++) {
		startingScore[i] = jjLocalPlayers[i].score;
	}
}

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;
	
	levelSeconds = storeSeconds;
	levelMinutes = storeMinutes;
	scoreSeconds = storeScoreSeconds;
}

bool onDrawScore(jjPLAYER@ play, jjCANVAS@ canvas) {
	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" + play.gems[GEM::PURPLE], STRING::MEDIUM);
	}
	if (CurrentPopup !is null) {
		CurrentPopup.Draw(canvas);
		return !CurrentPopup.DrawHUD();
	}
	if (levelOver) {
			canvas.drawString(int(leftMargin), int(topMargin), "Level Score", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
			canvas.drawString(int(leftMargin), int(topMargin) + int(smallLine), formatInt(play.score - startingScore[play.localPlayerID]), smallScreen ? STRING::SMALL : STRING::MEDIUM);
			canvas.drawString(int(leftMargin), int(topMargin) + int(smallLine) + int(bigLine), "Completion Time", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
			if (levelSeconds < 10) {
				canvas.drawString(int(leftMargin), int(topMargin) + (int(smallLine) * 2) + int(bigLine), formatInt(levelMinutes) + ":0" + formatInt(levelSeconds), smallScreen ? STRING::SMALL : STRING::MEDIUM);
			} else {
			canvas.drawString(int(leftMargin), int(topMargin) + (int(smallLine) * 2) + int(bigLine), formatInt(levelMinutes) + ":" + formatInt(levelSeconds), smallScreen ? STRING::SMALL : STRING::MEDIUM); }
			canvas.drawString(int(leftMargin), int(topMargin) + (int(smallLine) * 2) + (int(bigLine) * 2), "Time Bonus", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
			canvas.drawString(int(leftMargin), int(topMargin) + (int(smallLine) * 3) + (int(bigLine) * 2), formatInt(timeBonus[play.localPlayerID]), smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
			canvas.drawString(int(leftMargin), int(topMargin) + (int(smallLine) * 3) + (int(bigLine) * 3), "Hit Penalty", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
			canvas.drawString(int(leftMargin), int(topMargin) + (int(smallLine) * 4) + (int(bigLine) * 3), formatInt(hitPenalty[play.localPlayerID] * -1), smallScreen ? STRING::SMALL : STRING::MEDIUM);
			canvas.drawString(int(leftMargin), int(topMargin) + (int(smallLine) * 4) + (int(bigLine) * 4), "Total", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
			canvas.drawString(int(leftMargin), int(topMargin) + (int(smallLine) * 5) + (int(bigLine) * 4), formatInt(play.score - startingScore[play.localPlayerID] + timeBonus[play.localPlayerID] - hitPenalty[play.localPlayerID]), smallScreen ? STRING::SMALL : STRING::MEDIUM);
			canvas.drawString(int(leftMargin), int(topMargin) + (int(smallLine) * 5) + (int(bigLine) * 5), "RANK", smallScreen ? STRING::SMALL : STRING::MEDIUM, STRING::BOUNCE, smallScreen? 8 : 16);
			if ((play.score - startingScore[play.localPlayerID] + timeBonus[play.localPlayerID] - hitPenalty[play.localPlayerID]) * jjLocalPlayerCount >= maxScore * 1.5) {
					canvas.drawString(int(leftIndent), int(topMargin) + (int(smallLine) * 6) + (int(bigLine) * 5), "S", smallScreen ? STRING::MEDIUM : STRING::LARGE, STRING::PALSHIFT, -24); // add confetti particles coming from letter in some future version if possible (this is a call to arms!!)
					if (!fanfarePlayed) {
						jjSamplePriority(SOUND::INTRO_BOEM1);
						fanfarePlayed = true;
					}
				} else if ((play.score - startingScore[play.localPlayerID] + timeBonus[play.localPlayerID] - hitPenalty[play.localPlayerID]) * jjLocalPlayerCount > maxScore * 1.3) {
					canvas.drawString(int(leftIndent), int(topMargin) + (int(smallLine) * 6) + (int(bigLine) * 5), "A", smallScreen ? STRING::MEDIUM : STRING::LARGE, STRING::PALSHIFT, -48);
					if (!fanfarePlayed) {
						jjSamplePriority(SOUND::INTRO_BOEM2);
						fanfarePlayed = true;
					}
				} else if ((play.score - startingScore[play.localPlayerID] + timeBonus[play.localPlayerID] - hitPenalty[play.localPlayerID]) * jjLocalPlayerCount > maxScore * 1.1) {
					canvas.drawString(int(leftIndent), int(topMargin) + (int(smallLine) * 6) + (int(bigLine) * 5), "B", smallScreen ? STRING::MEDIUM : STRING::LARGE, STRING::PALSHIFT, -40);
				} else if ((play.score - startingScore[play.localPlayerID] + timeBonus[play.localPlayerID] - hitPenalty[play.localPlayerID]) * jjLocalPlayerCount > maxScore * 0.9) {
					canvas.drawString(int(leftIndent), int(topMargin) + (int(smallLine) * 6) + (int(bigLine) * 5), "C", smallScreen ? STRING::MEDIUM : STRING::LARGE, STRING::PALSHIFT, -32);
				} else if ((play.score - startingScore[play.localPlayerID] + timeBonus[play.localPlayerID] - hitPenalty[play.localPlayerID]) * jjLocalPlayerCount > maxScore * 0.7) {
					canvas.drawString(int(leftIndent), int(topMargin) + (int(smallLine) * 6) + (int(bigLine) * 5), "D", smallScreen ? STRING::MEDIUM : STRING::LARGE, STRING::PALSHIFT, 16);
				} else {
					canvas.drawString(int(leftIndent), int(topMargin) + (int(smallLine) * 6) + (int(bigLine) * 5), "E", smallScreen ? STRING::MEDIUM : STRING::LARGE, STRING::PALSHIFT, 8);
				}
	}
	return false;
}
bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ canvas) { return CurrentPopup !is null && !CurrentPopup.DrawHUD(); }
bool onDrawHealth(jjPLAYER@ play, jjCANVAS@ canvas) { return CurrentPopup !is null && !CurrentPopup.DrawHUD(); }
bool onDrawLives(jjPLAYER@ play, jjCANVAS@ canvas) { return CurrentPopup !is null && !CurrentPopup.DrawHUD(); }
bool onDrawPlayerTimer(jjPLAYER@ play, jjCANVAS@ canvas) { return CurrentPopup !is null && !CurrentPopup.DrawHUD(); }

void onPlayer(jjPLAYER@ play) {
	const bool inCutscene = CurrentPopup !is null;
	jjCharacters[play.charCurr].canRun = !inCutscene; //block revving
	if (inCutscene) {
		play.timerPause();
		play.invincibility = -15;
		if (!CurrentPopup.Do())
			@CurrentPopup = null;
		PressingKeyToMakeCutsceneGoAway = true;
		play.keyLeft = play.keyRight = play.keyDown = play.keyUp = play.keyRun = play.keyFire = play.keyJump = play.keySelect = false;
		play.idle = 0;
	} else {
		if (play.keyFire || play.keySelect) {
			if (PressingKeyToMakeCutsceneGoAway)
				play.keySelect = play.keyFire = false;
		} else
			PressingKeyToMakeCutsceneGoAway = false;
			play.timerResume();
	}
	
	if (play.blink == -207) { hitPenalty[play.localPlayerID] += 1000; }
	if (countdownEOL == 140) {
		levelOver = true;
		if (scoreSeconds > (bestTime * 3)) { timeBonus[play.localPlayerID] = 0;
		} else if (scoreSeconds > bestTime) {
		timeDifference = bestTime * 3 - scoreSeconds; // level is over once any player finishes, so don't need scoreSeconds to be an array
		timeBonus[play.localPlayerID] = int(ceil(maxScore * (timeDifference / (bestTime * 2)) / 100) * 100);
		} else { timeBonus[play.localPlayerID] = maxScore; }
	}
}

void onMain()
{
	updateGems();
	if (dialogOver) { countdownEOL++; }
	if (countdownEOL == 140) {
		jjNxt();
	}
	
	if ((jjGameTicks % 70) == 0 && !levelOver && CurrentPopup == null) {
		levelSeconds++;
		scoreSeconds++; // not for display, but for calculation!
	}
	if (levelSeconds == 60) {
		levelMinutes++;
		levelSeconds = 0;
	}
	smallScreen = jjSubscreenWidth <= 400;
	leftMargin = jjSubscreenWidth / 16;
	leftIndent = smallScreen ? jjSubscreenWidth / 10 : jjSubscreenWidth / 12;
	topMargin = jjSubscreenHeight / 12;
	bigLine = jjSubscreenHeight / 12;
	smallLine = jjSubscreenHeight / 18;
}

void onPlayerTimerEnd(jjPLAYER@ p) {
	p.kill();
	
	if (jjDifficulty > 1) {
	if (jjDifficulty == 2) { p.timerStart(84140, false); }
		else { p.timerStart(63140, false); }
	}
}

void updateGems()
{
  for(int i=1;i<jjObjectCount;i++)
  {
    if(jjObjects[i].isActive)
    {
      if(jjObjects[i].eventID==OBJECT::SUPERGEM)
      {
        jjObjects[i].var[0]=jjParameterGet(jjObjects[i].xOrg/32,jjObjects[i].yOrg/32,0,2)+1;
      }
      if(jjObjects[i].eventID==OBJECT::FLICKERGEM)
      {
        if(jjEventGet(jjObjects[i].xOrg/32,jjObjects[i].yOrg/32)==OBJECT::SUPERGEM)
        {
          jjObjects[i].var[0]=jjParameterGet(jjObjects[i].xOrg/32,jjObjects[i].yOrg/32,0,2)+1;
        }
        else if(jjEventGet(jjObjects[i].xOrg/32,jjObjects[i].yOrg/32+1)==OBJECT::GEMSTOMP)
        {
          jjObjects[i].var[0]=jjParameterGet(jjObjects[i].xOrg/32,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(obj.xOrg / 32, obj.yOrg / 32, 0, 3);
    obj.var[7] = jjParameterGet(obj.xOrg / 32, 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;
	}
	return false;
}

void savePost(jjOBJ@ save) {
	switch(save.state) {
	case STATE::START:
		timerMsgCD = 0;
		break;
	case STATE::ACTION:
		if (timerMsgCD == 0) { 
			if (jjLocalPlayerCount == 1) { // not abusable in coop this way until onLevelReload ranking code is improved 
			storeSeconds = levelSeconds;
			storeMinutes = levelMinutes;
			storeScoreSeconds = scoreSeconds;
			}
			if (levelSeconds < 10) {
				jjAlert(formatInt(storeMinutes) + ":0" + formatInt(storeSeconds));
			} else {
				jjAlert(formatInt(storeMinutes) + ":" + formatInt(storeSeconds)); }
			timerMsgCD = 100;
		}
		break;
	case STATE::DONE:
		if (timerMsgCD > 0) { timerMsgCD--; }
		break;
	}	
	save.behave(BEHAVIOR::CHECKPOINT);
}

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("Gore.it");
		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;
				}
			),
		});
}