Downloads containing StoneAbyss8.j2as

Downloads
Name Author Game Mode Rating
JJ2+ Only: Stone AbyssFeatured Download Bloody_Body Single player 9.6 Download file

File preview

//spikes from IC - tubelec can be inserted to the tileset as well.
//why not to add a moving (platform) spiky ball to the boss area?
//coins in crates?
//colored gem rings
//autobomb for that central crate can be a solution
//double ammo
jjPAL Boss;
bool final=false,devanactivated=false, devanisdefeated = false;
int b=0, i,d=0;
uint elapsed = 0;

const float DEVANBACKGROUNDSPEED = 2;
const array<OBJECT::Object> devanGoodies = {OBJECT::FIVEHUNDREDBUMP, OBJECT::APPLE, OBJECT::REDGEM, OBJECT::SEEKERAMMO3, OBJECT::CAKE, OBJECT::CHEESE, OBJECT::BURGER};

	


 void onLevelLoad() {
 
//jjObjectPresets[OBJECT::DEVANROBOT].isBlastable = false;
jjObjectPresets[OBJECT::DEVANROBOT].ySpeed = 3.5;	//Will be referenced later for how fast he moves up and down. Could have been an
								//an external constant or something, but this is more semantic.
jjObjectPresets[OBJECT::DEVANROBOT].behavior = DevanBoss;
jjObjectPresets[OBJECT::DEVANROBOT].playerHandling = HANDLING::ENEMY;
jjObjectPresets[OBJECT::DEVANROBOT].energy = 100; 
 
jjObjectPresets[OBJECT::SPIKEPLATFORM].behavior = MovingPlatform;
jjObjectPresets[OBJECT::SPIKEPLATFORM].state = STATE::WAIT;
jjObjectPresets[OBJECT::SPIKEPLATFORM].determineCurAnim(ANIM::SPIKEPLAT,0);
jjObjectPresets[OBJECT::SPIKEPLATFORM].isFreezable = false;
jjObjectPresets[OBJECT::SPIKEPLATFORM].deactivates = false;

jjObjectPresets[OBJECT::SPIKEBOLL].behavior = MovingSpikeboll;
jjObjectPresets[OBJECT::SPIKEBOLL].state = STATE::WAIT;
jjObjectPresets[OBJECT::SPIKEBOLL].determineCurAnim(ANIM::SPIKEBOLL,0);
jjObjectPresets[OBJECT::SPIKEBOLL].isFreezable = false;
jjObjectPresets[OBJECT::SPIKEBOLL].deactivates = false;

jjObjectPresets[OBJECT::SKELETON].behavior = TufturtleRic;//Tufturt itself (like some other enemies) doesn't cause ricochets. So I had to use sceleton instead.
jjObjectPresets[OBJECT::SKELETON].scriptedCollisions = true;
jjObjectPresets[OBJECT::SKELETON].determineCurAnim(ANIM::TUFTUR, 0);
jjObjectPresets[OBJECT::SKELETON].xSpeed = 1;
jjObjectPresets[OBJECT::SKELETON].energy = 8;
jjObjectPresets[OBJECT::SKELETON].points = 600;
 
jjPalette.gradient(255, 77, 77,			154, 17, 17,		 	 		112, 8, 1.0);
jjPalette.gradient(129, 9, 9,			0, 0, 0,		 	 		120, 8, 1.0);
	//jjPalette.apply();
	
	Boss.gradient(0, 0,0,             0, 0,0,         0, 10, 1.0);
	Boss.gradient(255, 255,255,             255, 255,255,         10, 6, 1.0);
	Boss.gradient(199, 255,0,             199, 255,0,         16, 1, 1.0);
	Boss.gradient(143, 219,0,             0, 11,0,         17, 7, 1.0);
	Boss.gradient(255, 0,0,             163, 0,0,         24, 4, 1.0);
	Boss.gradient(135, 0,0,             11, 0,0,         28, 4, 1.0);
	Boss.gradient(187, 227,255,             0, 139,255,         32, 4, 1.0);
	Boss.gradient(0, 107,203,             0, 7,11,         36, 4, 1.0);
	Boss.gradient(255, 255,0,             255, 199,0,         40, 2, 1.0);
	Boss.gradient(255, 147,0,             255, 95,0,         42, 2, 1.0);
	Boss.gradient(203, 55,0,             11, 0,0,         44, 4, 1.0);
	Boss.gradient(251, 139,183,       239, 0,99,         48, 4, 1.0);            
	Boss.gradient(191, 0,71,      55, 0,19,         52, 4, 1.0);
	Boss.gradient(220, 165,113,             154, 129,100,         56, 3, 1.0);
	Boss.gradient(219, 195,0,             11, 7,0,         59, 5, 1.0);
	Boss.gradient(255, 243,211,             255, 243,211,         64, 1, 1.0);
	Boss.gradient(219, 207,175,             11, 7,7,         65, 7, 1.0);
	Boss.gradient(211, 231,255,             211, 231,255,         72, 1, 1.0);
	Boss.gradient(171, 195,219,             107, 127,155,         73, 3, 1.0);
	Boss.gradient(75, 95,119,             7, 7,11,         76, 4, 1.0);
	Boss.gradient(0, 255,195,             0, 11,7,         80, 8, 1.0);
	Boss.gradient(231, 119,255,             11, 0,7,         88, 8, 1.0);

	Boss.gradient(230, 200, 80,		30, 20, 0,		 	 		96, 16, 1.0);//metal platforms
	Boss.gradient(255, 77, 77,			154, 17, 17,		 	 	112, 8, 1.0);//wire and carrot bump
	Boss.gradient(129, 9, 9,			0, 0, 0,		 	 		120, 8, 1.0);//wire and carrot bump
	Boss.gradient(200, 120, 0,			20, 0, 0,		 	 		128, 16, 1.0);//wood
	Boss.gradient(210, 165, 140,		190, 152, 130,		 	 		144, 2, 1.0);
	Boss.gradient(255, 150, 20,		25, 5, 0,		 		 	146, 14, 1.0);//windows on pipes, lamps
	Boss.gradient(180, 180, 120,			20, 20, 0,		 	 		160, 16, 1.0);//board
	Boss.gradient(100, 40, 0,			0, 0, 20,		 	 		176, 16, 1.0);//background
	Boss.gradient(70, 40, 20,			0, 0, 0,		 	 		192, 16, 1.0);//background wall
	Boss.gradient(170, 140, 120,		30, 10, 0,		 	 		225, 16, 1.0);//wall
	
	//Boss.apply();
}


