Downloads containing BossrushV3.j2as

Downloads
Name Author Game Mode Rating
JJ2 1.23 vanilla: Miscellaneous stuff Violet CLM Multiple N/A Download file

File preview

uint gradientFrame;
jjPAL Palette = jjBackupPalette;
jjOBJ@ Robot;

array<float> originalLayerXSpeeds(3);

const uint TOP = 6, BOTTOM = 18;
const uint LEFT = 31, RIGHT = 100;
const uint BLOCKHEIGHT = 10;
const uint WIGGLEROOM = 17;
uint DrawX = LEFT, DrawY = 12;
array<array<array<uint16>>> Blocks;

void onLevelLoad() {
	jjTexturedBGUsed = true;
	jjTexturedBGStyle = TEXTURE::WARPHORIZON;
	jjTexturedBGTexture = TEXTURE::DIAMONDUSBETA;
	//jjTexturedBGFadePositionY = 0.8f;
	
	jjGenerateSettableTileArea(4, 0, 0, jjLayerWidth[4], jjLayerHeight[4]);
	for (uint i = 0; i < 3; ++i)
		originalLayerXSpeeds[i] = jjLayerXSpeed[5 + i];
	
	Palette.copyFrom(112, 16, 98, Palette);
	Palette.gradient(230,106,255, 86,47,106, 128,16);
	Palette.gradient(192,206,249, 121,165,224);
	Palette.gradient(180,192,245, 143,154,233, 160,16);
	for (uint i = 0; i < 32; ++i) {
		//if (i < 16)
		//	Palette.color[96 + i].setHSL(i * 16, 255, 128 - i*8);
		Palette.color[208 + i].setHSL(i * 8, 255, 128);
	}
	
	gradientFrame = jjAnimations[jjAnimSets[ANIM::CUSTOM[0]].allocate(array<uint> = {2})];
	jjPIXELMAP gradient(640, 480);
	for (uint y = 1; y < 480; ++y)
		for (uint x = 0; x < 640; ++x)
			gradient[x,y] = y/2;
	gradient.save(jjAnimFrames[gradientFrame]);
	jjPIXELMAP rainbow(20, 32);
	for (uint y = 0; y < 32; ++y)
		for (uint x = 0; x < 20; ++x)
			rainbow[x,y] = 208 + y;
	rainbow.save(jjAnimFrames[++gradientFrame]);
	jjAnimFrames[gradientFrame].hotSpotX = -10;
	
	jjCharacters[CHAR::SPAZ].doubleJumpCountMax = 2;
	
	jjObjectPresets[OBJECT::SILVERCOIN].behavior = Coin;
	jjObjectPresets[OBJECT::SILVERCOIN].points = 0; //don't create a score particle when collected
	jjObjectPresets[OBJECT::SILVERCOIN].deactivates = false;
	jjObjectPresets[OBJECT::SILVERCOIN].lightType = LIGHT::LASER;
	jjObjectPresets[OBJECT::SILVERCOIN].light = 1;
	jjObjectPresets[OBJECT::CARROT].behavior = Carrot;
	jjObjectPresets[OBJECT::CARROT].points = 0;
	jjObjectPresets[OBJECT::CARROT].deactivates = false;
	
	jjObjectPresets[OBJECT::DEVANROBOT].behavior = Boss;
	jjObjectPresets[OBJECT::DEVANROBOT].determineCurAnim(ANIM::ROBOT, 3);
	jjObjectPresets[OBJECT::DEVANROBOT].direction = -1;
	jjObjectPresets[OBJECT::DEVANROBOT].playerHandling = HANDLING::ENEMYBULLET; //I guess?
	jjObjectPresets[OBJECT::DEVANROBOT].animSpeed = 2;
	jjObjectPresets[OBJECT::DEVANROBOT].energy = 100;
	jjObjectPresets[OBJECT::DEVANROBOT].counter = 0;
	
	jjObjectPresets[OBJECT::STEADYLIGHT].behavior = FollowingLight;
	jjSetDarknessColor(jjPALCOLOR(255,255,255));
	
	{ //make slopes
		jjPIXELMAP slopeBase(0, 0, 96, 96, 4);
		array<jjMASKMAP@> singleWidthSlopeMask(3);
		array<array<jjMASKMAP@>> doubleWidthSlopeMask(2, array<jjMASKMAP@>(3));
		array<jjPIXELMAP@> singleWidthSlopeImageLeft(3);
		array<jjPIXELMAP@> singleWidthSlopeImageRight(3);
		array<array<jjPIXELMAP@>> doubleWidthSlopeImageLeft(2, array<jjPIXELMAP@>(3));
		array<array<jjPIXELMAP@>> doubleWidthSlopeImageRight(2, array<jjPIXELMAP@>(3));
		for (uint yTile = 0; yTile < 3; ++yTile) {
			@singleWidthSlopeMask[yTile] = @jjMASKMAP(false);
			@singleWidthSlopeImageLeft[yTile] = @jjPIXELMAP((yTile < 2) ? 0 : 25);
			@singleWidthSlopeImageRight[yTile] = @jjPIXELMAP((yTile < 2) ? 0 : 25);
			for (uint xTile = 0; xTile < 2; ++xTile) {
				@doubleWidthSlopeMask[xTile][yTile] = @jjMASKMAP(false);
				@doubleWidthSlopeImageLeft[xTile][yTile] = @jjPIXELMAP((yTile < 2) ? 0 : 25);
				@doubleWidthSlopeImageRight[xTile][yTile] = @jjPIXELMAP((yTile < 2) ? 0 : 25);
			}
		}
		for (uint y = 0; y < 96; ++y)
			for (uint x = 0; x < 64; ++x) {
				if (x < 32) {
					singleWidthSlopeMask[y / 32][x, y & 31] = (y + x) >= 52;
					if (y + x >= 32 && y + x < 96)
						singleWidthSlopeImageLeft[y / 32][x, y & 31] = slopeBase[x,y+x];
					if (y - x >= 0 && y - x < 64)
						singleWidthSlopeImageRight[y / 32][x, y & 31] = slopeBase[x, y - x + 32];
				}
				uint xh = x/2;
				doubleWidthSlopeMask[x / 32][y / 32][x & 31, y & 31] = (y + xh) >= 52;
				if (y + xh >= 32 && y + xh < 96)
					doubleWidthSlopeImageLeft[x / 32][y / 32][x, y & 31] = slopeBase[32+x,y+xh];
				if (y - xh >= 0 && y - xh < 64)
					doubleWidthSlopeImageRight[x / 32][y / 32][x, y & 31] = slopeBase[32+x, y - xh + 32];
			}
		for (uint yTile = 0; yTile < 3; ++yTile) {
			singleWidthSlopeMask[yTile].save(93 + yTile*10);
			singleWidthSlopeMask[yTile].save(98 + yTile*10 + TILE::HFLIPPED, true);
			singleWidthSlopeImageLeft[yTile].save(93 + yTile*10);
			singleWidthSlopeImageRight[yTile].save(98 + yTile*10);
			for (uint xTile = 0; xTile < 2; ++xTile) {
				doubleWidthSlopeMask[xTile][yTile].save(94 + xTile + yTile*10);
				doubleWidthSlopeMask[xTile][yTile].save(97 - xTile + yTile*10 + TILE::HFLIPPED, true);
				doubleWidthSlopeImageLeft[xTile][yTile].save(94 + xTile + yTile*10);
				doubleWidthSlopeImageRight[xTile][yTile].save(96 + xTile + yTile*10);
			}
		}
	}
	
	FindBlocks();
	
	onLevelReload();
	jjSetFadeColors();
}
void onLevelBegin() {
	jjLocalPlayers[0].lightType = LIGHT::NONE;
}
void onLevelReload() {
	Palette.apply();
	speedCounter = 3000;
	DefeatCounter = 0;
	playerTrail.resize(0);
	@Robot = jjObjects[jjAddObject(OBJECT::DEVANROBOT, 0, -64)];
	playerSpeed = 4; //initial distance between blocks
	DrawY = 12;
	LayoutLevel(false);
}