void onMain(){
//if (devanisdefeated = false)
//{jjAlert("jjGameTicks "+ formatInt(jjGameTicks, "1"));}
if (jjLocalPlayers[0].bossActivated) {
			d++;}
			
if (b<=99 && final && (jjGameTicks % 5) == 0) { 
b++;
		jjPalette.reset();
		jjPalette.copyFrom(
			1,		
			254,		
			1,		
			Boss,	
			b/100.0	
		);
		jjPalette.apply();
		}
		else if (b==99) {
		Boss.apply();
		
		}
		else if (b>=1) {
		++elapsed;
		if (devanisdefeated == false)
		{doDevanBattle();
		//jjAlert("jjGameTicks "+ formatInt(jjGameTicks, "1"));
		}
		}
updateGems();

//jjAlert("d "+ formatInt(d, "1"));

		}
 
void onLevelReload() {
jjSetLayerYSpeed(5,0,true);
jjSetLayerYSpeed(6,0,true);
jjSetLayerYSpeed(7,0,true);
jjSetLayerYSpeed(8,0,true);
devanisdefeated = false;
final=false;
b=0;
jjPalette.reset();
}

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 MovingPlatform(jjOBJ@ plat) {

//	jjDrawTile(plat.xPos - 31, plat.yPos - 14, 854);
	//jjDrawTile(plat.xPos + 1,  plat.yPos - 14, 855);
switch (plat.state){
case STATE::WAIT:
plat.state = STATE::FADEIN;
break;
case STATE::DEACTIVATE:
		plat.xOrg = plat.xAcc;
		plat.yOrg = plat.yAcc;
break;		
case STATE::FADEIN:

if (plat.yOrg<100*32&&plat.xOrg>51*32&&plat.xOrg<53*32&&jjTriggers[2])
	plat.yOrg = (82*32) + jjSin(++plat.counter*(1+0.2*jjDifficulty))*(16*32);
else if (plat.xOrg>60*32&&plat.xOrg<62*32&&plat.yOrg<100*32)
	plat.yOrg = (88*32) + abs(jjSin(++plat.counter*(1+jjDifficulty))*(8*32));
else if (plat.xOrg>73*32&&plat.xOrg<75*32&&plat.yOrg<40*32)
	plat.yOrg = (28*32) + (jjSin(++plat.counter*(1+jjDifficulty))*(8*32));	
else if (plat.xOrg>65*32&&plat.xOrg<67*32&&plat.yOrg<100*32)
	plat.yOrg = (85*32) + abs(jjSin(++plat.counter*(1.2+jjDifficulty))*(11*32));
else if (plat.xOrg>80*32&&plat.xOrg<82*32&&plat.yOrg<100*32)
	plat.yOrg = (85*32) + abs(jjSin(++plat.counter*(1.2+jjDifficulty))*(11*32));
else if (plat.xOrg>85*32&&plat.xOrg<87*32&&plat.yOrg<100*32)
	plat.yOrg = (88*32) + abs(jjSin(++plat.counter*(1+jjDifficulty))*(8*32));
 if (plat.yOrg>117*32&&plat.yOrg<130*32)
	plat.yOrg = (118*32) + abs(jjSin(++plat.counter*(1+jjDifficulty))*(10*32));
if (plat.xSpeed!=0||plat.ySpeed<0){
if (jjGameTicks%10==0)
{jjSample(plat.xOrg, plat.yOrg, SOUND::BUBBA_BUBBAEXPLO);}
		}
		break;
}
	plat.behave(BEHAVIOR::PLATFORM, true); 
	
}

void MovingSpikeboll(jjOBJ@ plat) {

//	jjDrawTile(plat.xPos - 31, plat.yPos - 14, 854);
	//jjDrawTile(plat.xPos + 1,  plat.yPos - 14, 855);
switch (plat.state){
case STATE::WAIT:
plat.state = STATE::FADEIN;
break;
case STATE::DEACTIVATE:
		plat.xOrg = plat.xAcc;
		plat.yOrg = plat.yAcc;
break;		
case STATE::FADEIN:

if (plat.xOrg>73*32&&plat.xOrg<75*32)
	plat.yOrg = (120*32) - jjSin(++plat.counter*(1+0.2*jjDifficulty))*(10*32);

if (plat.xSpeed!=0||plat.ySpeed<0){
if (jjGameTicks%10==0)
{jjSample(plat.xOrg, plat.yOrg, SOUND::BUBBA_BUBBAEXPLO);}
		}
		break;
}
//	plat.behave(BEHAVIOR::SPIKEBOLL, true); 
	
}

void TufturtleRic (jjOBJ@ enemy) {
jjPLAYER@ play = jjLocalPlayers[0];
	if (enemy.state == STATE::START) {
		enemy.direction = enemy.xSpeed = 1;
		enemy.counter = (jjRandom()&45) + 70;
		enemy.state = STATE::WALK;
	}

	enemy.behave(BEHAVIOR::WALKINGENEMY);
}