bool onDrawScore(jjPLAYER@ play, jjCANVAS@ screen) {
	if (!jjLowDetail) {
		const float scale = float(jjResolutionWidth) / 640.f;
		screen.drawResizedSpriteFromCurFrame(0, int(64 + jjSin(jjGameTicks << 1) * 64), gradientFrame - 1, scale, scale, SPRITE::ALPHAMAP, 176);
	}
	if (CoinsNeeded <= 9000 && Robot.counter == 0)
		screen.drawString(0x8000, 30, "" + play.coins + "/" + CoinsNeeded, STRING::MEDIUM);
	return true;
}
bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ screen) { return true; }

void FollowingLight(jjOBJ@ obj) {
	if (obj.state == STATE::START)
		obj.behave(BEHAVIOR::STEADYLIGHT); //pick up parameters
	obj.xPos = obj.xOrg + jjLocalPlayers[0].cameraX - (jjGameTicks%192);
}

class position {
	int xPos, yPos;
	position(float x, float y) { xPos = int(x); yPos = int(y); }
	position(){} //just so the script will compile
}
uint speedCounter = 0;
array<position> playerTrail;
float playerSpeed = 4;
bool playerOnFloor(jjPLAYER@ play) {
	return jjMaskedPixel(int(play.xPos), int(play.yPos) + 24);
}
void onPlayer(jjPLAYER@ play) {
	{
		play.idle = 0;
		if ((Robot.counter > 0 || Robot.behavior != Boss) && playerOnFloor(play)) { //robot in pain!
			speedCounter = 3000; //start over
			play.xSpeed = 0;
			play.specialMove = 0;
			play.coins = 0;
			play.keyRight = false;
			play.keyLeft = false;
			play.keyDown = false;
			play.keyUp = false;
			play.keyFire = false;
			play.keyJump = false;
			play.invincibility = -70;
			return;
		}
		if (play.xSpeed == 0 && play.buttstomp > 120 && Robot.counter == 0)
			play.hurt();
		play.keyRight = true;
		play.keyRun = true;
		while (playerTrail.length > uint(jjResolutionWidth / 2))
			playerTrail.removeLast();
		if (play.xSpeed > 1) //moving
			playerTrail.insertAt(0, position(play.xPos, play.yPos - 16));
		for (uint i = 0; i < playerTrail.length; ++i) {
			jjDrawSpriteFromCurFrame(playerTrail[i].xPos, playerTrail[i].yPos, gradientFrame, 0, SPRITE::BLEND_NORMAL, i);
		}
		//jjDrawString(play.xPos, play.yPos - 30, "" + play.xSpeed);
		if (play.buttstomp > 40 || play.specialMove > 0) { //not buttstomping
			playerSpeed = sqrt(speedCounter += 3) / 16.f;
			if (play.buttstomp <= 120 && play.fly == 0 && play.specialMove == 0) //started buttstomping
				play.xSpeed = playerSpeed / 2;
			else if (play.specialMove > 0)
				play.xSpeed = playerSpeed * 2;
			else play.xSpeed = playerSpeed;
		}
		if (speedCounter == 3003)
			play.morphTo(CHAR::SPAZ);
		if (speedCounter == 3099) {
			CoinsNeeded = 3 + jjDifficulty + DefeatCounter;
			play.showText("@@@@@#Collect " + CoinsNeeded + " Coins!", STRING::LARGE);
			play.activateBoss();
			play.boss = Robot.objectID;
		}
		if (play.xSpeed > 1 && playerOnFloor(play) && play.specialMove == 0 && jjGameTicks % int(play.xSpeed * 2) == 0)
			jjObjects[jjAddObject(OBJECT::EXPLOSION, play.xPos, play.yPos + 16)].determineCurAnim(ANIM::AMMO, 72);
		if (play.keyFire && play.specialMove == 0 && (playerOnFloor(play) || play.doubleJumpCount != -2)) {
			play.specialMove = 16;
			play.doubleJumpCount = -2;
			jjSample(play.xPos, play.yPos, SOUND::SPAZSOUNDS_KARATE7);
		}
		play.keyFire = false;
		
		if (play.xPos > RIGHT*32) {
			const int distanceX = int(RIGHT - LEFT - WIGGLEROOM) * 32;
			for (uint i = 0; i < 3; ++i)
				jjSetLayerXSpeed(5 + i, 0, false);
			play.offsetPosition(-distanceX, 0);
			for (uint i = 0; i < 3; ++i)
				jjSetLayerXSpeed(5 + i, originalLayerXSpeeds[i], false);
			for (uint i = 0; i < playerTrail.length; ++i)
				playerTrail[i].xPos -= distanceX;
			for (int i = jjObjectCount - 1; i >= 1; --i) {
				jjOBJ@ obj = jjObjects[i];
				if (obj.isActive)
					obj.xPos -= distanceX; //particularly the silver coins
			}
			LayoutLevel(true);
		}
	}
	/*if (play.ySpeed == 0 && play.buttstomp >= 121) { //on ground, can serve as checkpoint
		play.xOrg = play.xPos;
		play.yOrg = play.yPos;
	}*/
	if (abs(play.doubleJumpCount) == 1) {
		play.doubleJumpCount = 2;
		for (uint i = 0; i < 64; ++i) {
			jjPARTICLE@ spark = jjAddParticle(PARTICLE::SPARK);
			if (spark !is null) {
				spark.xPos = play.xPos;
				spark.yPos = play.yPos;
				spark.xSpeed = jjSin(i * 16) * 3;
				spark.ySpeed = jjCos(i * 16);
				spark.spark.color = (i & 0b11111000) + 8;
				spark.spark.colorStop = (i & 0b11111000) + 15;
			}
		}
	}
}