void RisingPickup(jjOBJ@ pickup) {
	pickup.yPos = pickup.yPos - 3*DEVANBACKGROUNDSPEED;
	pickup.xSpeed = pickup.ySpeed = 0; //don't want anyone shooting it out of the way
	if (pickup.eventID != OBJECT::FIVEHUNDREDBUMP && pickup.eventID != OBJECT::CARROTBUMP) {
	pickup.behave(BEHAVIOR::PICKUP, true); //mostly just handles the drawing, since it's not allowed to have speeds
}
	else if (pickup.eventID == OBJECT::FIVEHUNDREDBUMP || pickup.eventID == OBJECT::CARROTBUMP) {
	pickup.behave(BEHAVIOR::BUMP, true);}
}

void doDevanBattle() {
jjSetLayerYSpeed(5,4,true);
jjSetLayerYSpeed(6,3,true);
jjSetLayerYSpeed(7,2,true);
jjSetLayerYSpeed(8,1,true);
	//jjLayerYOffset[5] = elapsed * 2;
	//jjLayerYOffset[6] = elapsed * 1.5;
	//jjLayerYOffset[7] = elapsed;
	//jjLayerYOffset[8] = elapsed;//not using auto speeds because we want to be able to reset this whole thing afterwards
if (elapsed & 63 == 0) {
jjOBJ@ obj = jjObjects[jjAddObject(OBJECT::FIVEHUNDREDBUMP,  35 * 32 + jjRandom()%(32*24), 307*32)];
obj.lightType = LIGHT::BRIGHT;
		obj.light = 10;
		obj.behavior = RisingPickup; 
}
if (elapsed & 511 == 0) {
jjOBJ@ obj = jjObjects[jjAddObject(OBJECT::CARROTBUMP,  35 * 32 + jjRandom()%(32*24), 307*32)];
obj.lightType = LIGHT::BRIGHT;
		obj.light = 10;
		obj.behavior = RisingPickup; 
}

if (elapsed & 511 == 0) {
jjOBJ@ obj = jjObjects[jjAddObject(OBJECT::SPARK,  35 * 32 + jjRandom()%(32*24), 307*32)];
//obj.lightType = LIGHT::BRIGHT;
		//obj.light = 10;
		//obj.behavior = SPARK; 
}

	if (elapsed & 63 == 0) {
		jjOBJ@ obj = jjObjects[jjAddObject(devanGoodies[jjRandom()%devanGoodies.length], 35 * 32 + jjRandom()%(32*24), 307*32)];
		if (obj.eventID == OBJECT::APPLE) {
			obj.determineCurAnim(ANIM::ROBOT,0); //The robot boss's spike ball.
			obj.playerHandling = HANDLING::ENEMY; //hurts (one heart) to the touch, and bullets may potentially collide with it
			obj.energy = 0; //undestroyable by bullets... could still be destroyed by buttstomps, but the player is flying, so that's not an issue
		}
		obj.lightType = LIGHT::BRIGHT;
		obj.light = 10;
		obj.behavior = RisingPickup; //see below
	}
}


void DevanBoss(jjOBJ@ devan) {
jjPLAYER@ play = jjLocalPlayers[0];
if ( devan.energy==0) 
 play.cameraFreeze(36*32 + 320 - (jjResolutionWidth >> 1) + play.subscreenX, 289*32 + 240 - (jjResolutionHeight >> 1) + play.subscreenY, false, true);
			{		devan.counter==0;
					devan.counter += 1; 
			if (devan.energy==0&&++devan.counter>210)
			{ //play.cameraFreeze(36*32 + 320 - (jjResolutionWidth >> 1) + play.subscreenX, 289*32 + 240 - (jjResolutionHeight >> 1) + play.subscreenY, false, true);
			//jjEventSet(play.xPos / 32, play.yPos / 32, AREA::EOL);
			jjTriggers[30]=true;
			//play.cameraUnfreeze();
			jjLocalPlayers[0].fly = FLIGHT::NONE;
			devanisdefeated = true;
			//play.showText("@@Don't you think you've defeated me?@See you in HELL!");
			//if (++devan.counter>500)
			//{play.cameraUnfreeze();}
			//if (++devan.counter>450)
			//{play.warpToID(29,true);}
			}
	}
if (d==1)
 {devan.state == STATE::START;}
	if (devan.energy <= 0 && devan.state != STATE::DONE) { //shot 100+ times; time to go flying away
		devan.bulletHandling = HANDLING::IGNOREBULLET;  //no more collisions
		devan.playerHandling = HANDLING::EXPLOSION;	//
		devan.state = STATE::DONE;
		devan.determineCurAnim(ANIM::DEVAN, 4); //rotating
		devan.ySpeed = -5;
		devan.xSpeed = -3 * devan.direction;
		jjLocalPlayers[0].activateBoss(false);
		jjLocalPlayers[0].boss = 0;
	}

	
	
	switch(devan.state) {
		case STATE::DEACTIVATE:
			
			//jjEventSet(play.xPos / 32, play.yPos / 32, AREA::EOL);
			devan.delete(); //the xOrg and yOrg properties have changed at this point, so .deactivate() wouldn't be safe
			jjParameterSet(52, 290, -1, 1, 0); //object no longer exists, so JJ2 will create it again next time it's wanted
			return;
		case STATE::START:
			if (jjLocalPlayers[0].bossActivated) {
			
			
			
				jjLocalPlayers[0].boss = devan.objectID;
				devan.determineCurAnim(ANIM::BOSS, 0, false);
					//There are no actual boss events in the level, so JJ2 doesn't know
					//that it needs to load the sprites for the boss health meter.
				devan.state = STATE::FLOAT;
				devan.determineCurAnim(ANIM::DEVAN, 3); devan.var[1] = 6; devan.animSpeed = 15;
				devan.noHit = 16;
				//no break, so fall through to case STATE::FLOAT
			} else return;	//JJ2's real boss behaviors tend to switch to STATE::DELAYEDSTART
					//immediately and do the waiting for some player to have .bossActivated
					//equal true from there, but there's no harm in sticking with STATE::START
					//if there aren't any properties that need to be set in it
		case STATE::FLOAT:
			{
				int nearestPlayerID = devan.findNearestPlayer(512*512); //measures in square pixels
				if (nearestPlayerID >= 0) //negative number means no players exist within that range
					devan.direction = (devan.xPos > jjPlayers[nearestPlayerID].xPos) ? -1 : 1; //face you!
			}
			devan.yPos = devan.yOrg + jjSin(jjGameTicks*4)*10;
				//Float up and down a little, try to make it look like it's falling.
			if (++devan.counterEnd == 35) { //If Devan is idling, which is the whole point of STATE::FLOAT,
				devan.counterEnd = 0;	//every half second he randomly does something else! Sometimes
							//that something else is nothing; sometimes it's shooting a bullet;
							//other times he changes his state (state) to something else
							//entirely and doesn't return to STATE::FLOAT for a while.
				jjOBJ@ bullet;
				
				switch(jjRandom()&31) {
					case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: //do nothing
						break;
					case 10: case 11: case 12: //fall up
						devan.state = STATE::BOUNCE;
						devan.var[0] = 1; //Call randomizeDevanTarget() once done bouncing.
						devan.yOrg = 284*32; //Target yPos.
						break;
					case 13: case 14: case 15: //fall down
						devan.state = STATE::FALL;
						devan.var[0] = 1; //Call randomizeDevanTarget() once done falling.
						devan.yOrg = 306*32; //Target yPos.
						break;
					case 16: case 17: case 18: case 19: //teleport
						devan.state = STATE::FADEOUT;
						jjSample(devan.xPos, devan.yPos, SOUND::COMMON_TELPORT1, 0, 0);
						devan.determineCurAnim(ANIM::DEVAN, 2); devan.var[1] = 7; devan.animSpeed = 7;
						devan.bulletHandling = HANDLING::IGNOREBULLET;
						devan.frameID = 0;
						break;
					default: //shoot
						@bullet = jjObjects[jjAddObject(OBJECT::BLASTERBULLETPU, devan.xPos, devan.yPos, devan.objectID, CREATOR::OBJECT)]; //BLASTERBULLET would work as well, but this saves us the labor of setting .animSpeed (damage dealt) to 2 manually
						jjSample(devan.xPos, devan.yPos, SOUND::AMMO_FIREGUN1A);
						bullet.determineCurAnim(ANIM::DEVAN, 0);
						bullet.playerHandling = HANDLING::ENEMYBULLET;
						bullet.xSpeed = devan.direction * 4.5;
						bullet.counterEnd += 10; //lasts longer
						break;
				}
			}
			break;
		case STATE::FADEOUT: //warp away
			if (devan.frameID == 6) {
				devan.state = STATE::FADEIN;
				jjSample(devan.xPos, devan.yPos, SOUND::COMMON_TELPORT2, 0, 0);
				devan.determineCurAnim(ANIM::DEVAN, 5); devan.var[1] = 7; devan.animSpeed = 7;
				devan.frameID = 0;
				randomizeDevanTarget(devan);
				devan.yPos = devan.yOrg;
			}
			break;
		case STATE::FADEIN: //finish warping
			if (devan.frameID == 6) {
				devan.state = STATE::FLOAT;
				devan.determineCurAnim(ANIM::DEVAN, 3); devan.var[1] = 6; devan.animSpeed = 15;
				devan.noHit = 16;
				devan.frameID = 0;
			}
			break;
		case STATE::FALL: //move down
			devan.direction = (devan.xPos > jjLocalPlayers[0].xPos) ? -1 : 1; //Always look towards player 1.
			if (devan.yPos < devan.yOrg) {
				devan.yPos = devan.yPos + devan.ySpeed;
			} else if (devan.var[0] == 1) { //Just fell offscreen; now bounce back somewhere else!
				devan.state = STATE::BOUNCE;
				devan.var[0] = 0;
				randomizeDevanTarget(devan);
			} else {
				devan.state = STATE::FLOAT;
			}
			break;
		case STATE::BOUNCE: //move up
			devan.direction = (devan.xPos > jjLocalPlayers[0].xPos) ? -1 : 1; //Always look towards player 1.
			if (devan.yPos > devan.yOrg) {
				devan.yPos = devan.yPos - devan.ySpeed;
			} else if (devan.var[0] == 1) { //Just bounced offscreen; now fall back somewhere else!
				devan.state = STATE::FALL;
				devan.var[0] = 0;
				randomizeDevanTarget(devan);
			} else {
				devan.state = STATE::FLOAT;
			}
			break;
		case STATE::FREEZE:
			if (devan.freeze > 0) {
				devan.draw();
				devan.freeze -= 4;
			}
			if (devan.freeze < 4) {
				devan.unfreeze(0);
				devan.state = devan.oldState;
			}
			break;
		case STATE::DONE: //defeated
		//play.showText("@@Don't you think you've defeated me?@See you in HELL!");
			if (devan.yPos < 306*32) { //still flying away
				devan.xPos = devan.xPos + devan.xSpeed;
				devan.yPos = devan.yPos + devan.ySpeed;
				devan.ySpeed = devan.ySpeed + .1;
			} else { //End the scene and set up the next one.
				devan.deactivate(); //in case he's needed later
				jjTriggers[0] = true;
				//flags[fDevan] = false;
				if (jjPlayerCount > 1 || jjGameMode != GAME::SP) { //No boat scene for cooperative play, just wouldn't work
					jjLocalPlayers[0].fly = FLIGHT::NONE;
					jjNxt();
				} else {
					//flags[fBoat] = true;
					//reachedCheckpoint = true;
					jjTriggers[31] = false;	//so the bridges don't trigger themselves again
								//when revisited before they're even visible
					for (int i = 1; i < jjObjectCount; ++i) {
						jjOBJ@ obj = jjObjects[i];
						if (obj.isActive && obj.eventID == OBJECT::BRIDGE)
							obj.deactivate();
					}
				}
			}
			break;		
	}
	if ((jjGameTicks & devan.animSpeed) == 0) ++devan.frameID;
	devan.frameID %= devan.var[1];
	devan.determineCurFrame();
	devan.draw();
}