void Coin(jjOBJ@ obj) {
	obj.behave(BEHAVIOR::PICKUP, false);
	jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos + 4 * jjSin(int((jjGameTicks + obj.objectID * 8 + obj.xOrg + obj.yPos * 256) * 16)), obj.curFrame, obj.direction, SPRITE::SINGLEHUE, 208 + (jjGameTicks & 31));
	obj.xSpeed = obj.ySpeed = 0; //don't get shot
	if (obj.xPos < jjLocalPlayers[0].xPos - 96) {
		obj.particlePixelExplosion(0);
		obj.particlePixelExplosion(2);
		obj.delete();
		jjLocalPlayers[0].coins = 0;
		jjSamplePriority(SOUND::ROBOT_SHOOT);
		jjSamplePriority(SOUND::ROBOT_JMPCAN8);
	}
}
void Carrot(jjOBJ@ obj) {
	obj.behave(BEHAVIOR::PICKUP);
	obj.xSpeed = obj.ySpeed = 0; //don't get shot
	if (obj.xPos < jjLocalPlayers[0].xPos - WIGGLEROOM*32)
		obj.delete();
}

array<SOUND::Sample> MetalNoises = {SOUND::ROBOT_METAL1, SOUND::ROBOT_METAL2, SOUND::ROBOT_METAL3, SOUND::ROBOT_METAL4};
uint DefeatCounter = 0;
int CoinsNeeded = 9001; //will soon be reset
void Boss(jjOBJ@ obj) {
	if (obj.counter > 0) {
		--obj.counter;
		if (obj.counter > 250) {
			if (jjGameTicks & 31 == 0)
				jjLocalPlayers[0].cameraFreeze(obj.xPos, obj.yPos, true, false);
			if (jjGameTicks & 3 > 0) {
				jjOBJ@ shard = jjObjects[jjAddObject(OBJECT::SHARD, obj.xPos, obj.yPos, 0, CREATOR::OBJECT, BEHAVIOR::ROBOTSHARD)];
				shard.determineCurAnim(ANIM::ROBOT, 6 + (jjRandom() & 7));
				shard.lightType = LIGHT::POINT2;
				jjSamplePriority(MetalNoises[jjRandom() & 3]);
			} else {
				jjOBJ@ expl = jjObjects[jjAddObject(OBJECT::EXPLOSION, obj.xPos + (jjRandom() & 31) - 16, obj.yPos + (jjRandom() & 31) - 16)];
				expl.determineCurAnim(ANIM::AMMO, 77);
				expl.frameID = 4;
				expl.determineCurFrame();
				jjSamplePriority(SOUND::ROBOT_JMPCAN8);
				obj.justHit = 2;
			}
		} else if (obj.counter == 90) {
			if (obj.energy > 0)
				jjSamplePriority(SOUND::ROBOT_HYDRO2);
			else {
				obj.state = STATE::DONE;
				obj.particlePixelExplosion(0);
				obj.particlePixelExplosion(2);
			}
		} else if (obj.counter == 34) {
			jjLocalPlayers[0].cameraUnfreeze(false);
			if (obj.energy == 0)
				jjNxt("BossrushV3");
		}
	}
	if (obj.state != STATE::DONE) {
		jjPLAYER@ play = jjLocalPlayers[0];
		if (obj.yPos < play.yPos - 96 - 1.5)
			obj.yPos += 2;
		else if (obj.yPos > play.yPos - 96 + 1.5)
			obj.yPos -= 2;
		obj.xPos = play.xPos + 300 + jjSin(jjGameTicks * 5) * 8;
		
		if (play.coins >= CoinsNeeded) {
			play.coins = 0;
			++DefeatCounter;
			obj.energy -= 25;
			obj.counter = 6 * 70;
		}
		
		obj.frameID = jjGameTicks >> 2;
		obj.determineCurFrame();
		obj.draw();
		if (obj.counter == 0 && CoinsNeeded <= 9000) {
			if (play.coins != obj.var[0]) {
				if (play.coins > obj.var[0])
					obj.counterEnd = 40;
				obj.var[0] = play.coins;
			}
			if (obj.counterEnd > 0) --obj.counterEnd;
			for (int i = 0; i < CoinsNeeded; ++i) {
				int distance = (CoinsNeeded + 1 - play.coins);
				const int angle = int(i * 1024.f / float(CoinsNeeded)) + jjGameTicks*2;
				distance = (distance*10 + obj.counterEnd/4);
				jjDrawSpriteFromCurFrame(
					obj.xPos + jjSin(angle) * distance,
					obj.yPos - 10 + jjCos(angle) * distance,
					jjAnimations[jjAnimSets[ANIM::ROBOT]]
				);
				if (i < play.coins)
					jjDrawSpriteFromCurFrame(
						obj.xPos + jjSin(angle) * distance,
						obj.yPos - 10 + jjCos(angle) * distance,
						jjAnimations[jjObjectPresets[OBJECT::SILVERCOIN].curAnim],
						0,
						SPRITE::TRANSLUCENTSINGLEHUE, 208 + (jjGameTicks & 31)
					);
			}
		}
	}
}