void randomizeDevanTarget(jjOBJ@ devan) { //Used whenever Devan warps away or has fallen/bounced offscreen and is ready to come back
	devan.xPos = 35 * 32 + (jjRandom()%(32*23)) + 16;
	devan.yOrg = 287 * 32 + (jjRandom()%(32*18)) + 16;
}

	void onFunction15(jjPLAYER@ play) {
 jjTriggers[15]=true;
}
	void onFunction31(jjPLAYER@ play) {
	play.showText("@@Hey, rodent! You know... @I hate the rabbitkind!");
 jjTriggers[31]=true;
}

	void onFunction1(jjPLAYER@ play) {
 jjPalette.reset();
}

	void onFunction2(jjPLAYER@ play) {
	//play.activateBoss();
	jjTriggers[19]=true;
	jjLocalPlayers[0].bossActivated;
	play.cameraFreeze(36*32 + 320 - (jjResolutionWidth >> 1) + play.subscreenX, 289*32 + 240 - (jjResolutionHeight >> 1) + play.subscreenY, false, true);
 final=true;	
}

	void onObjectHit(jjOBJ@ obj, jjOBJ@ bullet, jjPLAYER@ play, int force) {
if (obj.eventID == OBJECT::FASTFEET) { 
	play.timerStart(2000/(jjDifficulty+1));
		play.jumpStrength = play.jumpStrength - 8;
		play.showText("@Heigth of jumps @ temporarily increased!", STRING::SMALL);
		obj.behavior = BEHAVIOR::EXPLOSION2; //this is ESSENTIAL. just like enemies die by getting their states set to STATE::KILL, and bullets die by getting their states set to STATE::EXPLODE, pickups die by getting their behavior set to BEHAVIOR::EXPLOSION2. yes, sometimes a little consistency is in fact too much to ask for.
		obj.scriptedCollisions = false; //or obj.playerHandling = HANDLING::EXPLOSION; or something like that
		obj.frameID = 0;
		jjSample(obj.xPos, obj.yPos, SOUND::BUBBA_BUBBABOUNCE2);
	}
	
	else if (obj.eventID == OBJECT::SKELETON){
	
			if (obj.energy <= 0) {
					if (bullet !is null) {
						if ((bullet.var[6] & 2) == 2) { //toaster and its ilk
							obj.particlePixelExplosion(1); //burny explosion
							jjSample(obj.xPos, obj.yPos, SOUND::COMMON_BURN);
						} else {
							obj.particlePixelExplosion(0);
						}
						obj.grantPickup(play, (bullet.eventID == OBJECT::BLASTERBULLET) ? 5 : 10);
							//JJ2 only ever calls grantPickup for enemies/crates destroyed
							//by bullets, but you can branch out a bit if you like
					} else {
						obj.particlePixelExplosion(2); //killed by physical contact
						jjSample(obj.xPos, obj.yPos, SOUND::COMMON_SPLAT1);
					}
					obj.state = STATE::KILL; //let the object's behavior function take care of deleting it
					play.score=play.score+600;
					jjPARTICLE@ particle = jjAddParticle(PARTICLE::STRING);
			if (particle !is null) {
				particle.xPos = obj.xPos;
				particle.yPos = obj.yPos;
				particle.string.text = "600";
				particle.ySpeed = -1.2;
				particle.xSpeed = -1.1;
			}	
					
				}
		
		if (force == 0) 
				{play.hurt();}
		else if (bullet.direction == obj.direction) {
				bullet.ricochet();
				//obj.bulletHandling = HANDLING::DESTROYBULLET;
				obj.energy += 1;
			}
			else {
			//play.showText("It works!", STRING::SMALL);
				obj.energy -= 1;
				obj.justHit = 5;
				bullet.delete();
			}
				
			}
	
	
		
			

	
}