void FindBlocks() {
	for (int blockL = LEFT; blockL < jjLayerWidth[4]; ++blockL) {
		int eventMarker = jjEventGet(blockL, 0);
		if (eventMarker == AREA::BELTLEFT) {
			int blockR = blockL + 1;
			while (jjEventGet(blockR, 0) != AREA::BELTRIGHT) ++blockR;
			array<array<uint16>> newBlock(blockR + 1 - blockL, array<uint16>(BLOCKHEIGHT, 0));
			for (uint x = 0; blockL <= blockR; ++blockL) {
				for (uint y = 1; y < BLOCKHEIGHT + 1; ++y) {
					uint16 tileID = jjTileGet(4, blockL, y);
					if (tileID != 0) {
						newBlock[x][y - 1] = tileID;
						//jjTileSet(4, blockL, y, 0); //not needed
					}
				}
				++x;
			}
			Blocks.insertLast(newBlock);
		}
	}
}
void LayoutLevel(bool transition) {
	const int SpaceBetweenBlocks = uint(playerSpeed);
	const uint layerHeight = jjLayerHeight[4];
	if (transition) {
		uint copyX = RIGHT - WIGGLEROOM;
		uint pasteX = LEFT;
		for (; copyX < DrawX; ++copyX) {
			for (uint y = 0; y < layerHeight; ++y)
				jjTileSet(4, pasteX, y, jjTileGet(4, copyX, y));
			++pasteX;
		}
		DrawX = pasteX;
	} else
		DrawX = LEFT;
	while (DrawX < RIGHT + WIGGLEROOM) {
		int space = SpaceBetweenBlocks;
		while (space-- >= 0) {
			for (uint y = 0; y < layerHeight; ++y)
				jjTileSet(4, DrawX, y, 0); //clear column
			++DrawX;
			if (space == 1)
				jjAddObject((jjRandom() & 31 > 0) ? OBJECT::SILVERCOIN : OBJECT::CARROT, DrawX * 32, (DrawY + BLOCKHEIGHT/2 - 1) * 32);
		}
		
		array<array<uint16>>@ block = @Blocks[jjRandom() % Blocks.length];
		for (uint x = 0; x < block.length; ++x) {
			for (uint y = 0; y < layerHeight; ++y) {
				uint yTile = y;
				if (y < DrawY)	//spread out to cover top/bottom with mask if needed
					yTile = DrawY;
				else if (y >= DrawY + BLOCKHEIGHT)
					yTile = DrawY + BLOCKHEIGHT - 1;
				jjTileSet(4, DrawX, y, block[x][yTile - DrawY]);
			}
			++DrawX;
		}
		
		uint rand = jjRandom();
		if (DrawY > TOP && (rand & 1) == 1)
			DrawY -= 2;
		else if (DrawY < BOTTOM && (rand & 2) == 2)
			DrawY += 2;
	}
}